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_EXTRA_LOGGING
38 * Translate glpk solver error codes to text
39 * @param retcode return code
40 * @return string with result
43 mlp_solve_to_string (int retcode)
50 return "invalid basis";
53 return "singular matrix";
56 return "ill-conditioned matrix";
59 return "invalid bounds";
62 return "solver failed";
65 return "objective lower limit reached";
68 return "objective upper limit reached";
71 return "iteration limit exceeded";
74 return "time limit exceeded";
77 return "no primal feasible solution";
80 return "root LP optimum not provided";
83 return "search terminated by application";
86 return "relative mip gap tolerance reached";
89 return "no dual feasible solution";
92 return "no convergence";
95 return "numerical instability";
98 return "invalid data";
101 return "result out of range";
105 return "unknown error";
109 return "unknown error";
114 * Translate glpk status error codes to text
115 * @param retcode return code
116 * @return string with result
119 mlp_status_to_string (int retcode)
123 return "solution is undefined";
126 return "solution is feasible";
129 return "solution is infeasible";
132 return "no feasible solution exists";
135 return "solution is optimal";
138 return "solution is unbounded";
142 return "unknown error";
146 return "unknown error";
150 * Find a peer in the DLL
151 * @param the peer to find
152 * @return the peer struct
154 static struct ATS_Peer *
155 mlp_find_peer (struct GAS_MLP_Handle *mlp, const struct GNUNET_PeerIdentity *peer)
157 struct ATS_Peer *res = mlp->peer_head;
160 if (0 == memcmp (peer, &res->id, sizeof (struct GNUNET_PeerIdentity)))
168 * Intercept GLPK terminal output
169 * @param info the mlp handle
170 * @param s the string to print
171 * @return 0: glpk prints output on terminal, 0 != surpress output
174 mlp_term_hook (void *info, const char *s)
176 /* Not needed atm struct MLP_information *mlp = info; */
177 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s", s);
182 * Delete the MLP problem and free the constrain matrix
184 * @param mlp the MLP handle
187 mlp_delete_problem (struct GAS_MLP_Handle *mlp)
191 if (mlp->prob != NULL)
192 glp_delete_prob(mlp->prob);
194 /* delete row index */
197 GNUNET_free (mlp->ia);
201 /* delete column index */
204 GNUNET_free (mlp->ja);
208 /* delete coefficients */
211 GNUNET_free (mlp->ar);
220 * Add constraints that are iterating over "forall addresses"
221 * and collects all existing peers for "forall peers" constraints
223 * @param cls GAS_MLP_Handle
224 * @param key Hashcode
225 * @param value ATS_Address
227 * @return GNUNET_OK to continue
230 create_constraint_it (void *cls, const GNUNET_HashCode * key, void *value)
232 struct GAS_MLP_Handle *mlp = cls;
233 struct ATS_Address *address = value;
234 struct MLP_information *mlpi;
235 unsigned int row_index;
238 GNUNET_assert (address->mlp_information != NULL);
239 mlpi = (struct MLP_information *) address->mlp_information;
241 /* c 1) bandwidth capping
242 * b_t + (-M) * n_t <= 0
244 row_index = glp_add_rows (mlp->prob, 1);
245 mlpi->r_c1 = row_index;
247 GNUNET_asprintf(&name, "c1_%s_%s", GNUNET_i2s(&address->peer), address->plugin);
248 glp_set_row_name (mlp->prob, row_index, name);
250 /* set row bounds: <= 0 */
251 glp_set_row_bnds (mlp->prob, row_index, GLP_UP, 0.0, 0.0);
252 mlp->ia[mlp->ci] = row_index;
253 mlp->ja[mlp->ci] = mlpi->c_b;
254 mlp->ar[mlp->ci] = 1;
257 mlp->ia[mlp->ci] = row_index;
258 mlp->ja[mlp->ci] = mlpi->c_n;
259 mlp->ar[mlp->ci] = -mlp->BIG_M;
262 /* c 3) minimum bandwidth
263 * b_t + (-n_t * b_min) >= 0
266 row_index = glp_add_rows (mlp->prob, 1);
268 GNUNET_asprintf(&name, "c3_%s_%s", GNUNET_i2s(&address->peer), address->plugin);
269 glp_set_row_name (mlp->prob, row_index, name);
271 mlpi->r_c3 = row_index;
272 /* set row bounds: >= 0 */
273 glp_set_row_bnds (mlp->prob, row_index, GLP_LO, 0.0, 0.0);
275 mlp->ia[mlp->ci] = row_index;
276 mlp->ja[mlp->ci] = mlpi->c_b;
277 mlp->ar[mlp->ci] = 1;
280 mlp->ia[mlp->ci] = row_index;
281 mlp->ja[mlp->ci] = mlpi->c_n;
282 mlp->ar[mlp->ci] = - (double) mlp->b_min;
285 /* c 4) minimum connections
286 * (1)*n_1 + ... + (1)*n_m >= n_min
288 mlp->ia[mlp->ci] = mlp->r_c4;
289 mlp->ja[mlp->ci] = mlpi->c_n;
290 mlp->ar[mlp->ci] = 1;
293 /* c 6) maximize diversity
294 * (1)*n_1 + ... + (1)*n_m - d == 0
296 mlp->ia[mlp->ci] = mlp->r_c6;
297 mlp->ja[mlp->ci] = mlpi->c_n;
298 mlp->ar[mlp->ci] = 1;
306 * Adds the problem constraints for all addresses
307 * Required for problem recreation after address deletion
309 * @param addresses all addresses
313 mlp_add_constraints_all_addresses (struct GAS_MLP_Handle *mlp, struct GNUNET_CONTAINER_MultiHashMap * addresses)
315 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|
362 int pi = ((7 * n_addresses) + (2 * n_addresses + mlp->m_q + 1));
367 int *ia = GNUNET_malloc (pi * sizeof (int));
371 int *ja = GNUNET_malloc (pi * sizeof (int));
375 double *ar= GNUNET_malloc (pi * sizeof (double));
378 /* Adding constraint rows
379 * This constraints are kind of "for all addresses"
380 * Feasibility constraints:
382 * c 1) bandwidth capping
383 * c 3) minimum bandwidth
384 * c 4) minimum number of connections
385 * c 6) maximize diversity
388 int min = mlp->n_min;
389 if (mlp->n_min > mlp->c_p)
392 mlp->r_c4 = glp_add_rows (mlp->prob, 1);
393 glp_set_row_name (mlp->prob, mlp->r_c4, "c4");
394 glp_set_row_bnds (mlp->prob, mlp->r_c4, GLP_LO, min, min);
396 /* Add row for c6) */
398 mlp->r_c6 = glp_add_rows (mlp->prob, 1);
399 /* Set type type to fix */
400 glp_set_row_bnds (mlp->prob, mlp->r_c6, GLP_FX, 0.0, 0.0);
402 ia[mlp->ci] = mlp->r_c6 ;
403 ja[mlp->ci] = mlp->c_d;
407 GNUNET_CONTAINER_multihashmap_iterate (addresses, create_constraint_it, mlp);
409 /* Adding constraint rows
410 * This constraints are kind of "for all peers"
411 * Feasibility constraints:
413 * c 2) 1 address per peer
414 * sum (n_p1_1 + ... + n_p1_n) = 1
417 /* Adding rows for c 2) */
418 row_index = glp_add_rows (mlp->prob, mlp->c_p);
420 struct ATS_Peer * peer = mlp->peer_head;
423 struct ATS_Address *addr = peer->head;
424 struct MLP_information *mlpi = NULL;
425 /* Adding row for c 2) */
426 GNUNET_asprintf(&name, "c2_%s", GNUNET_i2s(&peer->id));
427 glp_set_row_name (mlp->prob, row_index, name);
429 /* Set row bound == 1 */
430 glp_set_row_bnds (mlp->prob, row_index, GLP_FX, 1.0, 1.0);
434 mlpi = (struct MLP_information *) addr->mlp_information;
435 ia[mlp->ci] = row_index;
436 ja[mlp->ci] = mlpi->c_n;
445 /* For all quality metrics */
447 for (c = 0; c < mlp->m_q; c++)
449 struct ATS_Peer *p = mlp->peer_head;
452 ia[mlp->ci] = row_index;
453 ja[mlp->ci] = mlp->c_q[c];
465 * Add columns for all addresses
467 * @param cls GAS_MLP_Handle
468 * @param key Hashcode
469 * @param value ATS_Address
471 * @return GNUNET_OK to continue
474 create_columns_it (void *cls, const GNUNET_HashCode * key, void *value)
476 struct GAS_MLP_Handle *mlp = cls;
477 struct ATS_Address *address = value;
478 struct MLP_information *mlpi;
482 GNUNET_assert (address->mlp_information != NULL);
483 mlpi = address->mlp_information;
485 /* Add bandwidth column */
486 col = glp_add_cols (mlp->prob, 2);
490 GNUNET_asprintf (&name, "b_%s_%s", GNUNET_i2s (&address->peer), address->plugin);
491 glp_set_col_name (mlp->prob, mlpi->c_b , name);
493 /* Lower bound == 0 */
494 glp_set_col_bnds (mlp->prob, mlpi->c_b , GLP_LO, 0.0, 0.0);
495 /* Continuous value*/
496 glp_set_col_kind (mlp->prob, mlpi->c_b , GLP_CV);
497 /* Objective function coefficient == 0 */
498 glp_set_obj_coef (mlp->prob, mlpi->c_b , 0);
501 /* Add usage column */
502 GNUNET_asprintf (&name, "n_%s_%s", GNUNET_i2s (&address->peer), address->plugin);
503 glp_set_col_name (mlp->prob, mlpi->c_n, name);
505 /* Limit value : 0 <= value <= 1 */
506 glp_set_col_bnds (mlp->prob, mlpi->c_n, GLP_DB, 0.0, 1.0);
508 glp_set_col_kind (mlp->prob, mlpi->c_n, GLP_IV);
509 /* Objective function coefficient == 0 */
510 glp_set_obj_coef (mlp->prob, mlpi->c_n, 0);
518 * Create the MLP problem
520 * @param mlp the MLP handle
521 * @return GNUNET_OK or GNUNET_SYSERR
524 mlp_create_problem (struct GAS_MLP_Handle *mlp, struct GNUNET_CONTAINER_MultiHashMap * addresses)
533 GNUNET_assert (mlp->prob == NULL);
535 /* create the glpk problem */
536 mlp->prob = glp_create_prob ();
538 /* Set a problem name */
539 glp_set_prob_name (mlp->prob, "gnunet ats bandwidth distribution");
541 /* Set optimization direction to maximize */
542 glp_set_obj_dir (mlp->prob, GLP_MAX);
544 /* Adding invariant columns */
546 /* Diversity d column */
548 col = glp_add_cols (mlp->prob, 1);
551 glp_set_col_name (mlp->prob, col, "d");
552 /* Column objective function coefficient */
553 glp_set_obj_coef (mlp->prob, col, mlp->co_D);
554 /* Column lower bound = 0.0 */
555 glp_set_col_bnds (mlp->prob, col, GLP_LO, 0.0, 0.0);
557 /* Utilization u column */
559 col = glp_add_cols (mlp->prob, 1);
562 glp_set_col_name (mlp->prob, col, "u");
563 /* Column objective function coefficient */
564 glp_set_obj_coef (mlp->prob, col, mlp->co_U);
565 /* Column lower bound = 0.0 */
566 glp_set_col_bnds (mlp->prob, col, GLP_LO, 0.0, 0.0);
568 /* Relativity r column */
569 col = glp_add_cols (mlp->prob, 1);
572 glp_set_col_name (mlp->prob, col, "r");
573 /* Column objective function coefficient */
574 glp_set_obj_coef (mlp->prob, col, mlp->co_R);
575 /* Column lower bound = 0.0 */
576 glp_set_col_bnds (mlp->prob, col, GLP_LO, 0.0, 0.0);
578 /* Quality metric columns */
579 col = glp_add_cols(mlp->prob, mlp->m_q);
580 for (c = 0; c < mlp->m_q; c++)
582 mlp->c_q[c] = col + c;
583 GNUNET_asprintf (&name, "q_%u", mlp->q[c]);
584 glp_set_col_name (mlp->prob, col + c, name);
585 /* Column lower bound = 0.0 */
586 glp_set_col_bnds (mlp->prob, col + c, GLP_LO, 0.0, 0.0);
588 /* Coefficient == Qm */
589 glp_set_obj_coef (mlp->prob, col + c, mlp->co_Q[c]);
592 /* Add columns for addresses */
593 GNUNET_CONTAINER_multihashmap_iterate (addresses, create_columns_it, mlp);
595 /* Add constraints */
596 mlp_add_constraints_all_addresses (mlp, addresses);
598 /* Load the matrix */
599 glp_load_matrix(mlp->prob, (mlp->ci-1), mlp->ia, mlp->ja, mlp->ar);
605 * Solves the LP problem
607 * @param mlp the MLP Handle
608 * @return GNUNET_OK if could be solved, GNUNET_SYSERR on failure
611 mlp_solve_lp_problem (struct GAS_MLP_Handle *mlp)
614 struct GNUNET_TIME_Relative duration;
615 struct GNUNET_TIME_Absolute end;
616 struct GNUNET_TIME_Absolute start = GNUNET_TIME_absolute_get();
619 * Presolver is required if the problem was modified and an existing
620 * valid basis is now invalid */
621 if (mlp->presolver_required == GNUNET_YES)
622 mlp->control_param_lp.presolve = GLP_ON;
624 mlp->control_param_lp.presolve = GLP_OFF;
626 /* Solve LP problem to have initial valid solution */
628 res = glp_simplex(mlp->prob, &mlp->control_param_lp);
631 /* The LP problem instance has been successfully solved. */
633 else if (res == GLP_EITLIM)
635 /* simplex iteration limit has been exceeded. */
636 // TODO Increase iteration limit?
638 else if (res == GLP_ETMLIM)
640 /* Time limit has been exceeded. */
641 // TODO Increase time limit?
645 /* Problem was ill-defined, retry with presolver */
646 if (mlp->presolver_required == GNUNET_NO)
648 mlp->presolver_required = GNUNET_YES;
653 /* Problem was ill-defined, no way to handle that */
654 GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR,
656 "Solving LP problem failed: %i %s\n", res, mlp_solve_to_string(res));
657 return GNUNET_SYSERR;
661 end = GNUNET_TIME_absolute_get ();
662 duration = GNUNET_TIME_absolute_get_difference (start, end);
664 mlp->lp_total_duration =+ duration.rel_value;
666 GNUNET_STATISTICS_update (mlp->stats,"# LP problem solved", 1, GNUNET_NO);
667 GNUNET_STATISTICS_set (mlp->stats,"# LP execution time", duration.rel_value, GNUNET_NO);
668 GNUNET_STATISTICS_set (mlp->stats,"# LP execution time average",
669 mlp->lp_total_duration / mlp->lp_solved, GNUNET_NO);
672 /* Analyze problem status */
673 res = glp_get_status (mlp->prob);
675 /* solution is optimal */
677 /* solution is feasible */
681 /* Problem was ill-defined, no way to handle that */
683 GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR,
685 "Solving LP problem failed, no solution: %s\n", mlp_status_to_string(res));
686 return GNUNET_SYSERR;
690 /* solved sucessfully, no presolver required next time */
691 mlp->presolver_required = GNUNET_NO;
698 * Solves the MLP problem
700 * @param mlp the MLP Handle
701 * @return GNUNET_OK if could be solved, GNUNET_SYSERR on failure
704 mlp_solve_mlp_problem (struct GAS_MLP_Handle *mlp)
707 struct GNUNET_TIME_Relative duration;
708 struct GNUNET_TIME_Absolute end;
709 struct GNUNET_TIME_Absolute start = GNUNET_TIME_absolute_get();
711 /* solve MLP problem */
712 res = glp_intopt(mlp->prob, &mlp->control_param_mlp);
716 /* The MLP problem instance has been successfully solved. */
718 else if (res == GLP_EITLIM)
720 /* simplex iteration limit has been exceeded. */
721 // TODO Increase iteration limit?
723 else if (res == GLP_ETMLIM)
725 /* Time limit has been exceeded. */
726 // TODO Increase time limit?
730 /* Problem was ill-defined, no way to handle that */
731 GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR,
733 "Solving MLP problem failed: %s\n", mlp_solve_to_string(res));
734 return GNUNET_SYSERR;
737 end = GNUNET_TIME_absolute_get ();
738 duration = GNUNET_TIME_absolute_get_difference (start, end);
740 mlp->mlp_total_duration =+ duration.rel_value;
742 GNUNET_STATISTICS_update (mlp->stats,"# MLP problem solved", 1, GNUNET_NO);
743 GNUNET_STATISTICS_set (mlp->stats,"# MLP execution time", duration.rel_value, GNUNET_NO);
744 GNUNET_STATISTICS_set (mlp->stats,"# MLP execution time average",
745 mlp->mlp_total_duration / mlp->mlp_solved, GNUNET_NO);
747 /* Analyze problem status */
748 res = glp_mip_status(mlp->prob);
750 /* solution is optimal */
752 /* solution is feasible */
756 /* Problem was ill-defined, no way to handle that */
758 GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR,
760 "Solving MLP problem failed, %s\n\n", mlp_status_to_string(res));
761 return GNUNET_SYSERR;
768 int mlp_solve_problem (struct GAS_MLP_Handle *mlp);
771 mlp_scheduler (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
773 struct GAS_MLP_Handle *mlp = cls;
775 mlp->mlp_task = GNUNET_SCHEDULER_NO_TASK;
777 if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
781 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Scheduled problem solving\n");
783 if (mlp->addr_in_problem != 0)
784 mlp_solve_problem(mlp);
789 * Solves the MLP problem
791 * @param mlp the MLP Handle
792 * @return GNUNET_OK if could be solved, GNUNET_SYSERR on failure
795 mlp_solve_problem (struct GAS_MLP_Handle *mlp)
798 mlp->last_execution = GNUNET_TIME_absolute_get ();
800 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Problem solving\n");
807 GNUNET_asprintf(&name, "problem_%i", i);
808 glp_write_lp (mlp->prob, 0, name);
812 res = mlp_solve_lp_problem (mlp);
815 GNUNET_asprintf(&name, "problem_%i_lp_solution", i);
816 glp_print_sol (mlp->prob, name);
820 if (res != GNUNET_OK)
823 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "LP Problem solving failed\n");
825 return GNUNET_SYSERR;
828 res = mlp_solve_mlp_problem (mlp);
831 GNUNET_asprintf(&name, "problem_%i_mlp_solution", i);
832 glp_print_mip (mlp->prob, name);
835 if (res != GNUNET_OK)
838 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "MLP Problem solving failed\n");
840 return GNUNET_SYSERR;
844 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Problem solved: %i %s\n", res, mlp_status_to_string(res));
849 if (mlp->mlp_task != GNUNET_SCHEDULER_NO_TASK)
851 GNUNET_SCHEDULER_cancel(mlp->mlp_task);
852 mlp->mlp_task = GNUNET_SCHEDULER_NO_TASK;
854 mlp->mlp_task = GNUNET_SCHEDULER_add_delayed (mlp->exec_interval, &mlp_scheduler, mlp);
859 * Init the MLP problem solving component
861 * @param stats the GNUNET_STATISTICS handle
862 * @param max_duration maximum numbers of iterations for the LP/MLP Solver
863 * @param max_iterations maximum time limit for the LP/MLP Solver
864 * @return struct GAS_MLP_Handle * on success, NULL on fail
866 struct GAS_MLP_Handle *
867 GAS_mlp_init (const struct GNUNET_CONFIGURATION_Handle *cfg,
868 const struct GNUNET_STATISTICS_Handle *stats,
869 struct GNUNET_TIME_Relative max_duration,
870 unsigned int max_iterations)
872 struct GAS_MLP_Handle * mlp = GNUNET_malloc (sizeof (struct GAS_MLP_Handle));
877 long long unsigned int tmp;
880 struct GNUNET_TIME_Relative i_exec;
882 /* Init GLPK environment */
883 GNUNET_assert (glp_init_env() == 0);
885 /* Create initial MLP problem */
886 mlp->prob = glp_create_prob();
887 GNUNET_assert (mlp->prob != NULL);
889 /* Get diversity coefficient from configuration */
890 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_size (cfg, "ats",
893 D = (double) tmp / 100;
897 /* Get proportionality coefficient from configuration */
898 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_size (cfg, "ats",
901 R = (double) tmp / 100;
905 /* Get utilization coefficient from configuration */
906 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_size (cfg, "ats",
909 U = (double) tmp / 100;
913 /* Get quality metric coefficients from configuration */
916 int q[GNUNET_ATS_QualityPropertiesCount] = GNUNET_ATS_QualityProperties;
918 for (c = 0; c < GNUNET_ATS_QualityPropertiesCount; c++)
920 /* initialize quality coefficients with default value 1.0 */
924 if (q[c] == GNUNET_ATS_QUALITY_NET_DELAY)
926 if (q[c] == GNUNET_ATS_QUALITY_NET_DISTANCE)
930 if ((i_delay != -1) && (GNUNET_OK == GNUNET_CONFIGURATION_get_value_size (cfg, "ats",
931 "COEFFICIENT_QUALITY_DELAY",
934 mlp->co_Q[i_delay] = (double) tmp / 100;
936 mlp->co_Q[i_delay] = 1.0;
938 if ((i_distance != -1) && (GNUNET_OK == GNUNET_CONFIGURATION_get_value_size (cfg, "ats",
939 "COEFFICIENT_QUALITY_DISTANCE",
941 mlp->co_Q[i_distance] = (double) tmp / 100;
943 mlp->co_Q[i_distance] = 1.0;
945 /* Get minimum bandwidth per used address from configuration */
946 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_size (cfg, "ats",
953 /* Get minimum number of connections from configuration */
954 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_size (cfg, "ats",
961 /* Get minimum number of connections from configuration */
962 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_time (cfg, "ats",
965 mlp->exec_interval = i_exec;
967 mlp->exec_interval = GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 30);
969 mlp->stats = (struct GNUNET_STATISTICS_Handle *) stats;
970 mlp->max_iterations = max_iterations;
971 mlp->max_exec_duration = max_duration;
973 /* Redirect GLPK output to GNUnet logging */
974 glp_error_hook((void *) mlp, &mlp_term_hook);
976 /* Init LP solving parameters */
977 glp_init_smcp(&mlp->control_param_lp);
979 mlp->control_param_lp.msg_lev = GLP_MSG_ALL;
981 mlp->control_param_lp.msg_lev = GLP_MSG_OFF;
983 mlp->control_param_lp.it_lim = max_iterations;
984 mlp->control_param_lp.tm_lim = max_duration.rel_value;
986 /* Init MLP solving parameters */
987 glp_init_iocp(&mlp->control_param_mlp);
989 mlp->control_param_mlp.msg_lev = GLP_MSG_ALL;
991 mlp->control_param_mlp.msg_lev = GLP_MSG_OFF;
993 mlp->control_param_mlp.tm_lim = max_duration.rel_value;
995 mlp->last_execution = GNUNET_TIME_absolute_get_forever();
998 mlp->BIG_M = (double) UINT32_MAX;
1004 mlp->m_q = GNUNET_ATS_QualityPropertiesCount;
1010 * Updates a single address in the MLP problem
1012 * If the address did not exist before in the problem:
1013 * The MLP problem has to be recreated and the problem has to be resolved
1015 * Otherwise the addresses' values can be updated and the existing base can
1018 * @param mlp the MLP Handle
1019 * @param addresses the address hashmap
1020 * the address has to be already removed from the hashmap
1021 * @param address the address to update
1024 GAS_mlp_address_update (struct GAS_MLP_Handle *mlp, struct GNUNET_CONTAINER_MultiHashMap * addresses, struct ATS_Address *address)
1027 struct MLP_information *mlpi;
1030 GNUNET_STATISTICS_update (mlp->stats,"# LP address updates", 1, GNUNET_NO);
1032 /* We add a new address */
1033 if (address->mlp_information == NULL)
1039 if (new == GNUNET_YES)
1041 mlpi = GNUNET_malloc (sizeof (struct MLP_information));
1042 address->mlp_information = mlpi;
1043 mlp->addr_in_problem ++;
1045 /* Check for and add peer */
1046 struct ATS_Peer *peer = mlp_find_peer (mlp, &address->peer);
1050 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Adding new peer `%s'\n", GNUNET_i2s (&address->peer));
1052 peer = GNUNET_malloc (sizeof (struct ATS_Peer));
1056 for (c = 0; c < GNUNET_ATS_QualityPropertiesCount; c++)
1061 memcpy (&peer->id, &address->peer, sizeof (struct GNUNET_PeerIdentity));
1062 GNUNET_assert(address->prev == NULL);
1063 GNUNET_assert(address->next == NULL);
1064 GNUNET_CONTAINER_DLL_insert (peer->head, peer->tail, address);
1065 GNUNET_CONTAINER_DLL_insert (mlp->peer_head, mlp->peer_tail, peer);
1071 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Adding address to peer `%s'\n", GNUNET_i2s (&address->peer));
1073 GNUNET_CONTAINER_DLL_insert (peer->head, peer->tail, address);
1079 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Updating existing address to peer `%s'\n", GNUNET_i2s (&address->peer));
1084 if (new == GNUNET_YES)
1086 mlp_delete_problem (mlp);
1087 mlp_create_problem (mlp, addresses);
1088 mlp->presolver_required = GNUNET_YES;
1090 mlp_solve_problem (mlp);
1094 * Deletes a single address in the MLP problem
1096 * The MLP problem has to be recreated and the problem has to be resolved
1098 * @param mlp the MLP Handle
1099 * @param addresses the address hashmap
1100 * the address has to be already removed from the hashmap
1101 * @param address the address to delete
1104 GAS_mlp_address_delete (struct GAS_MLP_Handle *mlp, struct GNUNET_CONTAINER_MultiHashMap * addresses, struct ATS_Address *address)
1106 GNUNET_STATISTICS_update (mlp->stats,"# LP address deletions", 1, GNUNET_NO);
1108 /* Free resources */
1109 if (address->mlp_information != NULL)
1111 GNUNET_free (address->mlp_information);
1112 address->mlp_information = NULL;
1114 mlp->addr_in_problem --;
1117 /* Remove from peer list */
1118 struct ATS_Peer *head = mlp_find_peer (mlp, &address->peer);
1119 GNUNET_assert (head != NULL);
1121 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Deleting address for `%s'\n", GNUNET_i2s (&address->peer));
1123 GNUNET_CONTAINER_DLL_remove (head->head, head->tail, address);
1124 if ((head->head == NULL) && (head->tail == NULL))
1126 /* No address for peer left, remove peer */
1128 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Deleting peer `%s'\n", GNUNET_i2s (&address->peer));
1130 GNUNET_CONTAINER_DLL_remove (mlp->peer_head, mlp->peer_tail, head);
1135 /* Update problem */
1136 mlp_delete_problem (mlp);
1137 if ((GNUNET_CONTAINER_multihashmap_size (addresses) > 0) && (mlp->c_p > 0))
1139 mlp_create_problem (mlp, addresses);
1142 mlp->presolver_required = GNUNET_YES;
1143 mlp_solve_problem (mlp);
1148 * Changes the preferences for a peer in the MLP problem
1150 * @param mlp the MLP Handle
1151 * @param peer the peer
1152 * @param kind the kind to change the preference
1153 * @param float the score
1156 GAS_mlp_address_change_preference (struct GAS_MLP_Handle *mlp,
1157 const struct GNUNET_PeerIdentity *peer,
1158 enum GNUNET_ATS_PreferenceKind kind,
1161 GNUNET_STATISTICS_update (mlp->stats,"# LP address preference changes", 1, GNUNET_NO);
1163 struct ATS_Peer *p = mlp_find_peer (mlp, peer);
1165 /* Here we have to do the matching */
1169 * Shutdown the MLP problem solving component
1170 * @param mlp the MLP handle
1173 GAS_mlp_done (struct GAS_MLP_Handle *mlp)
1175 struct ATS_Peer * peer;
1176 struct ATS_Peer * tmp;
1178 if (mlp->mlp_task != GNUNET_SCHEDULER_NO_TASK)
1180 GNUNET_SCHEDULER_cancel(mlp->mlp_task);
1181 mlp->mlp_task = GNUNET_SCHEDULER_NO_TASK;
1184 /* clean up peer list */
1187 peer = mlp->peer_head;
1188 while (peer != NULL)
1190 GNUNET_CONTAINER_DLL_remove(mlp->peer_head, mlp->peer_tail, peer);
1196 mlp_delete_problem (mlp);
1198 /* Clean up GLPK environment */
1205 /* end of gnunet-service-ats_addresses_mlp.c */