some documentation
[oweals/gnunet.git] / src / ats / gnunet-service-ats_addresses_mlp.c
1 /*
2      This file is part of GNUnet.
3      (C) 2011 Christian Grothoff (and other contributing authors)
4
5      GNUnet is free software; you can redistribute it and/or modify
6      it under the terms of the GNU General Public License as published
7      by the Free Software Foundation; either version 3, or (at your
8      option) any later version.
9
10      GNUnet is distributed in the hope that it will be useful, but
11      WITHOUT ANY WARRANTY; without even the implied warranty of
12      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13      General Public License for more details.
14
15      You should have received a copy of the GNU General Public License
16      along with GNUnet; see the file COPYING.  If not, write to the
17      Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18      Boston, MA 02111-1307, USA.
19 */
20
21 /**
22  * @file ats/gnunet-service-ats_addresses_mlp.c
23  * @brief ats mlp problem solver
24  * @author Matthias Wachs
25  * @author Christian Grothoff
26  */
27 #include "platform.h"
28 #include "gnunet_util_lib.h"
29 #include "gnunet-service-ats_addresses.h"
30 #include "gnunet-service-ats_addresses_mlp.h"
31 #include "gnunet_statistics_service.h"
32 #include "glpk.h"
33
34 /**
35  *
36  * NOTE: Do not modify this documentation. This documentation is based on
37  * gnunet.org:/vcs/fsnsg/ats-paper.git/tech-doku/ats-tech-guide.tex
38  * use build_txt.sh to generate plaintext output
39  *
40  *    The MLP solver (mlp) tries to finds an optimal bandwidth assignmentby
41  *    optimizing an mixed integer programming problem. The MLP solver uses a
42  *    number of constraints to find the best adddress for a peer and an optimal
43  *    bandwidth assignment. mlp uses the GNU Linear Programming Kit to solve the
44  *    MLP problem.
45  *
46  *    We defined a constraint system to find an optimal bandwidth assignment.
47  *    This constraint system uses as an input data addresses, bandwidth quotas,
48  *    preferences and quality values. This constraint system is stored in an
49  *    matrix based equotation system.
50  *
51  *   5 Using GLPK
52  *
53  *    A (M)LP problem consists of a target function to optimizes, constraints
54  *    and rows and columns. FIXME GLP uses three arrays to index the matrix: two
55  *    integer arrays storing the row and column indices in the matrix and an
56  *    float array to store the coeeficient.
57  *
58  *    To solve the problem we first find an initial solution for the LP problem
59  *    using the LP solver and then find an MLP solution based on this solution
60  *    using the MLP solver.
61  *
62  *    Solving (M)LP problems has the property that finding an initial solution
63  *    for the LP problem is computationally expensive and finding the MLP
64  *    solution is cheaper. This is especially interesting an existing LP
65  *    solution can be reused if only coefficients in the matrix have changed
66  *    (addresses updated). Only when the problem size changes (addresses added
67  *    or deleted) a new LP solution has to be found.
68  *
69  *    Intended usage
70  *    The mlp solver solves the bandwidth assignment problem only on demand when
71  *    an address suggestion is requested. When an address is requested mlp the
72  *    solves the mlp problem and if the active address or the bandwidth assigned
73  *    changes it calls the callback to addresses. The mlp solver gets notified
74  *    about new addresses (adding sessions), removed addresses (address
75  *    deletions) and address updates. To benefit from the mlp properties
76  *    mentioned in section 5 the solver rembers if since the last solution
77  *    addresses were added or deleted (problem size changed, problem has to be
78  *    rebuild and solved from sratch) or if addresses were updated and the
79  *    existing solution can be reused.
80  *
81  *     5.1 Input data
82  *
83  *    The quotas for each network segment are passed by addresses. MLP can be
84  *    adapted using configuration settings and uses the following parameters:
85  *      * MLP_MAX_DURATION:
86  *        Maximum duration for a MLP solution procees (default: 3 sec.)
87  *      * MLP_MAX_DURATION:
88  *        Maximum number of iterations for a MLP solution process (default:
89  *        1024)
90  *      * MLP_MIN_CONNECTIONS:
91  *        Minimum number of desired connections (default: 4)
92  *      * MLP_MIN_BANDWIDTH:
93  *        Minimum amount of bandwidth assigned to an address (default: 1024)
94  *      * MLP_COEFFICIENT_D:
95  *        Diversity coefficient (default: 1.0)
96  *      * MLP_COEFFICIENT_R:
97  *        Relativity coefficient (default: 1.0)
98  *      * MLP_COEFFICIENT_U:
99  *        Utilization coefficient (default: 1.0)
100  *      * MLP_COEFFICIENT_D:
101  *        Diversity coefficient (default: 1.0)
102  *      * MLP_COEFFICIENT_QUALITY_DELAY:
103  *        Quality delay coefficient (default: 1.0)
104  *      * MLP_COEFFICIENT_QUALITY_DISTANCE:
105  *        Quality distance coefficient (default: 1.0)
106  *      * MLP_COEFFICIENT_QUALITY_DISTANCE:
107  *        Quality distance coefficient (default: 1.0)
108  *      * MLP_COEFFICIENT_QUALITY_DISTANCE:
109  *        Quality distance coefficient (default: 1.0)
110  *      * MLP_COEFFICIENT_QUALITY_DISTANCE:
111  *        Quality distance coefficient (default: 1.0)
112  *
113  *     5.2 Data structures used
114  *
115  *    mlp has for each known peer a struct ATS_Peer containing information about
116  *    a specific peer. The address field solver_information contains information
117  *    about the mlp properties of this address.
118  *
119  *     5.3 Initializing
120  *
121  *    During initialization mlp initializes the GLPK libray used to solve the
122  *    MLP problem: it initializes the glpk environment and creates an initial LP
123  *    problem. Next it loads the configuration values from the configuration or
124  *    uses the default values configured in -addresses_mlp.h. The quotas used
125  *    are given by addresses but may have to be adjusted. mlp uses a upper limit
126  *    for the bandwidth assigned called BIG M and a minimum amount of bandwidth
127  *    an address gets assigned as well as a minium desired number of
128  *    connections. If the configured quota is bigger than BIG M, it is reduced
129  *    to BIG M. If the configured quota is smaller than MLP_MIN_CONNECTIONS
130  *    *MLP_MIN_BANDWIDTH it is increased to this value.
131  *
132  *     5.4 Shutdown
133
134  */
135
136 #define LOG(kind,...) GNUNET_log_from (kind, "ats-mlp",__VA_ARGS__)
137
138 /**
139  * Print debug output for mlp problem creation
140  */
141 #define DEBUG_MLP_PROBLEM_CREATION GNUNET_NO
142
143 /**
144  * Enable GLPK verbose output
145  */
146 #define VERBOSE_GLPK GNUNET_NO
147
148 /**
149  * Maximize bandwidth assigned
150  *
151  * This option can be used to test if problem can be solved at all without
152  * optimizing for utility, diversity or relativity
153  *
154  */
155 #define MAXIMIZE_FOR_BANDWIDTH_ASSIGNED GNUNET_NO
156
157 /**
158  * Intercept GLPK terminal output
159  * @param info the mlp handle
160  * @param s the string to print
161  * @return 0: glpk prints output on terminal, 0 != surpress output
162  */
163 static int
164 mlp_term_hook (void *info, const char *s)
165 {
166   /* Not needed atm struct MLP_information *mlp = info; */
167   LOG (GNUNET_ERROR_TYPE_DEBUG, "%s", s);
168   return 1;
169 }
170
171
172 /**
173  * Reset peers for next problem creation
174  *
175  * @param cls not used
176  * @param key the key
177  * @param value ATS_Peer
178  * @return GNUNET_OK
179  */
180 static int
181 reset_peers (void *cls, const struct GNUNET_HashCode * key, void *value)
182  {
183          struct ATS_Peer *peer = value;
184          peer->processed = GNUNET_NO;
185          return GNUNET_OK;
186  }
187
188 /**
189  * Delete the MLP problem and free the constrain matrix
190  *
191  * @param mlp the MLP handle
192  */
193 static void
194 mlp_delete_problem (struct GAS_MLP_Handle *mlp)
195 {
196         int c;
197   if (mlp == NULL)
198         return;
199         if (mlp->p.prob != NULL)
200         {
201                 glp_delete_prob(mlp->p.prob);
202                 mlp->p.prob = NULL;
203         }
204
205         /* delete row index */
206         if (mlp->p.ia != NULL)
207         {
208                 GNUNET_free (mlp->p.ia);
209                 mlp->p.ia = NULL;
210         }
211
212         /* delete column index */
213         if (mlp->p.ja != NULL)
214         {
215                 GNUNET_free (mlp->p.ja);
216                 mlp->p.ja = NULL;
217         }
218
219         /* delete coefficients */
220         if (mlp->p.ar != NULL)
221         {
222                 GNUNET_free (mlp->p.ar);
223                 mlp->p.ar = NULL;
224         }
225         mlp->p.ci = 0;
226         mlp->p.prob = NULL;
227
228   mlp->p.c_d = MLP_UNDEFINED;
229   mlp->p.c_r = MLP_UNDEFINED;
230   mlp->p.r_c2 = MLP_UNDEFINED;
231   mlp->p.r_c4 = MLP_UNDEFINED;
232   mlp->p.r_c6 = MLP_UNDEFINED;
233   mlp->p.r_c9 = MLP_UNDEFINED;
234   for (c = 0; c < mlp->pv.m_q ; c ++)
235         mlp->p.r_q[c] = MLP_UNDEFINED;
236   for (c = 0; c < GNUNET_ATS_NetworkTypeCount; c ++)
237         mlp->p.r_quota[c] = MLP_UNDEFINED;
238   mlp->p.ci = MLP_UNDEFINED;
239
240
241   GNUNET_CONTAINER_multihashmap_iterate (mlp->peers, &reset_peers, NULL);
242 }
243
244
245 /**
246  * Translate ATS properties to text
247  * Just intended for debugging
248  *
249  * @param ats_index the ATS index
250  * @return string with result
251  */
252 const char *
253 mlp_ats_to_string (int ats_index)
254 {
255   switch (ats_index) {
256     case GNUNET_ATS_ARRAY_TERMINATOR:
257       return "GNUNET_ATS_ARRAY_TERMINATOR";
258     case GNUNET_ATS_UTILIZATION_UP:
259       return "GNUNET_ATS_UTILIZATION_UP";
260     case GNUNET_ATS_UTILIZATION_DOWN:
261       return "GNUNET_ATS_UTILIZATION_DOWN";
262     case GNUNET_ATS_COST_LAN:
263       return "GNUNET_ATS_COST_LAN";
264     case GNUNET_ATS_COST_WAN:
265       return "GNUNET_ATS_COST_LAN";
266     case GNUNET_ATS_COST_WLAN:
267       return "GNUNET_ATS_COST_WLAN";
268     case GNUNET_ATS_NETWORK_TYPE:
269       return "GNUNET_ATS_NETWORK_TYPE";
270     case GNUNET_ATS_QUALITY_NET_DELAY:
271       return "GNUNET_ATS_QUALITY_NET_DELAY";
272     case GNUNET_ATS_QUALITY_NET_DISTANCE:
273       return "GNUNET_ATS_QUALITY_NET_DISTANCE";
274     default:
275       GNUNET_break (0);
276       return "unknown";
277   }
278 }
279
280 /**
281  * Translate glpk status error codes to text
282  * @param retcode return code
283  * @return string with result
284  */
285 const char *
286 mlp_status_to_string (int retcode)
287 {
288   switch (retcode) {
289     case GLP_UNDEF:
290       return "solution is undefined";
291     case GLP_FEAS:
292       return "solution is feasible";
293     case GLP_INFEAS:
294       return "solution is infeasible";
295     case GLP_NOFEAS:
296       return "no feasible solution exists";
297     case GLP_OPT:
298       return "solution is optimal";
299     case GLP_UNBND:
300       return "solution is unbounded";
301     default:
302       GNUNET_break (0);
303       return "unknown error";
304   }
305 }
306
307 /**
308  * Translate glpk solver error codes to text
309  * @param retcode return code
310  * @return string with result
311  */
312 const char *
313 mlp_solve_to_string (int retcode)
314 {
315   switch (retcode) {
316     case 0:
317       return "ok";
318     case GLP_EBADB:
319       return "invalid basis";
320     case GLP_ESING:
321       return "singular matrix";
322     case GLP_ECOND:
323       return "ill-conditioned matrix";
324     case GLP_EBOUND:
325       return "invalid bounds";
326     case GLP_EFAIL:
327       return "solver failed";
328     case GLP_EOBJLL:
329       return "objective lower limit reached";
330     case GLP_EOBJUL:
331       return "objective upper limit reached";
332     case GLP_EITLIM:
333       return "iteration limit exceeded";
334     case GLP_ETMLIM:
335       return "time limit exceeded";
336     case GLP_ENOPFS:
337       return "no primal feasible solution";
338     case GLP_ENODFS:
339       return "no dual feasible solution";
340     case GLP_EROOT:
341       return "root LP optimum not provided";
342     case GLP_ESTOP:
343       return "search terminated by application";
344     case GLP_EMIPGAP:
345       return "relative mip gap tolerance reached";
346     case GLP_ENOFEAS:
347       return "no dual feasible solution";
348     case GLP_ENOCVG:
349       return "no convergence";
350     case GLP_EINSTAB:
351       return "numerical instability";
352     case GLP_EDATA:
353       return "invalid data";
354     case GLP_ERANGE:
355       return "result out of range";
356     default:
357       GNUNET_break (0);
358       return "unknown error";
359   }
360 }
361
362
363
364
365 struct CountContext
366 {
367         struct GNUNET_CONTAINER_MultiHashMap * peers;
368         int result;
369 };
370
371 static int
372 mlp_create_problem_count_addresses_it (void *cls, const struct GNUNET_HashCode *key, void *value)
373 {
374         struct CountContext *cctx = cls;
375   /* Check if we have to add this peer due to a pending request */
376   if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains(cctx->peers, key))
377         cctx->result++;
378   return GNUNET_OK;
379 }
380
381 static int mlp_create_problem_count_addresses (
382                 struct GNUNET_CONTAINER_MultiHashMap * peers,
383                 struct GNUNET_CONTAINER_MultiHashMap * addresses)
384 {
385         struct CountContext cctx;
386         cctx.peers = peers;
387         cctx.result = 0;
388   GNUNET_CONTAINER_multihashmap_iterate (addresses, &mlp_create_problem_count_addresses_it, &cctx);
389   return cctx.result;
390 }
391
392
393
394 static void
395 mlp_create_problem_set_value (struct MLP_Problem *p,
396                                                                                                                         int row, int col, double val,
397                                                                                                                         int line)
398 {
399         if ((p->ci) >= p->num_elements)
400         {
401                 LOG (GNUNET_ERROR_TYPE_DEBUG, "[P]: line %u: Request for index %u bigger than array size of %u\n",
402                                 line, p->ci + 1, p->num_elements);
403                 GNUNET_break (0);
404                 return;
405         }
406         if ((0 == row) || (0 == col))
407                 GNUNET_break (0);
408   p->ia[p->ci] = row ;
409   p->ja[p->ci] = col;
410   p->ar[p->ci] = val;
411 #if  DEBUG_MLP_PROBLEM_CREATION
412         LOG (GNUNET_ERROR_TYPE_DEBUG, "[P]: line %u: Set value [%u,%u] in index %u ==  %.2f\n",
413                         line, p->ia[p->ci], p->ja[p->ci], p->ci, p->ar[p->ci]);
414 #endif
415   p->ci++;
416 }
417
418 static int
419 mlp_create_problem_create_column (struct MLP_Problem *p, char *name,
420                 unsigned int type, unsigned int bound, double lb, double ub,
421                 double coef)
422 {
423         int col = glp_add_cols (p->prob, 1);
424   glp_set_col_name (p->prob, col, name);
425   glp_set_col_bnds (p->prob, col, bound, lb, ub);
426   glp_set_col_kind (p->prob, col, type);
427   glp_set_obj_coef (p->prob, col, coef);
428 #if  DEBUG_MLP_PROBLEM_CREATION
429         LOG (GNUNET_ERROR_TYPE_DEBUG, "[P]: Added column [%u] `%s': %.2f\n",
430                         col, name, coef);
431 #endif
432   return col;
433 }
434
435 static int
436 mlp_create_problem_create_constraint (struct MLP_Problem *p, char *name,
437                 unsigned int bound, double lb, double ub)
438 {
439         char * op;
440   int row = glp_add_rows (p->prob, 1);
441   /* set row name */
442   glp_set_row_name (p->prob, row, name);
443   /* set row bounds: <= 0 */
444   glp_set_row_bnds (p->prob, row, bound, lb, ub);
445   switch (bound) {
446                 case GLP_UP:
447                         GNUNET_asprintf(&op, "-inf <= x <= %.2f", ub);
448                         break;
449                 case GLP_DB:
450                         GNUNET_asprintf(&op, "%.2f <= x <= %.2f", lb, ub);
451                         break;
452                 case GLP_FX:
453                         GNUNET_asprintf(&op, "%.2f == x == %.2f", lb, ub);
454                         break;
455                 case GLP_LO:
456                         GNUNET_asprintf(&op, "%.2f <= x <= inf", lb);
457                         break;
458                 default:
459                         GNUNET_asprintf(&op, "ERROR");
460                         break;
461         }
462 #if  DEBUG_MLP_PROBLEM_CREATION
463                 LOG (GNUNET_ERROR_TYPE_DEBUG, "[P]: Added row [%u] `%s': %s\n",
464                                 row, name, op);
465 #endif
466         GNUNET_free (op);
467         return row;
468 }
469
470 /**
471  * Create the
472  * - address columns b and n
473  * - address dependent constraint rows c1, c3
474  * - peer dependent rows c2 and c9
475  * - Set address dependent entries in problem matrix as well
476  */
477 static int
478 mlp_create_problem_add_address_information (void *cls, const struct GNUNET_HashCode *key, void *value)
479 {
480   struct GAS_MLP_Handle *mlp = cls;
481   struct MLP_Problem *p = &mlp->p;
482   struct ATS_Address *address = value;
483   struct ATS_Peer *peer;
484   struct MLP_information *mlpi;
485   char *name;
486   int c;
487
488   /* Check if we have to add this peer due to a pending request */
489   if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains(mlp->peers, key))
490         return GNUNET_OK;
491
492   mlpi = address->solver_information;
493   if (NULL == mlpi)
494   {
495                 GNUNET_break (0);
496                 return GNUNET_OK;
497   }
498
499   /* Get peer */
500   peer = GNUNET_CONTAINER_multihashmap_get (mlp->peers, key);
501   if (peer->processed == GNUNET_NO)
502   {
503                 /* Add peer dependent constraints */
504                 /* Add constraint c2 */
505           GNUNET_asprintf(&name, "c2_%s", GNUNET_i2s(&address->peer));
506           peer->r_c2 = mlp_create_problem_create_constraint (p, name, GLP_FX, 1.0, 1.0);
507                 GNUNET_free (name);
508                 /* Add constraint c9 */
509           GNUNET_asprintf(&name, "c9_%s", GNUNET_i2s(&address->peer));
510           peer->r_c9 = mlp_create_problem_create_constraint (p, name, GLP_LO, 0.0, 0.0);
511                 GNUNET_free (name);
512           /* c 9) set coefficient */
513                 mlp_create_problem_set_value (p, peer->r_c9, p->c_r, -peer->f, __LINE__);
514
515                 peer->processed = GNUNET_YES;
516   }
517
518   /* Reset addresses' solver information */
519   mlpi->c_b = 0;
520   mlpi->c_n = 0;
521   mlpi->n = 0;
522   mlpi->r_c1 = 0;
523   mlpi->r_c3 = 0;
524   for (c = 0; c < mlp->pv.m_q; c++)
525         mlpi->r_q[0] = 0;
526
527   /* Add bandwidth column */
528   GNUNET_asprintf (&name, "b_%s_%s_%p", GNUNET_i2s (&address->peer), address->plugin, address);
529 #if TEST_MAX_BW_ASSIGNMENT
530   mlpi->c_b = mlp_create_problem_create_column (p, name, GLP_CV, GLP_LO, 0.0, 0.0, 1.0);
531 #else
532   mlpi->c_b = mlp_create_problem_create_column (p, name, GLP_CV, GLP_LO, 0.0, 0.0, 0.0);
533 #endif
534
535   GNUNET_free (name);
536
537   /* Add usage column */
538   GNUNET_asprintf (&name, "n_%s_%s_%p", GNUNET_i2s (&address->peer), address->plugin, address);
539   mlpi->c_n = mlp_create_problem_create_column (p, name, GLP_IV, GLP_DB, 0.0, 1.0, 0.0);
540   GNUNET_free (name);
541
542         /* Add address dependent constraints */
543         /* Add constraint c1) bandwidth capping
544    * b_t  + (-M) * n_t <= 0
545    * */
546   GNUNET_asprintf(&name, "c1_%s_%s_%p", GNUNET_i2s(&address->peer), address->plugin, address);
547   mlpi->r_c1 = mlp_create_problem_create_constraint (p, name, GLP_UP, 0.0, 0.0);
548         GNUNET_free (name);
549
550         /*  c1) set b = 1 coefficient */
551         mlp_create_problem_set_value (p, mlpi->r_c1, mlpi->c_b, 1, __LINE__);
552         /*  c1) set n = -M coefficient */
553         mlp_create_problem_set_value (p, mlpi->r_c1, mlpi->c_n, -mlp->pv.BIG_M, __LINE__);
554
555   /* Add constraint c 3) minimum bandwidth
556    * b_t + (-n_t * b_min) >= 0
557    * */
558   GNUNET_asprintf(&name, "c3_%s_%s_%p", GNUNET_i2s(&address->peer), address->plugin, address);
559         mlpi->r_c3 = mlp_create_problem_create_constraint (p, name, GLP_LO, 0.0, 0.0);
560         GNUNET_free (name);
561
562         /*  c3) set b = 1 coefficient */
563         mlp_create_problem_set_value (p, mlpi->r_c3, mlpi->c_b, 1, __LINE__);
564         /*  c3) set n = -b_min coefficient */
565         mlp_create_problem_set_value (p, mlpi->r_c3, mlpi->c_n, - ((double )mlp->pv.b_min), __LINE__);
566
567
568         /* Set coefficient entries in invariant rows */
569   /* c 4) minimum connections */
570         mlp_create_problem_set_value (p, p->r_c4, mlpi->c_n, 1, __LINE__);
571   /* c 6) maximize diversity */
572         mlp_create_problem_set_value (p, p->r_c6, mlpi->c_n, 1, __LINE__);
573   /* c 2) 1 address peer peer */
574         mlp_create_problem_set_value (p, peer->r_c2, mlpi->c_n, 1, __LINE__);
575   /* c 9) relativity */
576         mlp_create_problem_set_value (p, peer->r_c9, mlpi->c_b, 1, __LINE__);
577   /* c 8) utility */
578         mlp_create_problem_set_value (p, p->r_c8, mlpi->c_b, 1, __LINE__);
579
580   /* c 10) obey network specific quotas
581    * (1)*b_1 + ... + (1)*b_m <= quota_n
582    */
583   for (c = 0; c < GNUNET_ATS_NetworkTypeCount; c++)
584   {
585     if (mlp->pv.quota_index[c] == address->atsp_network_type)
586     {
587                 mlp_create_problem_set_value (p, p->r_quota[c], mlpi->c_b, 1, __LINE__);
588       break;
589     }
590   }
591
592   /* c 7) Optimize quality */
593   /* For all quality metrics, set quality of this address */
594   for (c = 0; c < mlp->pv.m_q; c++)
595         mlp_create_problem_set_value (p, p->r_q[c], mlpi->c_b, mlpi->q_averaged[c], __LINE__);
596
597
598   return GNUNET_OK;
599 }
600
601 /**
602  * Create the invariant columns c4, c6, c10, c8, c7
603  */
604 static void
605 mlp_create_problem_add_invariant_rows (struct GAS_MLP_Handle *mlp, struct MLP_Problem *p)
606 {
607   char *name;
608   int c;
609
610   /* Row for c4) minimum connection */
611   /* Number of minimum connections is min(|Peers|, n_min) */
612   p->r_c4 = mlp_create_problem_create_constraint (p, "c4", GLP_LO, (mlp->pv.n_min > p->num_peers) ? p->num_peers : mlp->pv.n_min, 0.0);
613
614   /* Add row for c6) */
615         p->r_c6 = mlp_create_problem_create_constraint (p, "c6", GLP_FX, 0.0, 0.0);
616   /* c6 )Setting -D */
617         mlp_create_problem_set_value (p, p->r_c6, p->c_d, -1, __LINE__);
618
619   /* Add rows for c 10) */
620   for (c = 0; c < GNUNET_ATS_NetworkTypeCount; c++)
621   {
622       char * text;
623       GNUNET_asprintf(&text, "c10_quota_ats_%s", GNUNET_ATS_print_network_type(mlp->pv.quota_index[c]));
624                 p->r_quota[c] = mlp_create_problem_create_constraint (p, text, GLP_DB, 0.0, mlp->pv.quota_out[c]);
625                 GNUNET_free (text);
626   }
627
628   /* Adding rows for c 8) */
629   p->r_c8 = mlp_create_problem_create_constraint (p, "c8", GLP_FX, 0.0, 0.0);
630   /* -u */
631         mlp_create_problem_set_value (p, p->r_c8, p->c_u, -1, __LINE__);
632
633         /* c 7) For all quality metrics */
634         for (c = 0; c < mlp->pv.m_q; c++)
635         {
636                 GNUNET_asprintf(&name, "c7_q%i_%s", c, mlp_ats_to_string(mlp->pv.q[c]));
637                 p->r_q[c] = mlp_create_problem_create_constraint (p, name, GLP_FX, 0.0, 0.0);
638                 GNUNET_free (name);
639                 mlp_create_problem_set_value (p, p->r_q[c], p->c_q[c], -1, __LINE__);
640         }
641 }
642
643
644 /**
645  * Create the invariant columns d, u, r, q0 ... qm
646  */
647 static void
648 mlp_create_problem_add_invariant_columns (struct GAS_MLP_Handle *mlp, struct MLP_Problem *p)
649 {
650   char *name;
651   int c;
652
653 #if TEST_MAX_BW_ASSIGNMENT
654   mlp->pv.co_D = 0.0;
655   mlp->pv.co_U = 0.0;
656
657 #endif
658   //mlp->pv.co_R = 0.0;
659
660   /* Diversity d column  */
661   p->c_d = mlp_create_problem_create_column (p, "d", GLP_CV, GLP_LO, 0.0, 0.0, mlp->pv.co_D);
662
663   /* Utilization u column  */
664   p->c_u = mlp_create_problem_create_column (p, "u", GLP_CV, GLP_LO, 0.0, 0.0, mlp->pv.co_U);
665
666   /* Relativity r column  */
667   p->c_r = mlp_create_problem_create_column (p, "r", GLP_CV, GLP_LO, 0.0, 0.0, mlp->pv.co_R);
668
669   /* Quality metric columns */
670   for (c = 0; c < mlp->pv.m_q; c++)
671   {
672     GNUNET_asprintf (&name, "q_%u", mlp->pv.q[c]);
673 #if TEST_MAX_BW_ASSIGNMENT
674         p->c_q[c] = mlp_create_problem_create_column (p, name, GLP_CV, GLP_LO, 0.0, 0.0, 0.0);
675 #else
676         p->c_q[c] = mlp_create_problem_create_column (p, name, GLP_CV, GLP_LO, 0.0, 0.0, mlp->pv.co_Q[c]);
677 #endif
678         GNUNET_free (name);
679   }
680 }
681
682
683 /**
684  * Create the MLP problem
685  *
686  * @param mlp the MLP handle
687  * @param addresses the hashmap containing all adresses
688  * @return GNUNET_OK or GNUNET_SYSERR
689  */
690 static int
691 mlp_create_problem (struct GAS_MLP_Handle *mlp, struct GNUNET_CONTAINER_MultiHashMap * addresses)
692 {
693   struct MLP_Problem *p = &mlp->p;
694         int res = GNUNET_OK;
695
696   GNUNET_assert (p->prob == NULL);
697   GNUNET_assert (p->ia == NULL);
698   GNUNET_assert (p->ja == NULL);
699   GNUNET_assert (p->ar == NULL);
700   /* Reset MLP problem struct */
701
702   /* create the glpk problem */
703   p->prob = glp_create_prob ();
704   GNUNET_assert (NULL != p->prob);
705   p->num_peers = GNUNET_CONTAINER_multihashmap_size (mlp->peers);
706   p->num_addresses = mlp_create_problem_count_addresses (mlp->peers, addresses);
707
708   /* Create problem matrix: 10 * #addresses + #q * #addresses + #q, + #peer + 2 + 1 */
709   p->num_elements = (10 * p->num_addresses + mlp->pv.m_q * p->num_addresses +  mlp->pv.m_q + p->num_peers + 2 + 1);
710         LOG (GNUNET_ERROR_TYPE_DEBUG, "Rebuilding problem for %u peer(s) and %u addresse(s) and %u quality metrics == %u elements\n",
711                         p->num_peers, p->num_addresses, mlp->pv.m_q, p->num_elements);
712
713   /* Set a problem name */
714   glp_set_prob_name (p->prob, "GNUnet ATS bandwidth distribution");
715   /* Set optimization direction to maximize */
716   glp_set_obj_dir (p->prob, GLP_MAX);
717
718   /* Create problem matrix */
719   /* last +1 caused by glpk index starting with one: [1..elements]*/
720   p->ci = 1;
721   /* row index */
722   p->ia = GNUNET_malloc (p->num_elements * sizeof (int));
723   /* column index */
724   p->ja = GNUNET_malloc (p->num_elements * sizeof (int));
725   /* coefficient */
726   p->ar = GNUNET_malloc (p->num_elements * sizeof (double));
727
728   if ((NULL == p->ia) || (NULL == p->ja) || (NULL == p->ar))
729   {
730                 LOG (GNUNET_ERROR_TYPE_ERROR, _("Problem size too large, cannot allocate memory!\n"));
731                 return GNUNET_SYSERR;
732   }
733
734   /* Adding invariant columns */
735   mlp_create_problem_add_invariant_columns (mlp, p);
736
737   /* Adding address independent constraint rows */
738   mlp_create_problem_add_invariant_rows (mlp, p);
739
740   /* Adding address independent constraint rows */
741   GNUNET_CONTAINER_multihashmap_iterate (addresses, &mlp_create_problem_add_address_information, mlp);
742
743   /* Load the matrix */
744         LOG (GNUNET_ERROR_TYPE_DEBUG, "Loading matrix\n");
745   glp_load_matrix(p->prob, (p->ci)-1, p->ia, p->ja, p->ar);
746
747   return res;
748 }
749
750 /**
751  * Solves the LP problem
752  *
753  * @param mlp the MLP Handle
754  * @return GNUNET_OK if could be solved, GNUNET_SYSERR on failure
755  */
756 static int
757 mlp_solve_lp_problem (struct GAS_MLP_Handle *mlp)
758 {
759         int res = 0;
760
761         res = glp_simplex(mlp->p.prob, &mlp->control_param_lp);
762         if (0 == res)
763                 LOG (GNUNET_ERROR_TYPE_DEBUG, "Solving LP problem: 0x%02X %s\n", res, mlp_solve_to_string(res));
764         else
765                 LOG (GNUNET_ERROR_TYPE_WARNING, "Solving LP problem failed: 0x%02X %s\n", res, mlp_solve_to_string(res));
766
767   /* Analyze problem status  */
768   res = glp_get_status (mlp->p.prob);
769   switch (res) {
770     /* solution is optimal */
771     case GLP_OPT:
772     /* solution is feasible */
773     case GLP_FEAS:
774       LOG (GNUNET_ERROR_TYPE_DEBUG, "Solving LP problem: 0x%02X %s\n",
775                 res, mlp_status_to_string(res));
776       return GNUNET_OK;
777     /* Problem was ill-defined, no way to handle that */
778     default:
779       LOG (GNUNET_ERROR_TYPE_WARNING, "Solving LP problem failed, no solution: 0x%02X %s\n",
780                 res, mlp_status_to_string(res));
781       return GNUNET_SYSERR;
782   }
783 }
784
785
786 /**
787  * Solves the MLP problem
788  *
789  * @param mlp the MLP Handle
790  * @return GNUNET_OK if could be solved, GNUNET_SYSERR on failure
791  */
792 int
793 mlp_solve_mlp_problem (struct GAS_MLP_Handle *mlp)
794 {
795         int res = 0;
796         res = glp_intopt(mlp->p.prob, &mlp->control_param_mlp);
797         if (0 == res)
798                 LOG (GNUNET_ERROR_TYPE_DEBUG, "Solving MLP problem: 0x%02X %s\n", res, mlp_solve_to_string(res));
799         else
800                 LOG (GNUNET_ERROR_TYPE_WARNING, "Solving MLP problem failed: 0x%02X %s\n", res, mlp_solve_to_string(res));
801   /* Analyze problem status  */
802   res = glp_mip_status(mlp->p.prob);
803   switch (res) {
804     /* solution is optimal */
805     case GLP_OPT:
806     /* solution is feasible */
807     case GLP_FEAS:
808       LOG (GNUNET_ERROR_TYPE_DEBUG, "Solving MLP problem: 0x%02X %s\n", res, mlp_status_to_string(res));
809       return GNUNET_OK;
810     /* Problem was ill-defined, no way to handle that */
811     default:
812       LOG (GNUNET_ERROR_TYPE_WARNING,"Solving MLP problem failed, 0x%02X %s\n\n", res, mlp_status_to_string(res));
813       return GNUNET_SYSERR;
814   }
815 }
816
817
818 /**
819  * Propagates the results when MLP problem was solved
820  *
821  * @param cls the MLP handle
822  * @param key the peer identity
823  * @param value the address
824  * @return GNUNET_OK to continue
825  */
826 int
827 mlp_propagate_results (void *cls, const struct GNUNET_HashCode *key, void *value)
828 {
829         struct GAS_MLP_Handle *mlp = cls;
830         struct ATS_Address *address;
831         struct MLP_information *mlpi;
832         double mlp_bw_in = MLP_NaN;
833         double mlp_bw_out = MLP_NaN;
834         double mlp_use = MLP_NaN;
835
836   /* Check if we have to add this peer due to a pending request */
837   if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains(mlp->peers, key))
838         return GNUNET_OK;
839   address = value;
840   GNUNET_assert (address->solver_information != NULL);
841   mlpi = address->solver_information;
842
843   mlp_bw_in = glp_mip_col_val(mlp->p.prob, mlpi->c_b);/* FIXME */
844   if (mlp_bw_in > (double) UINT32_MAX)
845   {
846                 LOG (GNUNET_ERROR_TYPE_DEBUG, "Overflow in assigned bandwidth, reducing ...\n" );
847                 mlp_bw_in = (double) UINT32_MAX;
848   }
849   mlp_bw_out = glp_mip_col_val(mlp->p.prob, mlpi->c_b);
850   if (mlp_bw_out > (double) UINT32_MAX)
851   {
852                 LOG (GNUNET_ERROR_TYPE_DEBUG, "Overflow in assigned bandwidth, reducing ...\n" );
853                 mlp_bw_out = (double) UINT32_MAX;
854   }
855   mlp_use = glp_mip_col_val(mlp->p.prob, mlpi->c_n);
856
857
858
859   if ((GLP_YES == mlp_use) && (GNUNET_NO == address->active))
860   {
861         /* Address switch: Activate address*/
862         LOG (GNUNET_ERROR_TYPE_DEBUG, "%s %.2f : enabling address\n", (1 == mlp_use) ? "[x]": "[ ]", mlp_bw_out);
863                 address->active = GNUNET_YES;
864                 address->assigned_bw_in.value__ = htonl (mlp_bw_in);
865                 mlpi->b_in.value__ = htonl(mlp_bw_in);
866                 address->assigned_bw_out.value__ = htonl (mlp_bw_out);
867                 mlpi->b_out.value__ = htonl(mlp_bw_out);
868                 mlpi->n = mlp_use;
869                 mlp->bw_changed_cb (mlp->bw_changed_cb_cls, address);
870   }
871   else if ((GLP_NO == mlp_use) && (GNUNET_YES == address->active))
872   {
873                 /* Address switch: Disable address*/
874         LOG (GNUNET_ERROR_TYPE_DEBUG, "%s %.2f : disabling address\n", (1 == mlp_use) ? "[x]": "[ ]", mlp_bw_out);
875                 address->active = GNUNET_NO;
876                 /* Set bandwidth to 0 */
877                 address->assigned_bw_in.value__ = htonl (0);
878                 mlpi->b_in.value__ = htonl(mlp_bw_in);
879                 address->assigned_bw_out.value__ = htonl (0);
880                 mlpi->b_out.value__ = htonl(mlp_bw_out);
881                 mlpi->n = mlp_use;
882                 mlp->bw_changed_cb (mlp->bw_changed_cb_cls, address);
883   }
884   else if ((mlp_bw_out != ntohl(address->assigned_bw_out.value__)) ||
885                                  (mlp_bw_in != ntohl(address->assigned_bw_in.value__)))
886   {
887         /* Bandwidth changed */
888                 LOG (GNUNET_ERROR_TYPE_DEBUG, "%s %.2f : bandwidth changed\n", (1 == mlp_use) ? "[x]": "[ ]", mlp_bw_out);
889                 address->assigned_bw_in.value__ = htonl (mlp_bw_in);
890                 mlpi->b_in.value__ = htonl(mlp_bw_in);
891                 address->assigned_bw_out.value__ = htonl (mlp_bw_out);
892                 mlpi->b_out.value__ = htonl(mlp_bw_out);
893                 mlpi->n = mlp_use;
894                 mlp->bw_changed_cb (mlp->bw_changed_cb_cls, address);
895   }
896   else
897   {
898     LOG (GNUNET_ERROR_TYPE_DEBUG, "%s %.2f : no change\n", (1 == mlp_use) ? "[x]": "[ ]", mlp_bw_out);
899   }
900
901   return GNUNET_OK;
902 }
903
904
905
906 /**
907  * Solves the MLP problem
908  *
909  * @param solver the MLP Handle
910  * @param addresses the address hashmap
911  * @return GNUNET_OK if could be solved, GNUNET_SYSERR on failure
912  */
913 int
914 GAS_mlp_solve_problem (void *solver, struct GNUNET_CONTAINER_MultiHashMap * addresses)
915 {
916         struct GAS_MLP_Handle *mlp = solver;
917         char *filename;
918         int res_lp = 0;
919         int res_mip = 0;
920         struct GNUNET_TIME_Absolute start_build;
921         struct GNUNET_TIME_Relative duration_build;
922         struct GNUNET_TIME_Absolute start_lp;
923         struct GNUNET_TIME_Relative duration_lp;
924         struct GNUNET_TIME_Absolute start_mlp;
925         struct GNUNET_TIME_Relative duration_mlp;
926         GNUNET_assert (NULL != solver);
927
928         if ((GNUNET_NO == mlp->mlp_prob_changed) && (GNUNET_NO == mlp->mlp_prob_updated))
929         {
930                 LOG (GNUNET_ERROR_TYPE_DEBUG, "No changes to problem\n");
931                 return GNUNET_OK;
932         }
933
934         if (GNUNET_YES == mlp->mlp_prob_changed)
935         {
936                         LOG (GNUNET_ERROR_TYPE_DEBUG, "Problem size changed, rebuilding\n");
937                         mlp_delete_problem (mlp);
938                         start_build = GNUNET_TIME_absolute_get();
939                         if (GNUNET_SYSERR == mlp_create_problem (mlp, addresses))
940                                 return GNUNET_SYSERR;
941                         duration_build = GNUNET_TIME_absolute_get_duration (start_build);
942                         mlp->control_param_lp.presolve = GLP_YES;
943                         mlp->control_param_mlp.presolve = GNUNET_NO; /* No presolver, we have LP solution */
944         }
945         else
946         {
947                         LOG (GNUNET_ERROR_TYPE_DEBUG, "Problem was updated, resolving\n");
948                         duration_build.rel_value = 0;
949         }
950
951         /* Run LP solver */
952         LOG (GNUNET_ERROR_TYPE_DEBUG, "Running LP solver %s\n", (GLP_YES == mlp->control_param_lp.presolve)? "with presolver": "without presolver");
953         start_lp = GNUNET_TIME_absolute_get();
954         res_lp = mlp_solve_lp_problem (mlp);
955         duration_lp = GNUNET_TIME_absolute_get_duration (start_lp);
956
957
958   /* Run LP solver */
959         LOG (GNUNET_ERROR_TYPE_DEBUG, "Running MLP solver \n");
960         start_mlp = GNUNET_TIME_absolute_get();
961         res_mip = mlp_solve_mlp_problem (mlp);
962
963         duration_mlp = GNUNET_TIME_absolute_get_duration (start_mlp);
964
965         /* Save stats */
966         mlp->ps.lp_res = res_lp;
967         mlp->ps.mip_res = res_mip;
968         mlp->ps.build_dur = duration_build;
969         mlp->ps.lp_dur = duration_lp;
970         mlp->ps.mip_dur = duration_mlp;
971         mlp->ps.lp_presolv = mlp->control_param_lp.presolve;
972         mlp->ps.mip_presolv = mlp->control_param_mlp.presolve;
973         mlp->ps.p_cols = glp_get_num_cols (mlp->p.prob);
974         mlp->ps.p_rows = glp_get_num_rows (mlp->p.prob);
975         mlp->ps.p_elements = mlp->p.num_elements;
976
977         LOG (GNUNET_ERROR_TYPE_DEBUG, "Execution time: Build %llu ms, LP %llu ms,  MLP %llu ms\n",
978                         (unsigned long long) duration_build.rel_value,
979                         (unsigned long long) duration_lp.rel_value,
980                         (unsigned long long) duration_mlp.rel_value);
981
982         /* Propagate result*/
983         if ((GNUNET_OK == res_lp) && (GNUNET_OK == res_mip))
984                 GNUNET_CONTAINER_multihashmap_iterate (addresses, &mlp_propagate_results, mlp);
985
986         struct GNUNET_TIME_Absolute time = GNUNET_TIME_absolute_get();
987         if (GNUNET_YES == mlp->write_mip_mps)
988         {
989         /* Write problem and solution to disk */
990         GNUNET_asprintf (&filename, "problem_p_%u_a%u_%llu.mps", mlp->p.num_peers, mlp->p.num_addresses, time.abs_value);
991         glp_write_mps(mlp->p.prob, GLP_MPS_FILE, NULL, filename);
992         GNUNET_free (filename);
993         }
994         if (GNUNET_YES == mlp->write_mip_sol)
995         {
996                 GNUNET_asprintf (&filename, "problem_p_%u_a%u_%llu.sol", mlp->p.num_peers, mlp->p.num_addresses, time.abs_value);
997                 glp_print_mip (mlp->p.prob, filename );
998                 GNUNET_free (filename);
999         }
1000
1001         /* Reset change and update marker */
1002         mlp->control_param_lp.presolve = GLP_NO;
1003         mlp->mlp_prob_updated = GNUNET_NO;
1004         mlp->mlp_prob_changed = GNUNET_NO;
1005
1006         if ((GNUNET_OK == res_lp) && (GNUNET_OK == res_mip))
1007                 return GNUNET_OK;
1008         else
1009                 return GNUNET_SYSERR;
1010 }
1011
1012 /**
1013  * Add a single address to the solve
1014  *
1015  * @param solver the solver Handle
1016  * @param addresses the address hashmap containing all addresses
1017  * @param address the address to add
1018  */
1019 void
1020 GAS_mlp_address_add (void *solver, struct GNUNET_CONTAINER_MultiHashMap * addresses, struct ATS_Address *address)
1021 {
1022   struct GAS_MLP_Handle *mlp = solver;
1023   struct ATS_Peer *p;
1024   struct MLP_information *mlpi;
1025   int c1;
1026   int c2;
1027
1028   GNUNET_assert (NULL != solver);
1029   GNUNET_assert (NULL != addresses);
1030   GNUNET_assert (NULL != address);
1031
1032
1033   if (NULL == address->solver_information)
1034   {
1035                 address->solver_information = GNUNET_malloc (sizeof (struct MLP_information));
1036                 mlpi = address->solver_information;
1037           for (c1 = 0; c1 < mlp->pv.m_q; c1++)
1038           {
1039                 mlpi->q_averaged[c1] = DEFAULT_QUALITY;
1040                 for (c2 = 0; c2 < MLP_AVERAGING_QUEUE_LENGTH; c2++)
1041                         mlpi->q[c1][c2] = MLP_NaN;
1042           }
1043   }
1044   else
1045       LOG (GNUNET_ERROR_TYPE_ERROR, _("Adding address for peer `%s' multiple times\n"), GNUNET_i2s(&address->peer));
1046
1047   /* Is this peer included in the problem? */
1048   if (NULL == (p = GNUNET_CONTAINER_multihashmap_get (mlp->peers, &address->peer.hashPubKey)))
1049   {
1050     LOG (GNUNET_ERROR_TYPE_DEBUG, "Adding address for peer `%s' without address request \n", GNUNET_i2s(&address->peer));
1051         return;
1052   }
1053
1054         LOG (GNUNET_ERROR_TYPE_DEBUG, "Adding address for peer `%s' with address request \n", GNUNET_i2s(&address->peer));
1055         /* Problem size changed: new address for peer with pending request */
1056         mlp->mlp_prob_changed = GNUNET_YES;
1057         if (GNUNET_YES == mlp->mlp_auto_solve)
1058                 GAS_mlp_solve_problem (solver, addresses);
1059 }
1060
1061
1062 static void
1063 mlp_update_quality (struct GAS_MLP_Handle *mlp,
1064                 struct GNUNET_CONTAINER_MultiHashMap *addresses,
1065                 struct ATS_Address * address,
1066                                                                                 const struct GNUNET_ATS_Information *ats, uint32_t ats_count)
1067 {
1068   struct MLP_information *mlpi = address->solver_information;
1069   unsigned int c_ats_entry;
1070   unsigned int c_queue_entries;
1071   unsigned int c_cmp;
1072   unsigned int c_queue_it;
1073   unsigned int c_row;
1074   unsigned int c_qual;
1075   unsigned int c_net;
1076   int qual_changed;
1077   int type_index;
1078   int avg_index;
1079   uint32_t type;
1080   uint32_t value;
1081   uint32_t old_value;
1082   double avg;
1083   double *queue;
1084   int rows;
1085   double *val;
1086   int *ind;
1087
1088
1089         LOG (GNUNET_ERROR_TYPE_DEBUG, "Updating %u quality metrics for peer `%s'\n",
1090       ats_count, GNUNET_i2s (&address->peer));
1091
1092         GNUNET_assert (NULL != mlp);
1093   GNUNET_assert (NULL != address);
1094   GNUNET_assert (NULL != address->solver_information);
1095   GNUNET_assert (NULL != ats);
1096
1097   if (NULL == mlp->p.prob)
1098         return;
1099
1100   qual_changed = GNUNET_NO;
1101   for (c_ats_entry = 0; c_ats_entry < ats_count; c_ats_entry++)
1102   {
1103                 type = ntohl (ats[c_ats_entry].type);
1104                 value = ntohl (ats[c_ats_entry].value);
1105                 type_index = -1;
1106                 avg_index = -1;
1107
1108                 /* Check for network update */
1109                 if (type == GNUNET_ATS_NETWORK_TYPE)
1110                 {
1111                                 if (address->atsp_network_type != value)
1112                                 {
1113                                 LOG (GNUNET_ERROR_TYPE_DEBUG, "Updating network for peer `%s' from `%s' to `%s'\n",
1114                               GNUNET_i2s (&address->peer),
1115                               GNUNET_ATS_print_network_type(address->atsp_network_type),
1116                               GNUNET_ATS_print_network_type(value));
1117                                 }
1118
1119                                 old_value = address->atsp_network_type;
1120                           address->atsp_network_type = value;
1121                                 if (mlpi->c_b == MLP_UNDEFINED)
1122                                         continue; /* This address is not yet in the matrix*/
1123
1124                           rows = glp_get_num_rows(mlp->p.prob);
1125                           ind = GNUNET_malloc (rows * sizeof (int) + 1);
1126                           val = GNUNET_malloc (rows * sizeof (double) + 1);
1127                           int length = glp_get_mat_col (mlp->p.prob, mlpi->c_b, ind, val);
1128
1129                           for (c_net = 0; c_net <= length + 1; c_net ++)
1130                           {
1131                                 if (ind[c_net] == mlp->p.r_quota[old_value])
1132                                         break; /* Found index for old network */
1133                           }
1134                           val[c_net] = 0.0;
1135                                 glp_set_mat_col (mlp->p.prob, mlpi->c_b, length, ind, val);
1136                                 /* Set updated column */
1137                                 ind[c_net] = mlp->p.r_quota[value];
1138                                 val[c_net] = 1.0;
1139                                 glp_set_mat_col (mlp->p.prob, mlpi->c_b, length, ind, val);
1140                           GNUNET_free (ind);
1141                           GNUNET_free (val);
1142
1143                           rows = glp_get_num_rows(mlp->p.prob);
1144                           ind = GNUNET_malloc (rows * sizeof (int) + 1);
1145                           val = GNUNET_malloc (rows * sizeof (double) + 1);
1146                           length = glp_get_mat_col (mlp->p.prob, mlpi->c_b, ind, val);
1147
1148                           for (c_net = 0; c_net <= length + 1; c_net ++)
1149                           {
1150                                 if (ind[c_net] == mlp->p.r_quota[value])
1151                                         LOG (GNUNET_ERROR_TYPE_DEBUG, "Removing old network index [%u] == [%f]\n",ind[c_net],val[c_net]);
1152                                 if (ind[c_net] == mlp->p.r_quota[old_value])
1153                                 {
1154                                         LOG (GNUNET_ERROR_TYPE_DEBUG, "Setting new network index [%u] == [%f]\n",ind[c_net],val[c_net]);
1155                                         break;
1156                                 }
1157                           }
1158                           GNUNET_free (ind);
1159                           GNUNET_free (val);
1160                           mlp->mlp_prob_changed = GNUNET_YES;
1161                                 continue;
1162                 }
1163
1164
1165                 /* Find index for this ATS type */
1166           for (c_cmp = 0; c_cmp < mlp->pv.m_q; c_cmp++)
1167           {
1168             if (type == mlp->pv.q[c_cmp])
1169             {
1170                 type_index = c_cmp;
1171               break;
1172             }
1173           }
1174           if (-1 == type_index)
1175                 continue; /* quality index not found */
1176
1177           /* Get average queue index */
1178           avg_index = mlpi->q_avg_i[type_index];
1179
1180           /* Update averaging queue */
1181           mlpi->q[type_index][avg_index] = value;
1182
1183           /* Update averaging index */
1184       if (mlpi->q_avg_i[type_index] + 1 < (MLP_AVERAGING_QUEUE_LENGTH))
1185         mlpi->q_avg_i[type_index] ++;
1186       else
1187         mlpi->q_avg_i[type_index] = 0;
1188
1189           /* Update average depending on ATS type */
1190       switch (type)
1191       {
1192         case GNUNET_ATS_QUALITY_NET_DISTANCE:
1193         case GNUNET_ATS_QUALITY_NET_DELAY:
1194                 c_queue_entries = 0;
1195                 avg = 0;
1196           for (c_queue_it = 0; c_queue_it < MLP_AVERAGING_QUEUE_LENGTH; c_queue_it++)
1197           {
1198             if (mlpi->q[type_index][c_queue_it] != MLP_NaN)
1199             {
1200               queue = mlpi->q[type_index] ;
1201               avg += queue[c_queue_it];
1202               c_queue_entries ++;
1203             }
1204           }
1205           if ((c_queue_entries > 0) && (avg > 0))
1206             /* avg = 1 / ((q[0] + ... + q[l]) /c3) => c3 / avg*/
1207             mlpi->q_averaged[type_index] = (double) c_queue_entries / avg;
1208           else
1209             mlpi->q_averaged[type_index] = 0.0;
1210
1211           LOG (GNUNET_ERROR_TYPE_DEBUG, "Updating peer `%s': `%s' average sum of %u elements == %f, average == %f, weight == %f\n",
1212             GNUNET_i2s (&address->peer),
1213             mlp_ats_to_string(mlp->pv.q[type_index]),
1214             c_queue_entries,
1215             avg,
1216             avg / (double) c_queue_entries,
1217             mlpi->q_averaged[type_index]);
1218           qual_changed = GNUNET_YES;
1219                 break;
1220         default:
1221                 GNUNET_break (0);
1222                 LOG (GNUNET_ERROR_TYPE_DEBUG, _("Update for ATS type `%s' not implemented!\n"),
1223                                 mlp_ats_to_string(type));
1224       }
1225   }
1226
1227   /* Changed, but quality will be automatically set during rebuild */
1228   if ((GNUNET_YES == mlp->mlp_prob_changed) &&
1229           (GNUNET_YES == mlp->mlp_auto_solve))
1230   {
1231                 GAS_mlp_solve_problem (mlp, addresses);
1232                 return;
1233   }
1234
1235   /* Update problem matrix if required */
1236   if (GNUNET_NO == qual_changed)
1237         return;
1238
1239   /* Address not yet included in matrix */
1240   if (MLP_UNDEFINED == mlpi->c_b)
1241         return;
1242
1243   /* Update c7) [r_q[index]][c_b] = f_q * q_averaged[type_index]
1244    * Get column mlpi->c_b */
1245   rows = glp_get_num_rows(mlp->p.prob);
1246   ind = GNUNET_malloc (rows * sizeof (int) + 1);
1247   val = GNUNET_malloc (rows * sizeof (double) + 1);
1248   int length = glp_get_mat_col (mlp->p.prob, mlpi->c_b, ind, val);
1249
1250         for (c_qual = 0; c_qual < mlp->pv.m_q; c_qual++)
1251         {
1252                 for (c_row = 0; c_row <= length; c_row ++)
1253                 {
1254                                 if (ind[c_row] == mlp->p.r_q[c_qual])
1255                                         val[c_row] = mlpi->q_averaged[c_qual];
1256                 }
1257         }
1258         /* Set updated column */
1259         glp_set_mat_col (mlp->p.prob, mlpi->c_b, length, ind, val);
1260   GNUNET_free (ind);
1261   GNUNET_free (val);
1262   mlp->mlp_prob_updated = GNUNET_YES;
1263 }
1264
1265 /**
1266  * Updates a single address in the MLP problem
1267  *
1268  * If the address did not exist before in the problem:
1269  * The MLP problem has to be recreated and the problem has to be resolved
1270  *
1271  * Otherwise the addresses' values can be updated and the existing base can
1272  * be reused
1273  *
1274  * @param solver the solver Handle
1275  * @param addresses the address hashmap containing all addresses
1276  * @param address the update address
1277  * @param session the new session (if changed otherwise current)
1278  * @param in_use the new address in use state (if changed otherwise current)
1279  * @param atsi the latest ATS information
1280  * @param atsi_count the atsi count
1281  */
1282 void
1283 GAS_mlp_address_update (void *solver,
1284                         struct GNUNET_CONTAINER_MultiHashMap *addresses,
1285                         struct ATS_Address *address,
1286                         uint32_t session,
1287                         int in_use,
1288                         const struct GNUNET_ATS_Information *atsi,
1289                         uint32_t atsi_count)
1290 {
1291         struct ATS_Peer *p;
1292         struct GAS_MLP_Handle *mlp = solver;
1293         struct MLP_information *mlpi = address->solver_information;
1294
1295         GNUNET_assert (NULL != solver);
1296         GNUNET_assert (NULL != addresses);
1297         GNUNET_assert (NULL != address);
1298         GNUNET_assert ((NULL != atsi) || (0 == atsi_count));
1299
1300   if (NULL == mlpi)
1301   {
1302       LOG (GNUNET_ERROR_TYPE_ERROR, _("Updating address for peer `%s' not added before\n"), GNUNET_i2s(&address->peer));
1303       return;
1304   }
1305         mlp_update_quality (mlp, addresses, address, atsi, atsi_count);
1306
1307   /* Is this peer included in the problem? */
1308   if (NULL == (p = GNUNET_CONTAINER_multihashmap_get (mlp->peers, &address->peer.hashPubKey)))
1309   {
1310     LOG (GNUNET_ERROR_TYPE_DEBUG, "Updating address for peer `%s' without address request \n", GNUNET_i2s(&address->peer));
1311         return;
1312   }
1313         LOG (GNUNET_ERROR_TYPE_DEBUG, "Updating address for peer `%s' with address request \n", GNUNET_i2s(&address->peer));
1314
1315         /* Problem size changed: new address for peer with pending request */
1316         mlp->mlp_prob_updated = GNUNET_YES;
1317         if (GNUNET_YES == mlp->mlp_auto_solve)
1318                 GAS_mlp_solve_problem (solver, addresses);
1319   return;
1320 }
1321
1322 /**
1323  * Deletes a single address in the MLP problem
1324  *
1325  * The MLP problem has to be recreated and the problem has to be resolved
1326  *
1327  * @param solver the MLP Handle
1328  * @param addresses the address hashmap
1329  *        the address has to be already removed from the hashmap
1330  * @param address the address to delete
1331  * @param session_only delete only session not whole address
1332  */
1333 void
1334 GAS_mlp_address_delete (void *solver,
1335     struct GNUNET_CONTAINER_MultiHashMap * addresses,
1336     struct ATS_Address *address,
1337     int session_only)
1338 {
1339         struct ATS_Peer *p;
1340         struct GAS_MLP_Handle *mlp = solver;
1341         struct MLP_information *mlpi;
1342
1343         GNUNET_assert (NULL != solver);
1344         GNUNET_assert (NULL != addresses);
1345         GNUNET_assert (NULL != address);
1346
1347         mlpi = address->solver_information;
1348
1349         if (NULL != mlpi)
1350         {
1351                         GNUNET_free (mlpi);
1352                         address->solver_information = NULL;
1353         }
1354
1355   /* Is this peer included in the problem? */
1356   if (NULL == (p = GNUNET_CONTAINER_multihashmap_get (mlp->peers, &address->peer.hashPubKey)))
1357   {
1358     LOG (GNUNET_ERROR_TYPE_DEBUG, "Deleting address for peer `%s' without address request \n", GNUNET_i2s(&address->peer));
1359         return;
1360   }
1361         LOG (GNUNET_ERROR_TYPE_DEBUG, "Deleting address for peer `%s' with address request \n", GNUNET_i2s(&address->peer));
1362
1363         /* Problem size changed: new address for peer with pending request */
1364         mlp->mlp_prob_changed = GNUNET_YES;
1365         if (GNUNET_YES == mlp->mlp_auto_solve)
1366                 GAS_mlp_solve_problem (solver, addresses);
1367   return;
1368 }
1369
1370
1371 /**
1372  * Find the active address in the set of addresses of a peer
1373  * @param cls destination
1374  * @param key peer id
1375  * @param value address
1376  * @return GNUNET_OK
1377  */
1378 static int
1379 mlp_get_preferred_address_it (void *cls, const struct GNUNET_HashCode * key, void *value)
1380 {
1381
1382   struct ATS_Address *aa = (struct ATS_Address *) cls;
1383   struct ATS_Address *addr = value;
1384   struct MLP_information *mlpi = addr->solver_information;
1385   if (mlpi == NULL)
1386     return GNUNET_YES;
1387   if (mlpi->n == GNUNET_YES)
1388   {
1389     aa = addr;
1390       aa->assigned_bw_in = mlpi->b_in;
1391       aa->assigned_bw_out = mlpi->b_out;
1392     return GNUNET_NO;
1393   }
1394   return GNUNET_YES;
1395 }
1396
1397
1398 /**
1399  * Get the preferred address for a specific peer
1400  *
1401  * @param solver the MLP Handle
1402  * @param addresses address hashmap
1403  * @param peer the peer
1404  * @return suggested address
1405  */
1406 const struct ATS_Address *
1407 GAS_mlp_get_preferred_address (void *solver,
1408                                struct GNUNET_CONTAINER_MultiHashMap * addresses,
1409                                const struct GNUNET_PeerIdentity *peer)
1410 {
1411   struct GAS_MLP_Handle *mlp = solver;
1412   struct ATS_Peer *p;
1413   struct ATS_Address *res = NULL;
1414
1415   GNUNET_assert (NULL != solver);
1416   GNUNET_assert (NULL != addresses);
1417   GNUNET_assert (NULL != peer);
1418
1419   LOG (GNUNET_ERROR_TYPE_DEBUG, "Getting preferred address for `%s'\n",
1420                 GNUNET_i2s (peer));
1421
1422   /* Is this peer included in the problem? */
1423   if (NULL == (p = GNUNET_CONTAINER_multihashmap_get (mlp->peers, &peer->hashPubKey)))
1424   {
1425           LOG (GNUNET_ERROR_TYPE_DEBUG, "Adding peer `%s' to list of peers with requests\n",
1426                         GNUNET_i2s (peer));
1427
1428           p = GNUNET_malloc (sizeof (struct ATS_Peer));
1429           p->id = (*peer);
1430           p->f = DEFAULT_PEER_PREFERENCE;
1431           GNUNET_CONTAINER_multihashmap_put (mlp->peers, &peer->hashPubKey, p, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
1432
1433           /* Added new peer, we have to rebuild problem before solving */
1434           mlp->mlp_prob_changed = GNUNET_YES;
1435   }
1436   if (GNUNET_YES == mlp->mlp_auto_solve)
1437         GAS_mlp_solve_problem (mlp, addresses);
1438
1439   /* Get prefered address */
1440   GNUNET_CONTAINER_multihashmap_get_multiple (addresses, &peer->hashPubKey,
1441                                                                                                                                                                                 mlp_get_preferred_address_it, res);
1442
1443   return res;
1444 }
1445
1446
1447 /**
1448  * Stop notifying about address and bandwidth changes for this peer
1449  *
1450  * @param solver the MLP handle
1451  * @param addresses address hashmap
1452  * @param peer the peer
1453  */
1454 void
1455 GAS_mlp_stop_get_preferred_address (void *solver,
1456                                      struct GNUNET_CONTAINER_MultiHashMap *addresses,
1457                                      const struct GNUNET_PeerIdentity *peer)
1458 {
1459   struct GAS_MLP_Handle *mlp = solver;
1460   struct ATS_Peer *p = NULL;
1461
1462   GNUNET_assert (NULL != solver);
1463   GNUNET_assert (NULL != addresses);
1464   GNUNET_assert (NULL != peer);
1465
1466   if (NULL != (p = GNUNET_CONTAINER_multihashmap_get (mlp->peers, &peer->hashPubKey)))
1467   {
1468         GNUNET_CONTAINER_multihashmap_remove (mlp->peers, &peer->hashPubKey, p);
1469         GNUNET_free (p);
1470   }
1471 }
1472
1473
1474 /**
1475  * Changes the preferences for a peer in the MLP problem
1476  *
1477  * @param solver the MLP Handle
1478  * @param client client
1479  * @param peer the peer
1480  * @param kind the kind to change the preference
1481  * @param score the score
1482  */
1483 void
1484 GAS_mlp_address_change_preference (void *solver,
1485                                    void *client,
1486                                    const struct GNUNET_PeerIdentity *peer,
1487                                    enum GNUNET_ATS_PreferenceKind kind,
1488                                    float score)
1489 {
1490   //struct GAS_MLP_Handle *mlp = solver;
1491
1492   LOG (GNUNET_ERROR_TYPE_DEBUG, "Changing preference for address for peer `%s'\n",
1493                 GNUNET_i2s(peer));
1494
1495   return;
1496 #if 0
1497   GNUNET_STATISTICS_update (mlp->stats,"# LP address preference changes", 1, GNUNET_NO);
1498
1499   //struct ATS_Peer *p = mlp_find_peer (mlp, peer);
1500   //FIXME to finish implementation
1501   /* Here we have to do the matching */
1502 #endif
1503 }
1504
1505
1506 static int
1507 mlp_free_peers (void *cls, const struct GNUNET_HashCode *key, void *value)
1508 {
1509         struct GNUNET_CONTAINER_MultiHashMap *map = cls;
1510         struct ATS_Peer *p = value;
1511
1512         GNUNET_CONTAINER_multihashmap_remove (map, key, value);
1513         GNUNET_free (p);
1514
1515         return GNUNET_OK;
1516 }
1517
1518
1519 /**
1520  * Shutdown the MLP problem solving component
1521  *
1522  * @param solver the solver handle
1523  */
1524 void
1525 GAS_mlp_done (void *solver)
1526 {
1527   struct GAS_MLP_Handle *mlp = solver;
1528   GNUNET_assert (mlp != NULL);
1529
1530   LOG (GNUNET_ERROR_TYPE_DEBUG, "Shutting down mlp solver\n");
1531   mlp_delete_problem (mlp);
1532
1533   GNUNET_CONTAINER_multihashmap_iterate (mlp->peers, &mlp_free_peers, mlp->peers);
1534   GNUNET_CONTAINER_multihashmap_destroy (mlp->peers);
1535   mlp->peers = NULL;
1536
1537   /* Clean up GLPK environment */
1538   glp_free_env();
1539   GNUNET_free (mlp);
1540
1541   LOG (GNUNET_ERROR_TYPE_DEBUG, "Shutdown down of mlp solver complete\n");
1542 }
1543
1544
1545 /**
1546  * Init the MLP problem solving component
1547  *
1548  * @param cfg the GNUNET_CONFIGURATION_Handle handle
1549  * @param stats the GNUNET_STATISTICS handle
1550  * @param network array of GNUNET_ATS_NetworkType with length dest_length
1551  * @param out_dest array of outbound quotas
1552  * @param in_dest array of outbound quota
1553  * @param dest_length array length for quota arrays
1554  * @param bw_changed_cb callback for changed bandwidth amounts
1555  * @param bw_changed_cb_cls cls for callback
1556  * @return struct GAS_MLP_Handle on success, NULL on fail
1557  */
1558 void *
1559 GAS_mlp_init (const struct GNUNET_CONFIGURATION_Handle *cfg,
1560               const struct GNUNET_STATISTICS_Handle *stats,
1561               int *network,
1562               unsigned long long *out_dest,
1563               unsigned long long *in_dest,
1564               int dest_length,
1565               GAS_bandwidth_changed_cb bw_changed_cb,
1566               void *bw_changed_cb_cls)
1567 {
1568   struct GAS_MLP_Handle * mlp = GNUNET_malloc (sizeof (struct GAS_MLP_Handle));
1569
1570   double D;
1571   double R;
1572   double U;
1573   unsigned long long tmp;
1574   unsigned int b_min;
1575   unsigned int n_min;
1576   int c;
1577   int c2;
1578   int found;
1579
1580   struct GNUNET_TIME_Relative max_duration;
1581   long long unsigned int max_iterations;
1582
1583   /* Init GLPK environment */
1584   int res = glp_init_env();
1585   switch (res) {
1586     case 0:
1587         LOG (GNUNET_ERROR_TYPE_DEBUG, "GLPK: `%s'\n",
1588           "initialization successful");
1589       break;
1590     case 1:
1591         LOG (GNUNET_ERROR_TYPE_DEBUG, "GLPK: `%s'\n",
1592           "environment is already initialized");
1593       break;
1594     case 2:
1595         LOG (GNUNET_ERROR_TYPE_ERROR, "Could not init GLPK: `%s'\n",
1596           "initialization failed (insufficient memory)");
1597       GNUNET_free(mlp);
1598       return NULL;
1599       break;
1600     case 3:
1601         LOG (GNUNET_ERROR_TYPE_ERROR, "Could not init GLPK: `%s'\n",
1602           "initialization failed (unsupported programming model)");
1603       GNUNET_free(mlp);
1604       return NULL;
1605       break;
1606     default:
1607       break;
1608   }
1609
1610
1611   mlp->pv.BIG_M = (double) BIG_M_VALUE;
1612
1613   /* Get timeout for iterations */
1614   if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_time(cfg, "ats", "MLP_MAX_DURATION", &max_duration))
1615   {
1616     max_duration = MLP_MAX_EXEC_DURATION;
1617   }
1618
1619   /* Get maximum number of iterations */
1620   if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_size(cfg, "ats", "MLP_MAX_ITERATIONS", &max_iterations))
1621   {
1622     max_iterations = MLP_MAX_ITERATIONS;
1623   }
1624
1625   /* Get diversity coefficient from configuration */
1626   if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_size (cfg, "ats",
1627                                                       "MLP_COEFFICIENT_D",
1628                                                       &tmp))
1629     D = (double) tmp / 100;
1630   else
1631     D = DEFAULT_D;
1632
1633   /* Get proportionality coefficient from configuration */
1634   if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_size (cfg, "ats",
1635                                                       "MLP_COEFFICIENT_R",
1636                                                       &tmp))
1637     R = (double) tmp / 100;
1638   else
1639     R = DEFAULT_R;
1640
1641   /* Get utilization coefficient from configuration */
1642   if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_size (cfg, "ats",
1643                                                       "MLP_COEFFICIENT_U",
1644                                                       &tmp))
1645     U = (double) tmp / 100;
1646   else
1647     U = DEFAULT_U;
1648
1649   /* Get quality metric coefficients from configuration */
1650   int i_delay = MLP_NaN;
1651   int i_distance = MLP_NaN;
1652   int q[GNUNET_ATS_QualityPropertiesCount] = GNUNET_ATS_QualityProperties;
1653   for (c = 0; c < GNUNET_ATS_QualityPropertiesCount; c++)
1654   {
1655     /* initialize quality coefficients with default value 1.0 */
1656                 mlp->pv.co_Q[c] = DEFAULT_QUALITY;
1657
1658     mlp->pv.q[c] = q[c];
1659     if (q[c] == GNUNET_ATS_QUALITY_NET_DELAY)
1660       i_delay = c;
1661     if (q[c] == GNUNET_ATS_QUALITY_NET_DISTANCE)
1662       i_distance = c;
1663   }
1664
1665   if ((i_delay != MLP_NaN) && (GNUNET_OK == GNUNET_CONFIGURATION_get_value_size (cfg, "ats",
1666                                                       "MLP_COEFFICIENT_QUALITY_DELAY",
1667                                                       &tmp)))
1668
1669         mlp->pv.co_Q[i_delay] = (double) tmp / 100;
1670   else
1671         mlp->pv.co_Q[i_delay] = DEFAULT_QUALITY;
1672
1673   if ((i_distance != MLP_NaN) && (GNUNET_OK == GNUNET_CONFIGURATION_get_value_size (cfg, "ats",
1674                                                       "MLP_COEFFICIENT_QUALITY_DISTANCE",
1675                                                       &tmp)))
1676         mlp->pv.co_Q[i_distance] = (double) tmp / 100;
1677   else
1678         mlp->pv.co_Q[i_distance] = DEFAULT_QUALITY;
1679
1680   /* Get minimum bandwidth per used address from configuration */
1681   if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_size (cfg, "ats",
1682                                                       "MLP_MIN_BANDWIDTH",
1683                                                       &tmp))
1684     b_min = tmp;
1685   else
1686   {
1687     b_min = ntohl (GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT.value__);
1688   }
1689
1690   /* Get minimum number of connections from configuration */
1691   if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_size (cfg, "ats",
1692                                                       "MLP_MIN_CONNECTIONS",
1693                                                       &tmp))
1694     n_min = tmp;
1695   else
1696     n_min = DEFAULT_MIN_CONNECTIONS;
1697
1698   /* Init network quotas */
1699   int quotas[GNUNET_ATS_NetworkTypeCount] = GNUNET_ATS_NetworkType;
1700   for (c = 0; c < GNUNET_ATS_NetworkTypeCount; c++)
1701   {
1702                 found = GNUNET_NO;
1703           for (c2 = 0; c2 < dest_length; c2++)
1704           {
1705                         if (quotas[c] == network[c2])
1706                   {
1707                                         mlp->pv.quota_index[c] = network[c2];
1708                                         mlp->pv.quota_out[c] = out_dest[c2];
1709                       mlp->pv.quota_in[c] = in_dest[c2];
1710                       found = GNUNET_YES;
1711                       LOG (GNUNET_ERROR_TYPE_DEBUG, "Quota for network `%s' (in/out) %llu/%llu\n",
1712                                                                 GNUNET_ATS_print_network_type(mlp->pv.quota_index[c]),
1713                                                                 mlp->pv.quota_out[c],
1714                                                                 mlp->pv.quota_in[c]);
1715                       break;
1716                   }
1717           }
1718
1719       /* Check if defined quota could make problem unsolvable */
1720       if ((n_min * b_min) > mlp->pv.quota_out[c])
1721       {
1722         LOG (GNUNET_ERROR_TYPE_INFO, _("Adjusting inconsistent outbound quota configuration for network `%s', is %llu must be at least %llu\n"),
1723                         GNUNET_ATS_print_network_type(mlp->pv.quota_index[c]),
1724                         mlp->pv.quota_out[c],
1725                         (n_min * b_min));
1726         mlp->pv.quota_out[c] = (n_min * b_min);
1727       }
1728       if ((n_min * b_min) > mlp->pv.quota_in[c])
1729       {
1730         LOG (GNUNET_ERROR_TYPE_INFO, _("Adjusting inconsistent inbound quota configuration for network `%s', is %llu must be at least %llu\n"),
1731                         GNUNET_ATS_print_network_type(mlp->pv.quota_index[c]),
1732                         mlp->pv.quota_in[c],
1733                         (n_min * b_min));
1734         mlp->pv.quota_in[c] = (n_min * b_min);
1735       }
1736
1737       /* Check if bandwidth is too big to make problem solvable */
1738       if (mlp->pv.BIG_M < mlp->pv.quota_out[c])
1739       {
1740         LOG (GNUNET_ERROR_TYPE_INFO, _("Adjusting outbound quota configuration for network `%s'from %llu to %.0f\n"),
1741                         GNUNET_ATS_print_network_type(mlp->pv.quota_index[c]),
1742                         mlp->pv.quota_out[c],
1743                         mlp->pv.BIG_M);
1744         mlp->pv.quota_out[c] = mlp->pv.BIG_M ;
1745       }
1746       if (mlp->pv.BIG_M < mlp->pv.quota_in[c])
1747       {
1748         LOG (GNUNET_ERROR_TYPE_INFO, _("Adjusting inbound quota configuration for network `%s' from %llu to %.0f\n"),
1749                         GNUNET_ATS_print_network_type(mlp->pv.quota_index[c]),
1750                         mlp->pv.quota_in[c],
1751                         mlp->pv.BIG_M);
1752         mlp->pv.quota_in[c] = mlp->pv.BIG_M ;
1753       }
1754
1755           if (GNUNET_NO == found)
1756                         {
1757                 mlp->pv.quota_in[c] = ntohl(GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT.value__);
1758                 mlp->pv.quota_out[c] = ntohl(GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT.value__);
1759                                 LOG (GNUNET_ERROR_TYPE_INFO, _("Using default quota configuration for network `%s' (in/out) %llu/%llu\n"),
1760                                                 GNUNET_ATS_print_network_type(mlp->pv.quota_index[c]),
1761                                                 mlp->pv.quota_in[c],
1762                                                 mlp->pv.quota_out[c]);
1763                         }
1764   }
1765
1766   /* Assign options to handle */
1767   mlp->stats = (struct GNUNET_STATISTICS_Handle *) stats;
1768   mlp->bw_changed_cb = bw_changed_cb;
1769   mlp->bw_changed_cb_cls = bw_changed_cb_cls;
1770   /* Setting MLP Input variables */
1771   mlp->pv.co_D = D;
1772   mlp->pv.co_R = R;
1773   mlp->pv.co_U = U;
1774   mlp->pv.b_min = b_min;
1775   mlp->pv.n_min = n_min;
1776   mlp->pv.m_q = GNUNET_ATS_QualityPropertiesCount;
1777   mlp->write_mip_mps = GNUNET_NO;
1778   mlp->write_mip_sol = GNUNET_NO;
1779   mlp->mlp_prob_changed = GNUNET_NO;
1780   mlp->mlp_prob_updated = GNUNET_NO;
1781   mlp->mlp_auto_solve = GNUNET_YES;
1782   mlp->peers = GNUNET_CONTAINER_multihashmap_create (10, GNUNET_NO);
1783
1784   /* Setup GLPK */
1785   /* Redirect GLPK output to GNUnet logging */
1786   glp_term_hook (&mlp_term_hook, (void *) mlp);
1787
1788   /* Init LP solving parameters */
1789   glp_init_smcp(&mlp->control_param_lp);
1790   mlp->control_param_lp.msg_lev = GLP_MSG_OFF;
1791 #if VERBOSE_GLPK
1792   mlp->control_param_lp.msg_lev = GLP_MSG_ALL;
1793 #endif
1794   mlp->control_param_lp.it_lim = max_iterations;
1795   mlp->control_param_lp.tm_lim = max_duration.rel_value;
1796
1797   /* Init MLP solving parameters */
1798   glp_init_iocp(&mlp->control_param_mlp);
1799   mlp->control_param_mlp.msg_lev = GLP_MSG_OFF;
1800 #if VERBOSE_GLPK
1801   mlp->control_param_mlp.msg_lev = GLP_MSG_ALL;
1802 #endif
1803   mlp->control_param_mlp.tm_lim = max_duration.rel_value;
1804
1805   LOG (GNUNET_ERROR_TYPE_DEBUG, "solver ready\n");
1806
1807   return mlp;
1808 }
1809
1810 /* end of gnunet-service-ats_addresses_mlp.c */