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