2 This file is part of GNUnet.
3 (C) 2011 Christian Grothoff (and other contributing authors)
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.
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.
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.
22 * @file ats/gnunet-service-ats_addresses_mlp.c
23 * @brief ats mlp problem solver
24 * @author Matthias Wachs
25 * @author Christian Grothoff
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"
34 #define WRITE_MLP GNUNET_NO
35 #define DEBUG_ATS GNUNET_YES
36 #define VERBOSE_GLPK GNUNET_NO
39 * Translate glpk solver error codes to text
40 * @param retcode return code
41 * @return string with result
44 mlp_solve_to_string (int retcode)
51 return "invalid basis";
54 return "singular matrix";
57 return "ill-conditioned matrix";
60 return "invalid bounds";
63 return "solver failed";
66 return "objective lower limit reached";
69 return "objective upper limit reached";
72 return "iteration limit exceeded";
75 return "time limit exceeded";
78 return "no primal feasible solution";
81 return "root LP optimum not provided";
84 return "search terminated by application";
87 return "relative mip gap tolerance reached";
90 return "no dual feasible solution";
93 return "no convergence";
96 return "numerical instability";
99 return "invalid data";
102 return "result out of range";
106 return "unknown error";
110 return "unknown error";
115 * Translate glpk status error codes to text
116 * @param retcode return code
117 * @return string with result
120 mlp_status_to_string (int retcode)
124 return "solution is undefined";
127 return "solution is feasible";
130 return "solution is infeasible";
133 return "no feasible solution exists";
136 return "solution is optimal";
139 return "solution is unbounded";
143 return "unknown error";
147 return "unknown error";
151 * Find a peer in the DLL
152 * @param the peer to find
153 * @return the peer struct
155 static struct ATS_Peer *
156 mlp_find_peer (struct GAS_MLP_Handle *mlp, const struct GNUNET_PeerIdentity *peer)
158 struct ATS_Peer *res = mlp->peer_head;
161 if (0 == memcmp (peer, &res->id, sizeof (struct GNUNET_PeerIdentity)))
169 * Intercept GLPK terminal output
170 * @param info the mlp handle
171 * @param s the string to print
172 * @return 0: glpk prints output on terminal, 0 != surpress output
175 mlp_term_hook (void *info, const char *s)
177 /* Not needed atm struct MLP_information *mlp = info; */
178 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s", s);
183 * Delete the MLP problem and free the constrain matrix
185 * @param mlp the MLP handle
188 mlp_delete_problem (struct GAS_MLP_Handle *mlp)
192 if (mlp->prob != NULL)
193 glp_delete_prob(mlp->prob);
195 /* delete row index */
198 GNUNET_free (mlp->ia);
202 /* delete column index */
205 GNUNET_free (mlp->ja);
209 /* delete coefficients */
212 GNUNET_free (mlp->ar);
221 * Add constraints that are iterating over "forall addresses"
222 * and collects all existing peers for "forall peers" constraints
224 * @param cls GAS_MLP_Handle
225 * @param key Hashcode
226 * @param value ATS_Address
228 * @return GNUNET_OK to continue
231 create_constraint_it (void *cls, const GNUNET_HashCode * key, void *value)
233 struct GAS_MLP_Handle *mlp = cls;
234 struct ATS_Address *address = value;
235 struct MLP_information *mlpi;
236 unsigned int row_index;
239 GNUNET_assert (address->mlp_information != NULL);
240 mlpi = (struct MLP_information *) address->mlp_information;
242 /* c 1) bandwidth capping
243 * b_t + (-M) * n_t <= 0
245 row_index = glp_add_rows (mlp->prob, 1);
246 mlpi->r_c1 = row_index;
248 GNUNET_asprintf(&name, "c1_%s_%s", GNUNET_i2s(&address->peer), address->plugin);
249 glp_set_row_name (mlp->prob, row_index, name);
251 /* set row bounds: <= 0 */
252 glp_set_row_bnds (mlp->prob, row_index, GLP_UP, 0.0, 0.0);
253 mlp->ia[mlp->ci] = row_index;
254 mlp->ja[mlp->ci] = mlpi->c_b;
255 mlp->ar[mlp->ci] = 1;
258 mlp->ia[mlp->ci] = row_index;
259 mlp->ja[mlp->ci] = mlpi->c_n;
260 mlp->ar[mlp->ci] = -mlp->BIG_M;
263 /* c 3) minimum bandwidth
264 * b_t + (-n_t * b_min) >= 0
267 row_index = glp_add_rows (mlp->prob, 1);
269 GNUNET_asprintf(&name, "c3_%s_%s", GNUNET_i2s(&address->peer), address->plugin);
270 glp_set_row_name (mlp->prob, row_index, name);
272 mlpi->r_c3 = row_index;
273 /* set row bounds: >= 0 */
274 glp_set_row_bnds (mlp->prob, row_index, GLP_LO, 0.0, 0.0);
276 mlp->ia[mlp->ci] = row_index;
277 mlp->ja[mlp->ci] = mlpi->c_b;
278 mlp->ar[mlp->ci] = 1;
281 mlp->ia[mlp->ci] = row_index;
282 mlp->ja[mlp->ci] = mlpi->c_n;
283 mlp->ar[mlp->ci] = - (double) mlp->b_min;
286 /* c 4) minimum connections
287 * (1)*n_1 + ... + (1)*n_m >= n_min
289 mlp->ia[mlp->ci] = mlp->r_c4;
290 mlp->ja[mlp->ci] = mlpi->c_n;
291 mlp->ar[mlp->ci] = 1;
294 /* c 6) maximize diversity
295 * (1)*n_1 + ... + (1)*n_m - d == 0
297 mlp->ia[mlp->ci] = mlp->r_c6;
298 mlp->ja[mlp->ci] = mlpi->c_n;
299 mlp->ar[mlp->ci] = 1;
307 * Adds the problem constraints for all addresses
308 * Required for problem recreation after address deletion
310 * @param addresses all addresses
314 mlp_add_constraints_all_addresses (struct GAS_MLP_Handle *mlp, struct GNUNET_CONTAINER_MultiHashMap * addresses)
316 unsigned int n_addresses;
321 n_addresses = GNUNET_CONTAINER_multihashmap_size(addresses);
323 /* Required indices in the constrain matrix
325 * feasibility constraints:
327 * c 1) bandwidth capping
328 * #rows: |n_addresses|
329 * #indices: 2 * |n_addresses|
331 * c 2) one active address per peer
333 * #indices: |n_addresses|
335 * c 3) minium bandwidth assigned
336 * #rows: |n_addresses|
337 * #indices: 2 * |n_addresses|
339 * c 4) minimum number of active connections
341 * #indices: |n_addresses|
343 * c 5) maximum ressource consumption
344 * #rows: |ressources|
345 * #indices: |n_addresses|
347 * Sum for feasibility constraints:
348 * #rows: 3 * |n_addresses| + |ressources| + |peers| + 1
349 * #indices: 7 * |n_addresses|
351 * optimality constraints:
355 * #indices: |n_addresses| + 1
358 * #rows: |quality properties|
359 * #indices:|quality properties| + |n_addresses|
363 * #indices: |n_addresses| + 1
367 * #indices: |n_addresses| + |peers|
370 int pi = ((7 * n_addresses) + (3 * n_addresses + mlp->m_q + 2));
375 int *ia = GNUNET_malloc (pi * sizeof (int));
379 int *ja = GNUNET_malloc (pi * sizeof (int));
383 double *ar= GNUNET_malloc (pi * sizeof (double));
386 /* Adding constraint rows
387 * This constraints are kind of "for all addresses"
388 * Feasibility constraints:
390 * c 1) bandwidth capping
391 * c 3) minimum bandwidth
392 * c 4) minimum number of connections
393 * c 6) maximize diversity
396 int min = mlp->n_min;
397 if (mlp->n_min > mlp->c_p)
400 mlp->r_c4 = glp_add_rows (mlp->prob, 1);
401 glp_set_row_name (mlp->prob, mlp->r_c4, "c4");
402 glp_set_row_bnds (mlp->prob, mlp->r_c4, GLP_LO, min, min);
404 /* Add row for c6) */
406 mlp->r_c6 = glp_add_rows (mlp->prob, 1);
407 /* Set type type to fix */
408 glp_set_row_bnds (mlp->prob, mlp->r_c6, GLP_FX, 0.0, 0.0);
410 ia[mlp->ci] = mlp->r_c6 ;
411 ja[mlp->ci] = mlp->c_d;
415 GNUNET_CONTAINER_multihashmap_iterate (addresses, create_constraint_it, mlp);
417 /* Adding constraint rows
418 * This constraints are kind of "for all peers"
419 * Feasibility constraints:
421 * c 2) 1 address per peer
422 * sum (n_p1_1 + ... + n_p1_n) = 1
425 * sum (f_p * b_p1_1 + ... + f_p * b_p1_n) - u = 0
428 * V p : sum (bt_1 + ... +bt_n) - f_p * r = 0
431 /* Adding rows for c 8) */
432 mlp->r_c8 = glp_add_rows (mlp->prob, mlp->c_p);
433 glp_set_row_name (mlp->prob, mlp->r_c8, "c8");
434 /* Set row bound == 0 */
435 glp_set_row_bnds (mlp->prob, mlp->r_c8, GLP_FX, 0.0, 0.0);
437 ia[mlp->ci] = mlp->r_c8;
438 ja[mlp->ci] = mlp->c_u;
442 struct ATS_Peer * peer = mlp->peer_head;
445 struct ATS_Address *addr = peer->head;
446 struct MLP_information *mlpi = NULL;
448 /* Adding rows for c 2) */
449 peer->r_c2 = glp_add_rows (mlp->prob, 1);
450 GNUNET_asprintf(&name, "c2_%s", GNUNET_i2s(&peer->id));
451 glp_set_row_name (mlp->prob, peer->r_c2, name);
453 /* Set row bound == 1 */
454 glp_set_row_bnds (mlp->prob, peer->r_c2, GLP_FX, 1.0, 1.0);
457 /* Adding rows for c 9) */
458 peer->r_c9 = glp_add_rows (mlp->prob, 1);
459 GNUNET_asprintf(&name, "c9_%s", GNUNET_i2s(&peer->id));
460 glp_set_row_name (mlp->prob, peer->r_c9, name);
462 /* Set row bound == 0 */
463 glp_set_row_bnds (mlp->prob, peer->r_c9, GLP_LO, 0.0, 0.0);
466 ia[mlp->ci] = peer->r_c9;
467 ja[mlp->ci] = mlp->c_r;
473 mlpi = (struct MLP_information *) addr->mlp_information;
475 ia[mlp->ci] = peer->r_c2;
476 ja[mlp->ci] = mlpi->c_n;
480 ia[mlp->ci] = mlp->r_c8;
481 ja[mlp->ci] = mlpi->c_b;
482 ar[mlp->ci] = peer->f;
485 ia[mlp->ci] = peer->r_c9;
486 ja[mlp->ci] = mlpi->c_b;
496 /* For all quality metrics */
498 for (c = 0; c < mlp->m_q; c++)
500 struct ATS_Peer *p = mlp->peer_head;
503 ia[mlp->ci] = row_index;
504 ja[mlp->ci] = mlp->c_q[c];
516 * Add columns for all addresses
518 * @param cls GAS_MLP_Handle
519 * @param key Hashcode
520 * @param value ATS_Address
522 * @return GNUNET_OK to continue
525 create_columns_it (void *cls, const GNUNET_HashCode * key, void *value)
527 struct GAS_MLP_Handle *mlp = cls;
528 struct ATS_Address *address = value;
529 struct MLP_information *mlpi;
533 GNUNET_assert (address->mlp_information != NULL);
534 mlpi = address->mlp_information;
536 /* Add bandwidth column */
537 col = glp_add_cols (mlp->prob, 2);
541 GNUNET_asprintf (&name, "b_%s_%s", GNUNET_i2s (&address->peer), address->plugin);
542 glp_set_col_name (mlp->prob, mlpi->c_b , name);
544 /* Lower bound == 0 */
545 glp_set_col_bnds (mlp->prob, mlpi->c_b , GLP_LO, 0.0, 0.0);
546 /* Continuous value*/
547 glp_set_col_kind (mlp->prob, mlpi->c_b , GLP_CV);
548 /* Objective function coefficient == 0 */
549 glp_set_obj_coef (mlp->prob, mlpi->c_b , 0);
552 /* Add usage column */
553 GNUNET_asprintf (&name, "n_%s_%s", GNUNET_i2s (&address->peer), address->plugin);
554 glp_set_col_name (mlp->prob, mlpi->c_n, name);
556 /* Limit value : 0 <= value <= 1 */
557 glp_set_col_bnds (mlp->prob, mlpi->c_n, GLP_DB, 0.0, 1.0);
559 glp_set_col_kind (mlp->prob, mlpi->c_n, GLP_IV);
560 /* Objective function coefficient == 0 */
561 glp_set_obj_coef (mlp->prob, mlpi->c_n, 0);
569 * Create the MLP problem
571 * @param mlp the MLP handle
572 * @return GNUNET_OK or GNUNET_SYSERR
575 mlp_create_problem (struct GAS_MLP_Handle *mlp, struct GNUNET_CONTAINER_MultiHashMap * addresses)
584 GNUNET_assert (mlp->prob == NULL);
586 /* create the glpk problem */
587 mlp->prob = glp_create_prob ();
589 /* Set a problem name */
590 glp_set_prob_name (mlp->prob, "gnunet ats bandwidth distribution");
592 /* Set optimization direction to maximize */
593 glp_set_obj_dir (mlp->prob, GLP_MAX);
595 /* Adding invariant columns */
597 /* Diversity d column */
599 col = glp_add_cols (mlp->prob, 1);
602 glp_set_col_name (mlp->prob, col, "d");
603 /* Column objective function coefficient */
604 glp_set_obj_coef (mlp->prob, col, mlp->co_D);
605 /* Column lower bound = 0.0 */
606 glp_set_col_bnds (mlp->prob, col, GLP_LO, 0.0, 0.0);
608 /* Utilization u column */
610 col = glp_add_cols (mlp->prob, 1);
613 glp_set_col_name (mlp->prob, col, "u");
614 /* Column objective function coefficient */
615 glp_set_obj_coef (mlp->prob, col, mlp->co_U);
616 /* Column lower bound = 0.0 */
617 glp_set_col_bnds (mlp->prob, col, GLP_LO, 0.0, 0.0);
619 /* Relativity r column */
620 col = glp_add_cols (mlp->prob, 1);
623 glp_set_col_name (mlp->prob, col, "r");
624 /* Column objective function coefficient */
625 glp_set_obj_coef (mlp->prob, col, mlp->co_R);
626 /* Column lower bound = 0.0 */
627 glp_set_col_bnds (mlp->prob, col, GLP_LO, 0.0, 0.0);
629 /* Quality metric columns */
630 col = glp_add_cols(mlp->prob, mlp->m_q);
631 for (c = 0; c < mlp->m_q; c++)
633 mlp->c_q[c] = col + c;
634 GNUNET_asprintf (&name, "q_%u", mlp->q[c]);
635 glp_set_col_name (mlp->prob, col + c, name);
636 /* Column lower bound = 0.0 */
637 glp_set_col_bnds (mlp->prob, col + c, GLP_LO, 0.0, 0.0);
639 /* Coefficient == Qm */
640 glp_set_obj_coef (mlp->prob, col + c, mlp->co_Q[c]);
643 /* Add columns for addresses */
644 GNUNET_CONTAINER_multihashmap_iterate (addresses, create_columns_it, mlp);
646 /* Add constraints */
647 mlp_add_constraints_all_addresses (mlp, addresses);
649 /* Load the matrix */
650 glp_load_matrix(mlp->prob, (mlp->ci-1), mlp->ia, mlp->ja, mlp->ar);
656 * Solves the LP problem
658 * @param mlp the MLP Handle
659 * @return GNUNET_OK if could be solved, GNUNET_SYSERR on failure
662 mlp_solve_lp_problem (struct GAS_MLP_Handle *mlp)
665 struct GNUNET_TIME_Relative duration;
666 struct GNUNET_TIME_Absolute end;
667 struct GNUNET_TIME_Absolute start = GNUNET_TIME_absolute_get();
670 * Presolver is required if the problem was modified and an existing
671 * valid basis is now invalid */
672 if (mlp->presolver_required == GNUNET_YES)
673 mlp->control_param_lp.presolve = GLP_ON;
675 mlp->control_param_lp.presolve = GLP_OFF;
677 /* Solve LP problem to have initial valid solution */
679 res = glp_simplex(mlp->prob, &mlp->control_param_lp);
682 /* The LP problem instance has been successfully solved. */
684 else if (res == GLP_EITLIM)
686 /* simplex iteration limit has been exceeded. */
687 // TODO Increase iteration limit?
689 else if (res == GLP_ETMLIM)
691 /* Time limit has been exceeded. */
692 // TODO Increase time limit?
696 /* Problem was ill-defined, retry with presolver */
697 if (mlp->presolver_required == GNUNET_NO)
699 mlp->presolver_required = GNUNET_YES;
704 /* Problem was ill-defined, no way to handle that */
705 GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR,
707 "Solving LP problem failed: %i %s\n", res, mlp_solve_to_string(res));
708 return GNUNET_SYSERR;
712 end = GNUNET_TIME_absolute_get ();
713 duration = GNUNET_TIME_absolute_get_difference (start, end);
715 mlp->lp_total_duration =+ duration.rel_value;
717 GNUNET_STATISTICS_update (mlp->stats,"# LP problem solved", 1, GNUNET_NO);
718 GNUNET_STATISTICS_set (mlp->stats,"# LP execution time", duration.rel_value, GNUNET_NO);
719 GNUNET_STATISTICS_set (mlp->stats,"# LP execution time average",
720 mlp->lp_total_duration / mlp->lp_solved, GNUNET_NO);
723 /* Analyze problem status */
724 res = glp_get_status (mlp->prob);
726 /* solution is optimal */
728 /* solution is feasible */
732 /* Problem was ill-defined, no way to handle that */
734 GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR,
736 "Solving LP problem failed, no solution: %s\n", mlp_status_to_string(res));
737 return GNUNET_SYSERR;
741 /* solved sucessfully, no presolver required next time */
742 mlp->presolver_required = GNUNET_NO;
749 * Solves the MLP problem
751 * @param mlp the MLP Handle
752 * @return GNUNET_OK if could be solved, GNUNET_SYSERR on failure
755 mlp_solve_mlp_problem (struct GAS_MLP_Handle *mlp)
758 struct GNUNET_TIME_Relative duration;
759 struct GNUNET_TIME_Absolute end;
760 struct GNUNET_TIME_Absolute start = GNUNET_TIME_absolute_get();
762 /* solve MLP problem */
763 res = glp_intopt(mlp->prob, &mlp->control_param_mlp);
767 /* The MLP problem instance has been successfully solved. */
769 else if (res == GLP_EITLIM)
771 /* simplex iteration limit has been exceeded. */
772 // TODO Increase iteration limit?
774 else if (res == GLP_ETMLIM)
776 /* Time limit has been exceeded. */
777 // TODO Increase time limit?
781 /* Problem was ill-defined, no way to handle that */
782 GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR,
784 "Solving MLP problem failed: %s\n", mlp_solve_to_string(res));
785 return GNUNET_SYSERR;
788 end = GNUNET_TIME_absolute_get ();
789 duration = GNUNET_TIME_absolute_get_difference (start, end);
791 mlp->mlp_total_duration =+ duration.rel_value;
793 GNUNET_STATISTICS_update (mlp->stats,"# MLP problem solved", 1, GNUNET_NO);
794 GNUNET_STATISTICS_set (mlp->stats,"# MLP execution time", duration.rel_value, GNUNET_NO);
795 GNUNET_STATISTICS_set (mlp->stats,"# MLP execution time average",
796 mlp->mlp_total_duration / mlp->mlp_solved, GNUNET_NO);
798 /* Analyze problem status */
799 res = glp_mip_status(mlp->prob);
801 /* solution is optimal */
803 /* solution is feasible */
807 /* Problem was ill-defined, no way to handle that */
809 GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR,
811 "Solving MLP problem failed, %s\n\n", mlp_status_to_string(res));
812 return GNUNET_SYSERR;
819 int mlp_solve_problem (struct GAS_MLP_Handle *mlp);
822 mlp_scheduler (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
824 struct GAS_MLP_Handle *mlp = cls;
826 mlp->mlp_task = GNUNET_SCHEDULER_NO_TASK;
828 if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
832 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Scheduled problem solving\n");
834 if (mlp->addr_in_problem != 0)
835 mlp_solve_problem(mlp);
840 * Solves the MLP problem
842 * @param mlp the MLP Handle
843 * @return GNUNET_OK if could be solved, GNUNET_SYSERR on failure
846 mlp_solve_problem (struct GAS_MLP_Handle *mlp)
849 mlp->last_execution = GNUNET_TIME_absolute_get ();
851 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Problem solving\n");
858 GNUNET_asprintf(&name, "problem_%i", i);
859 glp_write_lp (mlp->prob, 0, name);
863 res = mlp_solve_lp_problem (mlp);
866 GNUNET_asprintf(&name, "problem_%i_lp_solution", i);
867 glp_print_sol (mlp->prob, name);
871 if (res != GNUNET_OK)
874 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "LP Problem solving failed\n");
876 return GNUNET_SYSERR;
879 res = mlp_solve_mlp_problem (mlp);
882 GNUNET_asprintf(&name, "problem_%i_mlp_solution", i);
883 glp_print_mip (mlp->prob, name);
886 if (res != GNUNET_OK)
889 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "MLP Problem solving failed\n");
891 return GNUNET_SYSERR;
895 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Problem solved\n");
900 if (mlp->mlp_task != GNUNET_SCHEDULER_NO_TASK)
902 GNUNET_SCHEDULER_cancel(mlp->mlp_task);
903 mlp->mlp_task = GNUNET_SCHEDULER_NO_TASK;
905 mlp->mlp_task = GNUNET_SCHEDULER_add_delayed (mlp->exec_interval, &mlp_scheduler, mlp);
910 * Init the MLP problem solving component
912 * @param stats the GNUNET_STATISTICS handle
913 * @param max_duration maximum numbers of iterations for the LP/MLP Solver
914 * @param max_iterations maximum time limit for the LP/MLP Solver
915 * @return struct GAS_MLP_Handle * on success, NULL on fail
917 struct GAS_MLP_Handle *
918 GAS_mlp_init (const struct GNUNET_CONFIGURATION_Handle *cfg,
919 const struct GNUNET_STATISTICS_Handle *stats,
920 struct GNUNET_TIME_Relative max_duration,
921 unsigned int max_iterations)
923 struct GAS_MLP_Handle * mlp = GNUNET_malloc (sizeof (struct GAS_MLP_Handle));
928 long long unsigned int tmp;
931 struct GNUNET_TIME_Relative i_exec;
933 /* Init GLPK environment */
934 GNUNET_assert (glp_init_env() == 0);
936 /* Create initial MLP problem */
937 mlp->prob = glp_create_prob();
938 GNUNET_assert (mlp->prob != NULL);
940 /* Get diversity coefficient from configuration */
941 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_size (cfg, "ats",
944 D = (double) tmp / 100;
948 /* Get proportionality coefficient from configuration */
949 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_size (cfg, "ats",
952 R = (double) tmp / 100;
956 /* Get utilization coefficient from configuration */
957 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_size (cfg, "ats",
960 U = (double) tmp / 100;
964 /* Get quality metric coefficients from configuration */
967 int q[GNUNET_ATS_QualityPropertiesCount] = GNUNET_ATS_QualityProperties;
969 for (c = 0; c < GNUNET_ATS_QualityPropertiesCount; c++)
971 /* initialize quality coefficients with default value 1.0 */
975 if (q[c] == GNUNET_ATS_QUALITY_NET_DELAY)
977 if (q[c] == GNUNET_ATS_QUALITY_NET_DISTANCE)
981 if ((i_delay != -1) && (GNUNET_OK == GNUNET_CONFIGURATION_get_value_size (cfg, "ats",
982 "COEFFICIENT_QUALITY_DELAY",
985 mlp->co_Q[i_delay] = (double) tmp / 100;
987 mlp->co_Q[i_delay] = 1.0;
989 if ((i_distance != -1) && (GNUNET_OK == GNUNET_CONFIGURATION_get_value_size (cfg, "ats",
990 "COEFFICIENT_QUALITY_DISTANCE",
992 mlp->co_Q[i_distance] = (double) tmp / 100;
994 mlp->co_Q[i_distance] = 1.0;
996 /* Get minimum bandwidth per used address from configuration */
997 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_size (cfg, "ats",
1004 /* Get minimum number of connections from configuration */
1005 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_size (cfg, "ats",
1012 /* Get minimum number of connections from configuration */
1013 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_time (cfg, "ats",
1014 "ATS_EXEC_INTERVAL",
1016 mlp->exec_interval = i_exec;
1018 mlp->exec_interval = GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 30);
1020 mlp->stats = (struct GNUNET_STATISTICS_Handle *) stats;
1021 mlp->max_iterations = max_iterations;
1022 mlp->max_exec_duration = max_duration;
1024 /* Redirect GLPK output to GNUnet logging */
1025 glp_error_hook((void *) mlp, &mlp_term_hook);
1027 /* Init LP solving parameters */
1028 glp_init_smcp(&mlp->control_param_lp);
1030 mlp->control_param_lp.msg_lev = GLP_MSG_ALL;
1032 mlp->control_param_lp.msg_lev = GLP_MSG_OFF;
1034 mlp->control_param_lp.it_lim = max_iterations;
1035 mlp->control_param_lp.tm_lim = max_duration.rel_value;
1037 /* Init MLP solving parameters */
1038 glp_init_iocp(&mlp->control_param_mlp);
1040 mlp->control_param_mlp.msg_lev = GLP_MSG_ALL;
1042 mlp->control_param_mlp.msg_lev = GLP_MSG_OFF;
1044 mlp->control_param_mlp.tm_lim = max_duration.rel_value;
1046 mlp->last_execution = GNUNET_TIME_absolute_get_forever();
1049 mlp->BIG_M = (double) UINT32_MAX;
1055 mlp->m_q = GNUNET_ATS_QualityPropertiesCount;
1061 * Updates a single address in the MLP problem
1063 * If the address did not exist before in the problem:
1064 * The MLP problem has to be recreated and the problem has to be resolved
1066 * Otherwise the addresses' values can be updated and the existing base can
1069 * @param mlp the MLP Handle
1070 * @param addresses the address hashmap
1071 * the address has to be already removed from the hashmap
1072 * @param address the address to update
1075 GAS_mlp_address_update (struct GAS_MLP_Handle *mlp, struct GNUNET_CONTAINER_MultiHashMap * addresses, struct ATS_Address *address)
1078 struct MLP_information *mlpi;
1081 GNUNET_STATISTICS_update (mlp->stats,"# LP address updates", 1, GNUNET_NO);
1083 /* We add a new address */
1084 if (address->mlp_information == NULL)
1090 if (new == GNUNET_YES)
1092 mlpi = GNUNET_malloc (sizeof (struct MLP_information));
1093 address->mlp_information = mlpi;
1094 mlp->addr_in_problem ++;
1096 /* Check for and add peer */
1097 struct ATS_Peer *peer = mlp_find_peer (mlp, &address->peer);
1101 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Adding new peer `%s'\n", GNUNET_i2s (&address->peer));
1103 peer = GNUNET_malloc (sizeof (struct ATS_Peer));
1107 for (c = 0; c < GNUNET_ATS_QualityPropertiesCount; c++)
1113 memcpy (&peer->id, &address->peer, sizeof (struct GNUNET_PeerIdentity));
1114 GNUNET_assert(address->prev == NULL);
1115 GNUNET_assert(address->next == NULL);
1116 GNUNET_CONTAINER_DLL_insert (peer->head, peer->tail, address);
1117 GNUNET_CONTAINER_DLL_insert (mlp->peer_head, mlp->peer_tail, peer);
1123 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Adding address to peer `%s'\n", GNUNET_i2s (&address->peer));
1125 GNUNET_CONTAINER_DLL_insert (peer->head, peer->tail, address);
1131 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Updating existing address to peer `%s'\n", GNUNET_i2s (&address->peer));
1136 if (new == GNUNET_YES)
1138 mlp_delete_problem (mlp);
1139 mlp_create_problem (mlp, addresses);
1140 mlp->presolver_required = GNUNET_YES;
1142 mlp_solve_problem (mlp);
1146 * Deletes a single address in the MLP problem
1148 * The MLP problem has to be recreated and the problem has to be resolved
1150 * @param mlp the MLP Handle
1151 * @param addresses the address hashmap
1152 * the address has to be already removed from the hashmap
1153 * @param address the address to delete
1156 GAS_mlp_address_delete (struct GAS_MLP_Handle *mlp, struct GNUNET_CONTAINER_MultiHashMap * addresses, struct ATS_Address *address)
1158 GNUNET_STATISTICS_update (mlp->stats,"# LP address deletions", 1, GNUNET_NO);
1160 /* Free resources */
1161 if (address->mlp_information != NULL)
1163 GNUNET_free (address->mlp_information);
1164 address->mlp_information = NULL;
1166 mlp->addr_in_problem --;
1169 /* Remove from peer list */
1170 struct ATS_Peer *head = mlp_find_peer (mlp, &address->peer);
1171 GNUNET_assert (head != NULL);
1173 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Deleting address for `%s'\n", GNUNET_i2s (&address->peer));
1175 GNUNET_CONTAINER_DLL_remove (head->head, head->tail, address);
1176 if ((head->head == NULL) && (head->tail == NULL))
1178 /* No address for peer left, remove peer */
1180 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Deleting peer `%s'\n", GNUNET_i2s (&address->peer));
1182 GNUNET_CONTAINER_DLL_remove (mlp->peer_head, mlp->peer_tail, head);
1187 /* Update problem */
1188 mlp_delete_problem (mlp);
1189 if ((GNUNET_CONTAINER_multihashmap_size (addresses) > 0) && (mlp->c_p > 0))
1191 mlp_create_problem (mlp, addresses);
1194 mlp->presolver_required = GNUNET_YES;
1195 mlp_solve_problem (mlp);
1200 * Changes the preferences for a peer in the MLP problem
1202 * @param mlp the MLP Handle
1203 * @param peer the peer
1204 * @param kind the kind to change the preference
1205 * @param float the score
1208 GAS_mlp_address_change_preference (struct GAS_MLP_Handle *mlp,
1209 const struct GNUNET_PeerIdentity *peer,
1210 enum GNUNET_ATS_PreferenceKind kind,
1213 GNUNET_STATISTICS_update (mlp->stats,"# LP address preference changes", 1, GNUNET_NO);
1215 struct ATS_Peer *p = mlp_find_peer (mlp, peer);
1217 /* Here we have to do the matching */
1221 * Shutdown the MLP problem solving component
1222 * @param mlp the MLP handle
1225 GAS_mlp_done (struct GAS_MLP_Handle *mlp)
1227 struct ATS_Peer * peer;
1228 struct ATS_Peer * tmp;
1230 if (mlp->mlp_task != GNUNET_SCHEDULER_NO_TASK)
1232 GNUNET_SCHEDULER_cancel(mlp->mlp_task);
1233 mlp->mlp_task = GNUNET_SCHEDULER_NO_TASK;
1236 /* clean up peer list */
1239 peer = mlp->peer_head;
1240 while (peer != NULL)
1242 GNUNET_CONTAINER_DLL_remove(mlp->peer_head, mlp->peer_tail, peer);
1248 mlp_delete_problem (mlp);
1250 /* Clean up GLPK environment */
1257 /* end of gnunet-service-ats_addresses_mlp.c */