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"
35 #define WRITE_MLP GNUNET_NO
36 #define DEBUG_ATS GNUNET_YES
37 /* A very big value */
41 * Translate glpk solver error codes to text
42 * @param retcode return code
43 * @return string with result
46 mlp_solve_to_string (int retcode)
53 return "invalid basis";
56 return "singular matrix";
59 return "ill-conditioned matrix";
62 return "invalid bounds";
65 return "solver failed";
68 return "objective lower limit reached";
71 return "objective upper limit reached";
74 return "iteration limit exceeded";
77 return "time limit exceeded";
80 return "no primal feasible solution";
83 return "root LP optimum not provided";
86 return "search terminated by application";
89 return "relative mip gap tolerance reached";
92 return "no dual feasible solution";
95 return "no convergence";
98 return "numerical instability";
101 return "invalid data";
104 return "result out of range";
108 return "unknown error";
112 return "unknown error";
117 * Translate glpk status error codes to text
118 * @param retcode return code
119 * @return string with result
122 mlp_status_to_string (int retcode)
126 return "solution is undefined";
129 return "solution is feasible";
132 return "solution is infeasible";
135 return "no feasible solution exists";
138 return "solution is optimal";
141 return "solution is unbounded";
145 return "unknown error";
149 return "unknown error";
153 * Find a peer in the DLL
154 * @param the peer to find
155 * @return the peer struct
157 static struct ATS_Peer *
158 mlp_find_peer (struct GAS_MLP_Handle *mlp, const struct GNUNET_PeerIdentity *peer)
160 struct ATS_Peer *res = mlp->peer_head;
163 if (0 == memcmp (peer, &res->id, sizeof (struct GNUNET_PeerIdentity)))
171 * Intercept GLPK terminal output
172 * @param info the mlp handle
173 * @param s the string to print
174 * @return 0: glpk prints output on terminal, 0 != surpress output
177 mlp_term_hook (void *info, const char *s)
179 /* Not needed atm struct MLP_information *mlp = info; */
180 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s", s);
185 * Delete the MLP problem and free the constrain matrix
187 * @param mlp the MLP handle
190 mlp_delete_problem (struct GAS_MLP_Handle *mlp)
194 if (mlp->prob != NULL)
195 glp_delete_prob(mlp->prob);
197 /* delete row index */
200 GNUNET_free (mlp->ia);
204 /* delete column index */
207 GNUNET_free (mlp->ja);
211 /* delete coefficients */
214 GNUNET_free (mlp->ar);
223 * Add constraints that are iterating over "forall addresses"
224 * and collects all existing peers for "forall peers" constraints
226 * @param cls GAS_MLP_Handle
227 * @param key Hashcode
228 * @param value ATS_Address
230 * @return GNUNET_OK to continue
233 create_constraint_it (void *cls, const GNUNET_HashCode * key, void *value)
235 struct GAS_MLP_Handle *mlp = cls;
236 struct ATS_Address *address = value;
237 struct MLP_information *mlpi;
238 unsigned int row_index;
240 GNUNET_assert (address->mlp_information != NULL);
241 mlpi = (struct MLP_information *) address->mlp_information;
243 /* c 1) bandwidth capping
244 * b_t + (-M) * n_t <= 0
246 row_index = glp_add_rows (mlp->prob, 1);
247 mlpi->r_c1 = row_index;
248 /* set row bounds: <= 0 */
249 glp_set_row_bnds (mlp->prob, row_index, GLP_UP, 0.0, 0.0);
251 mlp->ia[mlp->ci] = row_index;
252 mlp->ja[mlp->ci] = mlpi->c_b;
253 mlp->ar[mlp->ci] = 1;
256 mlp->ia[mlp->ci] = row_index;
257 mlp->ja[mlp->ci] = mlpi->c_n;
258 mlp->ar[mlp->ci] = -M;
261 /* c 3) minimum bandwidth
262 * b_t + (-n_t * b_min) >= 0
265 row_index = glp_add_rows (mlp->prob, 1);
266 mlpi->r_c3 = row_index;
267 /* set row bounds: >= 0 */
268 glp_set_row_bnds (mlp->prob, row_index, GLP_LO, 0.0, 0.0);
270 mlp->ia[mlp->ci] = row_index;
271 mlp->ja[mlp->ci] = mlpi->c_b;
272 mlp->ar[mlp->ci] = 1;
275 mlp->ia[mlp->ci] = row_index;
276 mlp->ja[mlp->ci] = mlpi->c_n;
277 mlp->ar[mlp->ci] = -mlp->b_min;
280 /* c 4) minimum connections
281 * (1)*n_1 + ... + (1)*n_m >= n_min
283 mlp->ia[mlp->ci] = mlp->r_c4;
284 mlp->ja[mlp->ci] = mlpi->c_n;
285 mlp->ar[mlp->ci] = 1;
288 /* c 6) maximize diversity
289 * (1)*n_1 + ... + (1)*n_m - d == 0
291 mlp->ia[mlp->ci] = mlp->r_c6;
292 mlp->ja[mlp->ci] = mlpi->c_n;
293 mlp->ar[mlp->ci] = 1;
302 * Adds the problem constraints for all addresses
303 * Required for problem recreation after address deletion
305 * @param addresses all addresses
309 mlp_add_constraints_all_addresses (struct GAS_MLP_Handle *mlp, struct GNUNET_CONTAINER_MultiHashMap * addresses)
311 unsigned int n_addresses;
316 n_addresses = GNUNET_CONTAINER_multihashmap_size(addresses);
318 /* Required indices in the constrain matrix
320 * feasibility constraints:
322 * c 1) bandwidth capping
323 * #rows: |n_addresses|
324 * #indices: 2 * |n_addresses|
326 * c 2) one active address per peer
328 * #indices: |n_addresses|
330 * c 3) minium bandwidth assigned
331 * #rows: |n_addresses|
332 * #indices: 2 * |n_addresses|
334 * c 4) minimum number of active connections
336 * #indices: |n_addresses|
338 * c 5) maximum ressource consumption
339 * #rows: |ressources|
340 * #indices: |n_addresses|
342 * Sum for feasibility constraints:
343 * #rows: 3 * |n_addresses| + |ressources| + |peers| + 1
344 * #indices: 7 * |n_addresses|
346 * optimality constraints:
350 * #indices: |n_addresses| + 1
353 * #rows: |quality properties|
354 * #indices:|quality properties| + |n_addresses|
357 int pi = ((7 * n_addresses) /*+ (2 * n_addresses + mlp->m_q + 1)*/);
362 int *ia = GNUNET_malloc (pi * sizeof (int));
366 int *ja = GNUNET_malloc (pi * sizeof (int));
370 double *ar= GNUNET_malloc (pi * sizeof (double));
373 /* Adding constraint rows
374 * This constraints are kind of "for all addresses"
375 * Feasibility constraints:
377 * c 1) bandwidth capping
378 * c 3) minimum bandwidth
379 * c 4) minimum number of connections
380 * c 6) maximize diversity
383 int min = mlp->n_min;
384 if (mlp->n_min > mlp->c_p)
387 mlp->r_c4 = glp_add_rows (mlp->prob, 1);
388 glp_set_row_bnds (mlp->prob, mlp->r_c4, GLP_FX, min, min);
390 /* Add row for c6) */
392 mlp->r_c6 = glp_add_rows (mlp->prob, 1);
393 /* Set type type to fix */
394 glp_set_row_bnds (mlp->prob, mlp->r_c6, GLP_FX, 0.0, 0.0);
396 ia[mlp->ci] = mlp->r_c6 ;
397 ja[mlp->ci] = mlp->c_d;
401 GNUNET_CONTAINER_multihashmap_iterate (addresses, create_constraint_it, mlp);
403 /* Adding constraint rows
404 * This constraints are kind of "for all peers"
405 * Feasibility constraints:
407 * c 2) 1 address per peer
408 * sum (n_p1_1 + ... + n_p1_n) = 1
411 /* Adding rows for c 2) */
412 row_index = glp_add_rows (mlp->prob, mlp->c_p);
414 struct ATS_Peer * peer = mlp->peer_head;
417 struct ATS_Address *addr = peer->head;
418 struct MLP_information *mlpi = (struct MLP_information *) addr->mlp_information;
419 /* Adding row for c 2) */
420 /* Set row bound == 1 */
421 glp_set_row_bnds (mlp->prob, row_index, GLP_FX, 1.0, 1.0);
425 ia[mlp->ci] = row_index;
426 ja[mlp->ci] = mlpi->c_n;
436 /* For all quality metrics */
438 for (c = 0; c < mlp->m_q; c++)
440 struct ATS_Peer *p = mlp->peer_head;
443 ia[mlp->ci] = row_index;
444 ja[mlp->ci] = mlp->c_q[c];
456 * Add columns for all addresses
458 * @param cls GAS_MLP_Handle
459 * @param key Hashcode
460 * @param value ATS_Address
462 * @return GNUNET_OK to continue
465 create_columns_it (void *cls, const GNUNET_HashCode * key, void *value)
467 struct GAS_MLP_Handle *mlp = cls;
468 struct ATS_Address *address = value;
469 struct MLP_information *mlpi;
473 GNUNET_assert (address->mlp_information != NULL);
474 mlpi = address->mlp_information;
476 /* Add bandwidth column */
477 col = glp_add_cols (mlp->prob, 2);
481 GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR,
483 "Culoumn %i %i\n", mlpi->c_b, mlpi->c_n);
485 GNUNET_asprintf (&name, "b_%s_%s", GNUNET_i2s (&address->peer), address->plugin);
486 glp_set_col_name (mlp->prob, mlpi->c_b , name);
488 /* Lower bound == 0 */
489 glp_set_col_bnds (mlp->prob, mlpi->c_b , GLP_LO, 0.0, 0.0);
490 /* Continuous value*/
491 glp_set_col_kind (mlp->prob, mlpi->c_b , GLP_CV);
492 /* Objective function coefficient == 0 */
493 glp_set_obj_coef (mlp->prob, mlpi->c_b , 0);
496 /* Add usage column */
497 GNUNET_asprintf (&name, "n_%s_%s", GNUNET_i2s (&address->peer), address->plugin);
498 glp_set_col_name (mlp->prob, mlpi->c_n, name);
500 /* Limit value : 0 <= value <= 1 */
501 glp_set_col_bnds (mlp->prob, mlpi->c_n, GLP_DB, 0.0, 1.0);
503 glp_set_col_kind (mlp->prob, mlpi->c_n, GLP_IV);
504 /* Objective function coefficient == 0 */
505 glp_set_obj_coef (mlp->prob, mlpi->c_n, 1);
513 * Create the MLP problem
515 * @param mlp the MLP handle
516 * @return GNUNET_OK or GNUNET_SYSERR
519 mlp_create_problem (struct GAS_MLP_Handle *mlp, struct GNUNET_CONTAINER_MultiHashMap * addresses)
527 GNUNET_assert (mlp->prob == NULL);
529 /* create the glpk problem */
530 mlp->prob = glp_create_prob ();
532 /* Set a problem name */
533 glp_set_prob_name (mlp->prob, "gnunet ats bandwidth distribution");
535 /* Set optimization direction to maximize */
536 glp_set_obj_dir (mlp->prob, GLP_MAX);
538 /* Adding invariant columns */
540 /* Diversity d column */
542 col = glp_add_cols (mlp->prob, 1);
545 glp_set_col_name (mlp->prob, col, "d");
546 /* Column objective function coefficient */
547 glp_set_obj_coef (mlp->prob, col, mlp->co_D);
548 /* Column lower bound = 0.0 */
549 glp_set_col_bnds (mlp->prob, col, GLP_LO, 0.0, 0.0);
551 /* Utilization u column */
553 col = glp_add_cols (mlp->prob, 1);
556 glp_set_col_name (mlp->prob, col, "u");
557 /* Column objective function coefficient */
558 glp_set_obj_coef (mlp->prob, col, mlp->co_U);
559 /* Column lower bound = 0.0 */
560 glp_set_col_bnds (mlp->prob, col, GLP_LO, 0.0, 0.0);
562 /* Relativity r column */
563 col = glp_add_cols (mlp->prob, 1);
566 glp_set_col_name (mlp->prob, col, "r");
567 /* Column objective function coefficient */
568 glp_set_obj_coef (mlp->prob, col, mlp->co_R);
569 /* Column lower bound = 0.0 */
570 glp_set_col_bnds (mlp->prob, col, GLP_LO, 0.0, 0.0);
572 /* Quality metric columns */
573 col = glp_add_cols(mlp->prob, mlp->m_q);
574 for (c = 0; c < mlp->m_q; c++)
576 mlp->c_q[c] = col + c;
577 GNUNET_asprintf (&name, "q_%u", mlp->q[c]);
578 glp_set_col_name (mlp->prob, col + c, name);
579 /* Column lower bound = 0.0 */
580 glp_set_col_bnds (mlp->prob, col + c, GLP_LO, 0.0, 0.0);
582 /* Coefficient == Qm */
583 glp_set_obj_coef (mlp->prob, col + c, mlp->co_Q[c]);
586 /* Add columns for addresses */
587 GNUNET_CONTAINER_multihashmap_iterate (addresses, create_columns_it, mlp);
589 /* Add constraints */
590 mlp_add_constraints_all_addresses (mlp, addresses);
592 /* Load the matrix */
593 glp_load_matrix(mlp->prob, (mlp->ci - 1), mlp->ia, mlp->ja, mlp->ar);
599 * Solves the LP problem
601 * @param mlp the MLP Handle
602 * @return GNUNET_OK if could be solved, GNUNET_SYSERR on failure
605 mlp_solve_lp_problem (struct GAS_MLP_Handle *mlp)
608 struct GNUNET_TIME_Relative duration;
609 struct GNUNET_TIME_Absolute end;
610 struct GNUNET_TIME_Absolute start = GNUNET_TIME_absolute_get();
613 * Presolver is required if the problem was modified and an existing
614 * valid basis is now invalid */
615 if (mlp->presolver_required == GNUNET_YES)
616 mlp->control_param_lp.presolve = GLP_ON;
618 mlp->control_param_lp.presolve = GLP_OFF;
620 /* Solve LP problem to have initial valid solution */
622 res = glp_simplex(mlp->prob, &mlp->control_param_lp);
625 /* The LP problem instance has been successfully solved. */
627 else if (res == GLP_EITLIM)
629 /* simplex iteration limit has been exceeded. */
630 // TODO Increase iteration limit?
632 else if (res == GLP_ETMLIM)
634 /* Time limit has been exceeded. */
635 // TODO Increase time limit?
639 /* Problem was ill-defined, retry with presolver */
640 if (mlp->presolver_required == GNUNET_NO)
642 mlp->presolver_required = GNUNET_YES;
647 /* Problem was ill-defined, no way to handle that */
648 GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR,
650 "Solving LP problem failed: %i %s\n", res, mlp_solve_to_string(res));
651 return GNUNET_SYSERR;
655 end = GNUNET_TIME_absolute_get ();
656 duration = GNUNET_TIME_absolute_get_difference (start, end);
658 mlp->lp_total_duration =+ duration.rel_value;
660 GNUNET_STATISTICS_update (mlp->stats,"# LP problem solved", 1, GNUNET_NO);
661 GNUNET_STATISTICS_set (mlp->stats,"# LP execution time", duration.rel_value, GNUNET_NO);
662 GNUNET_STATISTICS_set (mlp->stats,"# LP execution time average",
663 mlp->lp_total_duration / mlp->lp_solved, GNUNET_NO);
666 /* Analyze problem status */
667 res = glp_get_status (mlp->prob);
669 /* solution is optimal */
671 /* solution is feasible */
675 /* Problem was ill-defined, no way to handle that */
677 GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR,
679 "Solving LP problem failed, no solution: %s\n", mlp_status_to_string(res));
680 return GNUNET_SYSERR;
684 /* solved sucessfully, no presolver required next time */
685 mlp->presolver_required = GNUNET_NO;
692 * Solves the MLP problem
694 * @param mlp the MLP Handle
695 * @return GNUNET_OK if could be solved, GNUNET_SYSERR on failure
698 mlp_solve_mlp_problem (struct GAS_MLP_Handle *mlp)
701 struct GNUNET_TIME_Relative duration;
702 struct GNUNET_TIME_Absolute end;
703 struct GNUNET_TIME_Absolute start = GNUNET_TIME_absolute_get();
705 /* solve MLP problem */
706 res = glp_intopt(mlp->prob, &mlp->control_param_mlp);
710 /* The MLP problem instance has been successfully solved. */
712 else if (res == GLP_EITLIM)
714 /* simplex iteration limit has been exceeded. */
715 // TODO Increase iteration limit?
717 else if (res == GLP_ETMLIM)
719 /* Time limit has been exceeded. */
720 // TODO Increase time limit?
724 /* Problem was ill-defined, no way to handle that */
725 GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR,
727 "Solving MLP problem failed: %s\n", mlp_solve_to_string(res));
728 return GNUNET_SYSERR;
731 end = GNUNET_TIME_absolute_get ();
732 duration = GNUNET_TIME_absolute_get_difference (start, end);
734 mlp->mlp_total_duration =+ duration.rel_value;
736 GNUNET_STATISTICS_update (mlp->stats,"# MLP problem solved", 1, GNUNET_NO);
737 GNUNET_STATISTICS_set (mlp->stats,"# MLP execution time", duration.rel_value, GNUNET_NO);
738 GNUNET_STATISTICS_set (mlp->stats,"# MLP execution time average",
739 mlp->mlp_total_duration / mlp->mlp_solved, GNUNET_NO);
741 /* Analyze problem status */
742 res = glp_mip_status(mlp->prob);
744 /* solution is optimal */
746 /* solution is feasible */
750 /* Problem was ill-defined, no way to handle that */
752 GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR,
754 "Solving MLP problem failed, %s\n\n", mlp_status_to_string(res));
755 return GNUNET_SYSERR;
762 int mlp_solve_problem (struct GAS_MLP_Handle *mlp);
765 mlp_scheduler (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
767 struct GAS_MLP_Handle *mlp = cls;
769 mlp->mlp_task = GNUNET_SCHEDULER_NO_TASK;
771 if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
775 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Scheduled problem solving\n");
777 if (mlp->addr_in_problem != 0)
778 mlp_solve_problem(mlp);
783 * Solves the MLP problem
785 * @param mlp the MLP Handle
786 * @return GNUNET_OK if could be solved, GNUNET_SYSERR on failure
789 mlp_solve_problem (struct GAS_MLP_Handle *mlp)
792 mlp->last_execution = GNUNET_TIME_absolute_get ();
794 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Problem solving\n");
801 GNUNET_asprintf(&name, "problem_%i", i);
802 glp_write_lp (mlp->prob, 0, name);
806 res = mlp_solve_lp_problem (mlp);
809 GNUNET_asprintf(&name, "problem_%i_lp_solution", i);
810 glp_print_sol (mlp->prob, name);
814 if (res != GNUNET_OK)
817 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "LP Problem solving failed\n");
819 return GNUNET_SYSERR;
822 res = mlp_solve_mlp_problem (mlp);
825 GNUNET_asprintf(&name, "problem_%i_mlp_solution", i);
826 glp_print_mip (mlp->prob, name);
831 if (res != GNUNET_OK)
834 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "MLP Problem solving failed\n");
836 return GNUNET_SYSERR;
839 res = glp_mip_status(mlp->prob);
841 if (res != GNUNET_OK)
844 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "LP Problem solving failed\n");
846 return GNUNET_SYSERR;
850 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Problem solved: %i %s\n", res, mlp_status_to_string(res));
855 if (mlp->mlp_task != GNUNET_SCHEDULER_NO_TASK)
857 GNUNET_SCHEDULER_cancel(mlp->mlp_task);
858 mlp->mlp_task = GNUNET_SCHEDULER_NO_TASK;
860 mlp->mlp_task = GNUNET_SCHEDULER_add_delayed (mlp->exec_interval, &mlp_scheduler, mlp);
865 * Init the MLP problem solving component
867 * @param stats the GNUNET_STATISTICS handle
868 * @param max_duration maximum numbers of iterations for the LP/MLP Solver
869 * @param max_iterations maximum time limit for the LP/MLP Solver
870 * @return struct GAS_MLP_Handle * on success, NULL on fail
872 struct GAS_MLP_Handle *
873 GAS_mlp_init (const struct GNUNET_CONFIGURATION_Handle *cfg,
874 const struct GNUNET_STATISTICS_Handle *stats,
875 struct GNUNET_TIME_Relative max_duration,
876 unsigned int max_iterations)
878 struct GAS_MLP_Handle * mlp = GNUNET_malloc (sizeof (struct GAS_MLP_Handle));
883 long long unsigned int tmp;
886 struct GNUNET_TIME_Relative i_exec;
888 /* Init GLPK environment */
889 GNUNET_assert (glp_init_env() == 0);
891 /* Create initial MLP problem */
892 mlp->prob = glp_create_prob();
893 GNUNET_assert (mlp->prob != NULL);
895 /* Get diversity coefficient from configuration */
896 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_size (cfg, "ats",
899 D = (double) tmp / 100;
903 /* Get proportionality coefficient from configuration */
904 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_size (cfg, "ats",
907 R = (double) tmp / 100;
911 /* Get utilization coefficient from configuration */
912 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_size (cfg, "ats",
915 U = (double) tmp / 100;
919 /* Get quality metric coefficients from configuration */
922 int q[GNUNET_ATS_QualityPropertiesCount] = GNUNET_ATS_QualityProperties;
924 for (c = 0; c < GNUNET_ATS_QualityPropertiesCount; c++)
926 /* initialize quality coefficients with default value 1.0 */
930 if (q[c] == GNUNET_ATS_QUALITY_NET_DELAY)
932 if (q[c] == GNUNET_ATS_QUALITY_NET_DISTANCE)
936 if ((i_delay != -1) && (GNUNET_OK == GNUNET_CONFIGURATION_get_value_size (cfg, "ats",
937 "COEFFICIENT_QUALITY_DELAY",
940 mlp->co_Q[i_delay] = (double) tmp / 100;
942 mlp->co_Q[i_delay] = 1.0;
944 if ((i_distance != -1) && (GNUNET_OK == GNUNET_CONFIGURATION_get_value_size (cfg, "ats",
945 "COEFFICIENT_QUALITY_DISTANCE",
947 mlp->co_Q[i_distance] = (double) tmp / 100;
949 mlp->co_Q[i_distance] = 1.0;
951 /* Get minimum bandwidth per used address from configuration */
952 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_size (cfg, "ats",
959 /* Get minimum number of connections from configuration */
960 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_size (cfg, "ats",
967 /* Get minimum number of connections from configuration */
968 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_time (cfg, "ats",
971 mlp->exec_interval = i_exec;
973 mlp->exec_interval = GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 30);
975 mlp->stats = (struct GNUNET_STATISTICS_Handle *) stats;
976 mlp->max_iterations = max_iterations;
977 mlp->max_exec_duration = max_duration;
979 /* Redirect GLPK output to GNUnet logging */
980 glp_error_hook((void *) mlp, &mlp_term_hook);
982 /* Init LP solving parameters */
983 glp_init_smcp(&mlp->control_param_lp);
985 mlp->control_param_lp.msg_lev = GLP_MSG_ALL;
987 mlp->control_param_lp.msg_lev = GLP_MSG_OFF;
989 mlp->control_param_lp.it_lim = max_iterations;
990 mlp->control_param_lp.tm_lim = max_duration.rel_value;
992 /* Init MLP solving parameters */
993 glp_init_iocp(&mlp->control_param_mlp);
995 mlp->control_param_mlp.msg_lev = GLP_MSG_ALL;
997 mlp->control_param_mlp.msg_lev = GLP_MSG_OFF;
999 mlp->control_param_mlp.tm_lim = max_duration.rel_value;
1001 mlp->last_execution = GNUNET_TIME_absolute_get_forever();
1008 mlp->m_q = GNUNET_ATS_QualityPropertiesCount;
1014 * Updates a single address in the MLP problem
1016 * If the address did not exist before in the problem:
1017 * The MLP problem has to be recreated and the problem has to be resolved
1019 * Otherwise the addresses' values can be updated and the existing base can
1022 * @param mlp the MLP Handle
1023 * @param addresses the address hashmap
1024 * the address has to be already removed from the hashmap
1025 * @param address the address to update
1028 GAS_mlp_address_update (struct GAS_MLP_Handle *mlp, struct GNUNET_CONTAINER_MultiHashMap * addresses, struct ATS_Address *address)
1031 struct MLP_information *mlpi;
1034 GNUNET_STATISTICS_update (mlp->stats,"# LP address updates", 1, GNUNET_NO);
1036 /* We add a new address */
1037 if (address->mlp_information == NULL)
1043 if (new == GNUNET_YES)
1045 mlpi = GNUNET_malloc (sizeof (struct MLP_information));
1046 address->mlp_information = mlpi;
1047 mlp->addr_in_problem ++;
1049 /* Check for and add peer */
1050 struct ATS_Peer *peer = mlp_find_peer (mlp, &address->peer);
1054 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Adding new peer `%s'\n", GNUNET_i2s (&address->peer));
1056 peer = GNUNET_malloc (sizeof (struct ATS_Peer));
1060 for (c = 0; c < GNUNET_ATS_QualityPropertiesCount; c++)
1065 memcpy (&peer->id, &address->peer, sizeof (struct GNUNET_PeerIdentity));
1066 GNUNET_assert(address->prev == NULL);
1067 GNUNET_assert(address->next == NULL);
1068 GNUNET_CONTAINER_DLL_insert (peer->head, peer->tail, address);
1069 GNUNET_CONTAINER_DLL_insert (mlp->peer_head, mlp->peer_tail, peer);
1075 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Adding address to peer `%s'\n", GNUNET_i2s (&address->peer));
1077 GNUNET_CONTAINER_DLL_insert (peer->head, peer->tail, address);
1083 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Updating existing address to peer `%s'\n", GNUNET_i2s (&address->peer));
1088 if (new == GNUNET_YES)
1090 mlp_delete_problem (mlp);
1091 mlp_create_problem (mlp, addresses);
1092 mlp->presolver_required = GNUNET_YES;
1094 mlp_solve_problem (mlp);
1098 * Deletes a single address in the MLP problem
1100 * The MLP problem has to be recreated and the problem has to be resolved
1102 * @param mlp the MLP Handle
1103 * @param addresses the address hashmap
1104 * the address has to be already removed from the hashmap
1105 * @param address the address to delete
1108 GAS_mlp_address_delete (struct GAS_MLP_Handle *mlp, struct GNUNET_CONTAINER_MultiHashMap * addresses, struct ATS_Address *address)
1110 GNUNET_STATISTICS_update (mlp->stats,"# LP address deletions", 1, GNUNET_NO);
1112 /* Free resources */
1113 if (address->mlp_information != NULL)
1115 GNUNET_free (address->mlp_information);
1116 address->mlp_information = NULL;
1118 mlp->addr_in_problem --;
1121 /* Remove from peer list */
1122 struct ATS_Peer *head = mlp_find_peer (mlp, &address->peer);
1123 GNUNET_assert (head != NULL);
1125 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Deleting address for `%s'\n", GNUNET_i2s (&address->peer));
1127 GNUNET_CONTAINER_DLL_remove (head->head, head->tail, address);
1128 if ((head->head == NULL) && (head->tail == NULL))
1130 /* No address for peer left, remove peer */
1132 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Deleting peer `%s'\n", GNUNET_i2s (&address->peer));
1134 GNUNET_CONTAINER_DLL_remove (mlp->peer_head, mlp->peer_tail, head);
1139 /* Update problem */
1140 mlp_delete_problem (mlp);
1141 if ((GNUNET_CONTAINER_multihashmap_size (addresses) > 0) && (mlp->c_p > 0))
1144 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "mlp_create_problem %i\n",__LINE__);
1146 mlp_create_problem (mlp, addresses);
1149 mlp->presolver_required = GNUNET_YES;
1150 mlp_solve_problem (mlp);
1155 * Changes the preferences for a peer in the MLP problem
1157 * @param mlp the MLP Handle
1158 * @param peer the peer
1159 * @param kind the kind to change the preference
1160 * @param float the score
1163 GAS_mlp_address_change_preference (struct GAS_MLP_Handle *mlp,
1164 const struct GNUNET_PeerIdentity *peer,
1165 enum GNUNET_ATS_PreferenceKind kind,
1168 GNUNET_STATISTICS_update (mlp->stats,"# LP address preference changes", 1, GNUNET_NO);
1170 struct ATS_Peer *p = mlp_find_peer (mlp, peer);
1172 /* Here we have to do the matching */
1176 * Shutdown the MLP problem solving component
1177 * @param mlp the MLP handle
1180 GAS_mlp_done (struct GAS_MLP_Handle *mlp)
1182 struct ATS_Peer * peer;
1183 struct ATS_Peer * tmp;
1185 if (mlp->mlp_task != GNUNET_SCHEDULER_NO_TASK)
1187 GNUNET_SCHEDULER_cancel(mlp->mlp_task);
1188 mlp->mlp_task = GNUNET_SCHEDULER_NO_TASK;
1191 /* clean up peer list */
1194 peer = mlp->peer_head;
1195 while (peer != NULL)
1197 GNUNET_CONTAINER_DLL_remove(mlp->peer_head, mlp->peer_tail, peer);
1203 mlp_delete_problem (mlp);
1205 /* Clean up GLPK environment */
1212 /* end of gnunet-service-ats_addresses_mlp.c */