PIPS
sc_simplex_feasibility.h
Go to the documentation of this file.
1 /*
2 
3  $Id: sc_simplex_feasibility.h 1641 2016-03-02 08:20:19Z coelho $
4 
5  Copyright 1989-2016 MINES ParisTech
6 
7  This file is part of Linear/C3 Library.
8 
9  Linear/C3 Library is clear software: you can redistribute it and/or modify it
10  under the terms of the GNU Lesser General Public License as published by
11  the clear Software Foundation, either version 3 of the License, or
12  any later version.
13 
14  Linear/C3 Library is distributed in the hope that it will be useful, but WITHOUT ANY
15  WARRANTY; without even the implied warranty of MERCHANTABILITY or
16  FITNESS FOR A PARTICULAR PURPOSE.
17 
18  See the GNU Lesser General Public License for more details.
19 
20  You should have received a copy of the GNU Lesser General Public License
21  along with Linear/C3 Library. If not, see <http://www.gnu.org/licenses/>.
22 
23 */
24 
25 /**
26  * @file
27  * This header provides functions to test whether a constraint system is
28  * feasible, using the simplex method.
29  * It can be used with any of the headers @c arith_fixprec.c or @c
30  * arith_mulprec.c, this in fixed- or multiple-precision.
31  */
32 
33 #ifndef LINEAR_SC_SIMPLEX_FEASIBILITY_H
34 #define LINEAR_SC_SIMPLEX_FEASIBILITY_H
35 
36 #include <stdlib.h>
37 #include <stdio.h>
38 #include <stdint.h>
39 #include <strings.h>
40 #include <limits.h>
41 
42 #include "boolean.h"
43 #include "assert.h"
44 #include "vecteur.h"
45 #include "contrainte.h"
46 #include "sc.h"
47 
48 // debugging
49 #ifndef LINEAR_DEBUG_SIMPLEX
50 #define DEBUG(code) {}
51 #else
52 #define DEBUG(code) {code}
53 #endif
54 
55 // memory management
56 static void* safe_malloc(size_t size)
57 {
58  void* m = malloc(size);
59  if (m == NULL) {
60  fprintf(stderr, "[" __FILE__ "] out of memory\n");
61  abort();
62  }
63  return m;
64 }
65 
66 /**
67  * @name Variables
68  * Each variable is represented by a non-negative, integer value.
69  */
70 /**@{*/
71 
72 /**
73  * Type of variables.
74  */
75 typedef int var_t;
76 
77 /**
78  * A special value used to represent the absence of variable.
79  */
80 #define VAR_NULL (-1)
81 
82 /**
83  * Maximum number of variables.
84  */
85 #define VAR_MAXNB (1971)
86 
87 /**
88  * Output @a var on stdio stream @a stream.
89  */
90 #define var_fprint(stream, var) (fprintf(stream, "x%d", var))
91 
92 /**
93  * Output @a var on @c stdout.
94  */
95 #define var_print(var) (var_fprint(stdout, var))
96 
97 /**@}*/
98 
99 /**
100  * @name Vectors
101  * A vector is a structure to map each variable to a rational value.
102  */
103 /**@{*/
104 
105 /**
106  * Type of vectors.
107  * Typically, most of values are equal to zero, so a sparse, linked-list
108  * structure is used.
109  * Internally, variables are ordered by decreasing order.
110  */
111 typedef struct vec_s {
112  var_t var; /**< mapped variable */
113  qval_t coeff; /**< value associated to the variable */
114  struct vec_s* succ; /**< rest of the vector */
116 
117 /**
118  * The empty vector.
119  */
120 #define VEC_NULL NULL
121 
122 /**
123  * Set @a vec to be the empty vector.
124  */
125 #define vec_init(vec) (vec = VEC_NULL)
126 
127 /**
128  * Free the space occupied by @a pvec.
129  */
130 static void vec_clear(vec_p* pvec)
131 {
132  while (*pvec != VEC_NULL) {
133  vec_p succ = (*pvec)->succ;
134  qval_clear((*pvec)->coeff);
135  free(*pvec);
136  *pvec = succ;
137  }
138 }
139 
140 /**
141  * Copy @a vec into @a pvec.
142  */
143 static void vec_set(vec_p* pvec, vec_p vec)
144 {
145  vec_clear(pvec);
146  bool first = true;
147  vec_p* last = NULL;
148  for (; vec != VEC_NULL; vec = vec->succ) {
149  *last = safe_malloc(sizeof(vec_s));
150  (*last)->var = vec->var;
151  qval_init((*last)->coeff);
152  qval_set((*last)->coeff, vec->coeff);
153  if (first) {
154  *pvec = *last;
155  first = false;
156  }
157  last = &(*last)->succ;
158  }
159  if (!first) {
160  *last = VEC_NULL;
161  }
162 }
163 
164 /**
165  * Add the element (@a var, @coeff) to @a pvec, in first position.
166  * @a var must be greater to any variable in @a pvec s.t. @a pvec remains
167  * consistent.
168  */
170 {
171  assert(*pvec == VEC_NULL || (*pvec)->var < var);
172  vec_p hd = safe_malloc(sizeof(vec_s));
173  hd->var = var;
174  qval_init(hd->coeff); qval_set(hd->coeff, coeff);
175  hd->succ = *pvec;
176  *pvec = hd;
177 }
178 
179 /**
180  * Add the element (@a var, @a coeff) to @a pvec.
181  */
182 static void vec_append(vec_p* pvec, var_t var, qval_t coeff)
183 {
184  if (!qval_equal_i(coeff, 0, 1)) {
185  while (*pvec != VEC_NULL && (*pvec)->var > var) {
186  pvec = &(*pvec)->succ;
187  }
188  }
189  vec_append_atfirst(pvec, var, coeff);
190 }
191 
192 /**
193  * Get the value associated to @a var in @a vec, and store it into @a coeff.
194  */
196 {
197  while (vec != VEC_NULL && vec->var > var) {
198  vec = vec->succ;
199  }
200  if (vec != VEC_NULL && vec->var == var) {
201  qval_set(coeff, vec->coeff);
202  }
203  else {
204  qval_set_i(coeff, 0, 1);
205  }
206 }
207 
208 /**
209  * Set @a pvec to @a pvec + @a vec.
210  */
211 static void vec_iadd(vec_p* pvec, vec_p vec)
212 {
213  for (; vec != VEC_NULL; vec = vec->succ) {
214  var_t var = vec->var;
215  while (*pvec != VEC_NULL && (*pvec)->var > var) {
216  pvec = &(*pvec)->succ;
217  }
218  if (*pvec == VEC_NULL || (*pvec)->var < var) {
219  // a new variable is added
220  vec_p hd = safe_malloc(sizeof(vec_s));
221  hd->var = var;
222  qval_init(hd->coeff); qval_set(hd->coeff, vec->coeff);
223  hd->succ = *pvec;
224  *pvec = hd;
225  pvec = &(*pvec)->succ;
226  }
227  else {
228  // the variable is present in the original vector
229  assert((*pvec)->var == var);
230  qval_add((*pvec)->coeff, (*pvec)->coeff, vec->coeff);
231  if (qval_equal_i((*pvec)->coeff, 0, 1)) {
232  vec_p tl = (*pvec)->succ;
233  qval_clear((*pvec)->coeff);
234  free(*pvec);
235  *pvec = tl;
236  }
237  else {
238  pvec = &(*pvec)->succ;
239  }
240  }
241  }
242 }
243 
244 /**
245  * Set @a pvec to @a coeff times @a pvec.
246  */
247 static void vec_imul(vec_p* pvec, qval_t coeff)
248 {
249  if (qval_equal_i(coeff, 0, 1)) {
250  vec_clear(pvec);
251  }
252  else {
253  vec_p vec;
254  for (vec = *pvec; vec != VEC_NULL; vec = vec->succ) {
255  qval_mul(vec->coeff, vec->coeff, coeff);
256  }
257  }
258 }
259 
260 /**
261  * Set @a pvec to @a pvec + @a coeff times @a vec.
262  */
263 static void vec_iaddmul(vec_p* pvec, qval_t coeff, vec_p vec)
264 {
265  if (qval_equal_i(coeff, 0, 1)) {
266  return;
267  }
268  else {
269  qval_t tmp;
270  qval_init(tmp);
271  for (; vec != VEC_NULL; vec = vec->succ) {
272  var_t var = vec->var;
273  while (*pvec != VEC_NULL && (*pvec)->var > var) {
274  pvec = &(*pvec)->succ;
275  }
276  if (*pvec == VEC_NULL || (*pvec)->var < var) {
277  // a new variable is added
278  vec_p hd = safe_malloc(sizeof(vec_s));
279  hd->var = var;
280  qval_init(hd->coeff); qval_mul(hd->coeff, coeff, vec->coeff);
281  hd->succ = *pvec;
282  *pvec = hd;
283  pvec = &(*pvec)->succ;
284  }
285  else {
286  // the variable is present in the original vector
287  assert((*pvec)->var == var);
288  qval_mul(tmp, coeff, vec->coeff);
289  qval_add((*pvec)->coeff, (*pvec)->coeff, tmp);
290  if (qval_equal_i((*pvec)->coeff, 0, 1)) {
291  vec_p tl = (*pvec)->succ;
292  qval_clear((*pvec)->coeff);
293  free(*pvec);
294  *pvec = tl;
295  }
296  else {
297  pvec = &(*pvec)->succ;
298  }
299  }
300  }
301  qval_clear(tmp);
302  }
303 }
304 
305 /**
306  * Set @a vec to -@a vec.
307  */
308 static void vec_ineg(vec_p vec)
309 {
310  for (; vec != VEC_NULL; vec = vec->succ) {
311  qval_neg(vec->coeff, vec->coeff);
312  }
313 }
314 
315 /**
316  * Output @a vec on stdio stream @a stream.
317  */
318 static int NOWUNUSED vec_fprint(FILE* stream, vec_p vec)
319 {
320  if (vec == VEC_NULL) {
321  return fprintf(stream, "0");
322  }
323  else {
324  int c = qval_fprint(stream, vec->coeff);
325  c += fprintf(stream, " ");
326  c += var_fprint(stream, vec->var);
327  for (vec = vec->succ; vec != VEC_NULL; vec = vec->succ) {
328  if (qval_cmp_i(vec->coeff, 0, 1) > 0) {
329  c += fprintf(stream, " + ");
330  c += qval_fprint(stream, vec->coeff);
331  }
332  else {
333  c += fprintf(stream, " - ");
334  qval_neg(vec->coeff, vec->coeff);
335  c += qval_fprint(stream, vec->coeff);
336  qval_neg(vec->coeff, vec->coeff);
337  }
338  c += fprintf(stream, " ");
339  c += var_fprint(stream, vec->var);
340  }
341  return c;
342  }
343 }
344 
345 /**
346  * Output @a vec on @c stdout.
347  */
348 #define vec_print(vec) (vec_fprint(stdout, vec))
349 
350 /**@}*/
351 
352 /**
353  * @name Linear Constraints
354  * A linear constraint is either a linear equality
355  * (@a a1 @a x1 + ... + @a an @a xn = @a b) or a linear inequality
356  * (@a a1 @a x1 + ... + @a an @a xn <= @a b).
357  */
358 /**@{*/
359 
360 /**
361  * Type of linear constraint relations.
362  */
363 typedef enum
364 {
365  CONSTR_EQ, /**< equality */
366  CONSTR_LE /**< inequality */
368 
369 /**
370  * Type of linear constraint.
371  */
372 typedef struct constr_s {
373  vec_p vec; /**< coefficients of variables */
374  constrrel_t rel; /**< equality or inequality relation */
375  qval_t cst; /**< constant term */
377 
378 /**
379  * Type of linear constraint.
380  */
381 typedef constr_s constr_t[1];
382 
383 /**
384  * Initialize @a constr and set it to 0 = 0.
385  */
386 static void constr_init(constr_p constr)
387 {
388  vec_init(constr->vec);
389  constr->rel = CONSTR_EQ;
390  qval_init(constr->cst);
391 }
392 
393 /**
394  * Free the space occupied by @a constr.
395  */
396 static void constr_clear(constr_p constr)
397 {
398  vec_clear(&constr->vec);
399  qval_clear(constr->cst);
400 }
401 
402 /**
403  * Copy @a constr2 into @a constr1.
404  */
405 static void NOWUNUSED constr_set(constr_p constr1, constr_p constr2)
406 {
407  vec_set(&constr1->vec, constr2->vec);
408  constr1->rel = constr2->rel;
409  qval_set(constr1->cst, constr2->cst);
410 }
411 
412 /**
413  * Get the coefficient of @a var in @a constr, and store it into @a coeff.
414  */
415 #define constr_get_coeff(coeff, constr, var) \
416  (vec_get_coeff(coeff, (constr)->vec, var))
417 
418 /**
419  * Set @a constr1 to @a constr1 + @a constr2.
420  * @a constr2 must be an equality.
421  */
422 static void constr_iadd(constr_p constr1, constr_p constr2)
423 {
424  // general case is not needed
425  assert(constr2->rel == CONSTR_EQ);
426  vec_iadd(&constr1->vec, constr2->vec);
427  qval_add(constr1->cst, constr1->cst, constr2->cst);
428 }
429 
430 /**
431  * Set @a constr to @a coeff times @a constr.
432  * @a constr must be an equality or @a coeff a non-negative value.
433  */
434 static void constr_imul(constr_p constr, qval_t coeff)
435 {
436  vec_imul(&constr->vec, coeff);
437  qval_mul(constr->cst, constr->cst, coeff);
438 }
439 
440 /**
441  * Set @a constr1 to @a constr1 + @a coeff times @a constr2.
442  * @a constr2 must be an equality or @a coeff a non-negative value.
443  */
444 static void constr_iaddmul(constr_p constr1, qval_t coeff, constr_p constr2)
445 {
446  if (!qval_equal_i(coeff, 0, 1)) {
447  vec_iaddmul(&constr1->vec, coeff, constr2->vec);
448  qval_t tmp;
449  qval_init(tmp);
450  qval_mul(tmp, coeff, constr2->cst);
451  qval_add(constr1->cst, constr1->cst, tmp);
452  qval_clear(tmp);
453  }
454 }
455 
456 /**
457  * Turn @a constr into an equivalent constraint whose constant term is
458  * non-negative.
459  * @a constr must be an equality.
460  */
461 static void constr_makepos(constr_p constr)
462 {
463  assert(constr->rel == CONSTR_EQ);
464  if (qval_cmp_i(constr->cst, 0, 1) < 0) {
465  vec_ineg(constr->vec);
466  qval_neg(constr->cst, constr->cst);
467  }
468 }
469 
470 /**
471  * Make @a pivot_var coefficient null in @a constr, using @a pivot_constr.
472  * @a pivot_constr must be an equality.
473  */
474 static void constr_apply_pivot(constr_p constr, var_t pivot_var,
475  constr_p pivot_constr)
476 {
477  qval_t coeff;
478  qval_init(coeff);
479  constr_get_coeff(coeff, constr, pivot_var);
480  qval_neg(coeff, coeff);
481  constr_iaddmul(constr, coeff, pivot_constr);
482  qval_clear(coeff);
483 }
484 
485 /**
486  * Output @a constr on stdio stream @a stream.
487  */
488 static int NOWUNUSED constr_fprint(FILE* stream, constr_p constr)
489 {
490  int c = vec_fprint(stream, constr->vec);
491  if (constr->rel == CONSTR_EQ) {
492  c += fprintf(stream, " == ");
493  }
494  else {
495  c += fprintf(stream, " <= ");
496  }
497  c += qval_fprint(stream, constr->cst);
498  return c;
499 }
500 
501 /**
502  * Output @a constr on @c stdout.
503  */
504 #define constr_print(constr) (constr_fprint(stdout, constr))
505 
506 /**@}*/
507 
508 /**
509  * @name Simplex Tableau
510  * A simplex tableau consists in a list of constraint, an objective function to
511  * minimize and its current value. Those data evolve when the simplex is
512  * running.
513  */
514 /**@{*/
515 
516 /**
517  * Type of simplex tableau.
518  * The objective function and the associated value are stored into a constraint
519  * @c obj, other constraints are in the constraint table @c constr.
520  */
521 typedef struct table_s {
522  constr_t obj; /**< objective function and value */
523  constr_t* constrs; /**< constraints */
524  int nbvars; /**< number of variables */
525  int nbconstrs; /**< number of constraints */
527 
528 /**
529  * Type of simplex tableau.
530  */
531 typedef table_s table_t[1];
532 
533 /**
534  * Initialize @a tbl, with room for @a nbconstrs constraints.
535  */
536 static void table_init(table_p tbl, int nbconstrs)
537 {
538  constr_init(tbl->obj);
539  tbl->constrs = safe_malloc(nbconstrs * sizeof(constr_t));
540  int i;
541  for (i = 0; i < nbconstrs; i++) {
542  constr_init(tbl->constrs[i]);
543  }
544  tbl->nbvars = 0;
545  tbl->nbconstrs = nbconstrs;
546 }
547 
548 /**
549  * Free the space occupied by @a tbl.
550  */
551 static void table_clear(table_p tbl)
552 {
553  constr_clear(tbl->obj);
554  int i;
555  for (i = 0; i < tbl->nbconstrs; i++) {
556  constr_clear(tbl->constrs[i]);
557  }
558  free(tbl->constrs);
559 }
560 
561 /**
562  * Number of variables in @a tbl.
563  */
564 #define table_get_nbvars(tbl) ((tbl)->nbvars)
565 
566 /**
567  * Number of constraints in @a tbl.
568  */
569 #define table_get_nbconstrs(tbl) ((tbl)->nbconstrs)
570 
571 /**
572  * Turn constraints into @a tbl into equivalent ones, whose constant term is
573  * non-negative.
574  * All constraints must be equalities.
575  */
576 static void table_makepos(table_p tbl)
577 {
578  int i;
579  for (i = 0; i < tbl->nbconstrs; i++) {
580  constr_makepos(tbl->constrs[i]);
581  }
582 }
583 
584 /**
585  * Ensure that all variables in @a tbl are non-negative.
586  * Each occurrence of a unknown-sign variable @a a @a x is turned into
587  * @a a @a x+ - @a a @a x-, where @x+ and @x- are new, non-negative variables.
588  * Each occurrence of a negative variable @a a @a x is turned into -@a a @a x',
589  * where @a x' is a new, non-negative variable.
590  * We try to do this only when necessary, to limit the amount of newly created
591  * variables.
592  */
593 static void table_addsignvars(table_p tbl)
594 {
595  // first, we try to determine the sign of variables
596  static int vars_info[VAR_MAXNB]; // -1 negative or null, +1 positive or null, 0 unknown
597  int i;
598  for (i = 0; i < VAR_MAXNB; i++) {
599  vars_info[i] = 0;
600  }
601  for (i = 0; i < tbl->nbconstrs; i++) {
602  constr_p constr = tbl->constrs[i];
603  vec_p vec = constr->vec;
604  if (vec != VEC_NULL && vec->succ == VEC_NULL) {
605  var_t var = vec->var;
606  int lsign = value_sign(qval_cmp_i(vec->coeff, 0, 1));
607  assert(lsign != 0);
608  int rsign = value_sign(qval_cmp_i(constr->cst, 0, 1));
609  int sign;
610  if (constr->rel == CONSTR_EQ) {
611  sign = rsign == 0 ? 1 : lsign * rsign;
612  }
613  else {
614  sign = rsign == 0 ? -lsign : (rsign == 1 ? 0 : lsign * rsign);
615  }
616  if (sign != 0 && vars_info[var] == 0) {
617  vars_info[var] = sign;
618  }
619  }
620  }
621  // negative variables are inverted
622  for (i = 0; i < tbl->nbconstrs; i++) {
623  constr_p constr = tbl->constrs[i];
624  vec_p vec;
625  for (vec = constr->vec; vec != VEC_NULL; vec = vec->succ) {
626  var_t var = vec->var;
627  if (vars_info[var] < 0) {
628  qval_neg(vec->coeff, vec->coeff);
629  }
630  }
631  }
632  // unknown sign variables are split
633  var_t var;
634  for (var = tbl->nbvars - 1; var >= 0; var--) {
635  if (vars_info[var] == 0) {
636  vars_info[var] = tbl->nbvars;
637  tbl->nbvars++;
638  }
639  else {
640  vars_info[var] = VAR_NULL;
641  }
642  }
643  // and then, injected into constraints
644  qval_t coeff;
645  qval_init(coeff);
646  for (i = 0; i < tbl->nbconstrs; i++) {
647  constr_p constr = tbl->constrs[i];
648  vec_p vec;
649  for (vec = constr->vec; vec != VEC_NULL; vec = vec->succ) {
650  var_t var = vec->var;
651  if (vars_info[var] != VAR_NULL) {
652  qval_neg(coeff, vec->coeff);
653  vec_append_atfirst(&constr->vec, vars_info[var], coeff);
654  }
655  }
656  }
657  qval_clear(coeff);
658 }
659 
660 /**
661  * Ensure that all constraints in @a tbl are equalities.
662  * A new offset variable is introduced into inequalities to turn them in
663  * equalities. E.g., inequality @a a1 @a x1 + ... + @a an @a xn <= @a b
664  * becomes: @a a1 @a x1 + ... + @a an @a xn + y = @a b.
665  */
666 static void table_addofsvars(table_p tbl)
667 {
668  qval_t one;
669  qval_init(one); qval_set_i(one, 1, 1);
670  int i;
671  for (i = 0; i < tbl->nbconstrs; i++) {
672  constr_p constr = tbl->constrs[i];
673  if (constr->rel == CONSTR_LE) {
674  vec_append_atfirst(&constr->vec, tbl->nbvars, one);
675  tbl->nbvars++;
676  constr->rel = CONSTR_EQ;
677  }
678  }
679  qval_clear(one);
680 }
681 
682 static int NOWUNUSED table_fprint(FILE*, table_p);
683 
684 /**
685  * Canonicalize @a tbl: ensure that all variables are non-negative, and all
686  * constraints are equalities whose constant term is non-negative.
687  */
688 static void table_canonicalize(table_p tbl)
689 {
690  DEBUG(
691  fprintf(stderr, "Initial system:\n");
692  table_fprint(stderr, tbl);
693  );
694  table_addsignvars(tbl);
695  DEBUG(
696  fprintf(stderr, "\nWith signed variables:\n");
697  table_fprint(stderr, tbl);
698  );
699  table_addofsvars(tbl);
700  DEBUG(
701  fprintf(stderr, "\nWith offset variables:\n");
702  table_fprint(stderr, tbl);
703  );
704  table_makepos(tbl);
705  DEBUG(
706  fprintf(stderr, "\nWith positive constants:\n");
707  table_fprint(stderr, tbl);
708  );
709 }
710 
711 /**
712  * Initialize the objective function and value from constraints in @a tbl.
713  */
714 static void table_set_obj(table_p tbl)
715 {
716  constr_p obj = tbl->obj;
717  int i;
718  for (i = 0; i < tbl->nbconstrs; i++) {
719  constr_p constr = tbl->constrs[i];
720  constr_iadd(obj, constr);
721  }
722 }
723 
724 /**
725  * Add objective variables to each constraint of @tbl whose constant term is
726  * not zero.
727  */
728 static void table_addobjvars(table_p tbl)
729 {
730  qval_t one;
731  qval_init(one); qval_set_i(one, 1, 1);
732  int i;
733  for (i = 0; i < tbl->nbconstrs; i++) {
734  constr_p constr = tbl->constrs[i];
735  assert(qval_cmp_i(constr->cst, 0, 1) >= 0);
736  if (!qval_equal_i(constr->cst, 0, 1)) {
737  var_t var = tbl->nbvars;
738  vec_append_atfirst(&constr->vec, var, one);
739  tbl->nbvars++;
740  }
741  }
742  qval_clear(one);
743 }
744 
745 /**
746  * Canonicalize @a tbl, set the objective and add objective variables.
747  */
748 static void table_prepare(table_p tbl)
749 {
750  table_canonicalize(tbl);
751  table_set_obj(tbl);
752  table_addobjvars(tbl);
753  DEBUG(
754  fprintf(stderr, "\nWith objective:\n");
755  table_fprint(stderr, tbl);
756  fprintf(stderr, "\n");
757  );
758 }
759 
760 /**
761  * Get the next pivot variable in @tbl.
762  * Bland's rule is used to ensure termination: pivot variable is the
763  * lowest-numbered variable whose objective coefficient is negative.
764  */
766 {
767  var_t var = VAR_NULL;
768  vec_p vec;
769  for (vec = tbl->obj->vec; vec != VEC_NULL; vec = vec->succ) {
770  if (qval_cmp_i(vec->coeff, 0, 1) > 0) {
771  var = vec->var;
772  }
773  }
774  return var;
775 }
776 
777 /**
778  * Retrieve the variable associated with the row (i.e. constraint) @a row in @a
779  * tbl.
780  */
781 static var_t table_get_assocvar(table_p tbl, int row)
782 {
783  if (row != -1) {
784  qval_t tmp;
785  qval_init(tmp);
786  constr_p constr = tbl->constrs[row];
787  vec_p vec;
788  for (vec = constr->vec; vec != VEC_NULL; vec = vec->succ) {
789  if (qval_equal_i(vec->coeff, 1, 1)) {
790  var_t var = vec->var;
791  bool unitcol = true;
792  int i;
793  for (i = 0; i < tbl->nbconstrs; i++) {
794  if (i != row) {
795  constr_get_coeff(tmp, tbl->constrs[i], var);
796  if (!qval_equal_i(tmp, 0, 1)) {
797  unitcol = false;
798  break;
799  }
800  }
801  }
802  if (unitcol) {
803  return var;
804  }
805  }
806  }
807  qval_clear(tmp);
808  }
809  return VAR_NULL;
810 }
811 
812 /**
813  * Get the next pivot row (i.e. constraint) in @tbl, corresponding to pivot
814  * variable @var.
815  * Bland's rule is used to ensure termination: among the rows with the best
816  * ratio, choose the one whose associated variable index is the smaller.
817  */
818 static int table_get_pivotrow(table_p tbl, var_t var)
819 {
820  int pivot_row = -1;
821  if (var != VAR_NULL) {
822  var_t pivot_assoc = VAR_NULL;
823  qval_t pivot_ratio, ratio;
824  qval_init(pivot_ratio); qval_init(ratio);
825  int i;
826  for (i = 0; i < tbl->nbconstrs; i++) {
827  constr_p constr = tbl->constrs[i];
828  constr_get_coeff(ratio, constr, var);
829  if (qval_cmp_i(ratio, 0, 1) > 0) {
830  assert(qval_cmp_i(constr->cst, 0, 1) >= 0);
831  qval_div(ratio, constr->cst, ratio);
832  if (pivot_row == -1 || qval_cmp(ratio, pivot_ratio) < 0) {
833  pivot_row = i;
834  pivot_assoc = table_get_assocvar(tbl, pivot_row);
835  qval_set(pivot_ratio, ratio);
836  }
837  else if (qval_cmp(ratio, pivot_ratio) == 0) {
838  var_t assoc = table_get_assocvar(tbl, i);
839  if (assoc < pivot_assoc) {
840  pivot_row = i;
841  pivot_assoc = assoc;
842  }
843  }
844  }
845  }
846  qval_clear(pivot_ratio); qval_clear(ratio);
847  }
848  return pivot_row;
849 }
850 
851 /**
852  * Get the next pivot variable and row in @tbl, and store them in @a pvar and
853  * @a prow respectively.
854  */
855 static bool table_get_pivot(table_p tbl, var_t* pvar, int* prow)
856 {
857  *pvar = table_get_pivotvar(tbl);
858  *prow = table_get_pivotrow(tbl, *pvar);
859  return *prow != -1;
860 }
861 
862 /**
863  * Apply pivot (@a var, @a row) in @a tbl.
864  */
865 static void table_apply_pivot(table_p tbl, var_t var, int row)
866 {
867  constr_p constr = tbl->constrs[row];
868  // pivot constraint is normalized s.t. its coefficient on var is 1
869  qval_t coeff;
870  qval_init(coeff);
871  constr_get_coeff(coeff, constr, var);
872  qval_inv(coeff, coeff);
873  constr_imul(constr, coeff);
874  qval_clear(coeff);
875  // then is substracted from other constraints s.t. the coefficient on var is 0
876  constr_apply_pivot(tbl->obj, var, constr);
877  int i;
878  for (i = 0; i < tbl->nbconstrs; i++) {
879  if (i != row) {
880  constr_apply_pivot(tbl->constrs[i], var, constr);
881  }
882  }
883 }
884 
885 /**
886  * Run simplex algorithm on @tbl.
887  */
888 static void table_run_simplex(table_p tbl)
889 {
890  int i = 0;
891  while (true) {
892  var_t var;
893  int row;
894  if (table_get_pivot(tbl, &var, &row)) {
895  table_apply_pivot(tbl, var, row);
896  i++;
897  DEBUG(
898  fprintf(stderr, "After iteration %d:\n", i);
899  fprintf(stderr, "Pivot variable: ");
900  var_fprint(stderr, var);
901  fprintf(stderr, "\nPivot row: %d\nTable:\n", row);
902  table_fprint(stderr, tbl);
903  fprintf(stderr, "\n");
904  if (i > 200) {
905  fprintf(stderr, "Seems to long, exiting...\n");
906  exit(42);
907  }
908  );
909  }
910  else {
911  break;
912  }
913  }
914 }
915 
916 /**
917  * Determine whether the constraint system described in @a tbl is feasible,
918  * using simplex method.
919  */
921 {
922  table_prepare(tbl);
923  table_run_simplex(tbl);
924  return qval_equal_i(tbl->obj->cst, 0, 1);
925 }
926 
927 /**
928  * Output @a tbl on stdio stream @a stream.
929  */
930 static int NOWUNUSED table_fprint(FILE* stream, table_p tbl)
931 {
932  int c = constr_fprint(stream, tbl->obj);
933  c += fprintf(stream, "\n");
934  int i;
935  for (i = 0; i < 40; i++) {
936  c += fprintf(stream, "-");
937  }
938  c += fprintf(stream, "\n");
939  if (tbl->nbconstrs == 0) {
940  c += fprintf(stream, "true\n");
941  }
942  else {
943  for (i = 0; i < tbl->nbconstrs; i++) {
944  c += fprintf(stream, "(%2d: ", i);
945  c += var_fprint(stream, table_get_assocvar(tbl, i));
946  c += fprintf(stream, ") ");
947  c += constr_fprint(stream, tbl->constrs[i]);
948  c += fprintf(stream, "\n");
949  }
950  }
951  for (i = 0; i < 40; i++) {
952  c += fprintf(stream, "-");
953  }
954  c += fprintf(stream, "\n");
955  return c;
956 }
957 
958 /**
959  * Output @a tbl on @c stdout.
960  */
961 #define table_print(tbl) (table_fprint(stdout, tbl))
962 
963 /**@}*/
964 
965 /**
966  * @name Datatype Conversion
967  * Here are utility functions to convert Linear types (@c Variable, @c Vecteur,
968  * @c Contrainte, @c Systeme) to datatypes used in this files.
969  * In most of conversion functions, a variable table @a vartbl is passed, to
970  * help translating Linear named variables into indices.
971  */
972 /**@{*/
973 
974 /**
975  * Type of variable tables.
976  */
977 typedef struct {
978  int nbvars; /**< number of variables */
979  Variable names[VAR_MAXNB]; /** names of variables */
981 
982 /**
983  * Type of variable tables.
984  */
985 typedef vartbl_s vartbl_t[1];
986 
987 /**
988  * Initialize @vartbl to an empty table.
989  */
990 static void vartbl_init(vartbl_p vartbl)
991 {
992  vartbl->nbvars = 0;
993 }
994 
995 /**
996  * Free the space occupied by @a vartbl.
997  */
998 #define vartbl_clear(vartbl)
999 
1000 /**
1001  * Get the variable index associated to @a name, creating a new one if
1002  * necessary.
1003  */
1004 static var_t vartbl_find(vartbl_p vartbl, Variable name)
1005 {
1006  int i;
1007  for (i = 0; i < vartbl->nbvars; i++) {
1008  if (vartbl->names[i] == name) {
1009  return i;
1010  }
1011  }
1012  vartbl->names[vartbl->nbvars] = name;
1013  return vartbl->nbvars++;
1014 }
1015 
1016 /**
1017  * Copy @a vec into @a pvec.
1018  */
1019 static void vec_set_vecteur(vartbl_t vartbl, vec_p* pvec, Pvecteur vec)
1020 {
1021  vec_clear(pvec);
1022  qval_t coeff;
1023  qval_init(coeff);
1024  for (; vec != NULL; vec = vec->succ) {
1025  if (vec->var != TCST) {
1026  var_t var = vartbl_find(vartbl, vec->var);
1027  qval_set_i(coeff, vec->val, 1);
1028  vec_append(pvec, var, coeff);
1029  }
1030  }
1031  qval_clear(coeff);
1032 }
1033 
1034 /**
1035  * Copy @a constr2 into @a constr1.
1036  */
1037 static void constr_set_contrainte(vartbl_t vartbl,
1038  constr_p constr1, Pcontrainte constr2, bool is_ineq)
1039 {
1040  vec_set_vecteur(vartbl, &constr1->vec, constr2->vecteur);
1041  constr1->rel = is_ineq ? CONSTR_LE : CONSTR_EQ;
1042  Pvecteur vec;
1043  for (vec = constr2->vecteur; vec != NULL; vec = vec->succ) {
1044  if (vec->var == TCST) {
1045  qval_set_i(constr1->cst, -vec->val, 1);
1046  break;
1047  }
1048  }
1049 }
1050 
1051 /**
1052  * Initialize @a tbl from @a sys.
1053  */
1055 {
1056  vartbl_t vartbl;
1057  vartbl_init(vartbl);
1058  table_init(tbl, sys->nb_eq + sys->nb_ineq);
1059  int i = 0;
1060  Pcontrainte constr;
1061  for (constr = sys->egalites; constr != NULL; constr = constr->succ) {
1062  constr_set_contrainte(vartbl, tbl->constrs[i], constr, false);
1063  i++;
1064  }
1065  for (constr = sys->inegalites; constr != NULL; constr = constr->succ) {
1066  constr_set_contrainte(vartbl, tbl->constrs[i], constr, true);
1067  i++;
1068  }
1069  tbl->nbvars = vartbl->nbvars;
1070  vartbl_clear(vartbl);
1071 }
1072 
1073 /**@}*/
1074 
1075 /**
1076  * Main Function
1077  */
1078 /**@{*/
1079 
1080 /**
1081  * Determine whether a system @a sys of equations and inequations is feasible.
1082  * Parameter @a ofl_ctrl indicates whether an overflow control is performed
1083  * (possible values: @c NO_OFL_CTRL, @c FWD_OFL_CTRL).
1084  */
1085 static inline bool sc_get_feasibility(Psysteme sys, int ofl_ctrl)
1086 {
1087  if (ofl_ctrl != FWD_OFL_CTRL) {
1088  fprintf(stderr, "[sc_simplexe_feasibility] "
1089  "should not (yet) be called with control %d...\n", ofl_ctrl);
1090  }
1091  volatile table_p tbl = safe_malloc(sizeof(table_t));
1092  table_init_set_systeme(tbl, sys);
1094  table_clear(tbl);
1095  free(tbl);
1096  if (ofl_ctrl == FWD_OFL_CTRL) {
1097  RETHROW();
1098  }
1099  return true;
1100  }
1101  bool feasible = table_get_feasibility(tbl);
1102  table_clear(tbl);
1103  free(tbl);
1105  return feasible;
1106 }
1107 
1108 /**@}*/
1109 
1110 #endif
1111 
qval_s qval_t[1]
Type of rational numbers.
#define NOWUNUSED
Definition: arith_fixprec.h:48
#define qval_clear(q)
Free the space occupied by q.
#define qval_equal_i(q1, q2num, q2den)
Return non-zero if q and q2num/q2den are equal, zero if they are non-equal.
#define qval_cmp_i(q1, q2num, q2den)
Compare q1 and q2num/q2den.
#define qval_neg(q1, q2)
Set q1 to -q2.
#define qval_fprint(stream, q)
Output q on stdio stream stream.
#define qval_init(q)
Initialize q and set its value to 0/1.
#define qval_set(q1, q2)
Set the value of q1 from q2.
#define qval_div(q1, q2, q3)
Set q1 to q2/q3.
#define qval_mul(q1, q2, q3)
Set q1 to q2 times q3.
#define qval_set_i(q1, q2num, q2den)
Set the value of q to q2num/q2den.
#define qval_cmp(q1, q2)
Compare q1 and q2.
#define qval_inv(q1, q2)
Set q1 to 1/q2.
#define qval_add(q1, q2, q3)
Set q1 to q2 + q3.
#define CATCH(what)
@ overflow_error
@ simplex_arithmetic_error
@ timeout_error
#define UNCATCH(what)
#define RETHROW()
#define value_sign(v)
trian operators on values
void * malloc(YYSIZE_T)
void free(void *)
#define exit(code)
Definition: misc-local.h:54
#define abort()
Definition: misc-local.h:53
#define assert(ex)
Definition: newgen_assert.h:41
int fprintf()
test sc_min : ce test s'appelle par : programme fichier1.data fichier2.data ...
static bool table_get_pivot(table_p tbl, var_t *pvar, int *prow)
Get the next pivot variable and row in @tbl, and store them in pvar and prow respectively.
static void vec_set_vecteur(vartbl_t vartbl, vec_p *pvec, Pvecteur vec)
Copy vec into pvec.
static void table_init_set_systeme(table_p tbl, Psysteme sys)
Initialize tbl from sys.
struct constr_s * constr_p
#define var_fprint(stream, var)
Output var on stdio stream stream.
static void vec_append(vec_p *pvec, var_t var, qval_t coeff)
Add the element (var, coeff) to pvec.
static bool sc_get_feasibility(Psysteme sys, int ofl_ctrl)
Main Function.
static void table_init(table_p tbl, int nbconstrs)
Initialize tbl, with room for nbconstrs constraints.
static void vec_ineg(vec_p vec)
Set vec to -vec.
#define VEC_NULL
The empty vector.
static int table_get_pivotrow(table_p tbl, var_t var)
struct vec_s * vec_p
struct vartbl_s * vartbl_p
static void constr_clear(constr_p constr)
Free the space occupied by constr.
static void constr_init(constr_p constr)
Initialize constr and set it to 0 = 0.
static var_t table_get_assocvar(table_p tbl, int row)
Retrieve the variable associated with the row (i.e.
static void table_addsignvars(table_p tbl)
Ensure that all variables in tbl are non-negative.
#define DEBUG(code)
static int NOWUNUSED table_fprint(FILE *, table_p)
Output tbl on stdio stream stream.
static void table_clear(table_p tbl)
Free the space occupied by tbl.
static void table_run_simplex(table_p tbl)
Run simplex algorithm on @tbl.
static void NOWUNUSED constr_set(constr_p constr1, constr_p constr2)
Copy constr2 into constr1.
struct constr_s constr_s
Type of linear constraint.
static void vec_iadd(vec_p *pvec, vec_p vec)
Set pvec to pvec + vec.
static void vec_get_coeff(qval_t coeff, vec_p vec, var_t var)
Get the value associated to var in vec, and store it into coeff.
static void table_set_obj(table_p tbl)
Initialize the objective function and value from constraints in tbl.
static void vec_set(vec_p *pvec, vec_p vec)
Copy vec into pvec.
static void vec_append_atfirst(vec_p *pvec, var_t var, qval_t coeff)
Add the element (var, @coeff) to pvec, in first position.
#define constr_get_coeff(coeff, constr, var)
Get the coefficient of var in constr, and store it into coeff.
static void table_canonicalize(table_p tbl)
Canonicalize tbl: ensure that all variables are non-negative, and all constraints are equalities whos...
struct vec_s vec_s
Type of vectors.
static void constr_iadd(constr_p constr1, constr_p constr2)
Set constr1 to constr1 + constr2.
#define vec_init(vec)
Set vec to be the empty vector.
static void * safe_malloc(size_t size)
struct table_s * table_p
static var_t table_get_pivotvar(table_p tbl)
Get the next pivot variable in @tbl.
#define vartbl_clear(vartbl)
Free the space occupied by vartbl.
table_s table_t[1]
Type of simplex tableau.
static void constr_makepos(constr_p constr)
Turn constr into an equivalent constraint whose constant term is non-negative.
static void table_addofsvars(table_p tbl)
Ensure that all constraints in tbl are equalities.
static int NOWUNUSED vec_fprint(FILE *stream, vec_p vec)
Output vec on stdio stream stream.
static void table_addobjvars(table_p tbl)
Add objective variables to each constraint of @tbl whose constant term is not zero.
#define VAR_MAXNB
Maximum number of variables.
static void constr_apply_pivot(constr_p constr, var_t pivot_var, constr_p pivot_constr)
Make pivot_var coefficient null in constr, using pivot_constr.
#define VAR_NULL
A special value used to represent the absence of variable.
static void vec_clear(vec_p *pvec)
Free the space occupied by pvec.
struct table_s table_s
Type of simplex tableau.
static void constr_imul(constr_p constr, qval_t coeff)
Set constr to coeff times constr.
constr_s constr_t[1]
Type of linear constraint.
static void table_apply_pivot(table_p tbl, var_t var, int row)
Apply pivot (var, row) in tbl.
static void vec_iaddmul(vec_p *pvec, qval_t coeff, vec_p vec)
Set pvec to pvec + coeff times vec.
static void table_makepos(table_p tbl)
Turn constraints into tbl into equivalent ones, whose constant term is non-negative.
vartbl_s vartbl_t[1]
Type of variable tables.
static void table_prepare(table_p tbl)
Canonicalize tbl, set the objective and add objective variables.
static int NOWUNUSED constr_fprint(FILE *stream, constr_p constr)
Output constr on stdio stream stream.
static bool table_get_feasibility(table_p tbl)
Determine whether the constraint system described in tbl is feasible, using simplex method.
static void constr_iaddmul(constr_p constr1, qval_t coeff, constr_p constr2)
Set constr1 to constr1 + coeff times constr2.
static var_t vartbl_find(vartbl_p vartbl, Variable name)
Get the variable index associated to name, creating a new one if necessary.
static void constr_set_contrainte(vartbl_t vartbl, constr_p constr1, Pcontrainte constr2, bool is_ineq)
Copy constr2 into constr1.
static void vartbl_init(vartbl_p vartbl)
Initialize @vartbl to an empty table.
constrrel_t
Type of linear constraint relations.
@ CONSTR_LE
inequality
@ CONSTR_EQ
equality
int var_t
Type of variables.
static void vec_imul(vec_p *pvec, qval_t coeff)
Set pvec to coeff times pvec.
Pvecteur vecteur
struct Scontrainte * succ
Pcontrainte inegalites
Definition: sc-local.h:71
Pcontrainte egalites
Definition: sc-local.h:70
int nb_ineq
Definition: sc-local.h:73
int nb_eq
Definition: sc-local.h:72
le type des coefficients dans les vecteurs: Value est defini dans le package arithmetique
Definition: vecteur-local.h:89
Value val
Definition: vecteur-local.h:91
Variable var
Definition: vecteur-local.h:90
struct Svecteur * succ
Definition: vecteur-local.h:92
Type of linear constraint.
qval_t cst
constant term
constrrel_t rel
equality or inequality relation
vec_p vec
coefficients of variables
Type of simplex tableau.
int nbvars
number of variables
int nbconstrs
number of constraints
constr_t * constrs
constraints
constr_t obj
objective function and value
Type of variable tables.
Variable names[VAR_MAXNB]
int nbvars
number of variables
Type of vectors.
var_t var
mapped variable
qval_t coeff
value associated to the variable
struct vec_s * succ
rest of the vector
#define TCST
VARIABLE REPRESENTANT LE TERME CONSTANT.
void * Variable
arithmetique is a requirement for vecteur, but I do not want to inforce it in all pips files....
Definition: vecteur-local.h:60
#define FWD_OFL_CTRL