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