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"
37 #define DEBUG_ATS GNUNET_YES
38 /* A very big value */
42 * Translate glpk solver error codes to text
43 * @param retcode return code
44 * @return string with result
47 mlp_solve_to_string (int retcode)
54 return "invalid basis";
57 return "singular matrix";
60 return "ill-conditioned matrix";
63 return "invalid bounds";
66 return "solver failed";
69 return "objective lower limit reached";
72 return "objective upper limit reached";
75 return "iteration limit exceeded";
78 return "time limit exceeded";
81 return "no primal feasible solution";
84 return "root LP optimum not provided";
87 return "search terminated by application";
90 return "relative mip gap tolerance reached";
93 return "no dual feasible solution";
96 return "no convergence";
99 return "numerical instability";
102 return "invalid data";
105 return "result out of range";
109 return "unknown error";
113 return "unknown error";
118 * Translate glpk status error codes to text
119 * @param retcode return code
120 * @return string with result
123 mlp_status_to_string (int retcode)
127 return "solution is undefined";
130 return "solution is feasible";
133 return "solution is infeasible";
136 return "no feasible solution exists";
139 return "solution is optimal";
142 return "solution is unbounded";
146 return "unknown error";
150 return "unknown error";
154 * Find a peer in the DLL
155 * @param the peer to find
156 * @return the peer struct
158 static struct ATS_Peer *
159 mlp_find_peer (struct GAS_MLP_Handle *mlp, const struct GNUNET_PeerIdentity *peer)
161 struct ATS_Peer *res = mlp->peer_head;
164 if (0 == memcmp (peer, &res->id, sizeof (struct GNUNET_PeerIdentity)))
172 * Intercept GLPK terminal output
173 * @param info the mlp handle
174 * @param s the string to print
175 * @return 0: glpk prints output on terminal, 0 != surpress output
178 mlp_term_hook (void *info, const char *s)
180 /* Not needed atm struct MLP_information *mlp = info; */
181 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s", s);
186 * Delete the MLP problem and free the constrain matrix
188 * @param mlp the MLP handle
191 mlp_delete_problem (struct GAS_MLP_Handle *mlp)
195 if (mlp->prob != NULL)
196 glp_delete_prob(mlp->prob);
198 /* delete row index */
201 GNUNET_free (mlp->ia);
205 /* delete column index */
208 GNUNET_free (mlp->ja);
212 /* delete coefficients */
215 GNUNET_free (mlp->ar);
224 * Add constraints that are iterating over "forall addresses"
225 * and collects all existing peers for "forall peers" constraints
227 * @param cls GAS_MLP_Handle
228 * @param key Hashcode
229 * @param value ATS_Address
231 * @return GNUNET_OK to continue
234 create_constraint_it (void *cls, const GNUNET_HashCode * key, void *value)
236 struct GAS_MLP_Handle *mlp = cls;
237 struct ATS_Address *address = value;
238 struct MLP_information *mlpi;
239 unsigned int row_index;
241 GNUNET_assert (address->mlp_information != NULL);
242 mlpi = (struct MLP_information *) address->mlp_information;
244 /* c 1) bandwidth capping
245 * b_t + (-M) * n_t <= 0
247 row_index = glp_add_rows (mlp->prob, 1);
248 mlpi->r_c1 = row_index;
249 /* set row bounds: <= 0 */
250 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_b;
259 mlp->ar[mlp->ci] = -M;
262 /* c 3) minimum bandwidth
263 * b_t + (-n_t * b_min) >= 0
266 row_index = glp_add_rows (mlp->prob, 1);
267 mlpi->r_c3 = row_index;
268 /* set row bounds: >= 0 */
269 glp_set_row_bnds (mlp->prob, row_index, GLP_LO, 0.0, 0.0);
271 mlp->ia[mlp->ci] = row_index;
272 mlp->ja[mlp->ci] = mlpi->c_b;
273 mlp->ar[mlp->ci] = 1;
276 mlp->ia[mlp->ci] = row_index;
277 mlp->ja[mlp->ci] = mlpi->c_b;
278 mlp->ar[mlp->ci] = -mlp->b_min;
281 /* c 4) minimum connections
282 * (1)*n_1 + ... + (1)*n_m >= n_min
284 mlp->ia[mlp->ci] = mlp->r_c4;
285 mlp->ja[mlp->ci] = mlpi->c_n;
286 mlp->ar[mlp->ci] = 1;
294 * Adds the problem constraints for all addresses
295 * Required for problem recreation after address deletion
297 * @param addresses all addresses
301 mlp_add_constraints_all_addresses (struct GAS_MLP_Handle *mlp, struct GNUNET_CONTAINER_MultiHashMap * addresses)
303 unsigned int n_addresses;
307 n_addresses = GNUNET_CONTAINER_multihashmap_size(addresses);
309 /* Required indices in the constrain matrix
311 * feasibility constraints:
313 * c 1) bandwidth capping
314 * #rows: |n_addresses|
315 * #indices: 2 * |n_addresses|
317 * c 2) one active address per peer
319 * #indices: |n_addresses|
321 * c 3) minium bandwidth assigned
322 * #rows: |n_addresses|
323 * #indices: 2 * |n_addresses|
325 * c 4) minimum number of active connections
327 * #indices: |n_addresses|
329 * c 5) maximum ressource consumption
330 * #rows: |ressources|
331 * #indices: |n_addresses|
333 * Sum for feasibility constraints:
334 * #rows: 3 * |n_addresses| + |ressources| + |peers| + 1
335 * #indices: 7 * |n_addresses|
337 * optimality constraints:
341 int pi = (7 * n_addresses);
346 int *ia = GNUNET_malloc (pi * sizeof (int));
350 int *ja = GNUNET_malloc (pi * sizeof (int));
354 double *ar= GNUNET_malloc (pi * sizeof (double));
357 /* Adding constraint rows
358 * This constraints are kind of "for all addresses"
359 * Feasibility constraints:
361 * c 1) bandwidth capping
362 * c 3) minimum bandwidth
363 * c 4) minimum number of connections
365 mlp->r_c4 = glp_add_rows (mlp->prob, 1);
366 glp_set_row_bnds (mlp->prob, mlp->r_c4, GLP_LO, mlp->n_min, 0.0);
368 GNUNET_CONTAINER_multihashmap_iterate (addresses, create_constraint_it, mlp);
370 /* Adding constraint rows
371 * This constraints are kind of "for all peers"
372 * Feasibility constraints:
374 * c 2) 1 address per peer
375 * sum (n_p1_1 + ... + n_p1_n) = 1
378 /* Adding rows for c 2) */
379 row_index = glp_add_rows (mlp->prob, mlp->c_p);
381 struct ATS_Peer * peer = mlp->peer_head;
384 struct ATS_Address *addr = peer->head;
385 struct MLP_information *mlpi = (struct MLP_information *) addr->mlp_information;
386 /* Adding row for c 2) */
387 /* Set row bound == 1 */
388 glp_set_row_bnds (mlp->prob, row_index, GLP_FX, 1.0, 1.0);
392 ia[mlp->ci] = row_index;
393 ja[mlp->ci] = mlpi->c_n;
406 * Add columns for all addresses
408 * @param cls GAS_MLP_Handle
409 * @param key Hashcode
410 * @param value ATS_Address
412 * @return GNUNET_OK to continue
415 create_columns_it (void *cls, const GNUNET_HashCode * key, void *value)
417 struct GAS_MLP_Handle *mlp = cls;
418 struct ATS_Address *address = value;
419 struct MLP_information *mlpi;
423 GNUNET_assert (address->mlp_information != NULL);
424 mlpi = address->mlp_information;
426 /* Add bandwidth column */
427 col = glp_add_cols (mlp->prob, 2);
431 GNUNET_asprintf (&name, "b_%s_%s", GNUNET_i2s (&address->peer), address->plugin);
432 glp_set_col_name (mlp->prob, mlpi->c_b , name);
434 /* Lower bound == 0 */
435 glp_set_col_bnds (mlp->prob, mlpi->c_b , GLP_LO, 0.0, 0.0);
436 /* Continuous value*/
437 glp_set_col_kind (mlp->prob, mlpi->c_b , GLP_CV);
438 /* Objective function coefficient == 0 */
439 glp_set_obj_coef (mlp->prob, mlpi->c_b , 0);
441 /* Add usage column */
442 GNUNET_asprintf (&name, "n_%s_%s", GNUNET_i2s (&address->peer), address->plugin);
443 glp_set_col_name (mlp->prob, mlpi->c_n, name);
445 /* Limit value : 0 <= value <= 1 */
446 glp_set_col_bnds (mlp->prob, mlpi->c_n, GLP_DB, 0.0, 1.0);
448 glp_set_col_kind (mlp->prob, mlpi->c_n, GLP_IV);
449 /* Objective function coefficient == 0 */
450 glp_set_obj_coef (mlp->prob, mlpi->c_n, 0);
458 * Create the MLP problem
460 * @param mlp the MLP handle
461 * @return GNUNET_OK or GNUNET_SYSERR
464 mlp_create_problem (struct GAS_MLP_Handle *mlp, struct GNUNET_CONTAINER_MultiHashMap * addresses)
472 /* Set a problem name */
473 glp_set_prob_name (mlp->prob, "gnunet ats bandwidth distribution");
475 /* Set optimization direction to maximize */
476 glp_set_obj_dir (mlp->prob, GLP_MAX);
478 /* Adding invariant columns */
480 /* Diversity d column */
482 col = glp_add_cols (mlp->prob, 1);
485 glp_set_col_name (mlp->prob, col, "d");
486 /* Column objective function coefficient */
487 glp_set_obj_coef (mlp->prob, col, mlp->co_D);
488 /* Column lower bound = 0.0 */
489 glp_set_col_bnds (mlp->prob, col, GLP_LO, 0.0, 0.0);
491 /* Utilization u column */
493 col = glp_add_cols (mlp->prob, 1);
496 glp_set_col_name (mlp->prob, col, "u");
497 /* Column objective function coefficient */
498 glp_set_obj_coef (mlp->prob, col, mlp->co_U);
499 /* Column lower bound = 0.0 */
500 glp_set_col_bnds (mlp->prob, col, GLP_LO, 0.0, 0.0);
502 /* Relativity r column */
503 col = glp_add_cols (mlp->prob, 1);
506 glp_set_col_name (mlp->prob, col, "r");
507 /* Column objective function coefficient */
508 glp_set_obj_coef (mlp->prob, col, mlp->co_R);
509 /* Column lower bound = 0.0 */
510 glp_set_col_bnds (mlp->prob, col, GLP_LO, 0.0, 0.0);
512 /* Quality metric columns */
513 col = glp_add_cols(mlp->prob, mlp->m_q);
514 for (c = 0; c < mlp->m_q; c++)
516 mlp->c_q[c] = col + c;
517 GNUNET_asprintf (&name, "q_%u", mlp->q[c]);
518 glp_set_col_name (mlp->prob, col + c, name);
519 /* Column lower bound = 0.0 */
520 glp_set_col_bnds (mlp->prob, col + c, GLP_LO, 0.0, 0.0);
522 /* Coefficient == Qm */
523 glp_set_obj_coef (mlp->prob, col + c, mlp->co_Q[c]);
526 /* Add columns for addresses */
527 GNUNET_CONTAINER_multihashmap_iterate (addresses, create_columns_it, mlp);
529 /* Add constraints */
530 mlp_add_constraints_all_addresses (mlp, addresses);
536 * Solves the LP problem
538 * @param mlp the MLP Handle
539 * @return GNUNET_OK if could be solved, GNUNET_SYSERR on failure
542 mlp_solve_lp_problem (struct GAS_MLP_Handle *mlp)
545 struct GNUNET_TIME_Relative duration;
546 struct GNUNET_TIME_Absolute end;
547 struct GNUNET_TIME_Absolute start = GNUNET_TIME_absolute_get();
550 * Presolver is required if the problem was modified and an existing
551 * valid basis is now invalid */
552 if (mlp->presolver_required == GNUNET_YES)
553 mlp->control_param_lp.presolve = GLP_ON;
555 mlp->control_param_lp.presolve = GLP_OFF;
557 /* Solve LP problem to have initial valid solution */
559 res = glp_simplex(mlp->prob, &mlp->control_param_lp);
562 /* The LP problem instance has been successfully solved. */
564 else if (res == GLP_EITLIM)
566 /* simplex iteration limit has been exceeded. */
567 // TODO Increase iteration limit?
569 else if (res == GLP_ETMLIM)
571 /* Time limit has been exceeded. */
572 // TODO Increase time limit?
576 /* Problem was ill-defined, retry with presolver */
577 if (mlp->presolver_required == GNUNET_NO)
579 mlp->presolver_required = GNUNET_YES;
584 /* Problem was ill-defined, no way to handle that */
585 GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR,
587 "Solving LP problem failed: %s\n", mlp_solve_to_string(res));
588 return GNUNET_SYSERR;
592 end = GNUNET_TIME_absolute_get ();
593 duration = GNUNET_TIME_absolute_get_difference (start, end);
595 mlp->lp_total_duration =+ duration.rel_value;
597 GNUNET_STATISTICS_update (mlp->stats,"# LP problem solved", 1, GNUNET_NO);
598 GNUNET_STATISTICS_set (mlp->stats,"# LP execution time", duration.rel_value, GNUNET_NO);
599 GNUNET_STATISTICS_set (mlp->stats,"# LP execution time average",
600 mlp->lp_total_duration / mlp->lp_solved, GNUNET_NO);
603 /* Analyze problem status */
604 res = glp_get_status (mlp->prob);
606 /* solution is optimal */
608 /* solution is feasible */
612 /* Problem was ill-defined, no way to handle that */
614 GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR,
616 "Solving LP problem failed, no solution: %s\n", mlp_status_to_string(res));
617 return GNUNET_SYSERR;
621 /* solved sucessfully, no presolver required next time */
622 mlp->presolver_required = GNUNET_NO;
629 * Solves the MLP problem
631 * @param mlp the MLP Handle
632 * @return GNUNET_OK if could be solved, GNUNET_SYSERR on failure
635 mlp_solve_mlp_problem (struct GAS_MLP_Handle *mlp)
638 struct GNUNET_TIME_Relative duration;
639 struct GNUNET_TIME_Absolute end;
640 struct GNUNET_TIME_Absolute start = GNUNET_TIME_absolute_get();
642 /* solve MLP problem */
643 res = glp_intopt(mlp->prob, &mlp->control_param_mlp);
647 /* The MLP problem instance has been successfully solved. */
649 else if (res == GLP_EITLIM)
651 /* simplex iteration limit has been exceeded. */
652 // TODO Increase iteration limit?
654 else if (res == GLP_ETMLIM)
656 /* Time limit has been exceeded. */
657 // TODO Increase time limit?
661 /* Problem was ill-defined, no way to handle that */
662 GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR,
664 "Solving MLP problem failed: %s\n", mlp_solve_to_string(res));
665 return GNUNET_SYSERR;
668 end = GNUNET_TIME_absolute_get ();
669 duration = GNUNET_TIME_absolute_get_difference (start, end);
671 mlp->mlp_total_duration =+ duration.rel_value;
673 GNUNET_STATISTICS_update (mlp->stats,"# MLP problem solved", 1, GNUNET_NO);
674 GNUNET_STATISTICS_set (mlp->stats,"# MLP execution time", duration.rel_value, GNUNET_NO);
675 GNUNET_STATISTICS_set (mlp->stats,"# MLP execution time average",
676 mlp->mlp_total_duration / mlp->mlp_solved, GNUNET_NO);
678 /* Analyze problem status */
679 res = glp_mip_status(mlp->prob);
681 /* solution is optimal */
683 /* solution is feasible */
687 /* Problem was ill-defined, no way to handle that */
689 GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR,
691 "Solving MLP problem failed, %s\n\n", mlp_status_to_string(res));
692 return GNUNET_SYSERR;
699 int mlp_solve_problem (struct GAS_MLP_Handle *mlp);
702 mlp_scheduler (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
704 struct GAS_MLP_Handle *mlp = cls;
706 mlp->mlp_task = GNUNET_SCHEDULER_NO_TASK;
708 if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
712 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Scheduled problem solving\n");
714 if (mlp->addr_in_problem != 0)
715 mlp_solve_problem(mlp);
720 * Solves the MLP problem
722 * @param mlp the MLP Handle
723 * @return GNUNET_OK if could be solved, GNUNET_SYSERR on failure
726 mlp_solve_problem (struct GAS_MLP_Handle *mlp)
729 mlp->last_execution = GNUNET_TIME_absolute_get ();
730 res = mlp_solve_lp_problem (mlp);
731 if (res == GNUNET_OK)
732 res = mlp_solve_mlp_problem (mlp);
737 if (mlp->mlp_task != GNUNET_SCHEDULER_NO_TASK)
739 GNUNET_SCHEDULER_cancel(mlp->mlp_task);
740 mlp->mlp_task = GNUNET_SCHEDULER_NO_TASK;
742 mlp->mlp_task = GNUNET_SCHEDULER_add_delayed (mlp->exec_interval, &mlp_scheduler, mlp);
747 * Init the MLP problem solving component
749 * @param stats the GNUNET_STATISTICS handle
750 * @param max_duration maximum numbers of iterations for the LP/MLP Solver
751 * @param max_iterations maximum time limit for the LP/MLP Solver
752 * @return struct GAS_MLP_Handle * on success, NULL on fail
754 struct GAS_MLP_Handle *
755 GAS_mlp_init (const struct GNUNET_CONFIGURATION_Handle *cfg,
756 const struct GNUNET_STATISTICS_Handle *stats,
757 struct GNUNET_TIME_Relative max_duration,
758 unsigned int max_iterations)
760 struct GAS_MLP_Handle * mlp = GNUNET_malloc (sizeof (struct GAS_MLP_Handle));
765 long long unsigned int tmp;
768 struct GNUNET_TIME_Relative i_exec;
770 /* Init GLPK environment */
771 GNUNET_assert (glp_init_env() == 0);
773 /* Create initial MLP problem */
774 mlp->prob = glp_create_prob();
775 GNUNET_assert (mlp->prob != NULL);
777 /* Get diversity coefficient from configuration */
778 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_size (cfg, "ats",
781 D = (double) tmp / 100;
785 /* Get proportionality coefficient from configuration */
786 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_size (cfg, "ats",
789 R = (double) tmp / 100;
793 /* Get utilization coefficient from configuration */
794 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_size (cfg, "ats",
797 U = (double) tmp / 100;
801 /* Get quality metric coefficients from configuration */
804 int q[GNUNET_ATS_QualityPropertiesCount] = GNUNET_ATS_QualityProperties;
806 for (c = 0; c < GNUNET_ATS_QualityPropertiesCount; c++)
808 /* initialize quality coefficients with default value 1.0 */
812 if (q[c] == GNUNET_ATS_QUALITY_NET_DELAY)
814 if (q[c] == GNUNET_ATS_QUALITY_NET_DISTANCE)
818 if ((i_delay != -1) && (GNUNET_OK == GNUNET_CONFIGURATION_get_value_size (cfg, "ats",
819 "COEFFICIENT_QUALITY_DELAY",
822 mlp->co_Q[i_delay] = (double) tmp / 100;
824 mlp->co_Q[i_delay] = 1.0;
826 if ((i_distance != -1) && (GNUNET_OK == GNUNET_CONFIGURATION_get_value_size (cfg, "ats",
827 "COEFFICIENT_QUALITY_DISTANCE",
829 mlp->co_Q[i_distance] = (double) tmp / 100;
831 mlp->co_Q[i_distance] = 1.0;
833 /* Get minimum bandwidth per used address from configuration */
834 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_size (cfg, "ats",
841 /* Get minimum number of connections from configuration */
842 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_size (cfg, "ats",
849 /* Get minimum number of connections from configuration */
850 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_time (cfg, "ats",
853 mlp->exec_interval = i_exec;
855 mlp->exec_interval = GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 30);
857 mlp->stats = (struct GNUNET_STATISTICS_Handle *) stats;
858 mlp->max_iterations = max_iterations;
859 mlp->max_exec_duration = max_duration;
861 /* Redirect GLPK output to GNUnet logging */
862 glp_error_hook((void *) mlp, &mlp_term_hook);
864 /* Init LP solving parameters */
865 glp_init_smcp(&mlp->control_param_lp);
867 mlp->control_param_lp.msg_lev = GLP_MSG_ALL;
869 mlp->control_param_lp.msg_lev = GLP_MSG_OFF;
871 mlp->control_param_lp.it_lim = max_iterations;
872 mlp->control_param_lp.tm_lim = max_duration.rel_value;
874 /* Init MLP solving parameters */
875 glp_init_iocp(&mlp->control_param_mlp);
877 mlp->control_param_mlp.msg_lev = GLP_MSG_ALL;
879 mlp->control_param_mlp.msg_lev = GLP_MSG_OFF;
881 mlp->control_param_mlp.tm_lim = max_duration.rel_value;
883 mlp->last_execution = GNUNET_TIME_absolute_get_forever();
890 mlp->m_q = GNUNET_ATS_QualityPropertiesCount;
896 * Updates a single address in the MLP problem
898 * If the address did not exist before in the problem:
899 * The MLP problem has to be recreated and the problem has to be resolved
901 * Otherwise the addresses' values can be updated and the existing base can
904 * @param mlp the MLP Handle
905 * @param addresses the address hashmap
906 * the address has to be already removed from the hashmap
907 * @param address the address to update
910 GAS_mlp_address_update (struct GAS_MLP_Handle *mlp, struct GNUNET_CONTAINER_MultiHashMap * addresses, struct ATS_Address *address)
913 struct MLP_information *mlpi;
916 GNUNET_STATISTICS_update (mlp->stats,"# LP address updates", 1, GNUNET_NO);
918 /* We add a new address */
919 if (address->mlp_information == NULL)
925 if (new == GNUNET_YES)
927 mlpi = GNUNET_malloc (sizeof (struct MLP_information));
928 address->mlp_information = mlpi;
929 mlp->addr_in_problem ++;
931 /* Check for and add peer */
932 struct ATS_Peer *peer = mlp_find_peer (mlp, &address->peer);
936 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Adding new peer `%s'\n", GNUNET_i2s (&address->peer));
938 peer = GNUNET_malloc (sizeof (struct ATS_Peer));
942 for (c = 0; c < GNUNET_ATS_QualityPropertiesCount; c++)
947 memcpy (&peer->id, &address->peer, sizeof (struct GNUNET_PeerIdentity));
948 GNUNET_assert(address->prev == NULL);
949 GNUNET_assert(address->next == NULL);
950 GNUNET_CONTAINER_DLL_insert (peer->head, peer->tail, address);
951 GNUNET_CONTAINER_DLL_insert (mlp->peer_head, mlp->peer_tail, peer);
957 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Adding address to peer `%s'\n", GNUNET_i2s (&address->peer));
959 GNUNET_CONTAINER_DLL_insert (peer->head, peer->tail, address);
965 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Updating existing address to peer `%s'\n", GNUNET_i2s (&address->peer));
970 if (new == GNUNET_YES)
971 mlp->presolver_required = GNUNET_YES;
972 mlp_solve_problem (mlp);
976 * Deletes a single address in the MLP problem
978 * The MLP problem has to be recreated and the problem has to be resolved
980 * @param mlp the MLP Handle
981 * @param addresses the address hashmap
982 * the address has to be already removed from the hashmap
983 * @param address the address to delete
986 GAS_mlp_address_delete (struct GAS_MLP_Handle *mlp, struct GNUNET_CONTAINER_MultiHashMap * addresses, struct ATS_Address *address)
988 GNUNET_STATISTICS_update (mlp->stats,"# LP address deletions", 1, GNUNET_NO);
991 if (address->mlp_information != NULL)
993 GNUNET_free (address->mlp_information);
994 address->mlp_information = NULL;
996 mlp->addr_in_problem --;
999 /* Remove from peer list */
1000 struct ATS_Peer *head = mlp_find_peer (mlp, &address->peer);
1001 GNUNET_assert (head != NULL);
1003 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Deleting address for `%s'\n", GNUNET_i2s (&address->peer));
1005 GNUNET_CONTAINER_DLL_remove (head->head, head->tail, address);
1006 if ((head->head == NULL) && (head->tail == NULL))
1008 /* No address for peer left, remove peer */
1010 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Deleting peer `%s'\n", GNUNET_i2s (&address->peer));
1012 GNUNET_CONTAINER_DLL_remove (mlp->peer_head, mlp->peer_tail, head);
1017 /* Update problem */
1018 mlp_delete_problem (mlp);
1019 if ((GNUNET_CONTAINER_multihashmap_size (addresses) > 0) && (mlp->c_p > 0))
1022 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "mlp_create_problem %i\n",__LINE__);
1024 mlp_create_problem (mlp, addresses);
1027 mlp->presolver_required = GNUNET_YES;
1028 mlp_solve_problem (mlp);
1033 * Changes the preferences for a peer in the MLP problem
1035 * @param mlp the MLP Handle
1036 * @param peer the peer
1037 * @param kind the kind to change the preference
1038 * @param float the score
1041 GAS_mlp_address_change_preference (struct GAS_MLP_Handle *mlp,
1042 const struct GNUNET_PeerIdentity *peer,
1043 enum GNUNET_ATS_PreferenceKind kind,
1046 GNUNET_STATISTICS_update (mlp->stats,"# LP address preference changes", 1, GNUNET_NO);
1048 struct ATS_Peer *p = mlp_find_peer (mlp, peer);
1050 /* Here we have to do the matching */
1054 * Shutdown the MLP problem solving component
1055 * @param mlp the MLP handle
1058 GAS_mlp_done (struct GAS_MLP_Handle *mlp)
1060 struct ATS_Peer * peer;
1061 struct ATS_Peer * tmp;
1063 if (mlp->mlp_task != GNUNET_SCHEDULER_NO_TASK)
1065 GNUNET_SCHEDULER_cancel(mlp->mlp_task);
1066 mlp->mlp_task = GNUNET_SCHEDULER_NO_TASK;
1069 /* clean up peer list */
1072 peer = mlp->peer_head;
1073 while (peer != NULL)
1075 GNUNET_CONTAINER_DLL_remove(mlp->peer_head, mlp->peer_tail, peer);
1081 mlp_delete_problem (mlp);
1083 /* Clean up GLPK environment */
1090 /* end of gnunet-service-ats_addresses_mlp.c */