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"
39 static struct GAS_MLP_Handle *GAS_mlp;
43 * Solves the LP problem
44 * @return GNUNET_OK if could be solved, GNUNET_SYSERR on failure
47 mlp_solve_lp_problem (struct GAS_MLP_Handle *mlp)
50 struct GNUNET_TIME_Relative duration;
51 struct GNUNET_TIME_Absolute end;
52 struct GNUNET_TIME_Absolute start = GNUNET_TIME_absolute_get();
55 * Presolver is required if the problem was modified and an existing
56 * valid basis is now invalid */
57 if (mlp->presolver_required == GNUNET_YES)
58 mlp->control_param_lp.presolve = GLP_ON;
60 mlp->control_param_lp.presolve = GLP_OFF;
62 /* Solve LP problem to have initial valid solution */
64 res = glp_simplex(mlp->prob, &mlp->control_param_lp);
67 /* The LP problem instance has been successfully solved. */
69 else if (res == GLP_EITLIM)
71 /* simplex iteration limit has been exceeded. */
72 // TODO Increase iteration limit?
74 else if (res == GLP_ETMLIM)
76 /* Time limit has been exceeded. */
77 // TODO Increase time limit?
81 /* Problem was ill-defined, retry with presolver */
82 if (mlp->presolver_required == GNUNET_NO)
84 mlp->presolver_required = GNUNET_YES;
89 /* Problem was ill-defined, no way to handle that */
90 GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR,
92 "Solving LP problem failed: glp_simplex error 0x%X", res);
97 end = GNUNET_TIME_absolute_get ();
98 duration = GNUNET_TIME_absolute_get_difference (start, end);
100 mlp->lp_total_duration =+ duration.rel_value;
102 GNUNET_STATISTICS_update (mlp->stats,"# LP problem solved", 1, GNUNET_NO);
103 GNUNET_STATISTICS_set (mlp->stats,"# LP execution time", duration.rel_value, GNUNET_NO);
104 GNUNET_STATISTICS_set (mlp->stats,"# LP execution time average",
105 mlp->lp_total_duration / mlp->lp_solved, GNUNET_NO);
108 /* Analyze problem status */
109 res = glp_get_status (mlp->prob);
111 /* solution is optimal */
113 /* solution is feasible */
117 /* Problem was ill-defined, no way to handle that */
119 GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR,
121 "Solving LP problem failed, no solution: glp_get_status 0x%X", res);
122 return GNUNET_SYSERR;
126 /* solved sucessfully, no presolver required next time */
127 mlp->presolver_required = GNUNET_NO;
134 * Solves the MLP problem
135 * @return GNUNET_OK if could be solved, GNUNET_SYSERR on failure
138 mlp_solve_mlp_problem (struct GAS_MLP_Handle *mlp)
141 struct GNUNET_TIME_Relative duration;
142 struct GNUNET_TIME_Absolute end;
143 struct GNUNET_TIME_Absolute start = GNUNET_TIME_absolute_get();
145 /* solve MLP problem */
146 res = glp_intopt(mlp->prob, &mlp->control_param_mlp);
150 /* The MLP problem instance has been successfully solved. */
152 else if (res == GLP_EITLIM)
154 /* simplex iteration limit has been exceeded. */
155 // TODO Increase iteration limit?
157 else if (res == GLP_ETMLIM)
159 /* Time limit has been exceeded. */
160 // TODO Increase time limit?
164 /* Problem was ill-defined, no way to handle that */
165 GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR,
167 "Solving MLP problem failed: glp_intopt error 0x%X", res);
168 return GNUNET_SYSERR;
171 end = GNUNET_TIME_absolute_get ();
172 duration = GNUNET_TIME_absolute_get_difference (start, end);
174 mlp->mlp_total_duration =+ duration.rel_value;
176 GNUNET_STATISTICS_update (mlp->stats,"# MLP problem solved", 1, GNUNET_NO);
177 GNUNET_STATISTICS_set (mlp->stats,"# MLP execution time", duration.rel_value, GNUNET_NO);
178 GNUNET_STATISTICS_set (mlp->stats,"# MLP execution time average",
179 mlp->mlp_total_duration / mlp->mlp_solved, GNUNET_NO);
181 /* Analyze problem status */
182 res = glp_mip_status(mlp->prob);
184 /* solution is optimal */
186 /* solution is feasible */
190 /* Problem was ill-defined, no way to handle that */
192 GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR,
194 "Solving MLP problem failed, no solution: glp_mip_status 0x%X", res);
195 return GNUNET_SYSERR;
203 * Solves the MLP problem
204 * @return GNUNET_OK if could be solved, GNUNET_SYSERR on failure
207 mlp_solve_problem (struct GAS_MLP_Handle *mlp)
210 mlp->last_execution = GNUNET_TIME_absolute_get ();
211 res = mlp_solve_lp_problem (mlp);
212 if (res == GNUNET_OK)
213 res = mlp_solve_mlp_problem (mlp);
218 * Init the MLP problem solving component
220 * @param stats the GNUNET_STATISTICS handle
221 * @param max_duration maximum numbers of iterations for the LP/MLP Solver
222 * @param max_iterations maximum time limit for the LP/MLP Solver
223 * @return GNUNET_OK on success, GNUNET_SYSERR on fail
226 GAS_mlp_init (const struct GNUNET_STATISTICS_Handle *stats,
227 struct GNUNET_TIME_Relative max_duration,
228 unsigned int max_iterations)
230 GAS_mlp = GNUNET_malloc (sizeof (struct GAS_MLP_Handle));
232 /* Init GLPK environment */
233 GNUNET_assert (glp_init_env() == 0);
235 /* Create initial MLP problem */
236 GAS_mlp->prob = glp_create_prob();
237 GNUNET_assert (GAS_mlp->prob != NULL);
239 GAS_mlp->stats = (struct GNUNET_STATISTICS_Handle *) stats;
240 GAS_mlp->max_iterations = max_iterations;
241 GAS_mlp->max_exec_duration = max_duration;
243 /* Init LP solving parameters */
244 glp_init_smcp(&GAS_mlp->control_param_lp);
246 GAS_mlp->control_param_lp.msg_lev = GLP_MSG_ALL;
248 GAS_mlp->control_param_lp.msg_lev = GLP_MSG_OFF;
250 GAS_mlp->control_param_lp.it_lim = max_iterations;
251 GAS_mlp->control_param_lp.tm_lim = max_duration.rel_value;
253 /* Init MLP solving parameters */
254 glp_init_iocp(&GAS_mlp->control_param_mlp);
256 GAS_mlp->control_param_mlp.msg_lev = GLP_MSG_ALL;
258 GAS_mlp->control_param_mlp.msg_lev = GLP_MSG_OFF;
260 GAS_mlp->control_param_mlp.tm_lim = max_duration.rel_value;
262 GAS_mlp->last_execution = GNUNET_TIME_absolute_get_forever();
267 * Updates a single address in the MLP problem
269 * If the address did not exist before in the problem:
270 * The MLP problem has to be recreated and the problem has to be resolved
272 * Otherwise the addresses' values can be updated and the existing base can
276 GAS_mlp_address_update (struct GNUNET_CONTAINER_MultiHashMap * addresses, struct ATS_Address *address)
280 GNUNET_STATISTICS_update (GAS_mlp->stats,"# LP address updates", 1, GNUNET_NO);
282 /* We update a new address */
283 if (address->mlp_information == NULL)
286 address->mlp_information = GNUNET_malloc (sizeof (struct MLP_information));
294 if (new == GNUNET_YES)
295 GAS_mlp->presolver_required = GNUNET_YES;
296 mlp_solve_problem (GAS_mlp);
300 * Deletes a single address in the MLP problem
302 * The MLP problem has to be recreated and the problem has to be resolved
305 GAS_mlp_address_delete (struct GNUNET_CONTAINER_MultiHashMap * addresses, struct ATS_Address *address)
307 GNUNET_STATISTICS_update (GAS_mlp->stats,"# LP address deletions", 1, GNUNET_NO);
310 if (address->mlp_information != NULL)
312 GNUNET_free (address->mlp_information);
313 address->mlp_information = NULL;
319 GAS_mlp->presolver_required = GNUNET_YES;
320 mlp_solve_problem (GAS_mlp);
324 * Deletes a single address in the MLP problem
327 GAS_mlp_address_change_preference (struct GNUNET_CONTAINER_MultiHashMap * addresses, struct ATS_Address *address)
329 GNUNET_STATISTICS_update (GAS_mlp->stats,"# LP address preference changes", 1, GNUNET_NO);
335 * Shutdown the MLP problem solving component
341 glp_delete_prob(GAS_mlp->prob);
343 /* Clean up GLPK environment */
346 GNUNET_free (GAS_mlp);
350 /* end of gnunet-service-ats_addresses_mlp.c */