Logo AND Algorithmique Numérique Distribuée

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