3 /* Copyright (c) 2007 Arnaud Legrand, Pedro Velho. All rights reserved. */
5 /* This program is free software; you can redistribute it and/or modify it
6 * under the terms of the license (GNU LGPL) which comes with this package. */
9 * Modelling the proportional fairness using the Lagrange Optimization
10 * Approach. For a detailed description see:
11 * "ssh://username@scm.gforge.inria.fr/svn/memo/people/pvelho/lagrange/ppf.ps".
14 #include "xbt/sysdep.h"
15 #include "xbt/mallocator.h"
16 #include "maxmin_private.h"
24 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(surf_lagrange, surf,
25 "Logging specific to SURF (lagrange)");
27 XBT_LOG_NEW_SUBCATEGORY(surf_writelambda, surf,
28 "Generates the lambda.in file. WARNING: the size of this file might be a few GBs.");
30 void lagrange_dicotomi_solve(lmm_system_t sys);
32 double partial_diff_mu(double mu, lmm_variable_t var1);
33 double partial_diff_lambda(double lambda, lmm_constraint_t cnst1);
35 void lagrange_dicotomi_solve(lmm_system_t sys)
40 int max_iterations= 1000000;
41 double epsilon_min_error = 0.00001;
42 double overall_error = 1;
43 double min, max, middle;
47 * Variables to manipulate the data structure proposed to model the maxmin
48 * fairness. See docummentation for more details.
50 xbt_swag_t elem_list = NULL;
51 lmm_element_t elem1 = NULL;
54 xbt_swag_t cnst_list = NULL;
55 lmm_constraint_t cnst1 = NULL;
57 xbt_swag_t var_list = NULL;
58 lmm_variable_t var1 = NULL;
67 FILE *gnuplot_file=NULL;
70 DEBUG0("Iterative method configuration snapshot =====>");
71 DEBUG1("#### Maximum number of iterations : %d", max_iterations);
72 DEBUG1("#### Minimum error tolerated : %e", epsilon_min_error);
75 if ( !(sys->modified))
79 * Initialize the var list variable with only the active variables.
80 * Associate an index in the swag variables. Initialize mu.
82 var_list = &(sys->variable_set);
84 xbt_swag_foreach(var1, var_list) {
85 if((var1->bound > 0.0) || (var1->weight <= 0.0)){
86 DEBUG1("#### NOTE var1(%d) is a boundless variable", i);
92 DEBUG2("#### var1(%d)->mu : %e", i, var1->mu);
93 DEBUG2("#### var1(%d)->weight: %e", i, var1->weight);
100 cnst_list=&(sys->active_constraint_set);
101 xbt_swag_foreach(cnst1, cnst_list) {
103 cnst1->new_lambda = 2.0;
104 DEBUG2("#### cnst1(%p)->lambda : %e", cnst1, cnst1->lambda);
110 * While doesn't reach a minimun error or a number maximum of iterations.
112 while(overall_error > epsilon_min_error && iteration < max_iterations){
118 * Compute the value of ----------- (\lambda^k, \mu^k) this portion
120 * of code depends on function f(x).
122 var_list = &(sys->variable_set);
123 //forall mu_i in mu_1, mu_2, ..., mu_n
124 xbt_swag_foreach(var1, var_list) {
125 if((var1->bound >= 0) && (var1->weight > 0) ){
126 //for each link with capacity cnsts[i] that uses flow of variable var1 do
130 while(overall_error < epsilon_min_error){
131 if( partial_diff_mu(min, var1)>0 && partial_diff_mu(max, var1)>0 ){
137 }else if( partial_diff_mu(min, var1)<0 && partial_diff_mu(max, var1)<0 ){
143 }else if( partial_diff_mu(min,var1)<0 && partial_diff_mu(max,var1) > 0 ){
145 middle = partial_diff_mu((fabs(min - max)/2), var1);
147 max = (fabs(min - max)/2);
148 }else if( middle < 0 ){
149 min = (fabs(min - max)/2);
151 WARN0("Found an optimal solution with 0 error!");
154 overall_error = fabs(min - max);
157 WARN0("The impossible happened, partial_diff(min) >0 && partial_diff(max) < 0");
163 if(var1->new_mu < 0){
171 * Compute the value of ------------- (\lambda^k, \mu^k) this portion
173 * of code depends on function f(x).
175 xbt_swag_foreach(cnst1, cnst_list) {
180 while(overall_error < epsilon_min_error){
181 if( partial_diff_lambda(min, cnst1) > 0 && partial_diff_lambda(max, cnst1) > 0 ){
187 }else if( partial_diff_lambda(min, cnst1) < 0 && partial_diff_lambda(max, cnst1) < 0 ){
193 }else if( partial_diff_lambda(min,cnst1) < 0 && partial_diff_lambda(max,cnst1) > 0 ){
195 middle = partial_diff_lambda((fabs(min - max)/2), cnst1);
197 max = (fabs(min - max)/2);
198 }else if( middle < 0 ){
199 min = (fabs(min - max)/2);
201 WARN0("Found an optimal solution with 0 error!");
204 overall_error = fabs(min - max);
207 WARN0("The impossible happened, partial_diff(min) >0 && partial_diff(max) < 0");
213 cnst1->new_lambda = cnst1->lambda;
215 if(cnst1->new_lambda < 0){
216 cnst1->new_lambda = 0;
222 * Now computes the values of each variable (\rho) based on
223 * the values of \lambda and \mu.
226 xbt_swag_foreach(var1, var_list) {
231 for(i=0; i<var1->cnsts_number; i++){
232 tmp += (var1->cnsts[i].constraint)->lambda;
237 //computes de overall_error
238 if(overall_error < fabs(var1->value - 1.0/tmp)){
239 overall_error = fabs(var1->value - 1.0/tmp);
242 var1->value = 1.0 / tmp;
248 /* Updating lambda's and mu's */
249 xbt_swag_foreach(var1, var_list)
250 if(!((var1->bound > 0.0) || (var1->weight <= 0.0)))
251 var1->mu = var1->new_mu;
254 xbt_swag_foreach(cnst1, cnst_list)
255 cnst1->lambda = cnst1->new_lambda;
259 //verify the KKT property
260 xbt_swag_foreach(cnst1, cnst_list){
262 elem_list = &(cnst1->element_set);
263 xbt_swag_foreach(elem1, elem_list) {
264 var1 = elem1->variable;
265 if(var1->weight<=0) continue;
269 tmp = tmp - cnst1->bound;
272 if(tmp != 0 || cnst1->lambda != 0){
273 WARN4("The link %s(%p) doesn't match the KKT property, value expected (=0) got (lambda=%e) (sum_rho=%e)", (char *)cnst1->id, cnst1, cnst1->lambda, tmp);
279 xbt_swag_foreach(var1, var_list){
280 if(var1->bound <= 0 || var1->weight <= 0) continue;
282 tmp = (var1->value - var1->bound);
285 if(tmp != 0 || var1->mu != 0){
286 WARN4("The flow %s(%p) doesn't match the KKT property, value expected (=0) got (lambda=%e) (sum_rho=%e)", (char *)var1->id, var1, var1->mu, tmp);
292 if(overall_error <= epsilon_min_error){
293 DEBUG1("The method converge in %d iterations.", iteration);
295 WARN1("Method reach %d iterations, which is the maxmimun number of iterations allowed.", iteration);
299 if(XBT_LOG_ISENABLED(surf_writelambda, xbt_log_priority_debug)) {
300 fclose(gnuplot_file);
308 double partial_diff_mu(double mu, lmm_variable_t var1){
309 double mu_partial=0.0;
312 //for each link with capacity cnsts[i] that uses flow of variable var1 do
313 for(i=0; i<var1->cnsts_number; i++)
314 mu_partial += (var1->cnsts[i].constraint)->lambda + mu;
316 mu_partial = (-1.0/mu_partial) + var1->bound;
322 double partial_diff_lambda(double lambda, lmm_constraint_t cnst1){
326 double lambda_partial=0.0;
327 xbt_swag_t elem_list = NULL;
328 lmm_element_t elem1 = NULL;
329 lmm_variable_t var1 = NULL;
332 elem_list = &(cnst1->element_set);
334 xbt_swag_foreach(elem1, elem_list) {
335 var1 = elem1->variable;
336 if(var1->weight<=0) continue;
339 for(i=0; i<var1->cnsts_number; i++){
340 tmp += (var1->cnsts[i].constraint)->lambda;
346 if(tmp==0) lambda_partial = 10e-8;
347 lambda_partial += (-1.0 / (tmp - 3*cnst1->lambda + 3*cnst1->lambda));
350 return lambda_partial;