Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Added the lazy management improvement for network models.
[simgrid.git] / src / surf / maxmin.c
1 /* Copyright (c) 2004, 2005, 2006, 2007, 2008, 2009, 2010. The SimGrid Team.
2  * All rights reserved.                                                     */
3
4 /* This program is free software; you can redistribute it and/or modify it
5  * under the terms of the license (GNU LGPL) which comes with this package. */
6
7
8 #include "xbt/sysdep.h"
9 #include "xbt/log.h"
10 #include "xbt/mallocator.h"
11 #include "maxmin_private.h"
12 #include <stdlib.h>
13 #include <stdio.h>              /* sprintf */
14 #include <math.h>
15 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(surf_maxmin, surf,
16                                 "Logging specific to SURF (maxmin)");
17
18 double sg_maxmin_precision = 0.00001;
19
20 static void *lmm_variable_mallocator_new_f(void);
21 static void lmm_variable_mallocator_free_f(void *var);
22 static void lmm_variable_mallocator_reset_f(void *var);
23 static void lmm_update_modified_set(lmm_system_t sys,
24                                     lmm_constraint_t cnst);
25 static void lmm_remove_all_modified_set(lmm_system_t sys);
26 int sg_maxmin_selective_update = 1;
27 static int Global_debug_id = 1;
28 static int Global_const_debug_id = 1;
29 extern xbt_swag_t keep_track;
30
31 lmm_system_t lmm_system_new(void)
32 {
33   lmm_system_t l = NULL;
34   s_lmm_variable_t var;
35   s_lmm_constraint_t cnst;
36
37   l = xbt_new0(s_lmm_system_t, 1);
38
39   l->modified = 0;
40   l->selective_update_active = sg_maxmin_selective_update;
41
42   DEBUG1("Setting selective_update_active flag to %d\n",
43          l->selective_update_active);
44
45   xbt_swag_init(&(l->variable_set),
46                 xbt_swag_offset(var, variable_set_hookup));
47   xbt_swag_init(&(l->constraint_set),
48                 xbt_swag_offset(cnst, constraint_set_hookup));
49
50   xbt_swag_init(&(l->active_constraint_set),
51                 xbt_swag_offset(cnst, active_constraint_set_hookup));
52
53   xbt_swag_init(&(l->modified_constraint_set),
54                 xbt_swag_offset(cnst, modified_constraint_set_hookup));
55   xbt_swag_init(&(l->saturated_variable_set),
56                 xbt_swag_offset(var, saturated_variable_set_hookup));
57   xbt_swag_init(&(l->saturated_constraint_set),
58                 xbt_swag_offset(cnst, saturated_constraint_set_hookup));
59
60   l->variable_mallocator = xbt_mallocator_new(64,
61                                               lmm_variable_mallocator_new_f,
62                                               lmm_variable_mallocator_free_f,
63                                               lmm_variable_mallocator_reset_f);
64
65   return l;
66 }
67
68 void lmm_system_free(lmm_system_t sys)
69 {
70   lmm_variable_t var = NULL;
71   lmm_constraint_t cnst = NULL;
72
73   while ((var = extract_variable(sys))) {
74     WARN2
75         ("Variable %p (%d) still in LMM system when freing it: this may be a bug",
76          var, var->id_int);
77     lmm_var_free(sys, var);
78   }
79
80   while ((cnst = extract_constraint(sys)))
81     lmm_cnst_free(sys, cnst);
82
83   xbt_mallocator_free(sys->variable_mallocator);
84   free(sys);
85 }
86
87 XBT_INLINE void lmm_variable_disable(lmm_system_t sys, lmm_variable_t var)
88 {
89   int i;
90   lmm_element_t elem = NULL;
91
92   XBT_IN2("(sys=%p, var=%p)", sys, var);
93   sys->modified = 1;
94
95   for (i = 0; i < var->cnsts_number; i++) {
96     elem = &var->cnsts[i];
97     xbt_swag_remove(elem, &(elem->constraint->element_set));
98     xbt_swag_remove(elem, &(elem->constraint->active_element_set));
99     if (!xbt_swag_size(&(elem->constraint->element_set)))
100       make_constraint_inactive(sys, elem->constraint);
101     else
102       lmm_update_modified_set(sys, elem->constraint);
103   }
104   var->cnsts_number = 0;
105   XBT_OUT;
106 }
107
108 static void lmm_var_free(lmm_system_t sys, lmm_variable_t var)
109 {
110
111   lmm_variable_disable(sys, var);
112   free(var->cnsts);
113   xbt_mallocator_release(sys->variable_mallocator, var);
114 }
115
116 static XBT_INLINE void lmm_cnst_free(lmm_system_t sys,
117                                      lmm_constraint_t cnst)
118 {
119 /*   xbt_assert0(xbt_swag_size(&(cnst->element_set)), */
120 /*            "This list should be empty!"); */
121   remove_active_constraint(sys, cnst);
122   free(cnst);
123 }
124
125 lmm_constraint_t lmm_constraint_new(lmm_system_t sys, void *id,
126                                     double bound_value)
127 {
128   lmm_constraint_t cnst = NULL;
129   s_lmm_element_t elem;
130
131   cnst = xbt_new0(s_lmm_constraint_t, 1);
132   cnst->id = id;
133   cnst->id_int = Global_const_debug_id++;
134   xbt_swag_init(&(cnst->element_set),
135                 xbt_swag_offset(elem, element_set_hookup));
136   xbt_swag_init(&(cnst->active_element_set),
137                 xbt_swag_offset(elem, active_element_set_hookup));
138
139   cnst->bound = bound_value;
140   cnst->usage = 0;
141   cnst->shared = 1;
142   insert_constraint(sys, cnst);
143
144   return cnst;
145 }
146
147 XBT_INLINE void lmm_constraint_shared(lmm_constraint_t cnst)
148 {
149   cnst->shared = 0;
150 }
151
152 XBT_INLINE int lmm_constraint_is_shared(lmm_constraint_t cnst)
153 {
154   return (cnst->shared);
155 }
156
157 XBT_INLINE void lmm_constraint_free(lmm_system_t sys,
158                                     lmm_constraint_t cnst)
159 {
160   remove_constraint(sys, cnst);
161   lmm_cnst_free(sys, cnst);
162 }
163
164 static void *lmm_variable_mallocator_new_f(void)
165 {
166   return xbt_new(s_lmm_variable_t, 1);
167 }
168
169 static void lmm_variable_mallocator_free_f(void *var)
170 {
171   xbt_free(var);
172 }
173
174 static void lmm_variable_mallocator_reset_f(void *var)
175 {
176   /* memset to zero like calloc */
177   memset(var, 0, sizeof(s_lmm_variable_t));
178 }
179
180 lmm_variable_t lmm_variable_new(lmm_system_t sys, void *id,
181                                 double weight,
182                                 double bound, int number_of_constraints)
183 {
184   lmm_variable_t var = NULL;
185   int i;
186
187   XBT_IN5("(sys=%p, id=%p, weight=%f, bound=%f, num_cons =%d)",
188           sys, id, weight, bound, number_of_constraints);
189
190   var = xbt_mallocator_get(sys->variable_mallocator);
191   var->id = id;
192   var->id_int = Global_debug_id++;
193   var->cnsts = xbt_new0(s_lmm_element_t, number_of_constraints);
194   for (i = 0; i < number_of_constraints; i++) {
195     /* Should be useless because of the 
196        calloc but it seems to help valgrind... */
197     var->cnsts[i].element_set_hookup.next = NULL;
198     var->cnsts[i].element_set_hookup.prev = NULL;
199     var->cnsts[i].active_element_set_hookup.next = NULL;
200     var->cnsts[i].active_element_set_hookup.prev = NULL;
201     var->cnsts[i].constraint = NULL;
202     var->cnsts[i].variable = NULL;
203     var->cnsts[i].value = 0.0;
204   }
205   var->cnsts_size = number_of_constraints;
206   var->cnsts_number = 0;        /* Should be useless because of the 
207                                    calloc but it seems to help valgrind... */
208   var->weight = weight;
209   var->bound = bound;
210   var->value = 0.0;
211
212
213   var->func_f = func_f_def;
214   var->func_fp = func_fp_def;
215   var->func_fpi = func_fpi_def;
216
217   if (weight)
218     xbt_swag_insert_at_head(var, &(sys->variable_set));
219   else
220     xbt_swag_insert_at_tail(var, &(sys->variable_set));
221   XBT_OUT;
222   return var;
223 }
224
225 void lmm_variable_free(lmm_system_t sys, lmm_variable_t var)
226 {
227   remove_variable(sys, var);
228   lmm_var_free(sys, var);
229 }
230
231 XBT_INLINE double lmm_variable_getvalue(lmm_variable_t var)
232 {
233   return (var->value);
234 }
235
236 XBT_INLINE double lmm_variable_getbound(lmm_variable_t var)
237 {
238   return (var->bound);
239 }
240
241 void lmm_expand(lmm_system_t sys, lmm_constraint_t cnst,
242                 lmm_variable_t var, double value)
243 {
244   lmm_element_t elem = NULL;
245
246   sys->modified = 1;
247
248   xbt_assert0(var->cnsts_number < var->cnsts_size, "Too much constraints");
249
250   elem = &(var->cnsts[var->cnsts_number++]);
251
252   elem->value = value;
253   elem->constraint = cnst;
254   elem->variable = var;
255
256   if (var->weight)
257     xbt_swag_insert_at_head(elem, &(elem->constraint->element_set));
258   else
259     xbt_swag_insert_at_tail(elem, &(elem->constraint->element_set));
260
261   make_constraint_active(sys, cnst);
262   lmm_update_modified_set(sys, cnst);
263 }
264
265 void lmm_expand_add(lmm_system_t sys, lmm_constraint_t cnst,
266                     lmm_variable_t var, double value)
267 {
268   int i;
269   sys->modified = 1;
270
271   for (i = 0; i < var->cnsts_number; i++)
272     if (var->cnsts[i].constraint == cnst)
273       break;
274
275   if (i < var->cnsts_number) {
276     if (cnst->shared)
277       var->cnsts[i].value += value;
278     else
279       var->cnsts[i].value = MAX(var->cnsts[i].value, value);
280     lmm_update_modified_set(sys, cnst);
281   } else
282     lmm_expand(sys, cnst, var, value);
283 }
284
285 void lmm_elem_set_value(lmm_system_t sys, lmm_constraint_t cnst,
286                         lmm_variable_t var, double value)
287 {
288   int i;
289
290   for (i = 0; i < var->cnsts_number; i++)
291     if (var->cnsts[i].constraint == cnst)
292       break;
293
294   if (i < var->cnsts_number) {
295     var->cnsts[i].value = value;
296     sys->modified = 1;
297     lmm_update_modified_set(sys, cnst);
298   } else
299     DIE_IMPOSSIBLE;
300 }
301
302 XBT_INLINE lmm_constraint_t lmm_get_cnst_from_var(lmm_system_t sys,
303                                                   lmm_variable_t var,
304                                                   int num)
305 {
306   if (num < var->cnsts_number)
307     return (var->cnsts[num].constraint);
308   else
309     return NULL;
310 }
311
312 XBT_INLINE int lmm_get_number_of_cnst_from_var(lmm_system_t sys,
313                                                lmm_variable_t var)
314 {
315   return (var->cnsts_number);
316 }
317
318 lmm_variable_t lmm_get_var_from_cnst(lmm_system_t sys,
319                                      lmm_constraint_t cnst,
320                                      lmm_element_t * elem)
321 {
322   if (!(*elem))
323     *elem = xbt_swag_getFirst(&(cnst->element_set));
324   else
325     *elem = xbt_swag_getNext(*elem, cnst->element_set.offset);
326   if (*elem)
327     return (*elem)->variable;
328   else
329     return NULL;
330 }
331
332 XBT_INLINE void *lmm_constraint_id(lmm_constraint_t cnst)
333 {
334   return cnst->id;
335 }
336
337 XBT_INLINE void *lmm_variable_id(lmm_variable_t var)
338 {
339   return var->id;
340 }
341
342 static XBT_INLINE void saturated_constraint_set_update(lmm_system_t sys,
343                                                        lmm_constraint_t
344                                                        cnst,
345                                                        double *min_usage)
346 {
347   lmm_constraint_t useless_cnst = NULL;
348
349   XBT_IN3("sys=%p, cnst=%p, min_usage=%f", sys, cnst, *min_usage);
350   if (cnst->usage <= 0) {
351     XBT_OUT;
352     return;
353   }
354   if (cnst->remaining <= 0) {
355     XBT_OUT;
356     return;
357   }
358   if ((*min_usage < 0) || (*min_usage > cnst->remaining / cnst->usage)) {
359     *min_usage = cnst->remaining / cnst->usage;
360     LOG3(xbt_log_priority_trace,
361          "min_usage=%f (cnst->remaining=%f, cnst->usage=%f)", *min_usage,
362          cnst->remaining, cnst->usage);
363     while ((useless_cnst =
364             xbt_swag_getFirst(&(sys->saturated_constraint_set))))
365       xbt_swag_remove(useless_cnst, &(sys->saturated_constraint_set));
366
367     xbt_swag_insert(cnst, &(sys->saturated_constraint_set));
368   } else if (*min_usage == cnst->remaining / cnst->usage) {
369     xbt_swag_insert(cnst, &(sys->saturated_constraint_set));
370   }
371   XBT_OUT;
372 }
373
374 static XBT_INLINE void saturated_variable_set_update(lmm_system_t sys)
375 {
376   lmm_constraint_t cnst = NULL;
377   xbt_swag_t cnst_list = NULL;
378   lmm_element_t elem = NULL;
379   xbt_swag_t elem_list = NULL;
380
381   cnst_list = &(sys->saturated_constraint_set);
382   while ((cnst = xbt_swag_getFirst(cnst_list))) {
383     elem_list = &(cnst->active_element_set);
384     xbt_swag_foreach(elem, elem_list) {
385       if (elem->variable->weight <= 0)
386         break;
387       if ((elem->value > 0))
388         xbt_swag_insert(elem->variable, &(sys->saturated_variable_set));
389     }
390     xbt_swag_remove(cnst, cnst_list);
391   }
392 }
393
394 void lmm_print(lmm_system_t sys)
395 {
396   lmm_constraint_t cnst = NULL;
397   lmm_element_t elem = NULL;
398   lmm_variable_t var = NULL;
399   xbt_swag_t cnst_list = NULL;
400   xbt_swag_t var_list = NULL;
401   xbt_swag_t elem_list = NULL;
402   char print_buf[1024];
403   char *trace_buf = xbt_malloc0(sizeof(char));
404   double sum = 0.0;
405
406   /* Printing Objective */
407   var_list = &(sys->variable_set);
408   sprintf(print_buf, "MAX-MIN ( ");
409   trace_buf =
410       xbt_realloc(trace_buf, strlen(trace_buf) + strlen(print_buf) + 1);
411   strcat(trace_buf, print_buf);
412   xbt_swag_foreach(var, var_list) {
413     sprintf(print_buf, "'%d'(%f) ", var->id_int, var->weight);
414     trace_buf =
415         xbt_realloc(trace_buf, strlen(trace_buf) + strlen(print_buf) + 1);
416     strcat(trace_buf, print_buf);
417   }
418   sprintf(print_buf, ")");
419   trace_buf =
420       xbt_realloc(trace_buf, strlen(trace_buf) + strlen(print_buf) + 1);
421   strcat(trace_buf, print_buf);
422   fprintf(stderr, "%s", trace_buf);
423   //DEBUG1("%20s", trace_buf); FIXME
424   trace_buf[0] = '\000';
425
426   DEBUG0("Constraints");
427   /* Printing Constraints */
428   cnst_list = &(sys->active_constraint_set);
429   xbt_swag_foreach(cnst, cnst_list) {
430     sum = 0.0;
431     elem_list = &(cnst->element_set);
432     sprintf(print_buf, "\t");
433     trace_buf =
434         xbt_realloc(trace_buf, strlen(trace_buf) + strlen(print_buf) + 1);
435     strcat(trace_buf, print_buf);
436     sprintf(print_buf, "%s(",(cnst->shared)?"":"max");
437     trace_buf =
438       xbt_realloc(trace_buf,
439                   strlen(trace_buf) + strlen(print_buf) + 1);
440     strcat(trace_buf, print_buf);      
441     xbt_swag_foreach(elem, elem_list) {
442       sprintf(print_buf, "%f.'%d'(%f) %s ", elem->value,
443               elem->variable->id_int, elem->variable->value,(cnst->shared)?"+":",");
444       trace_buf =
445           xbt_realloc(trace_buf,
446                       strlen(trace_buf) + strlen(print_buf) + 1);
447       strcat(trace_buf, print_buf);
448       if(cnst->shared) 
449         sum += elem->value * elem->variable->value;
450       else 
451         sum = MAX(sum,elem->value * elem->variable->value);
452     }
453     sprintf(print_buf, "0) <= %f ('%d')", cnst->bound, cnst->id_int);
454     trace_buf =
455         xbt_realloc(trace_buf, strlen(trace_buf) + strlen(print_buf) + 1);
456     strcat(trace_buf, print_buf);
457
458     if (!cnst->shared) {
459       sprintf(print_buf, " [MAX-Constraint]");
460       trace_buf =
461           xbt_realloc(trace_buf,
462                       strlen(trace_buf) + strlen(print_buf) + 1);
463       strcat(trace_buf, print_buf);
464     }
465     //   DEBUG1("%s", trace_buf);
466     fprintf(stderr, "%s\n", trace_buf);
467     trace_buf[0] = '\000';
468     xbt_assert3(!double_positive(sum - cnst->bound),
469                 "Incorrect value (%f is not smaller than %f): %g",
470                 sum, cnst->bound, sum - cnst->bound);
471   }
472
473   DEBUG0("Variables");
474   /* Printing Result */
475   xbt_swag_foreach(var, var_list) {
476     if (var->bound > 0) {
477       DEBUG4("'%d'(%f) : %f (<=%f)", var->id_int, var->weight, var->value,
478              var->bound);
479       xbt_assert2(!double_positive(var->value - var->bound),
480                   "Incorrect value (%f is not smaller than %f",
481                   var->value, var->bound);
482     } else {
483       DEBUG3("'%d'(%f) : %f", var->id_int, var->weight, var->value);
484     }
485   }
486
487   free(trace_buf);
488 }
489
490 void lmm_solve(lmm_system_t sys)
491 {
492   lmm_variable_t var = NULL;
493   lmm_constraint_t cnst = NULL;
494   lmm_element_t elem = NULL;
495   xbt_swag_t cnst_list = NULL;
496   xbt_swag_t var_list = NULL;
497   xbt_swag_t elem_list = NULL;
498   double min_usage = -1;
499   double min_bound = -1;
500
501   if (!(sys->modified))
502     return;
503
504   XBT_IN1("(sys=%p)", sys);
505
506   /*
507    * Compute Usage and store the variables that reach the maximum.
508    */
509   cnst_list =
510       sys->
511       selective_update_active ? &(sys->modified_constraint_set) :
512       &(sys->active_constraint_set);
513
514   DEBUG1("Active constraints : %d", xbt_swag_size(cnst_list));
515   /* Init: Only modified code portions */
516   xbt_swag_foreach(cnst, cnst_list) {
517     elem_list = &(cnst->element_set);
518     //DEBUG1("Variable set : %d", xbt_swag_size(elem_list));
519     xbt_swag_foreach(elem, elem_list) {
520       var = elem->variable;
521       if (var->weight <= 0.0)
522         break;
523       var->value = 0.0;
524     }
525   }
526
527   xbt_swag_foreach(cnst, cnst_list) {
528     /* INIT */
529     cnst->remaining = cnst->bound;
530     if (cnst->remaining == 0)
531       continue;
532     cnst->usage = 0;
533     elem_list = &(cnst->element_set);
534     xbt_swag_foreach(elem, elem_list) {
535       /* 0-weighted elements (ie, sleep actions) are at the end of the swag and we don't want to consider them */
536       if (elem->variable->weight <= 0)
537         break;
538       if ((elem->value > 0)) {
539         if (cnst->shared)
540           cnst->usage += elem->value / elem->variable->weight;
541         else if (cnst->usage < elem->value / elem->variable->weight)
542           cnst->usage = elem->value / elem->variable->weight;
543
544         make_elem_active(elem);
545         if(keep_track){
546             xbt_swag_insert((elem->variable)->id, keep_track);
547         }
548       }
549     }
550     DEBUG2("Constraint Usage '%d' : %f", cnst->id_int, cnst->usage);
551     /* Saturated constraints update */
552     saturated_constraint_set_update(sys, cnst, &min_usage);
553   }
554   saturated_variable_set_update(sys);
555
556   /* Saturated variables update */
557
558   do {
559     /* Fix the variables that have to be */
560     var_list = &(sys->saturated_variable_set);
561
562     xbt_swag_foreach(var, var_list) {
563       if (var->weight <= 0.0)
564         DIE_IMPOSSIBLE;
565       /* First check if some of these variables have reach their upper
566          bound and update min_usage accordingly. */
567       DEBUG5
568           ("var=%d, var->bound=%f, var->weight=%f, min_usage=%f, var->bound*var->weight=%f",
569            var->id_int, var->bound, var->weight, min_usage,
570            var->bound * var->weight);
571       if ((var->bound > 0) && (var->bound * var->weight < min_usage)) {
572         if (min_bound < 0)
573           min_bound = var->bound;
574         else
575           min_bound = MIN(min_bound, var->bound);
576         DEBUG1("Updated min_bound=%f", min_bound);
577       }
578     }
579
580
581     while ((var = xbt_swag_getFirst(var_list))) {
582       int i;
583
584       if (min_bound < 0) {
585         var->value = min_usage / var->weight;
586       } else {
587         if (min_bound == var->bound)
588           var->value = var->bound;
589         else {
590           xbt_swag_remove(var, var_list);
591           continue;
592         }
593       }
594       DEBUG5("Min usage: %f, Var(%d)->weight: %f, Var(%d)->value: %f ",
595              min_usage, var->id_int, var->weight, var->id_int, var->value);
596
597
598       /* Update usage */
599
600       for (i = 0; i < var->cnsts_number; i++) {
601         elem = &var->cnsts[i];
602         cnst = elem->constraint;
603         if (cnst->shared) {
604           double_update(&(cnst->remaining), elem->value * var->value);
605           double_update(&(cnst->usage), elem->value / var->weight);
606           make_elem_inactive(elem);
607         } else {                /* FIXME one day: We recompute usage.... :( */
608           cnst->usage = 0.0;
609           make_elem_inactive(elem);
610           elem_list = &(cnst->element_set);
611           xbt_swag_foreach(elem, elem_list) {
612             if (elem->variable->weight <= 0)
613               break;
614             if (elem->variable->value > 0)
615               break;
616             if ((elem->value > 0)) {
617               cnst->usage =
618                   MAX(cnst->usage, elem->value / elem->variable->weight);
619               DEBUG2("Constraint Usage %d : %f", cnst->id_int,
620                      cnst->usage);
621               make_elem_active(elem);
622             }
623           }
624         }
625       }
626       xbt_swag_remove(var, var_list);
627     }
628
629     /* Find out which variables reach the maximum */
630     cnst_list =
631         sys->selective_update_active ? &(sys->modified_constraint_set) :
632         &(sys->active_constraint_set);
633     min_usage = -1;
634     min_bound = -1;
635     xbt_swag_foreach(cnst, cnst_list) {
636       saturated_constraint_set_update(sys, cnst, &min_usage);
637     }
638     saturated_variable_set_update(sys);
639
640   } while (xbt_swag_size(&(sys->saturated_variable_set)));
641
642   sys->modified = 0;
643   if (sys->selective_update_active)
644     lmm_remove_all_modified_set(sys);
645
646   if (XBT_LOG_ISENABLED(surf_maxmin, xbt_log_priority_debug)) {
647     lmm_print(sys);
648   }
649   XBT_OUT;
650 }
651
652 /* Not a O(1) function */
653
654 void lmm_update(lmm_system_t sys, lmm_constraint_t cnst,
655                 lmm_variable_t var, double value)
656 {
657   int i;
658
659   for (i = 0; i < var->cnsts_number; i++)
660     if (var->cnsts[i].constraint == cnst) {
661       var->cnsts[i].value = value;
662       sys->modified = 1;
663       lmm_update_modified_set(sys, cnst);
664       return;
665     }
666 }
667
668 /** \brief Attribute the value bound to var->bound.
669  * 
670  *  \param sys the lmm_system_t
671  *  \param var the lmm_variable_t
672  *  \param bound the new bound to associate with var
673  * 
674  *  Makes var->bound equal to bound. Whenever this function is called 
675  *  a change is  signed in the system. To
676  *  avoid false system changing detection it is a good idea to test 
677  *  (bound != 0) before calling it.
678  *
679  */
680 void lmm_update_variable_bound(lmm_system_t sys, lmm_variable_t var,
681                                double bound)
682 {
683   int i;
684
685   sys->modified = 1;
686   var->bound = bound;
687
688   for (i = 0; i < var->cnsts_number; i++)
689     lmm_update_modified_set(sys, var->cnsts[i].constraint);
690
691 }
692
693
694 void lmm_update_variable_weight(lmm_system_t sys, lmm_variable_t var,
695                                 double weight)
696 {
697   int i;
698   lmm_element_t elem;
699
700   if (weight == var->weight)
701     return;
702   XBT_IN3("(sys=%p, var=%p, weight=%f)", sys, var, weight);
703   sys->modified = 1;
704   var->weight = weight;
705   xbt_swag_remove(var, &(sys->variable_set));
706   if (weight)
707     xbt_swag_insert_at_head(var, &(sys->variable_set));
708   else
709     xbt_swag_insert_at_tail(var, &(sys->variable_set));
710
711   for (i = 0; i < var->cnsts_number; i++) {
712     elem = &var->cnsts[i];
713     xbt_swag_remove(elem, &(elem->constraint->element_set));
714     if (weight)
715       xbt_swag_insert_at_head(elem, &(elem->constraint->element_set));
716     else
717       xbt_swag_insert_at_tail(elem, &(elem->constraint->element_set));
718
719     lmm_update_modified_set(sys, elem->constraint);
720   }
721   if (!weight)
722     var->value = 0.0;
723
724   XBT_OUT;
725 }
726
727 XBT_INLINE double lmm_get_variable_weight(lmm_variable_t var)
728 {
729   return var->weight;
730 }
731
732 XBT_INLINE void lmm_update_constraint_bound(lmm_system_t sys,
733                                             lmm_constraint_t cnst,
734                                             double bound)
735 {
736   sys->modified = 1;
737   lmm_update_modified_set(sys, cnst);
738   cnst->bound = bound;
739 }
740
741 XBT_INLINE int lmm_constraint_used(lmm_system_t sys, lmm_constraint_t cnst)
742 {
743   return xbt_swag_belongs(cnst, &(sys->active_constraint_set));
744 }
745
746 XBT_INLINE lmm_constraint_t lmm_get_first_active_constraint(lmm_system_t
747                                                             sys)
748 {
749   return xbt_swag_getFirst(&(sys->active_constraint_set));
750 }
751
752 XBT_INLINE lmm_constraint_t lmm_get_next_active_constraint(lmm_system_t
753                                                            sys,
754                                                            lmm_constraint_t
755                                                            cnst)
756 {
757   return xbt_swag_getNext(cnst, (sys->active_constraint_set).offset);
758 }
759
760 #ifdef HAVE_LATENCY_BOUND_TRACKING
761 XBT_INLINE int lmm_is_variable_limited_by_latency(lmm_variable_t var)
762 {
763   return (double_equals(var->bound, var->value));
764 }
765 #endif
766
767
768 /** \brief Update the constraint set propagating recursively to
769  *  other constraints so the system should not be entirely computed.
770  *
771  *  \param sys the lmm_system_t
772  *  \param cnst the lmm_constraint_t affected by the change
773  *
774  *  A recursive algorithm to optimize the system recalculation selecting only
775  *  constraints that have changed. Each constraint change is propagated
776  *  to the list of constraints for each variable.
777  */
778 static void lmm_update_modified_set(lmm_system_t sys,
779                                     lmm_constraint_t cnst)
780 {
781   lmm_element_t elem = NULL;
782   lmm_variable_t var = NULL;
783   xbt_swag_t elem_list = NULL;
784   int i;
785
786   /* return if selective update isn't active */
787   if (!sys->selective_update_active)
788     return;
789
790   //DEBUG1("Updating modified constraint set with constraint %d", cnst->id_int);
791
792   if (xbt_swag_belongs(cnst, &(sys->modified_constraint_set)))
793     return;
794
795   //DEBUG1("Inserting into modified constraint set %d", cnst->id_int);
796
797   /* add to modified set */
798   xbt_swag_insert(cnst, &(sys->modified_constraint_set));
799
800   elem_list = &(cnst->element_set);
801   xbt_swag_foreach(elem, elem_list) {
802     var = elem->variable;
803     for (i = 0; i < var->cnsts_number; i++)
804       if (cnst != var->cnsts[i].constraint) {
805         //DEBUG2("Updating modified %d calling for %d", cnst->id_int, var->cnsts[i].constraint->id_int);
806         lmm_update_modified_set(sys, var->cnsts[i].constraint);
807       }
808   }
809 }
810
811 /** \brief Remove all constraints of the modified_constraint_set.
812  *
813  *  \param sys the lmm_system_t
814  */
815 static void lmm_remove_all_modified_set(lmm_system_t sys)
816 {
817   lmm_element_t elem = NULL;
818   lmm_element_t elem_next = NULL;
819   xbt_swag_t elem_list = NULL;
820
821   elem_list = &(sys->modified_constraint_set);
822   xbt_swag_foreach_safe(elem, elem_next, elem_list) {
823     xbt_swag_remove(elem, elem_list);
824   }
825 }