fixes
[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_UP, 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, - ((double )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         mlp_create_problem_set_value (p, p->r_q[c], mlpi->c_b, mlpi->q_averaged[c], __LINE__);
983
984
985   return GNUNET_OK;
986 }
987
988 /**
989  * Create the invariant columns c4, c6, c10, c8, c7
990  */
991 static void
992 mlp_create_problem_add_invariant_rows (struct GAS_MLP_Handle *mlp, struct MLP_Problem *p)
993 {
994   char *name;
995   int c;
996
997   /* Row for c4) minimum connection */
998
999   /* Number of minimum connections is min(|Peers|, n_min) */
1000   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);
1001
1002   /* Add row for c6) */
1003         p->r_c6 = mlp_create_problem_create_constraint (p, "c6", GLP_FX, 0.0, 0.0);
1004   /* c6 )Setting -D */
1005         mlp_create_problem_set_value (p, p->r_c6, p->c_d, -1, __LINE__);
1006
1007   /* Add rows for c 10) */
1008   for (c = 0; c < GNUNET_ATS_NetworkTypeCount; c++)
1009   {
1010       char * text;
1011       GNUNET_asprintf(&text, "c10_quota_ats_%s", GNUNET_ATS_print_network_type(mlp->pv.quota_index[c]));
1012                 p->r_quota[c] = mlp_create_problem_create_constraint (p, text, GLP_DB, 0.0, mlp->pv.quota_out[c]);
1013                 GNUNET_free (text);
1014   }
1015
1016   /* Adding rows for c 8) */
1017   p->r_c8 = mlp_create_problem_create_constraint (p, "c8", GLP_FX, 0.0, 0.0);
1018   /* -u */
1019         mlp_create_problem_set_value (p, p->r_c8, p->c_u, -1, __LINE__);
1020
1021         /* c 7) For all quality metrics */
1022         for (c = 0; c < mlp->pv.m_q; c++)
1023         {
1024                 GNUNET_asprintf(&name, "c7_q%i_%s", c, mlp_ats_to_string(mlp->pv.q[c]));
1025                 p->r_q[c] = mlp_create_problem_create_constraint (p, name, GLP_FX, 0.0, 0.0);
1026                 GNUNET_free (name);
1027                 mlp_create_problem_set_value (p, p->r_q[c], p->c_q[c], -1, __LINE__);
1028         }
1029 }
1030
1031
1032 /**
1033  * Create the invariant columns d, u, r, q0 ... qm
1034  */
1035 static void
1036 mlp_create_problem_add_invariant_columns (struct GAS_MLP_Handle *mlp, struct MLP_Problem *p)
1037 {
1038   char *name;
1039   int c;
1040
1041   /* Diversity d column  */
1042   p->c_d = mlp_create_problem_create_column (p, "d", GLP_CV, GLP_LO, 0.0, 0.0, mlp->pv.co_D);
1043
1044   /* Utilization u column  */
1045   p->c_u = mlp_create_problem_create_column (p, "u", GLP_CV, GLP_LO, 0.0, 0.0, mlp->pv.co_U);
1046
1047   /* Relativity r column  */
1048   p->c_r = mlp_create_problem_create_column (p, "u", GLP_CV, GLP_LO, 0.0, 0.0, mlp->pv.co_R);
1049
1050   /* Quality metric columns */
1051   for (c = 0; c < mlp->pv.m_q; c++)
1052   {
1053     GNUNET_asprintf (&name, "q_%u", mlp->pv.q[c]);
1054         p->c_q[c] = mlp_create_problem_create_column (p, name, GLP_CV, GLP_LO, 0.0, 0.0, mlp->pv.co_Q[c]);
1055         GNUNET_free (name);
1056   }
1057 }
1058
1059
1060 /**
1061  * Create the MLP problem
1062  *
1063  * @param mlp the MLP handle
1064  * @param addresses the hashmap containing all adresses
1065  * @return GNUNET_OK or GNUNET_SYSERR
1066  */
1067 static int
1068 mlp_create_problem (struct GAS_MLP_Handle *mlp, struct GNUNET_CONTAINER_MultiHashMap * addresses)
1069 {
1070   struct MLP_Problem *p = &mlp->p;
1071         int res = GNUNET_OK;
1072
1073   GNUNET_assert (p->prob == NULL);
1074   GNUNET_assert (p->ia == NULL);
1075   GNUNET_assert (p->ja == NULL);
1076   GNUNET_assert (p->ar == NULL);
1077   /* Reset MLP problem struct */
1078
1079   /* create the glpk problem */
1080   p->prob = glp_create_prob ();
1081   GNUNET_assert (NULL != p->prob);
1082   p->num_peers = GNUNET_CONTAINER_multihashmap_size (mlp->peers);
1083   p->num_addresses = mlp_create_problem_count_addresses (mlp->peers, addresses);
1084
1085   /* Create problem matrix: 10 * #addresses + #q * #addresses + #q, + #peer + 2 + 1 */
1086   p->num_elements = (10 * p->num_addresses + mlp->pv.m_q * p->num_addresses +  mlp->pv.m_q + p->num_peers + 2 + 1);
1087         LOG (GNUNET_ERROR_TYPE_DEBUG, "Rebuilding problem for %u peer(s) and %u addresse(s) and %u quality metrics == %u elements\n",
1088                         p->num_peers, p->num_addresses, mlp->pv.m_q, p->num_elements);
1089         LOG (GNUNET_ERROR_TYPE_DEBUG, "Rebuilding %u \n", mlp->pv.b_min);
1090
1091   /* Set a problem name */
1092   glp_set_prob_name (p->prob, "GNUnet ATS bandwidth distribution");
1093   /* Set optimization direction to maximize */
1094   glp_set_obj_dir (p->prob, GLP_MAX);
1095
1096   /* Create problem matrix */
1097   /* last +1 caused by glpk index starting with one: [1..elements]*/
1098   p->ci = 1;
1099   /* row index */
1100   int *ia = GNUNET_malloc (p->num_elements * sizeof (int));
1101   p->ia = ia;
1102   /* column index */
1103   int *ja = GNUNET_malloc (p->num_elements * sizeof (int));
1104   p->ja = ja;
1105   /* coefficient */
1106   double *ar= GNUNET_malloc (p->num_elements * sizeof (double));
1107   p->ar = ar;
1108
1109   /* Adding invariant columns */
1110   mlp_create_problem_add_invariant_columns (mlp, p);
1111
1112   /* Adding address independent constraint rows */
1113   mlp_create_problem_add_invariant_rows (mlp, p);
1114
1115   /* Adding address independent constraint rows */
1116   GNUNET_CONTAINER_multihashmap_iterate (addresses, &mlp_create_problem_add_address_information, mlp);
1117
1118   /* Load the matrix */
1119         LOG (GNUNET_ERROR_TYPE_DEBUG, "Loading matrix\n");
1120   glp_load_matrix(p->prob, (p->ci)-1, p->ia, p->ja, p->ar);
1121
1122   return res;
1123 }
1124
1125 /**
1126  * Solves the LP problem
1127  *
1128  * @param mlp the MLP Handle
1129  * @return GNUNET_OK if could be solved, GNUNET_SYSERR on failure
1130  */
1131 static int
1132 mlp_solve_lp_problem (struct GAS_MLP_Handle *mlp)
1133 {
1134         int res = 0;
1135         if (GNUNET_YES == mlp->mlp_prob_changed)
1136         {
1137                 /* Problem was recreated: use LP presolver */
1138     mlp->control_param_lp.presolve = GLP_ON;
1139         }
1140         else
1141         {
1142                 /* Problem was not recreated: do not use LP presolver */
1143                 mlp->control_param_lp.presolve = GLP_OFF;
1144         }
1145
1146         res = glp_simplex(mlp->p.prob, &mlp->control_param_lp);
1147         if (0 == res)
1148                 LOG (GNUNET_ERROR_TYPE_DEBUG, "Solving LP problem: 0x%02X %s\n", res, mlp_solve_to_string(res));
1149         else
1150                 LOG (GNUNET_ERROR_TYPE_DEBUG, "Solving LP problem failed: 0x%02X %s\n", res, mlp_solve_to_string(res));
1151
1152   /* Analyze problem status  */
1153   res = glp_get_status (mlp->p.prob);
1154   switch (res) {
1155     /* solution is optimal */
1156     case GLP_OPT:
1157     /* solution is feasible */
1158     case GLP_FEAS:
1159       LOG (GNUNET_ERROR_TYPE_DEBUG, "Solving LP problem: 0x%02X %s\n",
1160                 res, mlp_status_to_string(res));
1161       return GNUNET_OK;
1162     /* Problem was ill-defined, no way to handle that */
1163     default:
1164       LOG (GNUNET_ERROR_TYPE_DEBUG, "Solving LP problem failed, no solution: 0x%02X %s\n",
1165                 res, mlp_status_to_string(res));
1166       return GNUNET_SYSERR;
1167   }
1168 }
1169
1170
1171 /**
1172  * Solves the MLP problem
1173  *
1174  * @param mlp the MLP Handle
1175  * @return GNUNET_OK if could be solved, GNUNET_SYSERR on failure
1176  */
1177 int
1178 mlp_solve_mlp_problem (struct GAS_MLP_Handle *mlp)
1179 {
1180         int res = 0;
1181         res = glp_intopt(mlp->p.prob, &mlp->control_param_mlp);
1182         if (0 == res)
1183                 LOG (GNUNET_ERROR_TYPE_DEBUG, "Solving MLP problem: 0x%02X %s\n", res, mlp_solve_to_string(res));
1184         else
1185                 LOG (GNUNET_ERROR_TYPE_DEBUG, "Solving MLP problem failed: 0x%02X %s\n", res, mlp_solve_to_string(res));
1186   /* Analyze problem status  */
1187   res = glp_mip_status(mlp->p.prob);
1188   switch (res) {
1189     /* solution is optimal */
1190     case GLP_OPT:
1191     /* solution is feasible */
1192     case GLP_FEAS:
1193       LOG (GNUNET_ERROR_TYPE_DEBUG, "Solving LP problem: %s\n", mlp_status_to_string(res));
1194       return GNUNET_OK;
1195     /* Problem was ill-defined, no way to handle that */
1196     default:
1197       LOG (GNUNET_ERROR_TYPE_DEBUG,"Solving MLP problem failed, %s\n\n", mlp_status_to_string(res));
1198       return GNUNET_SYSERR;
1199   }
1200 }
1201
1202
1203 /**
1204  * Solves the MLP problem
1205  *
1206  * @param mlp the MLP Handle
1207  * @return GNUNET_OK if could be solved, GNUNET_SYSERR on failure
1208  */
1209 int
1210 mlp_propagate_results (void *cls, const struct GNUNET_HashCode *key, void *value)
1211 {
1212         struct GAS_MLP_Handle *mlp = cls;
1213         struct ATS_Address *address;
1214         struct MLP_information *mlpi;
1215         double mlp_bw;
1216         double mlp_use;
1217
1218   /* Check if we have to add this peer due to a pending request */
1219   if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains(mlp->peers, key))
1220         return GNUNET_OK;
1221
1222   address = value;
1223   GNUNET_assert (address->solver_information != NULL);
1224   mlpi = address->solver_information;
1225
1226   mlp_bw = glp_mip_col_val(mlp->p.prob, mlpi->c_b);
1227   mlp_use = glp_mip_col_val(mlp->p.prob, mlpi->c_n);
1228
1229   if ((GLP_YES == mlp_use) && (GNUNET_NO == address->active))
1230   {
1231         /* Address switch: Activate address*/
1232                 address->active = GNUNET_YES;
1233                 address->assigned_bw_in.value__ = htonl (0);
1234                 address->assigned_bw_out.value__ = htonl (0);
1235                 mlp->bw_changed_cb (mlp->bw_changed_cb_cls, address);
1236   }
1237   else if ((GLP_NO == mlp_use) && (GNUNET_YES == address->active))
1238   {
1239                 /* Address switch: Disable address*/
1240                 address->active = GNUNET_NO;
1241                 /* Set bandwidth to 0 */
1242                 address->assigned_bw_in.value__ = htonl (0);
1243                 address->assigned_bw_out.value__ = htonl (0);
1244                 mlp->bw_changed_cb (mlp->bw_changed_cb_cls, address);
1245   }
1246   else if ((mlp_bw != ntohl(address->assigned_bw_out.value__)) ||
1247                                  (mlp_bw != ntohl(address->assigned_bw_in.value__)))
1248   {
1249         /* Bandwidth changed */
1250                 address->assigned_bw_in.value__ = htonl (mlp_bw);
1251                 address->assigned_bw_out.value__ = htonl (mlp_bw);
1252                 mlp->bw_changed_cb (mlp->bw_changed_cb_cls, address);
1253   }
1254
1255   return GNUNET_OK;
1256 }
1257
1258
1259
1260
1261 /**
1262  * Solves the MLP problem
1263  *
1264  * @param solver the MLP Handle
1265  * @param addresses the address hashmap
1266  * @return GNUNET_OK if could be solved, GNUNET_SYSERR on failure
1267  */
1268 int
1269 GAS_mlp_solve_problem (void *solver, struct GNUNET_CONTAINER_MultiHashMap * addresses)
1270 {
1271         struct GAS_MLP_Handle *mlp = solver;
1272         int res = 0;
1273         struct GNUNET_TIME_Absolute start_lp;
1274         struct GNUNET_TIME_Relative duration_lp;
1275         struct GNUNET_TIME_Absolute start_mlp;
1276         struct GNUNET_TIME_Relative duration_mlp;
1277         GNUNET_assert (NULL != solver);
1278
1279         if ((GNUNET_NO == mlp->mlp_prob_changed) && (GNUNET_NO == mlp->mlp_prob_updated))
1280         {
1281                 LOG (GNUNET_ERROR_TYPE_DEBUG, "No changes to problem\n");
1282                 return GNUNET_OK;
1283         }
1284
1285         if (GNUNET_YES == mlp->mlp_prob_changed)
1286         {
1287                         LOG (GNUNET_ERROR_TYPE_DEBUG, "Problem size changed, rebuilding\n");
1288                         mlp_delete_problem (mlp);
1289                         mlp_create_problem (mlp, addresses);
1290         }
1291         else
1292         {
1293                         LOG (GNUNET_ERROR_TYPE_DEBUG, "Problem was updated, resolving\n");
1294         }
1295
1296
1297         /* Run LP solver */
1298         LOG (GNUNET_ERROR_TYPE_DEBUG, "Running LP solver \n");
1299         start_lp = GNUNET_TIME_absolute_get();
1300         mlp_solve_lp_problem (mlp);
1301         duration_lp = GNUNET_TIME_absolute_get_duration (start_lp);
1302
1303   /* Run LP solver */
1304         LOG (GNUNET_ERROR_TYPE_DEBUG, "Running MLP solver \n");
1305         start_mlp = GNUNET_TIME_absolute_get();
1306         mlp_solve_lp_problem (mlp);
1307         duration_mlp = GNUNET_TIME_absolute_get_duration (start_mlp);
1308         LOG (GNUNET_ERROR_TYPE_DEBUG, "Solver took LP %llu ms,  MLP %llu ms\n",
1309                         (unsigned long long) duration_lp.rel_value,
1310                         (unsigned long long) duration_mlp.rel_value);
1311
1312         /* Store LP */
1313 #if DUMP_PROBLEM
1314         char *filename;
1315         GNUNET_asprintf (&filename, "problem_%llu.lp", GNUNET_TIME_absolute_get().abs_value);
1316         glp_write_lp (mlp->p.prob, 0, filename);
1317         GNUNET_free (filename);
1318 #endif
1319
1320         /* Propagate result*/
1321         if (GNUNET_OK == res)
1322         {
1323                 GNUNET_CONTAINER_multihashmap_iterate (addresses, &mlp_propagate_results, mlp);
1324         }
1325
1326         /* Reset change and update marker */
1327         mlp->mlp_prob_updated = GNUNET_NO;
1328         mlp->mlp_prob_changed = GNUNET_NO;
1329
1330         return res;
1331
1332         /* Solve problem */
1333 #if 0
1334   struct GAS_MLP_Handle *mlp = solver;
1335   int res;
1336
1337   GNUNET_assert (NULL != solver);
1338   GNUNET_assert (NULL != ctx);
1339
1340   /* Check if solving is already running */
1341   if (GNUNET_YES == mlp->semaphore)
1342   {
1343     if (mlp->mlp_task != GNUNET_SCHEDULER_NO_TASK)
1344     {
1345       GNUNET_SCHEDULER_cancel(mlp->mlp_task);
1346       mlp->mlp_task = GNUNET_SCHEDULER_NO_TASK;
1347     }
1348     mlp->mlp_task = GNUNET_SCHEDULER_add_delayed (mlp->exec_interval, &mlp_scheduler, mlp);
1349     return GNUNET_SYSERR;
1350   }
1351   mlp->semaphore = GNUNET_YES;
1352
1353   mlp->last_execution = GNUNET_TIME_absolute_get ();
1354
1355   ctx->lp_result = GNUNET_SYSERR;
1356   ctx->mlp_result = GNUNET_SYSERR;
1357   ctx->lp_duration = GNUNET_TIME_UNIT_FOREVER_REL;
1358   ctx->mlp_duration = GNUNET_TIME_UNIT_FOREVER_REL;
1359
1360   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Solve LP problem\n");
1361 #if WRITE_MLP
1362   char * name;
1363   static int i;
1364   i++;
1365   GNUNET_asprintf(&name, "problem_%i", i);
1366   glp_write_lp (mlp->prob, 0, name);
1367   GNUNET_free (name);
1368 # endif
1369
1370   res = mlp_solve_lp_problem (mlp, ctx);
1371   ctx->lp_result = res;
1372   if (res != GNUNET_OK)
1373   {
1374     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "LP Problem solving failed\n");
1375     mlp->semaphore = GNUNET_NO;
1376     return GNUNET_SYSERR;
1377   }
1378
1379 #if WRITE_MLP
1380   GNUNET_asprintf(&name, "problem_%i_lp_solution", i);
1381   glp_print_sol (mlp->prob,  name);
1382   GNUNET_free (name);
1383 # endif
1384
1385
1386   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Solve MLP problem\n");
1387   res = mlp_solve_mlp_problem (mlp, ctx);
1388   ctx->mlp_result = res;
1389   if (res != GNUNET_OK)
1390   {
1391     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "MLP Problem solving failed\n");
1392     mlp->semaphore = GNUNET_NO;
1393     return GNUNET_SYSERR;
1394   }
1395 #if WRITE_MLP
1396   GNUNET_asprintf(&name, "problem_%i_mlp_solution", i);
1397   glp_print_mip (mlp->prob, name);
1398   GNUNET_free (name);
1399 # endif
1400
1401   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Problem solved %s (LP duration %llu / MLP duration %llu)\n",
1402       (GNUNET_OK == res) ? "successfully" : "failed",
1403       ctx->lp_duration.rel_value,
1404       ctx->mlp_duration.rel_value);
1405   /* Process result */
1406   struct ATS_Peer *p = NULL;
1407   struct ATS_Address *a = NULL;
1408   struct MLP_information *mlpi = NULL;
1409
1410   for (p = mlp->peer_head; p != NULL; p = p->next)
1411   {
1412     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer `%s'\n", GNUNET_i2s (&p->id));
1413     for (a = p->head; a != NULL; a = a->next)
1414     {
1415       double b = 0.0;
1416       double n = 0.0;
1417
1418       mlpi = a->solver_information;
1419
1420       b = glp_mip_col_val(mlp->prob, mlpi->c_b);
1421       mlpi->b = b;
1422
1423       n = glp_mip_col_val(mlp->prob, mlpi->c_n);
1424       if (n == 1.0)
1425       {
1426         /* This is the address to be used */
1427         mlpi->n = GNUNET_YES;
1428       }
1429       else
1430       {
1431         /* This is the address not used */
1432         mlpi->n = GNUNET_NO;
1433       }
1434
1435       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "\tAddress %s %f\n",
1436           (n == 1.0) ? "[x]" : "[ ]", b);
1437
1438       /* Notify addresses */
1439       if ((ntohl(a->assigned_bw_in.value__) != b) ||
1440                 (ntohl(a->assigned_bw_out.value__) != b) ||
1441                 (mlpi->n != a->active))
1442       {
1443                 a->assigned_bw_in.value__ = htonl(b);
1444                 a->assigned_bw_out.value__ = htonl(b);
1445                 a->active = mlpi->n;
1446                 mlp->bw_changed_cb (mlp->bw_changed_cb_cls, a);
1447       }
1448     }
1449   }
1450
1451   if (mlp->mlp_task != GNUNET_SCHEDULER_NO_TASK)
1452   {
1453     GNUNET_SCHEDULER_cancel(mlp->mlp_task);
1454     mlp->mlp_task = GNUNET_SCHEDULER_NO_TASK;
1455   }
1456   mlp->mlp_task = GNUNET_SCHEDULER_add_delayed (mlp->exec_interval, &mlp_scheduler, mlp);
1457   mlp->semaphore = GNUNET_NO;
1458   return res;
1459 #endif
1460 }
1461
1462 /**
1463  * Add a single address to the solve
1464  *
1465  * @param solver the solver Handle
1466  * @param addresses the address hashmap containing all addresses
1467  * @param address the address to add
1468  */
1469 void
1470 GAS_mlp_address_add (void *solver, struct GNUNET_CONTAINER_MultiHashMap * addresses, struct ATS_Address *address)
1471 {
1472   struct GAS_MLP_Handle *mlp = solver;
1473   struct ATS_Peer *p;
1474
1475   GNUNET_assert (NULL != solver);
1476   GNUNET_assert (NULL != addresses);
1477   GNUNET_assert (NULL != address);
1478
1479         /* TODO Add address here */
1480
1481   /* Is this peer included in the problem? */
1482   if (NULL == (p = GNUNET_CONTAINER_multihashmap_get (mlp->peers, &address->peer.hashPubKey)))
1483   {
1484     LOG (GNUNET_ERROR_TYPE_DEBUG, "Adding address for peer `%s' without address request \n", GNUNET_i2s(&address->peer));
1485         return;
1486   }
1487   if (NULL != address->solver_information)
1488   {
1489                 GNUNET_break (0);
1490   }
1491
1492         LOG (GNUNET_ERROR_TYPE_DEBUG, "Adding address for peer `%s' with address request \n", GNUNET_i2s(&address->peer));
1493         /* Problem size changed: new address for peer with pending request */
1494         mlp->mlp_prob_changed = GNUNET_YES;
1495         if (GNUNET_YES == mlp->mlp_auto_solve)
1496                 GAS_mlp_solve_problem (solver, addresses);
1497 }
1498
1499 /**
1500  * Updates a single address in the MLP problem
1501  *
1502  * If the address did not exist before in the problem:
1503  * The MLP problem has to be recreated and the problem has to be resolved
1504  *
1505  * Otherwise the addresses' values can be updated and the existing base can
1506  * be reused
1507  *
1508  * @param solver the solver Handle
1509  * @param addresses the address hashmap containing all addresses
1510  * @param address the update address
1511  * @param session the new session (if changed otherwise current)
1512  * @param in_use the new address in use state (if changed otherwise current)
1513  * @param atsi the latest ATS information
1514  * @param atsi_count the atsi count
1515  */
1516 void
1517 GAS_mlp_address_update (void *solver,
1518                         struct GNUNET_CONTAINER_MultiHashMap *addresses,
1519                         struct ATS_Address *address,
1520                         uint32_t session,
1521                         int in_use,
1522                         const struct GNUNET_ATS_Information *atsi,
1523                         uint32_t atsi_count)
1524 {
1525         struct ATS_Peer *p;
1526         struct GAS_MLP_Handle *mlp = solver;
1527
1528         GNUNET_assert (NULL != solver);
1529         GNUNET_assert (NULL != addresses);
1530         GNUNET_assert (NULL != address);
1531         GNUNET_assert ((NULL != atsi) || (0 == atsi_count));
1532
1533         /* TODO Update address here */
1534
1535   /* Is this peer included in the problem? */
1536   if (NULL == (p = GNUNET_CONTAINER_multihashmap_get (mlp->peers, &address->peer.hashPubKey)))
1537   {
1538     LOG (GNUNET_ERROR_TYPE_DEBUG, "Updating address for peer `%s' without address request \n", GNUNET_i2s(&address->peer));
1539         return;
1540   }
1541         LOG (GNUNET_ERROR_TYPE_DEBUG, "Updating address for peer `%s' with address request \n", GNUNET_i2s(&address->peer));
1542
1543         /* Problem size changed: new address for peer with pending request */
1544         mlp->mlp_prob_updated = GNUNET_YES;
1545         if (GNUNET_YES == mlp->mlp_auto_solve)
1546                 GAS_mlp_solve_problem (solver, addresses);
1547   return;
1548
1549 #if 0
1550   GNUNET_STATISTICS_update (mlp->stats, "# MLP address updates", 1, GNUNET_NO);
1551
1552   /* We add a new address */
1553   if (address->solver_information == NULL)
1554     new = GNUNET_YES;
1555   else
1556     new = GNUNET_NO;
1557
1558   /* Do the update */
1559   if (new == GNUNET_YES)
1560   {
1561     mlpi = GNUNET_malloc (sizeof (struct MLP_information));
1562
1563     int c;
1564     for (c = 0; c < GNUNET_ATS_QualityPropertiesCount; c++)
1565     {
1566       int c2;
1567       mlpi->r_q[c] = 0;
1568       for (c2 = 0; c2 < MLP_AVERAGING_QUEUE_LENGTH; c2++)
1569         mlpi->q[c][c2] = -1.0; /* -1.0: invalid value */
1570       mlpi->q_avg_i[c] = 0;
1571       mlpi->q_averaged[c] = 0.0;
1572     }
1573
1574     address->solver_information = mlpi;
1575     mlp->num_addresses ++;
1576     GNUNET_STATISTICS_update (mlp->stats, "# addresses in MLP", 1, GNUNET_NO);
1577
1578     /* Check for and add peer */
1579     struct ATS_Peer *peer = mlp_find_peer (mlp, &address->peer);
1580     if (peer == NULL)
1581     {
1582
1583       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding new peer `%s'\n",
1584           GNUNET_i2s (&address->peer));
1585
1586       peer = GNUNET_malloc (sizeof (struct ATS_Peer));
1587       peer->head = NULL;
1588       peer->tail = NULL;
1589
1590       int c;
1591       for (c = 0; c < GNUNET_ATS_QualityPropertiesCount; c++)
1592       {
1593         peer->f_q[c] = 1.0;
1594       }
1595       peer->f = 1.0;
1596
1597       memcpy (&peer->id, &address->peer, sizeof (struct GNUNET_PeerIdentity));
1598       GNUNET_assert(address->prev == NULL);
1599       GNUNET_assert(address->next == NULL);
1600       GNUNET_CONTAINER_DLL_insert (peer->head, peer->tail, address);
1601       GNUNET_CONTAINER_DLL_insert (mlp->peer_head, mlp->peer_tail, peer);
1602       mlp->c_p ++;
1603       GNUNET_STATISTICS_update (mlp->stats, "# peers in MLP", 1, GNUNET_NO);
1604     }
1605     else
1606     {
1607
1608       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding address to peer `%s'\n",
1609           GNUNET_i2s (&address->peer));
1610
1611       GNUNET_CONTAINER_DLL_insert (peer->head, peer->tail, address);
1612     }
1613     update_quality (mlp, address);
1614   }
1615   else
1616   {
1617     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Updating existing address to peer `%s'\n",
1618         GNUNET_i2s (&address->peer));
1619
1620     update_quality (mlp, address);
1621   }
1622
1623   /* Recalculate */
1624   if (new == GNUNET_YES)
1625   {
1626     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Recreating problem: new address\n");
1627
1628     mlp_delete_problem (mlp);
1629     mlp_create_problem (mlp, peers);
1630     mlp->presolver_required = GNUNET_YES;
1631   }
1632   if (mlp->auto_solve == GNUNET_YES)
1633     GAS_mlp_solve_problem (mlp, &ctx);
1634 #endif
1635 }
1636
1637 /**
1638  * Deletes a single address in the MLP problem
1639  *
1640  * The MLP problem has to be recreated and the problem has to be resolved
1641  *
1642  * @param solver the MLP Handle
1643  * @param addresses the address hashmap
1644  *        the address has to be already removed from the hashmap
1645  * @param address the address to delete
1646  * @param session_only delete only session not whole address
1647  */
1648 void
1649 GAS_mlp_address_delete (void *solver,
1650     struct GNUNET_CONTAINER_MultiHashMap * addresses,
1651     struct ATS_Address *address,
1652     int session_only)
1653 {
1654         struct ATS_Peer *p;
1655         struct GAS_MLP_Handle *mlp = solver;
1656
1657         GNUNET_assert (NULL != solver);
1658         GNUNET_assert (NULL != addresses);
1659         GNUNET_assert (NULL != address);
1660
1661         /* TODO Delete address here */
1662         if (NULL != address->solver_information)
1663         {
1664                         GNUNET_free (address->solver_information);
1665                         address->solver_information = NULL;
1666         }
1667
1668   /* Is this peer included in the problem? */
1669   if (NULL == (p = GNUNET_CONTAINER_multihashmap_get (mlp->peers, &address->peer.hashPubKey)))
1670   {
1671     LOG (GNUNET_ERROR_TYPE_DEBUG, "Deleting address for peer `%s' without address request \n", GNUNET_i2s(&address->peer));
1672         return;
1673   }
1674         LOG (GNUNET_ERROR_TYPE_DEBUG, "Deleting address for peer `%s' with address request \n", GNUNET_i2s(&address->peer));
1675
1676         /* Problem size changed: new address for peer with pending request */
1677         mlp->mlp_prob_changed = GNUNET_YES;
1678         if (GNUNET_YES == mlp->mlp_auto_solve)
1679                 GAS_mlp_solve_problem (solver, addresses);
1680   return;
1681
1682 #if 0
1683   GNUNET_STATISTICS_update (mlp->stats,"# LP address deletions", 1, GNUNET_NO);
1684   struct GAS_MLP_SolutionContext ctx;
1685
1686   /* Free resources */
1687   if (address->solver_information != NULL)
1688   {
1689     GNUNET_free (address->solver_information);
1690     address->solver_information = NULL;
1691
1692     mlp->num_addresses --;
1693     GNUNET_STATISTICS_update (mlp->stats, "# addresses in MLP", -1, GNUNET_NO);
1694   }
1695
1696   /* Remove from peer list */
1697   struct ATS_Peer *head = mlp_find_peer (mlp, &address->peer);
1698   GNUNET_assert (head != NULL);
1699
1700   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Deleting address for `%s'\n", GNUNET_i2s (&address->peer));
1701
1702   GNUNET_CONTAINER_DLL_remove (head->head, head->tail, address);
1703   if ((head->head == NULL) && (head->tail == NULL))
1704   {
1705     /* No address for peer left, remove peer */
1706
1707     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Deleting peer `%s'\n", GNUNET_i2s (&address->peer));
1708
1709     GNUNET_CONTAINER_DLL_remove (mlp->peer_head, mlp->peer_tail, head);
1710     GNUNET_free (head);
1711     mlp->c_p --;
1712     GNUNET_STATISTICS_update (mlp->stats, "# peers in MLP", -1, GNUNET_NO);
1713   }
1714
1715   /* Update problem */
1716   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Recreating problem: new address\n");
1717
1718   mlp_delete_problem (mlp);
1719   if ((GNUNET_CONTAINER_multihashmap_size (peers) > 0) && (mlp->c_p > 0))
1720   {
1721     mlp_create_problem (mlp, peers);
1722
1723     /* Recalculate */
1724     mlp->presolver_required = GNUNET_YES;
1725     if (mlp->auto_solve == GNUNET_YES)
1726       GAS_mlp_solve_problem (mlp, &ctx);
1727   }
1728 #endif
1729 }
1730
1731
1732 /**
1733  * Find the active address in the set of addresses of a peer
1734  * @param cls destination
1735  * @param key peer id
1736  * @param value address
1737  * @return GNUNET_OK
1738  */
1739 static int
1740 mlp_get_preferred_address_it (void *cls, const struct GNUNET_HashCode * key, void *value)
1741 {
1742
1743   struct ATS_Address *aa = (struct ATS_Address *) cls;
1744   struct ATS_Address *addr = value;
1745   struct MLP_information *mlpi = addr->solver_information;
1746   if (mlpi == NULL)
1747     return GNUNET_YES;
1748   if (mlpi->n == GNUNET_YES)
1749   {
1750     aa = addr;
1751     if (mlpi->b > (double) UINT32_MAX)
1752       aa->assigned_bw_out.value__ = htonl (UINT32_MAX);
1753     else
1754       aa->assigned_bw_out.value__ = htonl((uint32_t) mlpi->b);
1755     aa->assigned_bw_in.value__ = htonl(0);
1756     return GNUNET_NO;
1757   }
1758   return GNUNET_YES;
1759 }
1760
1761
1762 /**
1763  * Get the preferred address for a specific peer
1764  *
1765  * @param solver the MLP Handle
1766  * @param addresses address hashmap
1767  * @param peer the peer
1768  * @return suggested address
1769  */
1770 const struct ATS_Address *
1771 GAS_mlp_get_preferred_address (void *solver,
1772                                struct GNUNET_CONTAINER_MultiHashMap * addresses,
1773                                const struct GNUNET_PeerIdentity *peer)
1774 {
1775   struct GAS_MLP_Handle *mlp = solver;
1776   struct ATS_Peer *p;
1777   struct ATS_Address *res = NULL;
1778
1779   GNUNET_assert (NULL != solver);
1780   GNUNET_assert (NULL != addresses);
1781   GNUNET_assert (NULL != peer);
1782
1783   LOG (GNUNET_ERROR_TYPE_DEBUG, "Getting preferred address for `%s'\n",
1784                 GNUNET_i2s (peer));
1785
1786   /* Is this peer included in the problem? */
1787   if (NULL == (p = GNUNET_CONTAINER_multihashmap_get (mlp->peers, &peer->hashPubKey)))
1788   {
1789           LOG (GNUNET_ERROR_TYPE_DEBUG, "Adding peer `%s' to list of peers with requests\n",
1790                         GNUNET_i2s (peer));
1791
1792           p = GNUNET_malloc (sizeof (struct ATS_Peer));
1793           p->id = (*peer);
1794           GNUNET_CONTAINER_multihashmap_put (mlp->peers, &peer->hashPubKey, p, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
1795
1796           /* Added new peer, we have to rebuild problem before solving */
1797           mlp->mlp_prob_changed = GNUNET_YES;
1798   }
1799   GAS_mlp_solve_problem (mlp, addresses);
1800
1801   /* Get prefered address */
1802   GNUNET_CONTAINER_multihashmap_get_multiple (addresses, &peer->hashPubKey,
1803                                                                                                                                                                                 mlp_get_preferred_address_it, res);
1804
1805   return res;
1806 }
1807
1808
1809 /**
1810  * Changes the preferences for a peer in the MLP problem
1811  *
1812  * @param solver the MLP Handle
1813  * @param client client
1814  * @param peer the peer
1815  * @param kind the kind to change the preference
1816  * @param score the score
1817  */
1818 void
1819 GAS_mlp_address_change_preference (void *solver,
1820                                    void *client,
1821                                    const struct GNUNET_PeerIdentity *peer,
1822                                    enum GNUNET_ATS_PreferenceKind kind,
1823                                    float score)
1824 {
1825   //struct GAS_MLP_Handle *mlp = solver;
1826
1827   LOG (GNUNET_ERROR_TYPE_DEBUG, "Changing preference for address for peer `%s'\n",
1828                 GNUNET_i2s(peer));
1829
1830   return;
1831 #if 0
1832   GNUNET_STATISTICS_update (mlp->stats,"# LP address preference changes", 1, GNUNET_NO);
1833
1834   //struct ATS_Peer *p = mlp_find_peer (mlp, peer);
1835   //FIXME to finish implementation
1836   /* Here we have to do the matching */
1837 #endif
1838 }
1839
1840
1841 static int
1842 mlp_free_peers (void *cls, const struct GNUNET_HashCode *key, void *value)
1843 {
1844         struct GNUNET_CONTAINER_MultiHashMap *map = cls;
1845         struct ATS_Peer *p = value;
1846
1847         GNUNET_CONTAINER_multihashmap_remove (map, key, value);
1848         GNUNET_free (p);
1849
1850         return GNUNET_OK;
1851 }
1852
1853
1854 /**
1855  * Shutdown the MLP problem solving component
1856  *
1857  * @param solver the solver handle
1858  */
1859 void
1860 GAS_mlp_done (void *solver)
1861 {
1862   struct GAS_MLP_Handle *mlp = solver;
1863   GNUNET_assert (mlp != NULL);
1864
1865   LOG (GNUNET_ERROR_TYPE_DEBUG, "Shutting down mlp solver\n");
1866   mlp_delete_problem (mlp);
1867
1868   GNUNET_CONTAINER_multihashmap_iterate (mlp->peers, &mlp_free_peers, mlp->peers);
1869   GNUNET_CONTAINER_multihashmap_destroy (mlp->peers);
1870   mlp->peers = NULL;
1871
1872   /* Clean up GLPK environment */
1873   glp_free_env();
1874   GNUNET_free (mlp);
1875
1876   LOG (GNUNET_ERROR_TYPE_DEBUG, "Shutdown down of mlp solver complete\n");
1877 }
1878
1879
1880 /**
1881  * Init the MLP problem solving component
1882  *
1883  * @param cfg the GNUNET_CONFIGURATION_Handle handle
1884  * @param stats the GNUNET_STATISTICS handle
1885  * @param network array of GNUNET_ATS_NetworkType with length dest_length
1886  * @param out_dest array of outbound quotas
1887  * @param in_dest array of outbound quota
1888  * @param dest_length array length for quota arrays
1889  * @param bw_changed_cb callback for changed bandwidth amounts
1890  * @param bw_changed_cb_cls cls for callback
1891  * @return struct GAS_MLP_Handle on success, NULL on fail
1892  */
1893 void *
1894 GAS_mlp_init (const struct GNUNET_CONFIGURATION_Handle *cfg,
1895               const struct GNUNET_STATISTICS_Handle *stats,
1896               int *network,
1897               unsigned long long *out_dest,
1898               unsigned long long *in_dest,
1899               int dest_length,
1900               GAS_bandwidth_changed_cb bw_changed_cb,
1901               void *bw_changed_cb_cls)
1902 {
1903   struct GAS_MLP_Handle * mlp = GNUNET_malloc (sizeof (struct GAS_MLP_Handle));
1904
1905   double D;
1906   double R;
1907   double U;
1908   unsigned long long tmp;
1909   unsigned int b_min;
1910   unsigned int n_min;
1911   int c;
1912   int c2;
1913   int found;
1914
1915   struct GNUNET_TIME_Relative max_duration;
1916   long long unsigned int max_iterations;
1917
1918   /* Init GLPK environment */
1919   int res = glp_init_env();
1920   switch (res) {
1921     case 0:
1922         LOG (GNUNET_ERROR_TYPE_DEBUG, "GLPK: `%s'\n",
1923           "initialization successful");
1924       break;
1925     case 1:
1926         LOG (GNUNET_ERROR_TYPE_DEBUG, "GLPK: `%s'\n",
1927           "environment is already initialized");
1928       break;
1929     case 2:
1930         LOG (GNUNET_ERROR_TYPE_ERROR, "Could not init GLPK: `%s'\n",
1931           "initialization failed (insufficient memory)");
1932       GNUNET_free(mlp);
1933       return NULL;
1934       break;
1935     case 3:
1936         LOG (GNUNET_ERROR_TYPE_ERROR, "Could not init GLPK: `%s'\n",
1937           "initialization failed (unsupported programming model)");
1938       GNUNET_free(mlp);
1939       return NULL;
1940       break;
1941     default:
1942       break;
1943   }
1944
1945
1946   mlp->pv.BIG_M = (double) BIG_M_VALUE;
1947
1948   /* Get timeout for iterations */
1949   if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_time(cfg, "ats", "MLP_MAX_DURATION", &max_duration))
1950   {
1951     max_duration = MLP_MAX_EXEC_DURATION;
1952   }
1953
1954   /* Get maximum number of iterations */
1955   if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_size(cfg, "ats", "MLP_MAX_ITERATIONS", &max_iterations))
1956   {
1957     max_iterations = MLP_MAX_ITERATIONS;
1958   }
1959
1960   /* Get diversity coefficient from configuration */
1961   if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_size (cfg, "ats",
1962                                                       "MLP_COEFFICIENT_D",
1963                                                       &tmp))
1964     D = (double) tmp / 100;
1965   else
1966     D = DEFAULT_D;
1967
1968   /* Get proportionality coefficient from configuration */
1969   if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_size (cfg, "ats",
1970                                                       "MLP_COEFFICIENT_R",
1971                                                       &tmp))
1972     R = (double) tmp / 100;
1973   else
1974     R = DEFAULT_R;
1975
1976   /* Get utilization coefficient from configuration */
1977   if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_size (cfg, "ats",
1978                                                       "MLP_COEFFICIENT_U",
1979                                                       &tmp))
1980     U = (double) tmp / 100;
1981   else
1982     U = DEFAULT_U;
1983
1984   /* Get quality metric coefficients from configuration */
1985   int i_delay = NaN;
1986   int i_distance = NaN;
1987   int q[GNUNET_ATS_QualityPropertiesCount] = GNUNET_ATS_QualityProperties;
1988   for (c = 0; c < GNUNET_ATS_QualityPropertiesCount; c++)
1989   {
1990     /* initialize quality coefficients with default value 1.0 */
1991                 mlp->pv.co_Q[c] = DEFAULT_QUALITY;
1992
1993     mlp->pv.q[c] = q[c];
1994     if (q[c] == GNUNET_ATS_QUALITY_NET_DELAY)
1995       i_delay = c;
1996     if (q[c] == GNUNET_ATS_QUALITY_NET_DISTANCE)
1997       i_distance = c;
1998   }
1999
2000   if ((i_delay != NaN) && (GNUNET_OK == GNUNET_CONFIGURATION_get_value_size (cfg, "ats",
2001                                                       "MLP_COEFFICIENT_QUALITY_DELAY",
2002                                                       &tmp)))
2003
2004         mlp->pv.co_Q[i_delay] = (double) tmp / 100;
2005   else
2006         mlp->pv.co_Q[i_delay] = DEFAULT_QUALITY;
2007
2008   if ((i_distance != NaN) && (GNUNET_OK == GNUNET_CONFIGURATION_get_value_size (cfg, "ats",
2009                                                       "MLP_COEFFICIENT_QUALITY_DISTANCE",
2010                                                       &tmp)))
2011         mlp->pv.co_Q[i_distance] = (double) tmp / 100;
2012   else
2013         mlp->pv.co_Q[i_distance] = DEFAULT_QUALITY;
2014
2015   /* Get minimum bandwidth per used address from configuration */
2016   if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_size (cfg, "ats",
2017                                                       "MLP_MIN_BANDWIDTH",
2018                                                       &tmp))
2019     b_min = tmp;
2020   else
2021   {
2022     b_min = ntohl (GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT.value__);
2023   }
2024
2025   /* Get minimum number of connections from configuration */
2026   if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_size (cfg, "ats",
2027                                                       "MLP_MIN_CONNECTIONS",
2028                                                       &tmp))
2029     n_min = tmp;
2030   else
2031     n_min = DEFAULT_MIN_CONNECTIONS;
2032
2033   /* Init network quotas */
2034   int quotas[GNUNET_ATS_NetworkTypeCount] = GNUNET_ATS_NetworkType;
2035   for (c = 0; c < GNUNET_ATS_NetworkTypeCount; c++)
2036   {
2037                 found = GNUNET_NO;
2038           for (c2 = 0; c2 < dest_length; c2++)
2039           {
2040                         if (quotas[c] == network[c2])
2041                   {
2042                                         mlp->pv.quota_index[c] = network[c2];
2043                                         mlp->pv.quota_out[c] = out_dest[c2];
2044                       mlp->pv.quota_in[c] = in_dest[c2];
2045                       found = GNUNET_YES;
2046                       LOG (GNUNET_ERROR_TYPE_DEBUG, "Quota for network `%s' (in/out) %llu/%llu\n",
2047                                                                 GNUNET_ATS_print_network_type(mlp->pv.quota_index[c]),
2048                                                                 mlp->pv.quota_out[c],
2049                                                                 mlp->pv.quota_in[c]);
2050                       break;
2051                   }
2052           }
2053
2054       /* Check if defined quota could make problem unsolvable */
2055       if ((n_min * b_min) > mlp->pv.quota_out[c])
2056       {
2057         LOG (GNUNET_ERROR_TYPE_INFO, _("Adjusting inconsistent outbound quota configuration for network `%s', is %llu must be at least %llu\n"),
2058                         GNUNET_ATS_print_network_type(mlp->pv.quota_index[c]),
2059                         mlp->pv.quota_out[c],
2060                         (n_min * b_min));
2061         mlp->pv.quota_out[c] = (n_min * b_min);
2062       }
2063       if ((n_min * b_min) > mlp->pv.quota_in[c])
2064       {
2065         LOG (GNUNET_ERROR_TYPE_INFO, _("Adjusting inconsistent inbound quota configuration for network `%s', is %llu must be at least %llu\n"),
2066                         GNUNET_ATS_print_network_type(mlp->pv.quota_index[c]),
2067                         mlp->pv.quota_in[c],
2068                         (n_min * b_min));
2069         mlp->pv.quota_in[c] = (n_min * b_min);
2070       }
2071
2072       /* Check if bandwidth is too big to make problem solvable */
2073       if (mlp->pv.BIG_M < mlp->pv.quota_out[c])
2074       {
2075         LOG (GNUNET_ERROR_TYPE_INFO, _("Adjusting outbound quota configuration for network `%s'from %llu to %.0f\n"),
2076                         GNUNET_ATS_print_network_type(mlp->pv.quota_index[c]),
2077                         mlp->pv.quota_out[c],
2078                         mlp->pv.BIG_M);
2079         mlp->pv.quota_out[c] = mlp->pv.BIG_M ;
2080       }
2081       if (mlp->pv.BIG_M < mlp->pv.quota_in[c])
2082       {
2083         LOG (GNUNET_ERROR_TYPE_INFO, _("Adjusting inbound quota configuration for network `%s' from %llu to %.0f\n"),
2084                         GNUNET_ATS_print_network_type(mlp->pv.quota_index[c]),
2085                         mlp->pv.quota_in[c],
2086                         mlp->pv.BIG_M);
2087         mlp->pv.quota_in[c] = mlp->pv.BIG_M ;
2088       }
2089
2090           if (GNUNET_NO == found)
2091                         {
2092                 mlp->pv.quota_in[c] = ntohl(GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT.value__);
2093                 mlp->pv.quota_out[c] = ntohl(GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT.value__);
2094                                 LOG (GNUNET_ERROR_TYPE_INFO, _("Using default quota configuration for network `%s' (in/out) %llu/%llu\n"),
2095                                                 GNUNET_ATS_print_network_type(mlp->pv.quota_index[c]),
2096                                                 mlp->pv.quota_in[c],
2097                                                 mlp->pv.quota_out[c]);
2098                         }
2099   }
2100
2101   /* Assign options to handle */
2102   mlp->stats = (struct GNUNET_STATISTICS_Handle *) stats;
2103   mlp->bw_changed_cb = bw_changed_cb;
2104   mlp->bw_changed_cb_cls = bw_changed_cb_cls;
2105   /* Setting MLP Input variables */
2106   mlp->pv.co_D = D;
2107   mlp->pv.co_R = R;
2108   mlp->pv.co_U = U;
2109   mlp->pv.b_min = b_min;
2110   mlp->pv.n_min = n_min;
2111   mlp->pv.m_q = GNUNET_ATS_QualityPropertiesCount;
2112   mlp->mlp_prob_changed = GNUNET_NO;
2113   mlp->mlp_prob_updated = GNUNET_NO;
2114   mlp->mlp_auto_solve = GNUNET_YES;
2115   mlp->peers = GNUNET_CONTAINER_multihashmap_create (10, GNUNET_NO);
2116
2117   /* Setup GLPK */
2118   /* Redirect GLPK output to GNUnet logging */
2119   glp_term_hook (&mlp_term_hook, (void *) mlp);
2120
2121   /* Init LP solving parameters */
2122   glp_init_smcp(&mlp->control_param_lp);
2123   mlp->control_param_lp.msg_lev = GLP_MSG_OFF;
2124 #if VERBOSE_GLPK
2125   mlp->control_param_lp.msg_lev = GLP_MSG_ALL;
2126 #endif
2127   mlp->control_param_lp.it_lim = max_iterations;
2128   mlp->control_param_lp.tm_lim = max_duration.rel_value;
2129
2130   /* Init MLP solving parameters */
2131   glp_init_iocp(&mlp->control_param_mlp);
2132   mlp->control_param_mlp.msg_lev = GLP_MSG_OFF;
2133 #if VERBOSE_GLPK
2134   mlp->control_param_mlp.msg_lev = GLP_MSG_ALL;
2135 #endif
2136   mlp->control_param_mlp.tm_lim = max_duration.rel_value;
2137
2138   LOG (GNUNET_ERROR_TYPE_DEBUG, "solver ready\n");
2139
2140   return mlp;
2141 }
2142
2143 /* end of gnunet-service-ats_addresses_mlp.c */