PIPS
sc_normalize.c
Go to the documentation of this file.
1 /*
2 
3  $Id: sc_normalize.c 1671 2019-06-26 19:14:11Z coelho $
4 
5  Copyright 1989-2016 MINES ParisTech
6 
7  This file is part of Linear/C3 Library.
8 
9  Linear/C3 Library is free 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 Free 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  /* package sc
26  *
27  * Normalization, which include some redundacy elimination
28  */
29 
30 #ifdef HAVE_CONFIG_H
31  #include "config.h"
32 #endif
33 
34 #include <string.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include "linear_assert.h"
38 /* #include <values.h> */
39 #include <limits.h>
40 
41 #include "boolean.h"
42 #include "arithmetique.h"
43 #include "vecteur.h"
44 #include "contrainte.h"
45 #include "sc.h"
46 ␌
47 
48 /* Two candidates for arithmetique/value.c, which does not exist, or
49  for value/value.c, which does not exist either. */
50 static void negate_value_interval(Value * pmin, Value * pmax)
51 {
52  Value t = value_uminus(*pmin);
53  *pmin = value_uminus(*pmax);
54  *pmax = t;
55 }
56 
57 static void swap_values(Value * p1, Value * p2)
58 {
59  Value t = *p1;
60  *p1 = *p2;
61  *p2 = t;
62 }
63 
64 static void swap_value_intervals(Value * px_min, Value * px_max,
65  Value * py_min, Value * py_max)
66 {
67  swap_values(px_min, py_min);
68  swap_values(px_max, py_max);
69 }
70 ␌
71 /* Bounding box (not really a box most of the time)
72  *
73  * The bounding box is made of all 1-D constraints found in a
74  * constraint system and is represented by five vectors ub, lb, cb, u
75  * and l.
76  *
77  * The function sc_bounded_normalization() and the function
78  * reduce_coefficients_with_bounding_box() both rely on numerical
79  * bounds l and b for vector x, such that l<=x<=b.
80  *
81  * However, lower and upper bounds are not always available for all
82  * components x_i of x. And 0 is a perfectly valid bound, that is not
83  * represented with linear sparse vector representation. Hence, the
84  * bound information cannot be carried by only two vectors. Four
85  * vectors are used, two basis vectors, lb and ub, used to specifiy if
86  * a bound is available, and two vectors l and b to contain the
87  * bounds.
88  *
89  * Note that l and u are not usual vectors. The constant bounds appear
90  * as variable coefficients. For instance, l=2u+3v, together with
91  * lb=u+v+w, means that the lower bounds for x_u, x_v and x_w are 2, 3
92  * and 0.
93  *
94  * When the lower and upper bounds are known and equal, another base vector,
95  * cb, is introduced to flag the constants.
96  *
97  * FI: I do not want to introduce a new data structure to represent a
98  * bounding box, and I do not like the idea of keeping independently
99  * five vectors...
100  *
101  * However, I could not think of a simple data structure to store the
102  * bounding box as a unique object. With more variables, it would be
103  * better to use hash tables to link variables to their lower and
104  * upper bound and to their value when they are constant. Hence the
105  * use of four sparse vectors as explained above.
106  */
107 ␌
108 /* Auxiliary functions for sc_bounded_normalization(): build the
109  * bounding box
110  *
111  * Update bound information for variable var. A lower or upper bound_p
112  * and bound_base_p must be passer regardless of lower_p. lower_p is
113  * only used to know how to tighten the bound if it is already
114  * defined. The information to use is:
115  *
116  * lower_p? var <= nb : var>=nb
117  *
118  * It is not possible to detect an empty system here because
119  * information on both bounds is not available simultaneously. lb, l,
120  * ub and u should all be passed for the check.
121  */
123  Pvecteur * bound_base_p,
124  Variable var,
125  Value nb, /* new bound */
126  bool lower_p)
127 {
128  if(vect_coeff(var, *bound_base_p)!=0) {
129  /* A bound is already known. It must be updated if the new one is better. */
130  Value pb = vect_coeff(var, *bound_p); /* previous bound */
131  if(lower_p) { /* bigger is better */
132  if(nb>pb) { /* update bound */
133  // vect_chg_coeff() should be used for a simpler update...
134  vect_add_elem(bound_p, var, value_minus(nb,pb));
135  }
136  else {
137  /* The current constraint is redundant */
138  ;
139  }
140  }
141  else { /* smaller is better */
142  if(nb<pb) { /* update bound */
143  vect_add_elem(bound_p, var, value_minus(nb,pb));
144  }
145  else {
146  /* The current constraint is redundant */
147  ;
148  }
149  }
150  }
151  else {
152  /* No bound is known yet */
153  base_add_dimension(bound_base_p, var);
154  vect_add_elem(bound_p, var, nb);
155  }
156 }
157 
158 /* Updates upper and lower bounds, (ubound_p, ubound_base_p) and
159  * (lbound_p, lbound_base_p), with equations var==nb
160  *
161  * Do not test for nb==0. This would increase the code size a lot for
162  * a very limited benefit.
163  *
164  * This function returns a boolean to signal an empy interval,
165  * i.e. a non-feasible system.
166  *
167  * Auxiliary function of sc_bounded_normalization()
168  */
170  Pvecteur * ubound_base_p,
171  Pvecteur * lbound_p,
172  Pvecteur * lbound_base_p,
173  Variable var,
174  Value nb) /* new bound */
175 {
176  bool empty_p = false;
177 
178  if(var==TCST) {
179  /* Some constraint like 0==0, i.e. the NULL vector, or 0==3 an impossible constraint */
180  // abort();
181  if(!value_zero_p(nb))
182  empty_p = true;
183  }
184  else {
185  /* Update the upper bound */
186  if(vect_coeff(var,*ubound_base_p)!=0) {
187  /* A pre-existing upper bound exists */
188  Value ob = vect_coeff(var, *ubound_p);
189  if(value_gt(ob, nb)) {
190  /* The new bound nb is stricter and consistent with the preexisting upper bound */
191  vect_add_elem(ubound_p, var, value_minus(nb,ob));
192  }
193  else if(value_eq(ob,nb))
194  ;
195  else {
196  empty_p = true;
197  //abort();
198  ; /* ignore the non feasability */
199  /* but maintain consistency to avoid a later abort */
200  //vect_add_elem(ubound_p, var, value_minus(nb,ob));
201  }
202  }
203  else {
204  base_add_dimension(ubound_base_p, var);
205  vect_add_elem(ubound_p, var, nb);
206  }
207 
208  /* Update the lower bound, almost identical, but for the
209  compatibility check */
210  if(vect_coeff(var,*lbound_base_p)!=0) {
211  /* A lower bound has already been defined */
212  Value ob = vect_coeff(var, *lbound_p);
213  if(value_lt(ob, nb)) {
214  /* The new bound nb is stricter and consistent with the
215  preexisting lower bound */
216  vect_add_elem(lbound_p, var, value_minus(nb,ob));
217  }
218  else if(value_eq(ob,nb))
219  ;
220  else {
221  empty_p = true;
222  /* ps is empty with contradictory equations and inequalities
223  supposedly trapped earlier */
224  // abort();
225  ; /* ignore the non feasability */
226  /* but maintain consistency to avoid a later abort */
227  //vect_add_elem(lbound_p, var, value_minus(nb,ob));
228  }
229  }
230  else {
231  base_add_dimension(lbound_base_p, var);
232  vect_add_elem(lbound_p, var, nb);
233  }
234  if(!empty_p && vect_coeff(var, *lbound_p)!=vect_coeff(var,*ubound_p))
235  abort();
236  }
237  return empty_p;
238 }
239 ␌
240 /* Use constants imposed by the bounding box to eliminate constant
241  * terms from constraint eq.
242  *
243  * Unless this is the constraint defining the bounding box? Destroy it
244  * any way to remove redundancy and expect the bounding box contraints
245  * to be added later.
246  *
247  * Constant variables are defined by basis cb and their value are
248  * found in l (See description of bounding box above).
249  */
250 static void
252  Pbase cb,
253  Pvecteur l,
254  bool is_inequality_p __attribute__ ((unused)))
255 {
257  Pvecteur vc;
258  Pvecteur dv = VECTEUR_NUL;
259 
260  /* Substitute constant variables, computing a delta value to be
261  added to the constant term and setting the variable coefficient
262  to zero; we should have not only lb and ub but also cb, the base
263  for the constant terms */
264  for(vc=v; !VECTEUR_NUL_P(vc); vc = vecteur_succ(vc)) {
265  Variable var = vecteur_var(vc);
266  Value c = vecteur_val(vc);
267  /* We could check here if var has a constant value and eliminate
268  it from the constraint v... if this did not break the
269  surrounding loop on v... So the update is accumulated into a
270  difference vector dv that is added to v at the end of the
271  loop */
272  if(vect_coeff(var, cb)!=0) {
273  Value delta = value_direct_multiply(c, vect_coeff(var, l));
274  vect_add_elem(&dv, TCST, delta);
275  vect_add_elem(&dv, var, value_uminus(c));
276  }
277  }
278  /* We should update here the constant term with delta, the
279  value accumulated with the constant terms */
280  if(!VECTEUR_NUL_P(dv)) {
281  Pvecteur nv = vect_add(v, dv);
282  bool substitute_p = true;
283  if(false && /*!is_inequality_p &&*/ VECTEUR_NUL_P(nv)) {
284  /* do not destroy this equation by simplification if it defines
285  a constant... */
286  int n = vect_size(v);
287  Value cst = vect_coeff(TCST, v);
288  if((n==1 && value_zero_p(cst)) || (n==2 && value_notzero_p(cst)))
289  substitute_p = false;
290  }
291  if(substitute_p) {
292  ifscdebug(1) {
293  /* For debugging: init_variable_debug_name(entity_local_name) */
294  fprintf(stderr, "Initial constraint v=%p:\n", v);
295  vect_dump(v);
296  fprintf(stderr, "Difference dv=%p:\n", dv);
297  vect_dump(dv);
298  fprintf(stderr, "New constraint nv=%p:\n", nv);
299  vect_dump(nv);
300  }
301  vect_rm(v);
302  vect_rm(dv);
303  v = nv;
304  contrainte_vecteur(eq) = nv;
305  //assert(vect_check(nv));
306  }
307  else {
308  vect_rm(dv);
309  vect_rm(nv);
310  //assert(vect_check(v));
311  }
312  }
313 }
314 ␌
315 /* v is supposed to be the equation of a line in a 2-D space. l, lb, u
316  * and ub define a bounding box for variables in v. Retrieve, when
317  * possible, two variables x and y, such that the coefficients for y in v
318  * is greater than the interval for x in the bounding box.
319  *
320  * Also, make sure that a, the coefficient for x is negative and that
321  * b, the coefficient for y is positive. If it is not true, change the
322  * frame accordingly and indicate it in *pcb for later conversions.
323  *
324  * The bounds are assumed initialized to VALUE_MIN and VALUE_MAX.
325  *
326  */
328  Pvecteur v,
329  Pvecteur l, Pvecteur lb,
330  Pvecteur u, Pvecteur ub,
331  Variable * px, Variable * py,
332  Value * px_min, Value * px_max,
333  int * pcb)
334 {
335  Pvecteur vc;
336  Value delta_1 = VALUE_MAX, delta_2 = VALUE_MAX;
337  Variable v_1 = NULL, v_2 = NULL;
338  Value a_1 = VALUE_ZERO, a_2 = VALUE_ZERO;
339  Value
340  v_1_min = VALUE_NAN, v_1_max = VALUE_NAN,
341  v_2_min = VALUE_NAN, v_2_max = VALUE_NAN;
342  Value a = VALUE_ZERO, b = VALUE_ZERO, c = VALUE_ZERO;
343  Value delta_x = VALUE_MAX;
344  Pvecteur nv = VECTEUR_NUL;
345 
346  // Retrieve the coefficients, the variables and their intervals
347  for(vc=v; !VECTEUR_UNDEFINED_P(vc); vc=vecteur_succ(vc)) {
348  Variable var = vecteur_var(vc);
349  if(var!=TCST) {
350  if(v_1==NULL) {
351  v_1 = var;
352  a_1 = vecteur_val(vc);
353  if(!value_zero_p(vect_coeff(var,lb))
354  && !value_zero_p(vect_coeff(var,ub))) {
355  v_1_min = vect_coeff(var, l);
356  v_1_max = vect_coeff(var, u);
357  delta_1 = value_minus(v_1_max, v_1_min);
358  }
359  }
360  else {
361  v_2 = var;
362  a_2 = vecteur_val(vc);
363  if(!value_zero_p(vect_coeff(var,lb))
364  && !value_zero_p(vect_coeff(var,ub))) {
365  v_2_min = vect_coeff(var, l);
366  v_2_max = vect_coeff(var, u);
367  delta_2 = value_minus(v_2_max, v_2_min);
368  }
369  }
370  }
371  else {
372  c = vecteur_val(vc);
373  }
374  }
375 
376  /* If both v1 and v2 are eligible as x, chose arbitrarily v1. This
377  is usually bad design because non determnistic, but I do not have
378  a sorting function available here... A vect_sort() should be
379  performed before calling this function. An intermediate option
380  would be to chose the maximum of a_i/delta_i. */
381  /* Is v1 eligible as x? */
382  if(value_gt(value_abs(a_2), delta_1)) {
383  *px = v_1;
384  *py = v_2;
385  *px_min = v_1_min;
386  *px_max = v_1_max;
387  a = a_1;
388  b = a_2;
389  delta_x = delta_1;
390  }
391  else
392  /* is v2 eligible as x? */
393  if(value_gt(value_abs(a_1), delta_2)) {
394  *px = v_2;
395  *py = v_1;
396  *px_min = v_2_min;
397  *px_max = v_2_max;
398  a = a_2;
399  b = a_1;
400  delta_x = delta_2;
401  }
402  else {
403  /* We assume here that at least one of the two variables is
404  eligible because it was tested earlier. */
405  assert(false);
406  }
407 
408  ifscdebug(1) {
409  assert(value_gt(value_abs(b), delta_x));
411  assert(value_pos_p(delta_x));
412  /* For debugging: init_variable_debug_name(entity_local_name) */
413  fprintf(stderr, "Selected constraint: %lld %s + %lld %s + %lld\n",
414  (long long int) a, variable_debug_name(*px),
415  (long long int) b, variable_debug_name(*py),
416  (long long int) c);
417  }
418 
419  if(value_pos_p(a)) {
420  a = value_uminus(a);
421  negate_value_interval(px_min, px_max);
422  *pcb |= 4;
423  }
424  if(value_neg_p(b)) {
425  b = value_uminus(b);
426  *pcb |= 2;
427  }
428  if(false && value_gt(value_abs(a),value_abs(b))) {
429  /* Let's forget about the slope in ]0,1[, let's try positive slopes */
430  ;
431  }
432 
433  ifscdebug(1) {
434  /* For debugging: init_variable_debug_name(entity_local_name) */
435  fprintf(stderr,
436  "Constraint after change of frame: %lld %s + %lld %s + %lld\n",
437  (long long int) a, variable_debug_name(*px),
438  (long long int) b, variable_debug_name(*py),
439  (long long int) c);
440  fprintf(stderr, "Change of frame: %d\n", *pcb);
441  }
442 
443  nv = vect_make(nv, *px, a, *py, b, NULL, NULL, NULL);
444  vect_add_elem(&nv, TCST, c);
445  vect_normalize(nv);
446 
447  ifscdebug(1) {
448  fprintf(stderr, "New constraint nv: ");
449  vect_dump(nv);
450  }
451 
452  return nv;
453 }
454 
455 /* Is it possible to reduce the magnitude of at least one constraint
456  * coefficient because it is larger than the intervals defined by
457  * the bounding box for the other variable?
458  *
459  * Note: the modularity wastes computations. It would be nice to
460  * benefit from a, b, dx and dy.
461  */
463  Pvecteur l,
464  Pvecteur lb,
465  Pvecteur u,
466  Pvecteur ub)
467 {
468  bool eligible_p = true;
469  bool bounded_p = false;
470  Value dx = VALUE_MAX; // width of bounding box
471  Value dy = VALUE_MAX; // height of bounding box
472  Value a = VALUE_ZERO;
473  Value b = VALUE_ZERO;
474  Variable x = VARIABLE_UNDEFINED; // Dangerous, same as TCST...
475 
476  /* v is a 2-D constraint */
477  eligible_p = (vect_size(v)==2 && value_zero_p(vect_coeff(TCST, v)))
478  || (vect_size(v)==3 && value_notzero_p(vect_coeff(TCST, v)));
479 
480  /* The two variables are bounded by a non-degenerated rectangle... */
481  /* At least one variable is bounded by an interval: sufficient condition */
482  if(eligible_p) {
483  Pvecteur vc;
484  for(vc=v; !VECTEUR_UNDEFINED_P(vc) && eligible_p; vc=vecteur_succ(vc)) {
485  Variable var = vecteur_var(vc);
486  bool var_bounded_p = false;
487  if(var!=TCST) {
488  if(value_pos_p(vect_coeff(var, lb)) && value_pos_p(vect_coeff(var, ub))) {
489  bounded_p = true;
490  var_bounded_p = true;
491  }
492  if(VARIABLE_UNDEFINED_P(x)) {
493  dx = var_bounded_p?
494  value_minus(vect_coeff(var,u),vect_coeff(var,l))
495  : VALUE_MAX;
496  a = value_abs(vect_coeff(var, vc));
497  x = var;
498  }
499  else {
500  dy = var_bounded_p?
501  value_minus(vect_coeff(var,u),vect_coeff(var,l))
502  : VALUE_MAX;
503  b = value_abs(vect_coeff(var, vc));
504  }
505  }
506  }
507 
508  /* The bounding box is not degenerated. If it is the case, the
509  constraint should have been simplified in a much easier
510  way. */
511  eligible_p = bounded_p && value_pos_p(dx) && value_pos_p(dy);
512  if(eligible_p)
513  /* make sure that at least one coefficient can be reduced */
514  eligible_p = value_gt(a,dy) || value_gt(b,dx);
515  }
516 
517  return eligible_p;
518 }
519 
520 /* Check that the coefficients on the first and second variables, x
521  * and y, define a increasing line.
522  *
523  * With a slope less than one? Used to be a condition, but was lifted.
524  *
525  * Internal check used after a change of frame.
526  *
527  * Note: dangerous use of term ordering inside a linear sparse vector.
528  *
529  * Should work, although inefficiently for large slopes.
530  */
532 {
533  Value a = VALUE_ZERO;
534  Value b = VALUE_ZERO;
535  Pvecteur vc;
536  bool ok_p = true;
537 
538  ok_p = (vect_size(v)==2 && value_zero_p(vect_coeff(TCST, v)))
539  || (vect_size(v)==3 && value_notzero_p(vect_coeff(TCST, v)));
540 
541  if(ok_p) {
542  for(vc=v; !VECTEUR_UNDEFINED_P(vc); vc=vecteur_succ(vc)) {
543  Variable var = vecteur_var(vc);
544  if(var!=TCST) {
545  if(value_zero_p(a))
546  a = vect_coeff(var, vc);
547  else
548  b = vect_coeff(var, vc);
549  }
550  }
551  }
552 
553  ok_p = value_neg_p(a) && value_pos_p(b) && value_gt(b, value_uminus(a));
554 
555  return ok_p;
556 }
557 ␌
558 /* Compute a normalized version of the constraint v and the
559  * corresponding change of basis.
560  *
561  * The change of basis is encoded by an integer belonging to the
562  * interval [0,7]. Bit 2 is used to encode a change of sign for x,
563  * bit 1, a change of sign for y and bit 0 a permutation between x and
564  * y.
565  *
566  * No new variable x' and y' are introduced. The new constraint is
567  * still expressed as a constraint on x and y.
568  *
569  * The bounds on x and y must be adapted into bound on x' and y'.
570  */
571 static Pvecteur
573  int * pcb,
574  Variable x,
575  Variable y,
576  Value * px_min,
577  Value * px_max,
578  Value * py_min,
579  Value * py_max)
580 {
581  Value a = VALUE_ZERO;
582  Value b = VALUE_ZERO;
583  Value c = VALUE_ZERO;
584  Value a_prime = VALUE_ZERO;
585  Value b_prime = VALUE_ZERO;
586  Pvecteur vc;
587  Pvecteur nv = VECTEUR_NUL; // new constraint
588 
589  ifscdebug(1) {
590  fprintf(stderr, "%s:\n", __FUNCTION__);
591  fprintf(stderr, "Constraint before change of basis:");
592  vect_dump(v);
593  fprintf(stderr, "Initial interval x_min=%lld, x_max=%lld\n",
594  *px_min, *px_max);
595  }
596 
597  for(vc=v; !VECTEUR_UNDEFINED_P(vc); vc=vecteur_succ(vc)) {
598  Variable var = vecteur_var(vc);
599  if(var!=TCST) {
600  if(var==x) {
601  a = vect_coeff(var, vc);
602  }
603  else {
604  b = vect_coeff(var, vc);
605  assert(y == vecteur_var(vc));
606  }
607  }
608  else
609  c = vect_coeff(var, vc);
610  }
611 
612  if(value_pos_p(a)) {
613  /* substitute x by x'=-x */
614  *pcb = 4;
615  /* FI: could cause an overflow */
616  value_assign(a_prime, value_uminus(a));
617  negate_value_interval(px_min, px_max);
618  }
619  else {
620  *pcb = 0;
621  value_assign(a_prime, a);
622  }
623  if(value_neg_p(b)) {
624  *pcb |= 2;
625  /* FI: could cause an overflow */
626  value_assign(b_prime, value_uminus(b));
627  negate_value_interval(py_min, py_max);
628  }
629  else {
630  // *pcb |= 0; i.e. unchanged
631  value_assign(b_prime, b);
632  }
633  if(value_gt(b_prime, value_uminus(a_prime))) {
634  /* Build a_prime x + b_prime y <= -c */
635  vect_add_elem(&nv, y, b_prime);
636  vect_add_elem(&nv, x, a_prime);
637  vect_add_elem(&nv, TCST, c);
638  }
639  else {
640  /* x and y must be exchanged: -b_prime x - a_prime y <= -c */
641  *pcb |= 1;
642  vect_add_elem(&nv, y, value_uminus(a_prime));
643  vect_add_elem(&nv, x, value_uminus(b_prime));
644  vect_add_elem(&nv, TCST, c);
645  swap_value_intervals(px_min, px_max, py_min, py_max);
646  }
647 
648  ifscdebug(1) {
649  /* Make sure that nv is properly built... */
650  fprintf(stderr, "%s:\n", __FUNCTION__);
651  fprintf(stderr, "Constraint after change of basis:");
652  vect_dump(nv);
653  fprintf(stderr, "Final interval x_min=%lld, x_max=%lld\n", *px_min, *px_max);
654  fprintf(stderr, "Chosen variables x=%s, y=%s\n", variable_debug_name(x),
656  fprintf(stderr, "Change of basis: %d\n", *pcb);
657 
659  }
660 
661  return nv;
662 }
663 
664 /* FI: Could be moved in vecteur library... */
665 /* Compute the equation of the line joining (x0,y0) and (x1,y1)
666  *
667  * (x1-x0) y = (y1 -y0) (x - x0) + y0 (x1-x0)
668  *
669  * as ax+by+c=0, where a, b and c are prime together.
670  */
672  Value x0, Value y0, Value x1, Value y1)
673 {
674  Value dx = value_minus(x1,x0);
675  Value dy = value_minus(y1,y0);
676  Value a = dy;
677  Value b = -dx;
678  assert(dx!=0 || dy!=0);
679  /* constant term: -x0 dy + y0 dx */
680  Value c = value_minus(value_mult(y0, dx), value_mult(x0, dy));
681  Pvecteur v = vect_new(x, a);
682  vect_add_elem(&v, y, b);
683  vect_add_elem(&v, TCST, c);
684  vect_normalize(v);
685  return v;
686 }
687 
688 /* Find the first *significant* integer point (*pfx, *pfy) starting
689  from (x0,y0) moving by (dx,dy) steps towards (xf,yf) that is
690  between the constraint up_c and low_c such that *pfx!=xf and
691  *pfx!=x0. Let x be *pfx and y be *pfy. Between the constraints
692  means up_c(x,y)<=0 and low_c(x,y)>0.
693 
694  The two constraints up_c and low_c have a positive slope with
695  respect to variables xv and yv over interval [x0,xf] or [xf,x0].
696 
697  Value yf is only useful for debugging.
698 
699  It would be possible to find the intermediate points faster using
700  intersections with the constraints instead of using an incremental
701  step-by-step approach.
702 
703  This is an auxiliary function for coefficient reduction.
704  */
706  Value y0,
707  Pvecteur up_c,
708  Pvecteur low_c,
709  Variable xv, Variable yv,
710  Value dx, Value dy,
711  Value xf, Value yf __attribute__ ((unused)),
712  Value * pfx, Value * pfy)
713 {
714  /* Retrieve coefficients of the two constraints */
715  Value a_up = vect_coeff(xv, up_c);
716  Value a_low = vect_coeff(xv, low_c);
717  Value b_up = vect_coeff(yv, up_c);
718  Value b_low = vect_coeff(yv, low_c);
719  Value c_up = vect_coeff(TCST, up_c);
720  Value c_low = vect_coeff(TCST, low_c);
721  /* FI: I am tired of using value macros */
722  Value up_0 = a_up * x0 + b_up * y0 + c_up;
723  Value low_0 = a_low * x0 + b_low * y0 + c_low;
724  Value up = up_0;
725  Value low = low_0;
726  Value x = x0, y = y0;
727  bool found = false; // (up <= 0 && low >=0); the first point is not
728  // relevant as intermediate point
729 
730  /* The two constraints have positive slopes, but not necessarily in
731  the ]0,1[ interval */
732  assert(a_up<0 && b_up>0 /* && b_up>-a_up */ );
733  assert(a_low<0 && b_low>0 /* && b_low>-a_low */ );
734 
735  /* Constraint up is higher than constraint low on interval [x0,xf] */
736  assert(!(up>0&&low<0));
737 
738  if(x0!=xf) {
739  /* There are other points to explore */
740  assert(dx!=0);
741  assert((xf>x0 && dx>0) || (xf<x0 && dx<0));
742 
743  while(!found && x!=xf) {
744  if(up>=0) {
745  if(dx>0) {
746  x += dx;
747  up += a_up*dx;
748  low += a_low*dx;
749  }
750  else {
751  y += dy;
752  up += b_up*dy;
753  low += b_low*dy;
754  }
755  }
756  if(low<=0 ) {
757  if(dx>0) {
758  y += dy;
759  up += b_up*dy;
760  low += b_low*dy;
761  }
762  else {
763  x += dx;
764  up += a_up*dx;
765  low += a_low*dx;
766  }
767  }
768  /* The intermediate point si strictly over the lower constraint
769  and meet the upper constraint. It is not the initial nor the
770  final point. */
771  found = (up <= 0 && low >0) && x!=x0 && x!=xf;
772  assert(!(up>0&&low<0) || x==x0 || x==xf);
773  }
774  }
775 
776  if(found) {
777  if(y-y0==0) { // slope12.c: this procedure may skip useful
778  //intermediate points, e.g. when the slope oscillates between 1/50 and
779  // 1/49...; it might be OK when the slope is down to 0...
780  /* Are there more integer points along this direction? If yes,
781  * find the last one.
782  *
783  * let ndx = x-x0, ndy = y - y0
784  *
785  * let x = x0 + th ndx and y = y0 + th ndy (x and y are new variables)
786  *
787  * what is the largest integer value for th such that up<=0?
788  *
789  * a_up x0 + a_up th ndx + b_up y0 + b_up th ndy + c_up <= 0
790  *
791  * th <= (-a_up x0 - b_up y0 - c_up)/(a_up ndx + b_up ndy)
792  *
793  * if a_up dx + b_up dy >=0. Else
794  *
795  * th >= (a_up x0 + b_up y0 + c_up)/(-a_up ndx - b_up ndy)
796  */
797  Value ndx = x - x0;
798  Value ndy = y - y0;
799  Value n = a_up*x0+b_up*y0+c_up;
800  Value d = a_up*ndx+b_up*ndy;
801  // The test might be useless, depending on pdiv's behavior
802  Value th = d>0? value_pdiv(value_uminus(n),d)
803  :value_pdiv(n-d-1,value_uminus(d));
804  // th==0 is always solution since (x0,y0) is solution
805  // d>0 implies an upper bound, and d<0 a lower bound
806  assert((d>0 && th>=0) || (d<0 && th<=0));
807 
808  /* then you should find the last one in the [x0,xf] interval...
809  *
810  * if ndx > 0, x0+k ndx<=xf else x0+ k ndx >= xf, x0-xf>=-k ndx
811  */
812  Value k = ndx>0? value_pdiv(xf-x0,ndx) : value_pdiv(x0-xf,-ndx);
813  assert(k>=0);
814 
815  /* The constraint on th is d th + n <=0 */
816  if(d<0) {
817  /* lower bound for th: any th positive is good */
818  assert(th<=0);
819  x = x0+k*ndx;
820  y = y0+k*ndy;
821  found = x!=xf; // Useful intermediate integer point?
822  }
823  else { /* d>0, upper bound for th */
824  /* This should occur for slope07, 08 and 09 */
825  assert(th>=0);
826  Value lambda = value_min(k,th);
827  x = x0+lambda*ndx;
828  y = y0+lambda*ndy;
829  found = x!=xf; // Useful intermediate integer point?
830  }
831  }
832  /* Make sure that (x,y) meets all the constraints */
833  if(found) {
834  assert(a_up*x+b_up*y+c_up<=0);
835  assert(a_low*x+b_low*y+c_low>=0);
836  assert(x!=x0); // y may be equal to y0
837  assert(x!=xf); // y may be equal to yf
838  }
839 
840  /* return the final resut */
841  *pfx = x;
842  *pfy = y;
843  }
844 
845  ifscdebug(1) {
846  if(found) {
847  fprintf(stderr, "Intermediate point: (%lld, %lld) for "
848  "[(%lld,%lld),(%lld,%lld)] "
849  "with saturations low %lld and up %lld\n",
850  x, y, x0, y0, xf, yf,
851  (a_low*x+b_low*y+c_low)/b_low,
852  (a_up*x+b_up*y+c_up)/b_up);
853  fprintf(stderr, "for constraints low and up:\n");
854  vect_dump(low_c);
855  vect_dump(up_c);
856  }
857  else {
858  fprintf(stderr, "No intermediate point found\n");
859  }
860  }
861 
862  return found;
863 }
864 
866  Value y0,
867  Pvecteur up,
868  Pvecteur low,
869  Variable x, Variable y,
870  Value xf, Value yf,
871  Value * pfx, Value * pfy)
872 {
873  assert(value_ge(xf,x0));
874  return find_first_integer_point_in_between(x0, y0, up, low, x, y,
876  xf, yf, pfx, pfy);
877 }
878 
880  Value y0,
881  Pvecteur up,
882  Pvecteur low,
883  Variable x, Variable y,
884  Value xf, Value yf,
885  Value * pfx, Value * pfy)
886 {
887  assert(value_le(xf,x0));
888  return find_first_integer_point_in_between(x0, y0, up, low, x, y,
890  xf, yf, pfx, pfy);
891 }
892 ␌
893 /* FI: a bit too specific for vecteur library? */
895 {
896  Value k = VALUE_ZERO;
897  Value a = vect_coeff(x, v);
898  Value b = vect_coeff(y, v);
899  Value c = vect_coeff(TCST, v);
900 
901  /* FI: overflow control should be added */
902  k = a*xv + b*yv + c;
903  return k;
904 }
905 
906 
907 /* Use the first eni+2 points in ilmpx and ilmpy to build at most
908  * eni+1 convex constraints, all upper bounds for y. As we build a
909  * partial convex hull, there should always be a solution.
910  *
911  * The value in ilmpx are assumed to be striclty increasing. The value
912  * in ilmpy are increasing. To be convex, the slopes of the successive
913  * constraints must be decreasing.
914  */
915 static
917  int ni, int eni,
918  Value ilmpx[ni+2], Value ilmpy[ni+2])
919 {
920  int nli = eni; // number of left intermediate points
921  int left = 0; // index of the first point
922  int right = 1;
923  int rightmost = eni+1; // index of the last point
924  assert(eni>=0);
925  assert(ni>=eni);
927  int count = 0;
928  int i;
929 
930  ifscdebug(1) {
931  fprintf(stderr, "%s: input arrays with %d effective points\n", __FUNCTION__, eni);
932  for(i=0;i<eni+2;i++)
933  fprintf(stderr, "(%lld, %lld)%s", ilmpx[i], ilmpy[i], i==eni+1? "":", ");
934  fprintf(stderr, "\n");
935  }
936 
937  while(nli>=0) {
938  /* build a constraint between left and right */
939  Pvecteur nv = vect_make_line(x, y, ilmpx[left], ilmpy[left],
940  ilmpx[right], ilmpy[right]);
941  nv = vect_multiply(nv, VALUE_MONE);
942  /* Check that all points meet the constraint */
943  bool failed_p = false;
944  for(i=0; i<eni+2 && !failed_p; i++) {
945  /* We could skip the left and right points... */
946  failed_p = value_pos_p(eval_2D_vecteur(nv, x, y, ilmpx[i], ilmpy[i]));
947  }
948  if(failed_p) {
949  ifscdebug(1)
950  fprintf(stderr, "%s: point %d =(%lld, %lld) is skipped (left=%d is unchanged).\n",
951  __FUNCTION__, right, ilmpx[right], ilmpy[right], left);
952  vect_rm(nv);
953  right++;
954  }
955  else {
956  ifscdebug(1)
957  fprintf(stderr, "%s: points %d =(%lld, %lld) and %d =(%lld, %lld) "
958  "are used as vertices to define a new constraint.\n",
959  __FUNCTION__, left, ilmpx[left], ilmpy[left],
960  right, ilmpx[right], ilmpy[right]);
961  left = right;
962  right++;
963  Pcontrainte nc = contrainte_make(nv);
964  contrainte_succ(nc) = ineq;
965  ineq = nc;
966  count++;
967  }
968  nli--;
969  }
970  /* There is always at least one constraint. */
972  /* All points have been used*/
973  assert(right-1==rightmost);
974  /* The constraints are chained backwards with respect to the vectices */
975  ifscdebug(1) {
976  fprintf(stderr, "%s: %d constraints obtained:\n", __FUNCTION__, count);
977  inegalites_dump(ineq);
978  }
979  return ineq;
980 }
981 
982 /* Find a set ineq of 2-D constraints equivalent to 2-D constraint
983  v==ax+by+c over the interval [lmpx,rmpx]. The slope of the
984  constraint v is assumed positive. The values lmpy and rmpy could be
985  computed from v and lmpx and rmpx but are passed down to simplify
986  debugging. The coefficients of the new constraints are smaller than
987  the coefficient of v, assuming that abs(b) is greater than
988  rmpx-lmpx.
989 
990  The function looks for intermediate points and build the
991  constraints fromm this set of points, making sure to skip some
992  intermediate points if the constraint they generate do not respect
993  convexity.
994  */
996  Variable x, Variable y,
997  Value lmpx, Value lmpy,
998  Value rmpx, Value rmpy)
999 {
1000  Pcontrainte ineq;
1001  /* No interesting intermediate point exists if lmpx and rmpx or lmpy
1002  and rmpy are too close. No values would be available for their
1003  coordinates. */
1004  Value delta_x = rmpx-lmpx-1; // cardinal of ]lmpx,rmpx[
1005  Value delta_y = rmpy-lmpy; // cardinal of ]lmpy,rmpy], y may not
1006  //vary between the last two points
1007  assert(delta_x>=0);
1008  assert(delta_y>=0);
1009  /* maximal number of intermediate points */
1010  int ni = (int) value_min(delta_x, delta_y);
1011  /* Look for at most for ni intermediate points, but reserve space to
1012  add the initial point and (perhaps) the final point. */
1013  Value ilmpx[ni+2], ilmpy[ni+2];
1014  /* The first element is the left most point */
1015  ilmpx[0] = lmpx;
1016  ilmpy[0] = lmpy;
1017  /* Effective number of intermediate points */
1018  int eni = 0;
1019  bool more_to_find_p = ni>0;
1020 
1021  /* The control structure of this piece of code could be improved by
1022  initializing ilmpx[0] and ilmpy[0] right away and by using a
1023  while(more_to_find_p) to avoid code replication. */
1024 
1025  while(more_to_find_p) {
1026  /* A lower upper bound for v */
1027  Pvecteur nv = vect_make_line(x, y, ilmpx[eni], ilmpy[eni], rmpx, rmpy);
1028  nv = vect_multiply(nv, VALUE_MONE);
1029 
1030  bool rfound = find_integer_point_to_the_right(ilmpx[eni],
1031  ilmpy[eni],
1032  v,
1033  nv,
1034  x, y,
1035  rmpx, rmpy,
1036  &ilmpx[eni+1], &ilmpy[eni+1]);
1037  if(rfound) {
1038  eni++;
1039  Value nlmpx = ilmpx[eni];
1040  Value nlmpy = ilmpy[eni];
1041  Value ndelta_x = rmpx-nlmpx-1;
1042  Value ndelta_y = rmpy-nlmpy; // the constraint may be horizontal
1043  assert(ndelta_x>=0);
1044  assert(ndelta_y>=0);
1045  int nni = (int) value_min(ndelta_x, ndelta_y);
1046  assert(nni<=ni);
1047  more_to_find_p = nni>0;
1048  }
1049  else
1050  more_to_find_p = false;
1051  }
1052 
1053  if(eni>0) {
1054  /* add the final point to the arrays ilmpx and ilmpy */
1055  ilmpx[eni+1] = rmpx;
1056  ilmpy[eni+1] = rmpy;
1057  /* Process the intermediate points */
1058  ineq = build_convex_constraints_from_vertices(x, y, ni, eni,
1059  ilmpx, ilmpy);
1060  }
1061 
1062  if(ni==0||eni==0) {
1063  /* One constraint generated by (lmpx,lmpy) and (rmpx,rmpy) */
1064  Pvecteur uv = vect_make_line(x, y, lmpx,lmpy,rmpx,rmpy);
1065  uv = vect_multiply(uv, VALUE_MONE);
1066  ineq = contrainte_make(uv);
1067  }
1068 
1069  return ineq;
1070 }
1071 
1072 /* Find a set ineq of 2-D constraints equivalent to 2-D constraint
1073  v==ax+by+c over the interval [lmpx,rmpx]. The slope of the
1074  constraints is assumed positive. The values lmpy and rmpy could be
1075  computed from v and lmpx and rmpx but are passed down to simplify
1076  debugging. The coefficients of the new constraints are smaller than
1077  the coefficient of v, assuming that abs(b) is greater than
1078  rmpx-lmpx.
1079 
1080  This function was based on the wrong assumption that at most three
1081  constraints were sufficient to replace exactly v. This is proved
1082  wrong by slope15.c.
1083 
1084  This function is now obsolete: it was based on the wrong assumption
1085  that three constraints at most would be necessary to replace one
1086  rational constraint. We ended up with a case requiring four
1087  constraints in linked_regions02 and we have no proof that the
1088  number of integer vertices, and hence the number of constraints is
1089  bounded by a smaller bound than min(dx,dy+1).
1090  */
1092  Value lmpx, Value lmpy,
1093  Value rmpx, Value rmpy)
1094 {
1095  Pcontrainte ineq;
1096 
1097  /* Look for intermediate points */
1098  Value ilmpx, ilmpy, irmpx, irmpy;
1099  /* A lower upper bound */
1100  Pvecteur nv = vect_make_line(x, y, lmpx, lmpy, rmpx, rmpy);
1101  nv = vect_multiply(nv, VALUE_MONE);
1102 
1103  /* Start with the initial point in order to be able to compute
1104  the slope of the new constraint later */
1105  bool rfound = find_integer_point_to_the_right(lmpx,
1106  lmpy,
1107  v,
1108  nv,
1109  x, y,
1110  rmpx, rmpy,
1111  &ilmpx, &ilmpy);
1112  bool lfound = find_integer_point_to_the_left(rmpx,
1113  rmpy,
1114  v,
1115  nv,
1116  x, y,
1117  lmpx, lmpy,
1118  &irmpx, &irmpy);
1119  assert(rfound==lfound);
1120  if(rfound) {
1121  if(ilmpx==irmpx) {
1122  /* Two constraints */
1123  double slope1 = ((double)(ilmpy-lmpy))/((double)(ilmpx-lmpx));
1124  double slope3 = ((double)(rmpy-irmpy))/((double)(rmpx-irmpx));
1125  Pvecteur fv = vect_make_line(x, y, lmpx,lmpy,ilmpx,ilmpy);
1126  fv = vect_multiply(fv, VALUE_MONE);
1127  Pvecteur lv = vect_make_line(x, y, irmpx,irmpy,rmpx,rmpy);
1128  lv = vect_multiply(lv, VALUE_MONE);
1129  ineq = contraintes_make(fv,lv, VECTEUR_NUL);
1130  /* assert convexity */
1131  assert(slope1>slope3);
1132  }
1133  else {
1134  /* Three constraints at most: be careful about the convexity, the
1135  slopes must be decreasing... */
1136  double slope1 = ((double)(ilmpy-lmpy))/((double)(ilmpx-lmpx));
1137  double slope2 = ((double)(irmpy-ilmpy))/((double)(irmpx-ilmpx));
1138  double slope3 = ((double)(rmpy-irmpy))/((double)(rmpx-irmpx));
1139  if(slope1>slope2 && slope2>slope3) {
1140  /* We still might have some integer points between
1141  (ilmpx,ilmpy) and (rmlpx,rlmpy)... */
1142  Pvecteur fv = vect_make_line(x, y, lmpx,lmpy,ilmpx,ilmpy);
1143  fv = vect_multiply(fv, VALUE_MONE);
1144  Pvecteur mv = vect_make_line(x, y, ilmpx,ilmpy,irmpx,irmpy);
1145  mv = vect_multiply(mv, VALUE_MONE);
1146  Pvecteur lv = vect_make_line(x, y, irmpx,irmpy,rmpx,rmpy);
1147  lv = vect_multiply(lv, VALUE_MONE);
1148  ineq = contraintes_make(fv, mv, lv, VECTEUR_NUL);
1149  }
1150  else if(slope2>slope1) {
1151  /* The first intermediate point, (ilmpx,ilmpy), cannot be used */
1152  double slope12 = ((double)(irmpy-lmpy))/((double)(irmpx-lmpx));
1153  if(slope12>slope3) {
1154  Pvecteur fv = vect_make_line(x, y, lmpx,lmpy,irmpx,irmpy);
1155  fv = vect_multiply(fv, VALUE_MONE);
1156  Pvecteur lv = vect_make_line(x, y, irmpx,irmpy,rmpx,rmpy);
1157  lv = vect_multiply(lv, VALUE_MONE);
1158  ineq = contraintes_make(fv, lv, VECTEUR_NUL);
1159  }
1160  else {
1161  /* FI: I assume it never happens... by definition of an
1162  intermediate point */
1163  fprintf(stderr, "not implemented.\n");
1164  abort();
1165  }
1166  }
1167  else {
1168  /* We must have slope2<slope3*/
1169  double slope23 = ((double)(rmpy-ilmpy))/((double)(rmpx-ilmpx));
1170  if(slope1>slope23) {
1171  Pvecteur fv = vect_make_line(x, y, lmpx,lmpy,ilmpx,ilmpy);
1172  fv = vect_multiply(fv, VALUE_MONE);
1173  Pvecteur lv = vect_make_line(x, y, ilmpx,ilmpy,rmpx,rmpy);
1174  lv = vect_multiply(lv, VALUE_MONE);
1175  ineq = contraintes_make(fv, lv, VECTEUR_NUL);
1176  }
1177  else {
1178  /* FI: I assume it never happens... by definition of an
1179  intermediate point. */
1180  fprintf(stderr, "not implemented.\n");
1181  abort();
1182  }
1183  }
1184  }
1185  }
1186  else {
1187  /* One constraint generated by (lmpx,lmpy) and (rmpx,rmpy) */
1188  Pvecteur uv = vect_make_line(x, y, lmpx,lmpy,rmpx,rmpy);
1189  uv = vect_multiply(uv, VALUE_MONE);
1190  ineq = contrainte_make(uv);
1191  }
1192  return ineq;
1193 }
1194 ␌
1195 /* Replace 2-D constraint v by a set of constraints when possible
1196  because variable x is bounded by [x_min,x_max]. The set of
1197  constraints contains one, two or three new constraints.
1198 
1199  The slope of constraint v wrt variable x is in interval ]0,1[. On
1200  other words, if v is interpreted as a x + b y + c <=0, a is
1201  negative and b is greater than -a. Also b is greater than
1202  |low-up|. All these constraints have been checked earlier.
1203  */
1204 static Pcontrainte
1206  Variable x,
1207  Value x_min,
1208  Value x_max,
1209  Variable y,
1210  Value y_min __attribute__ ((unused)),
1211  Value y_max __attribute__ ((unused)))
1212 {
1213  Value a = VALUE_ZERO;
1214  Value b = VALUE_ZERO;
1215  Value c = VALUE_ZERO;
1216  Value lmpx, lmpy; // left most vertex
1217  Value rmpx, rmpy; // right most vertex
1219 
1220  ifscdebug(1) {
1221  fprintf(stderr, "%s:\n", __FUNCTION__);
1222  fprintf(stderr, "Constraint after change of basis:");
1223  vect_fprint(stderr, v, variable_debug_name);
1224  fprintf(stderr, "Interval for %s: x_min=%lld, x_max=%lld\n",
1225  variable_debug_name(x), x_min, x_max);
1226  }
1227 
1228  /* Retrieve coefficients and variables in v = ax+by+c */
1229  Pvecteur vc;
1230  for(vc=v; !VECTEUR_UNDEFINED_P(vc); vc=vecteur_succ(vc)) {
1231  Variable var = vecteur_var(vc);
1232  if(var!=TCST) {
1233  if(var==x) {
1234  a = vect_coeff(var, vc);
1235  }
1236  else {
1237  b = vect_coeff(var, vc);
1238  }
1239  }
1240  else
1241  c = vect_coeff(var, vc);
1242  }
1243 
1244  /* Compute two integer vertices for x_min and x_max using constraint
1245  ax+by+c=0, y = (- c - ax)/b */
1246  assert(value_ne(x_min, VALUE_MIN) && value_ne(x_max, VALUE_MAX));
1247 
1248  /* Reminder: the slope is positive, the function is increasing and
1249  y_x_min and y_x_max are upper bounds */
1250  Value y_x_min =
1252  Value y_x_max =
1254 
1255  /* x must be bounded, but y bounds are useless; they simply make the
1256  resolution more complex */
1257  /* In case, both x and y are bounded we think it useful to take
1258  advantage of the interval product */
1259  if(false) {
1260  Value x_y_min, x_y_max;
1261  bool found_p, redundant_p;
1262  /* Compute two integer vertices for y_min and y_max using constraint
1263  ax+by+c=0, x = (- c - by)/a */
1264  x_y_min =
1266  x_y_max =
1268 
1269  /* The constraint ax+by+c=0 has at most two valid intersections with
1270  the bounding box. Because the slope is positive, 0<-a/b<1, the
1271  minimum point is obtained with x_min or y_min and the maximum
1272  point is obtained with x_max or y_max.
1273 
1274  Constraint redundant with the bounding box should have been
1275  eliminated earlier with a simpler technique.
1276  */
1277  if(value_ge(y_x_min, y_min) && value_le(y_x_min, y_max)) {
1278  if(value_lt(y_x_min, y_max)) {
1279  // The left most point is (x_min, y_x_min)
1280  lmpx = x_min;
1281  lmpy = y_x_min;
1282  found_p = true;
1283  }
1284  else {
1285  // The constraint is a redundant tangent
1286  redundant_p = true;
1287  }
1288  }
1289  if(!redundant_p && value_ge(x_y_min, x_min) && value_le(x_y_min, x_max)) {
1290  if(value_lt(x_y_min, x_max)) {
1291  // The left most point is (x_y_min, y_min)
1292  lmpx = x_min;
1293  lmpy = y_x_min;
1294  found_p = true;
1295  }
1296  else {
1297  // The constraint is a redundant tangent
1298  redundant_p = true;
1299  }
1300  }
1301  if(!found_p)
1302  redundant_p = true;
1303  assert(!redundant_p);
1304  fprintf(stderr, "lmpx=%d, lmpy=%d\n", (int) lmpx, (int) lmpy);
1305  if(value_ge(y_x_max, y_min) && value_le(y_x_max, y_max)) {
1306  if(value_lt(y_x_max, y_max)) {
1307  // The right most point is (x_max, y_x_max)
1308  rmpx = x_min;
1309  rmpy = y_x_min;
1310  found_p = true;
1311  }
1312  else if(value_lt(y_x_max, y_min)) {
1313  /* The constraint is a redundant tangent */
1314  redundant_p = true;
1315  }
1316  }
1317  if (!redundant_p && !found_p
1318  && value_ge(x_y_max, x_max) && value_le(x_y_max, x_max)) {
1319  if (value_lt(x_y_max, x_max)) {
1320  // The right most point is (x_y_max, y_max)
1321  rmpx = x_min;
1322  rmpy = y_x_min;
1323  found_p = true;
1324  }
1325  else {
1326  // The constraint is a redundant tangent
1327  redundant_p = true;
1328  }
1329  }
1330  if(!found_p)
1331  redundant_p = true;
1332  assert(!redundant_p && found_p);
1333  }
1334 
1335  /* The change of coordinates was meaningful when bounding both x and y */
1336  lmpx = x_min;
1337  lmpy = y_x_min;
1338  rmpx = x_max;
1339  rmpy = y_x_max;
1340  ifscdebug(1) {
1341  fprintf(stderr, "lmpx=%d, lmpy=%d\n", (int) lmpx, (int) lmpy);
1342  fprintf(stderr, "rmpx=%d, rmpy=%d\n", (int) rmpx, (int) rmpy);
1343  }
1344 
1345  if (value_le(value_minus(rmpy,lmpy), VALUE_ZERO)) {
1346  /* One new horizontal constraint defined by the two vertices lmp
1347  and rmp: y<=lmpy; test case slope01.c */
1348  Pvecteur nv = VECTEUR_NUL;
1349  nv = vect_make(nv, y, VALUE_ONE, NULL, NULL, NULL);
1350  vect_add_elem(&nv, TCST, value_uminus(lmpy));
1351  ineq = contrainte_make(nv);
1352  ifscdebug(1) fprintf(stderr, "Case slope01\n");
1353  }
1354  else if (value_le(value_minus(rmpy,lmpy), VALUE_ONE)) {
1355  // There may be one vertex on the left of rmp, lrmp, with a lrmpx
1356  // + b rmpy <= -c, b rmpy + c <= -ax, lrmpx >= (c + b rmpy -a -1)/(-a)
1357  Value lrmpx =
1358  value_pdiv(
1359  value_plus(c, value_plus(value_mult(b, rmpy),
1361  VALUE_MONE))),
1362  value_uminus(a));
1363  if(value_gt(lrmpx, lmpx) && value_lt(lrmpx, rmpx)) {
1364  /* Two constraints defined by (lmp,lrmp) and (lrmp, rmp). test
1365  case slope02.c */
1367  Pvecteur nv1 = vect_make_line(x, y, lmpx, lmpy, lrmpx, rmpy);
1368  nv1 = vect_multiply(nv1, VALUE_MONE);
1369  Pvecteur nv2 = vect_make(nv, y, VALUE_ONE, NULL, NULL, NULL);
1370  vect_add_elem(&nv2, TCST, value_uminus(rmpy));
1371  Pcontrainte ineq1 = contrainte_make(nv1);
1372  Pcontrainte ineq2 = contrainte_make(nv2);
1373  contrainte_succ(ineq1) = ineq2;
1374  ineq = ineq1;
1375  ifscdebug(1) fprintf(stderr, "Case slope02\n");
1376  }
1377  else if(value_eq(lrmpx, rmpx)) {
1378  /* Only one constraint defined by : test case slope03.c */
1379  Pvecteur nv = vect_make_line(x, y, lmpx, lmpy, lrmpx, rmpy);
1380  nv = vect_multiply(nv, VALUE_MONE);
1381  ineq = contrainte_make(nv);
1382  ifscdebug(1) fprintf(stderr, "Case slope03\n");
1383  }
1384  }
1385  else {
1386  /* The slope is sufficiently large to find up to three
1387  constraints: look for the leftmost and rightmost integer points
1388  between (lmpx, lmpy) and (rmpx,rmpy) that meet v and are above
1389  nv, the line between (lmpx,lmpy) and (rmpx,rmpy). Let them be
1390  (ilmpx, ilmpy) and (irmpx, irmpy).
1391 
1392  If ilmpx>irmpx, on constraint is enough, nv, because no
1393  intermediate points exist.
1394 
1395  If ilmpx=irmpx, two constraints are necessary and they are
1396  defined by the two couples of points ((lmpx,lmpy),(ilmpx,
1397  ilmpy) and ((irmpx, irmpy), (rmpx, rmpy)).
1398 
1399  Else ilmpx<irmpx, three constraints are necessary and they are
1400  defined by the segments delimited by the four points, (lmpx,
1401  lmpy), (ilmpx, ilmpy), (irmpx, irmpy) and (rmpx,rmpy). Only if
1402  no new intermediate point exists between the two intermediate
1403  points.
1404 
1405  Test case: slope04.c
1406  */
1407  /* Default option */
1408  if(false) {
1409  Pvecteur nv = vect_copy(v);
1410  ineq = contrainte_make(nv); // equivalent to doing nothing
1411  fprintf(stderr, "Not implemented yet\n");
1412  }
1413  else {
1414  /*
1415  ineq = find_intermediate_constraints(v, x, y,
1416  lmpx, lmpy,
1417  rmpx, rmpy);
1418  */
1420  lmpx, lmpy,
1421  rmpx, rmpy);
1422  }
1423  }
1424  return ineq;
1425 }
1426 ␌
1427 /* Perform a reverse change of base to go back into the source code
1428  frame */
1430  Variable x, Variable y)
1431 {
1432  if(cb&4) {
1433  Value a = vect_coeff(x, v);
1434  vect_chg_coeff(&v, x, value_uminus(a));
1435  }
1436  if(cb&2) {
1437  Value b = vect_coeff(y, v);
1438  vect_chg_coeff(&v, y, value_uminus(b));
1439  }
1440 }
1441 
1442 /* Perform the inverse change of basis and update the intervals for
1443  later checks. */
1445  Variable x, Variable y,
1446  Value *x_min, Value *x_max,
1447  Value *y_min, Value *y_max
1448 )
1449 {
1450  Pcontrainte ceq;
1451  for(ceq=eq; !CONTRAINTE_UNDEFINED_P(ceq); ceq = contrainte_succ(ceq)) {
1452  Pvecteur v = contrainte_vecteur(ceq);
1454  }
1455  if(cb&4)
1456  negate_value_interval(x_min,x_max);
1457  if(cb&2)
1458  negate_value_interval(y_min,y_max);
1459 }
1460 ␌
1461 /* debug function: check that all 2-D constraints c in ineq are equivalent
1462  to contraint v on interval [x_min,x_max].
1463 
1464  It is assumed that ineq contains 1, 2 or three constraints.
1465  */
1467  Variable x, Variable y,
1468  Value x_min, Value x_max)
1469 {
1470  Value a_v = vect_coeff(x,v);
1471  Value b_v = vect_coeff(y,v);
1472  Value c_v = vect_coeff(TCST,v);
1473  bool upper_p = value_pos_p(b_v);
1474  assert(a_v!=0 && b_v!=0);
1475 
1476  // FI: a tighter bound could be found with min(delta_x-1, delta_y-1);
1477 #define MAX_NUMBER_OF_CONSTRAINTS (x_max-x_min)
1481 
1482  Value i;
1483  int n=0; // number of constraints in ineq
1484  Pcontrainte cc;
1485 
1486  for(cc=ineq;
1488  cc = contrainte_succ(cc)) {
1489  Pvecteur cv = contrainte_vecteur(cc);
1490  /* FI: if the constraint list were properly built, there would be
1491  no NULL vector in the list... */
1492  if(!VECTEUR_NUL_P(cv)) {
1493  a[n] = vect_coeff(x, cv);
1494  b[n] = vect_coeff(y, cv);
1495  c[n] = vect_coeff(TCST, cv);
1496  if(upper_p) {
1497  assert(value_posz_p(b[n]));
1498  }
1499  else {
1500  assert(value_negz_p(b[n]));
1501  }
1502  // We could also assert a[n]<=a_v and b[n]<=b_v
1503  n++;
1504  }
1505  }
1506 
1507  /* FI: linked_regions02; I do not understand whu a NULL constraint
1508  is present in ineq... */
1510  assert(n>0);
1511  assert(value_gt(x_min, VALUE_MIN));
1512  assert(value_gt(VALUE_MAX, x_max));
1513  assert(value_ge(x_max,x_min));
1514 
1515  /* Scan the x interval */
1516  for(i=x_min;value_le(i,x_max); i++) {
1517  /* compute bound for y according to v */
1518  Value y_v = upper_p? value_pdiv(-a_v*i-c_v, b_v) :
1519  value_pdiv(a_v*i+c_v-b_v-1, -b_v);
1520  Value y_ineq = upper_p? VALUE_MAX:VALUE_MIN;
1521  int j;
1522  for(j=0;j<n;j++) {
1523  Value y_j = upper_p? value_pdiv(-a[j]*i-c[j], b[j]) :
1524  value_pdiv(a[j]*i+c[j]-b[j]-1, -b[j]);
1525  if(upper_p)
1526  // Decrease the upper bound
1527  y_ineq = (y_ineq>y_j)? y_j : y_ineq;
1528  else
1529  // Increase the lower bound
1530  y_ineq = (y_ineq<y_j)? y_j : y_ineq;
1531  }
1532  if(y_ineq!=y_v) {
1533  fprintf(stderr,
1534  "Discrepancy at x=%lld: initial bound=%lld, new bound=%lld\n",
1535  (long long int) i,
1536  (long long int) y_v, (long long int) y_ineq);
1537  fprintf(stderr, "Initial constraint: ");
1538  vect_dump(v);
1539  fprintf(stderr, "\nNew constraints: ");
1540  inegalites_dump(ineq);
1541  abort();
1542  }
1543  }
1544 }
1545 ␌
1546 /* If at least one of the coefficients of constraint v == ax+by<=c are
1547  * greater that the intervals of the bounding box, reduce them to be
1548  * at most the the size of the intervals.
1549  *
1550  * This is similar to a Gomory cut, but we apply the procedure to 2-D
1551  * constraints only.
1552  *
1553  * Three steps:
1554  *
1555  * 0. Check eligibility: 2-D constraint and either |a|>y_max-y_min or
1556  * |b|>x_max-x_min. Assume or ensure that gcd(a,b)=1. This step must
1557  * be performed by the caller.
1558  *
1559  * 1. Perform a change of basis M to obtain (x,y)^t = M(x',y')^t and
1560  * (a',b') = (a,b)M with b'>-a'>0
1561  *
1562  * 2. Simplify constraint a'x'+b'y'<=c. The corresponding line is in
1563  * the first quadrant and its slope is strictly less than 1 and
1564  * greater than 0. Up to three new constraints may be generated.
1565  *
1566  * 3. Apply M^-1 to the new contraints on (x',y') in order to obtain
1567  * constraints on x and y, and return the constraint list.
1568  */
1570  Pvecteur l,
1571  Pvecteur lb,
1572  Pvecteur u,
1573  Pvecteur ub)
1574 {
1576  Pvecteur nv = VECTEUR_NUL; // normalized constraint
1577  int cb = 0; // memorize the change of basis
1578  /* Beware of overflows if you compute the widths of these intervals... */
1579  Value x_min=VALUE_MIN, x_max=VALUE_MAX, y_min=VALUE_MIN, y_max=VALUE_MAX;
1580  Variable x, y;
1581 
1582  ifscdebug(1) {
1584 
1585  fprintf(stderr, "Initial constraint:\n");
1586  vect_fprint(stderr, v, variable_debug_name);
1587  }
1588 
1589  nv = compute_x_and_y_bounds(v, l, lb, u, ub, &x, &y, &x_min, &x_max, &cb);
1590 
1591  ifscdebug(1) {
1592  fprintf(stderr, "Bounds for the first variable %s: ", variable_debug_name(x));
1593  fprintf(stderr, "x_min=%lld, x_max=%lld\n", (long long int) x_min, (long long int) x_max);
1594  }
1595 
1596  if(false)
1598  &x, &y,
1599  &x_min, &x_max,
1600  &y_min, &y_max);
1601 
1602  ineq =
1604  x, x_min, x_max,
1605  y, y_min, y_max);
1606 
1607  /* Perform the reverse change of basis cb on constraints in
1608  constraint list ineq */
1609  if(cb!=0) {
1611  &x_min, &x_max, &y_min, &y_max);
1612  }
1613 
1614  if(!CONTRAINTE_UNDEFINED_P(ineq))
1615  check_coefficient_reduction(v, ineq, x, y, x_min, x_max);
1616 
1617  return ineq;
1618 }
1619 
1620 /* Add the constraints defined by cb, lb and ub in Psysteme ps
1621  *
1622  * This is necessary when all constraints redundant wrt the bounding
1623  * box are removed, for instance to detect simple equalities (x<=2 &&
1624  * x>=2) and to remove redundant constraints (x<=2 && x<=2).
1625  */
1626 static
1628  Pvecteur l, Pvecteur u)
1629 {
1630  Pvecteur cv;
1633 
1634  /* add the equalities */
1635  for(cv=cb; !VECTEUR_UNDEFINED_P(cv); cv = vecteur_succ(cv)) {
1636  Variable x = vecteur_var(cv);
1637  Value b = vect_coeff(x, l); // u might be used as well
1638  Pcontrainte c = contrainte_make_1D(VALUE_ONE, x, b, true);
1639  contrainte_succ(c) = eq;
1640  eq = c;
1641  }
1642 
1643  /* Add the upper bounds */
1644  for(cv=ub; !VECTEUR_UNDEFINED_P(cv); cv = vecteur_succ(cv)) {
1645  Variable x = vecteur_var(cv);
1646  if(!base_contains_variable_p(cb,x)) {
1647  Value b = vect_coeff(x, u);
1648  Pcontrainte c = contrainte_make_1D(VALUE_ONE, x, b, true);
1649  contrainte_succ(c) = ineq;
1650  ineq = c;
1651  }
1652  }
1653 
1654  /* Add the lower bounds */
1655  for(cv=lb; !VECTEUR_UNDEFINED_P(cv); cv = vecteur_succ(cv)) {
1656  Variable x = vecteur_var(cv);
1657  if(!base_contains_variable_p(cb,x)) {
1658  Value b = vect_coeff(x, l);
1659  Pcontrainte c = contrainte_make_1D(VALUE_ONE, x, b, false);
1660  contrainte_succ(c) = ineq;
1661  ineq = c;
1662  }
1663  }
1664 
1665  sc_add_egalites(ps, eq);
1666  sc_add_inegalites(ps, ineq);
1667  assert(sc_consistent_p(ps));
1668  return ps;
1669 }
1670 
1671 ␌
1672 /* Eliminate trivially redundant integer constraint using a O(n x d^2)
1673  * algorithm, where n is the number of constraints and d the
1674  * dimension. And possibly detect an non feasible constraint system
1675  * ps. Also, reduce the coefficients of 2-D constraints when possible.
1676  *
1677  * This function must not be used to decide emptyness when checking
1678  * redundancy with Fourier-Motzkin because this may increase the
1679  * initial rational convex polyhedron. No integer point is added, but
1680  * rational points may be added, which may lead to an accuracy loss
1681  * when a convex hull is performed.
1682  *
1683  * Principle: If two constant vectors, l et u, such that l<=x<=u,
1684  * where x is the vector representing all variables, then the bound b
1685  * of any constraint a.x<=b can be compared to a.k where k_i=u_i if
1686  * a_i is positive, and k_i=l_i elsewhere. The constraint can be
1687  * eliminated if a.k<=b.
1688  *
1689  * It is not necessary to have upper and lower bounds for all
1690  * components of x to compute the redundancy condition. It is
1691  * sufficient to meet the condition:
1692  *
1693  * \forall i s.t. a_i>0 \exists u_i and \forall i s.t. a_i<0 \exists b_i
1694  *
1695  * The complexity is O(n x d) where n is the number of constraints and
1696  * d the dimension, vs O(n^2 x d^2) for some other normalization
1697  * functions.
1698  *
1699  * With l and u available, we also use c, the vector containing
1700  * constant variables. The variables are substituted by their constant
1701  * values in equations and inequalities.
1702  *
1703  * The normalization is not rational. It assumes that only integer
1704  * points are relevant. For instance, 2x<=3 is reduced to x<=1. It
1705  * would be possible to use the same function in rational, but the
1706  * divisions should be removed, the bounding box would require six
1707  * vectors, with two new vectors used to keep the variable
1708  * coefficients, here 2, and the comparisons should be replaced by
1709  * rational comparisons. Quite a lot of changes, although the general
1710  * structure would stay the same.
1711  *
1712  * This function was developped to cope successfully with
1713  * Semantics/type03. The projection performed in
1714  * transformer_intra_to_inter() explodes without this function.
1715  *
1716  * Note that the upper and lower bounds, u and l, are stored in Pvecteur in an
1717  * unusual way. The coefficients are used to store the constants.
1718  *
1719  * Note also that constant terms are stored in the lhs in linear, but
1720  * they are computed here as rhs. In other words, x - 2 <=0 is the
1721  * internal storage, but the upper bound is 2 as in x<=2.
1722  *
1723  * Note that the simple inequalities used to compute the bounding box
1724  * cannot be eliminated. Hence, their exact copies are also
1725  * preserved. Another redundancy test is necessary to get rid of
1726  * them. They could be eliminated when computing the bounding box if
1727  * the function updating the bounds returned the information. Note
1728  * that non feasability cannot be checked because the opposite bound
1729  * vectors are not passed. If they were, then no simple return code
1730  * would do. THIS HAS BEEN CHANGED.
1731  *
1732  * The same is true for equations. But the function updating the
1733  * bounds cannot return directly two pieces of information: the
1734  * constraint system is empty or the constraint is redundant.
1735  *
1736  * It would be easier to simplify all constraints and then to add the
1737  * bounding box constraints. Constraints must be normalized initially
1738  * to avoid destroying useful constraints. For instance, 2i<=99
1739  * generates i<=49 whicg proves 21<=99 striclty redundant. THIS HAS
1740  * BEEN PARTIALLY CHANGED.
1741  *
1742  * Software engineering remarks
1743  *
1744  * This function could be renamed sc_bounded_redundancy_elimination()
1745  * and be placed into one of the two files, sc_elim_redund.c or
1746  * sc_elim_simple_redund.c. It just happened that redundancy
1747  * elimination uses normalization and gdb led me to
1748  * sc_normalization() when I tried to debug Semantics/type03.c.
1749  *
1750  * This function could be split into three functions, one to compute
1751  * the bounding box, one to simplify a constraint system according to
1752  * a bounding box and the third one calling those two, and the
1753  * coefficient reduction function, which also uses the bounding
1754  * box.
1755  *
1756  * This split could be useful when projecting a system because the
1757  * initial bounding box remains valid all along the projection, no
1758  * matter that happens to the initial constraint. However, the
1759  * bounding box might be improved with the projections... Since the
1760  * bounding box computation is fast enough, the function was not split
1761  * and the transformer (see Linear/C3 Library) projection uses it at each
1762  * stage. Note that the bouding box may also disappear via overflows
1763  * and redundancy detection. See for instance the disparition of
1764  * declaration constraints in convex array regions when the
1765  * corresponding option is set to true.
1766  */
1768 {
1769  /* Compute the trivial upper and lower bounds for the systeme
1770  basis. Since we cannot distinguish between "exist" and "0", we
1771  need two extra basis to know if the bound exists or not */
1772  //Pbase b = sc_base(ps);
1773  Pvecteur u = VECTEUR_NUL;
1774  Pvecteur l = VECTEUR_NUL;
1775  Pbase ub = BASE_NULLE;
1776  Pbase lb = BASE_NULLE;
1777  Pvecteur cb = VECTEUR_NUL;
1778  Pcontrainte eq = CONTRAINTE_UNDEFINED; /* can be an equation or an inequality */
1779  bool empty_p = false;
1780 
1781  assert(sc_consistent_p(ps));
1782 
1783  /* First look for bounds in equalities, although they may have been
1784  exploited otherwise */
1785  for(eq = sc_egalites(ps); !CONTRAINTE_UNDEFINED_P(eq) && !empty_p;
1786  eq = contrainte_succ(eq)) {
1787  empty_p = !egalite_normalize(eq);
1789  int n = vect_size(v);
1790  Value k;
1791  if(n==1) {
1792  Variable var = vecteur_var(v);
1793  update_lower_and_upper_bounds(&u, &ub, &l, &lb, var, VALUE_ZERO);
1794  }
1795  else if(n==2 && (k=vect_coeff(TCST,v))!=0) {
1796  Variable var = vecteur_var(v);
1797  Value c = vecteur_val(v);
1798 
1799  if(var==TCST) {
1800  Pvecteur vn = vecteur_succ(v);
1801  var = vecteur_var(vn);
1802  c = vecteur_val(vn);
1803  }
1804 
1805  /* FI: I do not trust the modulo operator */
1806  if(c<0) {
1807  c = -c;
1808  k = -k;
1809  }
1810 
1811  Value r = modulo(k,c);
1812  if(r==0) {
1813  /* FI: value_div() instead of value_pdiv(); reason? */
1814  Value b_var = -value_div(k,c);
1815  empty_p = update_lower_and_upper_bounds(&u, &ub, &l, &lb, var, b_var);
1816  }
1817  else {
1818  /* ps is empty with two contradictory equations supposedly trapped earlier */
1819  empty_p = true;;
1820  }
1821  }
1822  }
1823 
1824  if(!empty_p) {
1825  /* Secondly look for bounds in inequalities */
1826  for(eq=sc_inegalites(ps); !CONTRAINTE_UNDEFINED_P(eq)&& !empty_p;
1827  eq = contrainte_succ(eq)) {
1828  /* This normalization is necessary in case a division is
1829  involved, or a useful constraint may be removed. For instance
1830  2*i<=99 generates i<=49 which make 2*i<=99 strictly
1831  redundant. */
1832  empty_p = !inegalite_normalize(eq);
1834  int n = vect_size(v);
1835  Value k = VALUE_ZERO;
1836  if(n==1) {
1837  Variable var = vecteur_var(v);
1838  if(var!=TCST) {
1839  /* The variable is bounded by zero */
1840  Value c = vecteur_val(v);
1841  if(value_pos_p(c)) /* upper bound */
1843  else /* lower bound */
1845  }
1846  }
1847  else if(n==2 && (k=vect_coeff(TCST,v))!=0) {
1848  Variable var = vecteur_var(v);
1849  Value c = vecteur_val(v);
1850  if(var==TCST) {
1851  Pvecteur vn = vecteur_succ(v);
1852  var = vecteur_var(vn);
1853  c = vecteur_val(vn);
1854  }
1855  /* FI: I not too sure how div and pdiv operate nor on what I
1856  need here... This explains why the divisions are replicated
1857  after the test on the sign of the coefficient. */
1858  if(value_pos_p(c)) { /* upper bound */
1859  Value b_var = value_pdiv(-k,c);
1860  update_lower_or_upper_bound(&u, &ub, var, b_var, !value_pos_p(c));
1861  }
1862  else { /* lower bound */
1863  Value b_var = value_pdiv(k-c-1,-c);
1864  update_lower_or_upper_bound(&l, &lb, var, b_var, !value_pos_p(c));
1865  }
1866  }
1867  }
1868 
1869  /* Check that the bounding box is not empty because a lower bound
1870  is strictly greater than the corresponding upper bound. This
1871  could be checked above each time a new bound is defined or
1872  redefined. Also, build the constant base, cb */
1873  Pvecteur vc;
1874  for(vc=ub; !VECTEUR_UNDEFINED_P(vc) && !empty_p; vc=vecteur_succ(vc)) {
1875  Variable var = vecteur_var(vc);
1876  Value upper = vect_coeff(var, u);
1877  if(value_notzero_p(vect_coeff(var, lb))) {
1878  Value lower = vect_coeff(var, l);
1879  if(lower>upper)
1880  empty_p = true;
1881  else if(lower==upper) {
1882  vect_add_elem(&cb, var, VALUE_ONE);
1883  }
1884  }
1885  }
1886 
1887  /* The upper and lower bounds should be printed here for debug */
1888  ifscdebug(1) {
1889  if(!VECTEUR_NUL_P(ub) || !VECTEUR_NUL_P(lb)) {
1890  if(empty_p) {
1891  fprintf(stderr, "sc_bounded_normalization: empty bounding box\n");
1892  }
1893  else {
1894  fprintf(stderr, "sc_bounded_normalization: "
1895  "base for upper bound and upper bound:\n");
1896  vect_dump(ub);
1897  vect_dump(u);
1898  fprintf(stderr, "sc_bounded_normalization: "
1899  "base for lower bound and lower bound:\n");
1900  vect_dump(lb);
1901  vect_dump(l);
1902  fprintf(stderr, "sc_bounded_normalization: constraints found:\n");
1903  /* Impression par intervalle, avec verification l<=u quand l et u
1904  sont tous les deux disponibles */
1905  Pvecteur vc;
1906  for(vc=ub; !VECTEUR_UNDEFINED_P(vc); vc=vecteur_succ(vc)) {
1907  Variable var = vecteur_var(vc);
1908  Value upper = vect_coeff(var, u);
1909  if(vect_coeff(var, lb)!=0) {
1910  Value lower = vect_coeff(var, l);
1911  if(lower<upper)
1912  fprintf(stderr, "%d <= %s <= %d\n", (int) lower,
1913  variable_debug_name(var),
1914  (int) upper);
1915  else if(lower==upper)
1916  fprintf(stderr, "%s == %d\n", variable_debug_name(var),
1917  (int) upper);
1918  else /* lower>upper */
1919  abort(); // should have been filtered above
1920  }
1921  else {
1922  fprintf(stderr, "%s <= %d\n", variable_debug_name(var),
1923  (int) upper);
1924  }
1925  }
1926  for(vc=lb; !VECTEUR_UNDEFINED_P(vc); vc=vecteur_succ(vc)) {
1927  Variable var = vecteur_var(vc);
1928  Value lower = vect_coeff(var, l);
1929  if(vect_coeff(var, ub)==0) {
1930  fprintf(stderr, "%d <= %s \n", (int) lower,
1931  variable_debug_name(var));
1932  }
1933  }
1934  }
1935  }
1936  }
1937 
1938  if(!empty_p) {
1939  /* Simplify equalities using cb and l */
1940  if(base_dimension(cb) >=1) {
1941  for(eq=sc_egalites(ps); !CONTRAINTE_UNDEFINED_P(eq);
1942  eq = contrainte_succ(eq))
1944  }
1945 
1946  /* Check inequalities for redundancy with respect to ub and lb,
1947  if ub and lb contain a minum of information. Also simplify
1948  constraints using cb when possible. */
1949  if(base_dimension(ub)+base_dimension(lb) >=1) {
1950  for(eq=sc_inegalites(ps);
1951  !CONTRAINTE_UNDEFINED_P(eq) && !empty_p; eq = contrainte_succ(eq)) {
1952 
1954 
1956  int n = vect_size(v);
1957  Pvecteur vc;
1958  Value nlb = VALUE_ZERO; /* new lower bound: useful to check feasiblity */
1959  Value nub = VALUE_ZERO; /* new upper bound */
1960  Value ob = VALUE_ZERO; /* old bound */
1961  bool lb_failed_p = false; /* a lower bound cannot be estimated */
1962  bool ub_failed_p = false; /* the bounding box does not contain
1963  enough information to check
1964  redundancy with the upper bound */
1965 
1966  /* Try to compute the bounds nub and nlb implied by the bounding box */
1967  for(vc=v; !VECTEUR_NUL_P(vc) && !(ub_failed_p&&lb_failed_p);
1968  vc = vecteur_succ(vc)) {
1969  Variable var = vecteur_var(vc);
1970  Value c = vecteur_val(vc);
1971  if(var==TCST) { /* I assume the constraint to be consistent
1972  with only one coefficient per dimension */
1973  value_assign(ob, value_uminus(c)); /* move the bound to the
1974  right hand side of the
1975  inequality */
1976  }
1977  else {
1978  if(value_pos_p(c)) { /* an upper bound of var is needed */
1979  if(vect_coeff(var, ub)!=0) { /* the value macro should be used */
1980  Value ub_var = vect_coeff(var, u);
1981  value_addto(nub, value_mult(c, ub_var));
1982  }
1983  else {
1984  ub_failed_p = true;
1985  }
1986  if(vect_coeff(var, lb)!=0) {
1987  Value lb_var = vect_coeff(var, l);
1988  value_addto(nlb, value_mult(c, lb_var));
1989  //fprintf(stderr, "c=%lld, lb_var=%lld, nlb=%d\n", c, lb_var, nlb);
1990  }
1991  else {
1992  lb_failed_p = true;
1993  }
1994  }
1995  else { /* c<0 : a lower bound is needed for var*/
1996  if(vect_coeff(var, lb)!=0) {
1997  Value lb_var = vect_coeff(var, l);
1998  value_addto(nub, value_mult(c, lb_var));
1999  }
2000  else {
2001  ub_failed_p = true;
2002  }
2003  if(vect_coeff(var, ub)!=0) {
2004  Value ub_var = vect_coeff(var, u);
2005  value_addto(nlb, value_mult(c, ub_var));
2006  //fprintf(stderr, "c=%lld, ub_var=%lld, nlb=%d\n", c, ub_var, nlb);
2007  }
2008  else {
2009  lb_failed_p = true;
2010  }
2011  }
2012  }
2013  }
2014 
2015  /* If the new bound nub is tighter, nub <= ob, ob-nub >= 0 */
2016  if(!ub_failed_p) {
2017  /* Do not destroy the constraints defining the bounding box */
2018  bool posz_p = value_posz_p(value_minus(ob,nub));
2019  bool pos_p = value_pos_p(value_minus(ob,nub));
2020  if( posz_p
2021  || (n>2 && posz_p)
2022  || (n==2 && value_zero_p(vect_coeff(TCST, v)) && posz_p)
2023  || (n==2 && value_notzero_p(vect_coeff(TCST, v)) && pos_p)
2024  || (n==1 && value_zero_p(vect_coeff(TCST, v)) && pos_p)) {
2025  /* The constraint eq is redundant */
2026  ifscdebug(1) {
2027  fprintf(stderr, "Redundant constraint:\n");
2028  vect_dump(v);
2029  }
2031  }
2032  else { /* Preserve this constraint */
2033  ;
2034  }
2035  }
2036 
2037  /* The new estimated lower bound must be less than the upper
2038  bound of the constraint, or the system is empty.*/
2039  if(!lb_failed_p) { /* the estimated lower bound, nlb, must
2040  be less or equal to the effective
2041  upper bound ob: nlb <= ob, 0<=ob-nlb */
2042  /* if ob==nlb, an equation has been detected but it is
2043  hard to exploit here */
2044  bool pos_p = value_posz_p(value_minus(ob,nlb));
2045  if(!pos_p) /* to have a nice breakpoint location */
2046  empty_p = true;
2047  }
2048  }
2049  }
2050  }
2051  }
2052 
2053  /* Try to reduce coefficients of 2-D constraints when one variable
2054  belongs to an interval. */
2055  if(!empty_p) {
2057  for(eq=sc_inegalites(ps);
2058  !CONTRAINTE_UNDEFINED_P(eq) && !empty_p; eq = contrainte_succ(eq)) {
2059  (void) contrainte_normalize(eq, false);
2062  Pcontrainte nc = reduce_coefficients_with_bounding_box(v, l, lb, u, ub);
2063  if(!CONTRAINTE_UNDEFINED_P(nc)) {
2064  ifscdebug(1) {
2065  fprintf(stderr, "New constraints:\n");
2066  inegalites_dump(nc);
2067  }
2068  /* Remove constraint v */
2070  /* Add the new constraints to the new constraint list, ncl */
2071  ncl = contrainte_append(ncl, nc);
2072  }
2073  else {
2074  empty_p = true;
2075  }
2076  }
2077  }
2078  /* add the new constraint list to the system */
2080  assert(sc_consistent_p(ps));
2081  sc_add_inegalites(ps, ncl);
2082  assert(sc_consistent_p(ps));
2083  }
2084 
2085  if(empty_p) {
2086  Psysteme ns = sc_empty(sc_base(ps));
2087  sc_base(ps) = BASE_NULLE;
2088  sc_rm(ps);
2089  ps = ns;
2090  }
2091  else if(base_dimension(cb)>=1 || base_dimension(lb)>=1 || base_dimension(ub)>=1) {
2092  sc_elim_empty_constraints(ps, true);
2093  sc_elim_empty_constraints(ps, false);
2094  ps = add_bounding_box_constraints(ps, cb, lb, ub, l, u);
2095  }
2096 
2097  /* Free all elements of the bounding box */
2098  vect_rm(l), vect_rm(lb), vect_rm(u), vect_rm(ub);
2099  vect_rm(cb);
2100 
2101  assert(sc_consistent_p(ps));
2102  return ps;
2103 }
2104 ␌
2105 /* Psysteme sc_normalize(Psysteme ps): normalisation d'un systeme d'equation
2106  * et d'inequations lineaires en nombres entiers ps, en place.
2107  *
2108  * Normalisation de chaque contrainte, i.e. division par le pgcd des
2109  * coefficients (cf. ?!? )
2110  *
2111  * Verification de la non redondance de chaque contrainte avec les autres:
2112  *
2113  * Pour les egalites, on elimine une equation si on a un systeme d'egalites
2114  * de la forme :
2115  *
2116  * a1/ Ax - b == 0, ou b1/ Ax - b == 0,
2117  * Ax - b == 0, b - Ax == 0,
2118  *
2119  * ou c1/ 0 == 0
2120  *
2121  * Pour les inegalites, on elimine une inequation si on a un systeme de
2122  * contraintes de la forme :
2123  *
2124  * a2/ Ax - b <= c, ou b2/ 0 <= const (avec const >=0)
2125  * Ax - b <= c
2126  *
2127  * ou c2/ Ax == b,
2128  * Ax <= c avec b <= c,
2129  *
2130  * ou d2/ Ax <= b,
2131  * Ax <= c avec c >= b ou b >= c
2132  *
2133  * Il manque une elimination de redondance particuliere pour traiter
2134  * les booleens. Si on a deux vecteurs constants, l et u, tels que
2135  * l<=x<=u, alors la borne b de n'importe quelle contrainte a.x<=b
2136  * peut etre comparee a a.k ou k_i=u_i si a_i est positif et k_i=l_i
2137  * sinon. La contrainte a peut etre eliminee si a.k <= b. Si des
2138  * composantes de x n'aparaissent dans aucune contrainte, on ne
2139  * dispose en consequence pas de bornes, mais ca n'a aucune
2140  * importance. On veut donc avoir une condition pour chaque
2141  * contrainte: forall i s.t. a.i!=0 \exists l_i and b_i
2142  * s.t. l_i<=x_i<=b_i. Voir sc_bounded_normalization().
2143  *
2144  * sc_normalize retourne NULL quand la normalisation a montre que le systeme
2145  * etait non faisable
2146  *
2147  * BC: now returns sc_empty when not feasible to avoid unecessary copy_base
2148  * in caller.
2149  *
2150  * FI: should check the input for sc_empty_p()
2151  */
2153 {
2154  Pcontrainte eq;
2155  bool is_sc_fais = true;
2156 
2157  /* I do not want to disturb every pass of Linear/C3 Library that uses directly
2158  * or indirectly sc_normalize. Since sc_bounded_normalization()
2159  * has been developped specifically for transformer_projection(),
2160  * it is called directly from the function implementing
2161  * transformer_projection(). But it is not sufficient for type03.
2162  */
2163  static int francois=1;
2164  if(francois==1 && ps && !sc_empty_p(ps) && !sc_rn_p(ps))
2165  ps = sc_bounded_normalization(ps);
2166 
2167  /* FI: this takes (a lot of) time but I do not know why: O(n^2)? */
2168  ps = sc_safe_kill_db_eg(ps);
2169 
2170  if (ps && !sc_empty_p(ps) && !sc_rn_p(ps)) {
2171  for (eq = ps->egalites;
2172  (eq != NULL) && is_sc_fais;
2173  eq=eq->succ) {
2174  /* normalisation de chaque equation */
2175  if (eq->vecteur) {
2177  if ((is_sc_fais = egalite_normalize(eq))== true)
2178  is_sc_fais = sc_elim_simple_redund_with_eq(ps,eq);
2179  }
2180  }
2181  for (eq = ps->inegalites;
2182  (eq!=NULL) && is_sc_fais;
2183  eq=eq->succ) {
2184  if (eq->vecteur) {
2186  if ((is_sc_fais = inegalite_normalize(eq))== true)
2187  is_sc_fais = sc_elim_simple_redund_with_ineq(ps,eq);
2188  }
2189  }
2190 
2191  ps = sc_safe_kill_db_eg(ps);
2192  if (!sc_empty_p(ps))
2193  {
2194  sc_elim_empty_constraints(ps, true);
2195  sc_elim_empty_constraints(ps, false);
2196  }
2197  }
2198 
2199  if (!is_sc_fais)
2200  {
2201  /* FI: piece of code that will appear in many places... How
2202  * can we call it: empty_sc()? sc_make_empty()? sc_to_empty()?
2203  */
2204  Psysteme new_ps = sc_empty(sc_base(ps));
2205  sc_base(ps) = BASE_UNDEFINED;
2206  sc_rm(ps);
2207  ps = new_ps;
2208  }
2209  return(ps);
2210 }
2211 
2212 /* Psysteme sc_normalize2(Psysteme ps): normalisation d'un systeme d'equation
2213  * et d'inequations lineaires en nombres entiers ps, en place.
2214  *
2215  * Normalisation de chaque contrainte, i.e. division par le pgcd des
2216  * coefficients (cf. ?!? )
2217  *
2218  * Propagation des constantes definies par les equations dans les
2219  * inequations. E.g. N==1.
2220  *
2221  * Selection des variables de rang inferieur quand il y a ambiguite: N==M.
2222  * M is used wherever possible.
2223  *
2224  * Selection des variables eliminables exactement. E.g. N==4M. N is
2225  * substituted by 4M wherever possible. Ceci permet de raffiner les
2226  * constantes dans les inegalites.
2227  *
2228  * Les equations de trois variables ou plus ne sont pas utilisees pour ne
2229  * pas rendre les inegalites trop complexes.
2230  *
2231  * Verification de la non redondance de chaque contrainte avec les autres.
2232  *
2233  * Les contraintes sont normalisees par leurs PGCDs. Les constantes sont
2234  * propagees dans les inegalites. Les paires de variables equivalentes
2235  * sont propagees dans les inegalites en utilisant la variable de moindre
2236  * rang dans la base.
2237  *
2238  * Pour les egalites, on elimine une equation si on a un systeme d'egalites
2239  * de la forme :
2240  *
2241  * a1/ Ax - b == 0, ou b1/ Ax - b == 0,
2242  * Ax - b == 0, b - Ax == 0,
2243  *
2244  * ou c1/ 0 == 0
2245  *
2246  * Si on finit avec b==0, la non-faisabilite est detectee.
2247  *
2248  * Pour les inegalites, on elimine une inequation si on a un systeme de
2249  * contraintes de la forme :
2250  *
2251  * a2/ Ax - b <= c, ou b2/ 0 <= const (avec const >=0)
2252  * Ax - b <= c
2253  *
2254  * ou c2/ Ax == b,
2255  * Ax <= c avec b <= c,
2256  *
2257  * ou d2/ Ax <= b,
2258  * Ax <= c avec c >= b ou b >= c
2259  *
2260  * Les doubles inegalites syntaxiquement equivalentes a une egalite sont
2261  * detectees: Ax <= b, Ax >= b
2262  *
2263  * Si deux inegalites sont incompatibles, la non-faisabilite est detectee:
2264  * b <= Ax <= c et c < b.
2265  *
2266  * sc_normalize retourne NULL/SC_EMPTY quand la normalisation a montre que
2267  * le systeme etait non faisable.
2268  *
2269  * Une grande partie du travail est effectue dans sc_elim_db_constraints()
2270  *
2271  * FI: a revoir de pres; devrait retourner SC_EMPTY en cas de non faisabilite
2272  *
2273  */
2275  volatile Psysteme ps)
2276 {
2277  volatile Pcontrainte eq;
2278 
2279  ps = sc_elim_double_constraints(ps);
2280  sc_elim_empty_constraints(ps, true);
2281  sc_elim_empty_constraints(ps, false);
2282 
2283  if (!SC_UNDEFINED_P(ps)) {
2284  Pbase b = sc_base(ps);
2285 
2286  /* Eliminate variables linked by a two-term equation. Preserve integer
2287  information or choose variable with minimal rank in basis b if some
2288  ambiguity exists. */
2289  volatile Psysteme ps_backup = sc_copy(ps);
2290  bool failure_p = false;
2291  for (eq = ps->egalites; (!SC_UNDEFINED_P(ps) && eq != NULL); eq=eq->succ) {
2293  if(((vect_size(veq)==2) && (vect_coeff(TCST,veq)==VALUE_ZERO))
2294  || ((vect_size(veq)==3) && (vect_coeff(TCST,veq)!=VALUE_ZERO))) {
2295  Pbase bveq = make_base_from_vect(veq);
2296  Variable v1 = vecteur_var(bveq);
2297  Variable v2 = vecteur_var(vecteur_succ(bveq));
2298  volatile Variable v = VARIABLE_UNDEFINED;
2299  Value a1 = value_abs(vect_coeff(v1, veq));
2300  Value a2 = value_abs(vect_coeff(v2, veq));
2301 
2302  if(a1==a2) {
2303  /* Then, after normalization, a1 and a2 must be one */
2304  if(rank_of_variable(b, v1) < rank_of_variable(b, v2)) {
2305  v = v2;
2306  }
2307  else {
2308  v = v1;
2309  }
2310  }
2311  else if(value_one_p(a1)) {
2312  v = v1;
2313  }
2314  else if(value_one_p(a2)) {
2315  v = v2;
2316  }
2317  if(VARIABLE_DEFINED_P(v)) {
2318  /* An overflow is unlikely... but it should be handled here
2319  I guess rather than be subcontracted? */
2321  {
2322  /* The substitution of the variable defined by "eq" by its
2323  value leads to an overflow in one some unknown
2324  constraint of "ps". It might be better to trap the
2325  overflow at a lower level, when you know which
2326  constraint fails because the constraint could be
2327  removed altogether. */
2328  sc_rm(ps); /* */
2329  ps = ps_backup;
2330  failure_p = true;
2331  break;
2332  }
2333  TRY
2334  {
2335  sc_simple_variable_substitution_with_eq_ofl_ctrl(ps, eq, v, OFL_CTRL);
2336  }
2338  }
2339  }
2340  }
2341  if(!failure_p) {
2342  sc_rm(ps_backup);
2343  }
2344  }
2345 
2346  if (!SC_UNDEFINED_P(ps)) {
2347  /* Propagate constant definitions, only once although a triangular
2348  system might require n steps is the equations are in the worse order */
2349  volatile Psysteme ps_backup = sc_copy(ps);
2350  bool failure_p = false;
2351  for (eq = ps->egalites; (!SC_UNDEFINED_P(ps) && eq != NULL); eq=eq->succ) {
2353  if(((vect_size(veq)==1) && (vect_coeff(TCST,veq)==VALUE_ZERO))
2354  || ((vect_size(veq)==2) && (vect_coeff(TCST,veq)!=VALUE_ZERO))) {
2355  volatile Variable v = term_cst(veq)?
2356  vecteur_var(vecteur_succ(veq)) : vecteur_var(veq);
2357  Value a = term_cst(veq)? vecteur_val(vecteur_succ(veq)) : vecteur_val(veq);
2358 
2359  if(value_one_p(a) || value_mone_p(a) || vect_coeff(TCST,veq)==VALUE_ZERO
2360  || value_mod(vect_coeff(TCST,veq), a)==VALUE_ZERO) {
2361  /* An overflow is unlikely... but it should be handled here
2362  I guess rather than be subcontracted. */
2364  {
2365  /* The substitution of the variable defined by "eq" by its
2366  value leads to an overflow in one some unknown
2367  constraint of "ps". It might be better to trap the
2368  overflow at a lower level, when you know which
2369  constraint fails because the constraint could be
2370  removed altogether. */
2371  sc_rm(ps); /* */
2372  ps = ps_backup;
2373  failure_p = true;
2374  break;
2375  }
2376  TRY
2377  {
2378  sc_simple_variable_substitution_with_eq_ofl_ctrl(ps, eq, v, OFL_CTRL);
2379  }
2381  }
2382  else {
2383  sc_rm(ps);
2384  ps = SC_UNDEFINED;
2385  }
2386  }
2387  }
2388  if(!failure_p) {
2389  sc_rm(ps_backup);
2390  }
2391 
2392  ps = sc_elim_double_constraints(ps);
2393  sc_elim_empty_constraints(ps, true);
2394  sc_elim_empty_constraints(ps, false);
2395  }
2396 
2397  return(ps);
2398 }
2399 
2400 /*
2401  * ??? could be improved by rewriting *_elim_redond so that only
2402  * (in)eq may be removed?
2403  *
2404  * FC 02/11/94
2405  */
2406 
2408 Psysteme ps;
2409 Pcontrainte eq;
2410 {
2411  Pcontrainte c;
2412 
2413  if (!eq->vecteur) return(ps);
2414 
2416  if (egalite_normalize(eq))
2417  {
2418  c = ps->egalites,
2419  ps->egalites = eq,
2420  eq->succ = c;
2421  ps->nb_eq++;
2422 
2424  {
2425  sc_rm(ps);
2426  return(NULL);
2427  }
2428 
2429  sc_rm_empty_constraints(ps, true);
2430  }
2431 
2432  return(ps);
2433 }
2434 
2436 Psysteme ps;
2437 Pcontrainte ineq;
2438 {
2439  Pcontrainte c;
2440 
2441  if (!ineq->vecteur) return(ps);
2442 
2443  vect_normalize(ineq->vecteur);
2444  if (inegalite_normalize(ineq))
2445  {
2446  c = ps->inegalites,
2447  ps->inegalites = ineq,
2448  ineq->succ = c;
2449  ps->nb_ineq++;
2450 
2451  if (!sc_elim_simple_redund_with_ineq(ps, ineq))
2452  {
2453  sc_rm(ps);
2454  return(NULL);
2455  }
2456 
2457  sc_rm_empty_constraints(ps, false);
2458  }
2459 
2460  return(ps);
2461 }
2462 
2463 /* Psysteme sc_safe_normalize(Psysteme ps)
2464  * output : ps, normalized.
2465  * modifies : ps.
2466  * comment : when ps is not feasible, returns sc_empty.
2467  */
2469 Psysteme ps;
2470 {
2471 
2472  ps = sc_normalize(ps);
2473  return(ps);
2474 }
2475 
2477 {
2478 
2479  if(!sc_rational_feasibility_ofl_ctrl((sc), OFL_CTRL,true)) {
2480  sc_rm(sc);
2481  sc = SC_EMPTY;
2482  }
2483  return sc;
2484 }
2485 
2486 /* Psysteme sc_strong_normalize(Psysteme ps)
2487  *
2488  * Apply sc_normalize first. Then solve the equations in a copy
2489  * of ps and propagate in equations and inequations.
2490  *
2491  * Flag as redundant equations 0 == 0 and inequalities 0 <= k
2492  * with k a positive integer constant when they appear.
2493  *
2494  * Flag the system as non feasible if any equation 0 == k or any inequality
2495  * 0 <= -k with k a strictly positive constant appears.
2496  *
2497  * Then, we'll have to deal with remaining inequalities...
2498  *
2499  * Argument ps is not modified by side-effect but it is freed for
2500  * backward compatability. SC_EMPTY is returned for
2501  * backward compatability.
2502  *
2503  * The code is difficult to understand because a sparse representation
2504  * is used. proj_ps is initially an exact copy of ps, with the same constraints
2505  * in the same order. The one-to-one relationship between constraints
2506  * must be maintained when proj_ps is modified. This makes it impossible to
2507  * use most routines available in Linear.
2508  *
2509  * Note: this is a redundancy elimination algorithm a bit too strong
2510  * for sc_normalize.c...
2511  */
2513 {
2514  Psysteme new_ps =
2516  (ps, (Psysteme (*)(Psysteme)) NULL);
2517 
2518  return new_ps;
2519 }
2520 
2522 {
2523  /*
2524  Psysteme new_ps =
2525  sc_strong_normalize_and_check_feasibility
2526  (ps, sc_elim_redund);
2527  */
2528  Psysteme new_ps =
2531 
2532  return new_ps;
2533 }
2534 
2536  volatile Psysteme ps,
2537  Psysteme (*check_feasibility)(Psysteme))
2538 {
2539 
2540  volatile Psysteme new_ps = SC_UNDEFINED;
2541  volatile Psysteme proj_ps = SC_UNDEFINED;
2542  volatile bool feasible_p = true;
2543  /* Automatic variables read in a CATCH block need to be declared volatile as
2544  * specified by the documentation*/
2545  Psysteme volatile ps_backup = sc_copy(ps);
2546  /*
2547  fprintf(stderr, "[sc_strong_normalize]: Begin\n");
2548  */
2549 
2550 
2552  {
2553  /* CA */
2554  fprintf(stderr,"overflow error in normalization\n");
2555  new_ps=ps_backup;
2556  }
2557  TRY
2558  {
2559  if(!SC_UNDEFINED_P(ps)) {
2560  if(!SC_EMPTY_P(ps = sc_normalize(ps))) {
2564  Pcontrainte next_proj_eq = CONTRAINTE_UNDEFINED;
2565  Pcontrainte proj_ineq = CONTRAINTE_UNDEFINED;
2567  Pcontrainte new_ineq = CONTRAINTE_UNDEFINED;
2568 
2569  /*
2570  fprintf(stderr,
2571  "[sc_strong_normalize]: After call to sc_normalize\n");
2572  */
2573 
2574  /* We need an exact copy of ps to have equalities
2575  * and inequalities in the very same order
2576  *
2577  * FI: may have is has been fixed with sc_dup() by
2578  * now... see comments in sc_copy()
2579  */
2580  new_ps = sc_copy(ps);
2581  proj_ps = sc_copy(new_ps);
2582  sc_rm(new_ps);
2583  new_ps = sc_make(NULL, NULL);
2584 
2585  /*
2586  fprintf(stderr, "[sc_strong_normalize]: Input system %x\n",
2587  (unsigned int) ps);
2588  sc_default_dump(ps);
2589  fprintf(stderr, "[sc_strong_normalize]: Copy system %x\n",
2590  (unsigned int) ps);
2591  sc_default_dump(proj_ps);
2592  */
2593 
2594  /* Solve the equalities */
2595  for(proj_eq = sc_egalites(proj_ps),
2596  eq = sc_egalites(ps);
2597  !CONTRAINTE_UNDEFINED_P(proj_eq);
2598  eq = contrainte_succ(eq)) {
2599 
2600  /* proj_eq might suffer in the substitution... */
2601  next_proj_eq = contrainte_succ(proj_eq);
2602 
2603  if(egalite_normalize(proj_eq)) {
2604  if(CONTRAINTE_NULLE_P(proj_eq)) {
2605  /* eq is redundant */
2606  ;
2607  }
2608  else {
2610  /* keep eq */
2611  Variable v = TCST;
2612  Pvecteur pv;
2613 
2615  sc_add_egalite(new_ps, new_eq);
2616  /* use proj_eq to eliminate a variable */
2617 
2618  /* Let's use a variable with coefficient 1 if
2619  * possible
2620  */
2621  for( pv = contrainte_vecteur(proj_eq);
2622  !VECTEUR_NUL_P(pv);
2623  pv = vecteur_succ(pv)) {
2624  if(!term_cst(pv)) {
2625  v = vecteur_var(pv);
2626  if(value_one_p(vecteur_val(pv))) {
2627  break;
2628  }
2629  }
2630  }
2631  assert(v!=TCST);
2632 
2633  /* A softer substitution is needed in order to
2634  * preserve the relationship between ps and proj_ps
2635  */
2636  /*
2637  if(sc_empty_p(proj_ps =
2638  sc_variable_substitution_with_eq_ofl_ctrl
2639  (proj_ps, proj_eq, v, NO_OFL_CTRL))) {
2640  feasible_p = false;
2641  break;
2642  }
2643  else {
2644  ;
2645  }
2646  */
2647 
2648  /* proj_eq itself is going to be modified in proj_ps.
2649  * use a copy!
2650  */
2651  def = contrainte_copy(proj_eq);
2652  proj_ps =
2653  sc_simple_variable_substitution_with_eq_ofl_ctrl
2654  (proj_ps, def, v, NO_OFL_CTRL);
2655  contrainte_rm(def);
2656  /*
2657  int contrainte_subst_ofl_ctrl(v,def,c,eq_p, ofl_ctrl)
2658  */
2659  }
2660  }
2661  else {
2662  /* The system is not feasible. Stop */
2663  feasible_p = false;
2664  break;
2665  }
2666 
2667  /*
2668  fprintf(stderr,
2669  "Print the three systems at each elimination step:\n");
2670  fprintf(stderr, "[sc_strong_normalize]: Input system %x\n",
2671  (unsigned int) ps);
2672  sc_default_dump(ps);
2673  fprintf(stderr, "[sc_strong_normalize]: Copy system %x\n",
2674  (unsigned int) proj_ps);
2675  sc_default_dump(proj_ps);
2676  fprintf(stderr, "[sc_strong_normalize]: New system %x\n",
2677  (unsigned int) new_ps);
2678  sc_default_dump(new_ps);
2679  */
2680 
2681  proj_eq = next_proj_eq;
2682  }
2683  assert(!feasible_p ||
2685 
2686  /* Check the inequalities */
2687  for(proj_ineq = sc_inegalites(proj_ps),
2688  ineq = sc_inegalites(ps);
2689  feasible_p && !CONTRAINTE_UNDEFINED_P(proj_ineq);
2690  proj_ineq = contrainte_succ(proj_ineq),
2691  ineq = contrainte_succ(ineq)) {
2692 
2693  if(inegalite_normalize(proj_ineq)) {
2694  if(contrainte_constante_p(proj_ineq)
2695  && contrainte_verifiee(proj_ineq, false)) {
2696  /* ineq is redundant */
2697  ;
2698  }
2699  else {
2700  int i;
2701  i = sc_check_inequality_redundancy(proj_ineq, proj_ps);
2702  if(i==0) {
2703  /* keep ineq */
2704  new_ineq = contrainte_copy(ineq);
2705  sc_add_inegalite(new_ps, new_ineq);
2706  }
2707  else if(i==1) {
2708  /* ineq is redundant with another inequality:
2709  * destroy ineq to avoid the mutual elimination of
2710  * two identical constraints
2711  */
2712  eq_set_vect_nul(proj_ineq);
2713  }
2714  else if(i==2) {
2715  feasible_p = false;
2716  break;
2717  }
2718  else {
2719  assert(false);
2720  }
2721  }
2722  }
2723  else {
2724  /* The system is not feasible. Stop */
2725  feasible_p = false;
2726  break;
2727  }
2728  }
2729 
2730  /*
2731  fprintf(stderr,
2732  "Print the three systems after inequality normalization:\n");
2733  fprintf(stderr, "[sc_strong_normalize]: Input system %x\n",
2734  (unsigned int) ps);
2735  sc_default_dump(ps);
2736  fprintf(stderr, "[sc_strong_normalize]: Copy system %x\n",
2737  (unsigned int) proj_ps);
2738  sc_default_dump(proj_ps);
2739  fprintf(stderr, "[sc_strong_normalize]: New system %x\n",
2740  (unsigned int) new_ps);
2741  sc_default_dump(new_ps);
2742  */
2743 
2744  /* Check redundancy between residual inequalities */
2745 
2746  /* sc_elim_simple_redund_with_ineq(ps,ineg) */
2747 
2748  /* Well, sc_normalize should not be able to do much here! */
2749  /*
2750  new_ps = sc_normalize(new_ps);
2751  feasible_p = (!SC_EMPTY_P(new_ps));
2752  */
2753  }
2754  else {
2755  /*
2756  fprintf(stderr,
2757  "[sc_strong_normalize]:"
2758  " Non-feasibility detected by sc_normalize\n");
2759  */
2760  feasible_p = false;
2761  }
2762  }
2763  else {
2764  /*
2765  fprintf(stderr,
2766  "[sc_strong_normalize]: Empty system as input\n");
2767  */
2768  feasible_p = false;
2769  }
2770 
2771  if(feasible_p && check_feasibility != (Psysteme (*)(Psysteme)) NULL) {
2772  proj_ps = check_feasibility(proj_ps);
2773  feasible_p = !SC_EMPTY_P(proj_ps);
2774  }
2775 
2776  if(!feasible_p) {
2777  sc_rm(new_ps);
2778  //new_ps = SC_EMPTY; interpreted as R^n by the caller sometimes...
2779  new_ps = sc_empty(BASE_NULLE);
2780  }
2781  else {
2782  sc_base(new_ps) = sc_base(ps);
2783  sc_base(ps) = BASE_UNDEFINED;
2784  sc_dimension(new_ps) = sc_dimension(ps);
2785  /* FI: test added for breakpoint placement*/
2786  if(!sc_weak_consistent_p(new_ps))
2787  assert(sc_weak_consistent_p(new_ps));
2788  }
2789 
2790  sc_rm(proj_ps);
2791  sc_rm(ps);
2792  sc_rm(ps_backup);
2793  /*
2794  fprintf(stderr, "[sc_strong_normalize]: Final value of new system %x:\n",
2795  (unsigned int) new_ps);
2796  sc_default_dump(new_ps);
2797  fprintf(stderr, "[sc_strong_normalize]: End\n");
2798  */
2799 
2801  }
2802  return new_ps;
2803 }
2804 
2805 /* Psysteme sc_strong_normalize2(Psysteme ps)
2806  *
2807  * Apply sc_normalize first. Then solve the equations in
2808  * ps and propagate substitutions in equations and inequations.
2809  *
2810  * Flag as redundant equations 0 == 0 and inequalities 0 <= k
2811  * with k a positive integer constant when they appear.
2812  *
2813  * Flag the system as non feasible if any equation 0 == k or any inequality
2814  * 0 <= -k with k a strictly positive constant appears.
2815  *
2816  * Then, we'll have to deal with remaining inequalities...
2817  *
2818  * Argument ps is modified by side-effect. SC_EMPTY is returned for
2819  * backward compatability if ps is not feasible.
2820  *
2821  * Note: this is a redundancy elimination algorithm a bit too strong
2822  * for sc_normalize.c... but it's not strong enough to qualify as
2823  * a normalization procedure.
2824  */
2826 {
2827 
2828 #define if_debug_sc_strong_normalize_2 if(false)
2829 
2830  Psysteme new_ps = sc_make(NULL, NULL);
2831  bool feasible_p = true;
2832 
2833  /* Automatic variables read in a CATCH block need to be declared volatile as
2834  * specified by the documentation*/
2835  Psysteme volatile ps_backup = sc_copy(ps);
2836 
2838  {
2839  /* CA */
2840  fprintf(stderr,"overflow error in normalization\n");
2841  new_ps=ps_backup;
2842  }
2843  TRY
2844  {
2846  fprintf(stderr, "[sc_strong_normalize2]: Begin\n");
2847  }
2848 
2849  if(!SC_UNDEFINED_P(ps)) {
2850  if(!SC_EMPTY_P(ps = sc_normalize(ps))) {
2855 
2857  fprintf(stderr,
2858  "[sc_strong_normalize2]: After call to sc_normalize\n");
2859  fprintf(stderr, "[sc_strong_normalize2]: Input system %p\n",
2860  ps);
2861  sc_default_dump(ps);
2862  }
2863 
2864  /* Solve the equalities */
2865  for(eq = sc_egalites(ps);
2867  eq = next_eq) {
2868 
2869  /* eq might suffer in the substitution... */
2870  next_eq = contrainte_succ(eq);
2871 
2872  if(egalite_normalize(eq)) {
2873  if(CONTRAINTE_NULLE_P(eq)) {
2874  /* eq is redundant */
2875  ;
2876  }
2877  else {
2879  Variable v = TCST;
2880  Pvecteur pv;
2881 
2882  /* keep eq */
2884  sc_add_egalite(new_ps, new_eq);
2885 
2886  /* use eq to eliminate a variable */
2887 
2888  /* Let's use a variable with coefficient 1 if
2889  * possible
2890  */
2891  for( pv = contrainte_vecteur(eq);
2892  !VECTEUR_NUL_P(pv);
2893  pv = vecteur_succ(pv)) {
2894  if(!term_cst(pv)) {
2895  v = vecteur_var(pv);
2896  if(value_one_p(vecteur_val(pv))) {
2897  break;
2898  }
2899  }
2900  }
2901  assert(v!=TCST);
2902 
2903  /* A softer substitution is used
2904  */
2905  /*
2906  if(sc_empty_p(ps =
2907  sc_variable_substitution_with_eq_ofl_ctrl
2908  (ps, eq, v, OFL_CTRL))) {
2909  feasible_p = false;
2910  break;
2911  }
2912  else {
2913  ;
2914  }
2915  */
2916 
2917  /* eq itself is going to be modified in ps.
2918  * use a copy!
2919  */
2920  def = contrainte_copy(eq);
2921  ps =
2922  sc_simple_variable_substitution_with_eq_ofl_ctrl
2923  (ps, def, v, NO_OFL_CTRL);
2924  contrainte_rm(def);
2925  /*
2926  int contrainte_subst_ofl_ctrl(v,def,c,eq_p, ofl_ctrl)
2927  */
2928  }
2929  }
2930  else {
2931  /* The system is not feasible. Stop */
2932  feasible_p = false;
2933  break;
2934  }
2935 
2937  fprintf(stderr,
2938  "Print the two systems at each elimination step:\n");
2939  fprintf(stderr, "[sc_strong_normalize2]: Input system %p\n",
2940  ps);
2941  sc_default_dump(ps);
2942  fprintf(stderr, "[sc_strong_normalize2]: New system %p\n",
2943  new_ps);
2944  sc_default_dump(new_ps);
2945  }
2946 
2947  }
2948  assert(!feasible_p ||
2950 
2951  /* Check the inequalities */
2952  feasible_p = !SC_EMPTY_P(ps = sc_normalize(ps));
2953 
2955  fprintf(stderr,
2956  "Print the three systems after inequality normalization:\n");
2957  fprintf(stderr, "[sc_strong_normalize2]: Input system %p\n",
2958  ps);
2959  sc_default_dump(ps);
2960  fprintf(stderr, "[sc_strong_normalize2]: New system %p\n",
2961  new_ps);
2962  sc_default_dump(new_ps);
2963  }
2964  }
2965  else {
2967  fprintf(stderr,
2968  "[sc_strong_normalize2]:"
2969  " Non-feasibility detected by first call to sc_normalize\n");
2970  }
2971  feasible_p = false;
2972  }
2973  }
2974  else {
2976  fprintf(stderr,
2977  "[sc_strong_normalize2]: Empty system as input\n");
2978  }
2979  feasible_p = false;
2980  }
2981 
2982  if(!feasible_p) {
2983  sc_rm(new_ps);
2984  new_ps = SC_EMPTY;
2985  }
2986  else {
2987  base_rm(sc_base(new_ps));
2988  sc_base(new_ps) = base_copy(sc_base(ps));
2989  sc_dimension(new_ps) = sc_dimension(ps);
2990  /* copy projected inequalities left in ps */
2991  new_ps = sc_safe_append(new_ps, ps);
2992  /* sc_base(ps) = BASE_UNDEFINED; */
2993  assert(sc_weak_consistent_p(new_ps));
2994  }
2995 
2996  sc_rm(ps);
2997  sc_rm(ps_backup);
2999  fprintf(stderr,
3000  "[sc_strong_normalize2]: Final value of new system %p:\n",
3001  new_ps);
3002  sc_default_dump(new_ps);
3003  fprintf(stderr, "[sc_strong_normalize2]: End\n");
3004  }
3006  }
3007  return new_ps;
3008 }
3009 
3010 /* Psysteme sc_strong_normalize4(Psysteme ps,
3011  * char * (*variable_name)(Variable))
3012  */
3014 {
3015  /*
3016  Psysteme new_ps =
3017  sc_strong_normalize_and_check_feasibility2
3018  (ps, sc_normalize, variable_name, VALUE_MAX);
3019  */
3020 
3021  Psysteme new_ps =
3023  (ps, sc_normalize, variable_name, 2);
3024 
3025  return new_ps;
3026 }
3027 
3029 {
3030  /* Good, but pretty slow */
3031  /*
3032  Psysteme new_ps =
3033  sc_strong_normalize_and_check_feasibility2
3034  (ps, sc_elim_redund, variable_name, 2);
3035  */
3036 
3037  Psysteme new_ps =
3040 
3041  return new_ps;
3042 }
3043 
3044 /* Psysteme sc_strong_normalize_and_check_feasibility2
3045  * (Psysteme ps,
3046  * Psysteme (*check_feasibility)(Psysteme),
3047  * char * (*variable_name)(Variable),
3048  * int level)
3049  *
3050  * Same as sc_strong_normalize2() but equations are used by increasing
3051  * order of their numbers of variables, and, within one equation,
3052  * the lexicographic minimal variables is chosen among equivalent variables.
3053  *
3054  * Equations with more than "level" variables are not used for the
3055  * substitution. Unless level==VALUE_MAX.
3056  *
3057  * Finally, an additional normalization procedure is applied on the
3058  * substituted system. Another stronger normalization can be chosen
3059  * to benefit from the system size reduction (e.g. sc_elim_redund).
3060  * Or a light one to benefit from the inequality simplifications due
3061  * to equation solving (e.g. sc_normalize).
3062  */
3063 Psysteme
3065  volatile Psysteme ps,
3066  Psysteme (*check_feasibility)(Psysteme),
3067  char * (*variable_name)(Variable),
3068  int level)
3069 {
3070 
3071 #define if_debug_sc_strong_normalize_and_check_feasibility2 if(false)
3072 
3073  Psysteme new_ps = sc_make(NULL, NULL);
3074  bool feasible_p = true;
3075  /* Automatic variables read in a CATCH block need to be declared volatile as
3076  * specified by the documentation*/
3077  Psysteme volatile ps_backup = sc_copy(ps);
3078 
3080  {
3081  /* CA */
3082  fprintf(stderr,"overflow error in normalization\n");
3083  new_ps=ps_backup;
3084  }
3085  TRY
3086  {
3088  fprintf(stderr,
3089  "[sc_strong_normalize_and_check_feasibility2]"
3090  " Input system %p\n", ps);
3091  sc_default_dump(ps);
3092  }
3093 
3094  if(SC_UNDEFINED_P(ps)) {
3096  fprintf(stderr,
3097  "[sc_strong_normalize_and_check_feasibility2]"
3098  " Empty system as input\n");
3099  }
3100  feasible_p = false;
3101  }
3102  else if(SC_EMPTY_P(ps = sc_normalize(ps))) {
3104  fprintf(stderr,
3105  "[sc_strong_normalize_and_check_feasibility2]:"
3106  " Non-feasibility detected by first call to sc_normalize\n");
3107  }
3108  feasible_p = false;
3109  }
3110  else {
3115  int nvar;
3116  int neq = sc_nbre_egalites(ps);
3117 
3119  fprintf(stderr,
3120  "[sc_strong_normalize_and_check_feasibility2]"
3121  " Input system after normalization %p\n", ps);
3122  sc_default_dump(ps);
3123  }
3124 
3125 
3126  /*
3127  * Solve the equalities (if any)
3128  *
3129  * Start with equalities with the smallest number of variables
3130  * and stop when all equalities have been used and or when
3131  * all equalities left have too many variables.
3132  */
3133  for(nvar = 1;
3134  feasible_p && neq > 0 && nvar <= level /* && sc_nbre_egalites(ps) != 0 */;
3135  nvar++) {
3136  for(eq = sc_egalites(ps);
3137  feasible_p && !CONTRAINTE_UNDEFINED_P(eq);
3138  eq = next_eq) {
3139 
3140  /* eq might suffer in the substitution... */
3141  next_eq = contrainte_succ(eq);
3142 
3143  if(egalite_normalize(eq)) {
3144  if(CONTRAINTE_NULLE_P(eq)) {
3145  /* eq is redundant */
3146  ;
3147  }
3148  else {
3149  /* Equalities change because of substitutions.
3150  * Their dimensions may go under the present
3151  * required dimension, nvar. Hence the non-equality
3152  * test.
3153  */
3155 
3156  if(d<=nvar) {
3158  Variable v = TCST;
3159  Variable v1 = TCST;
3160  Variable v2 = TCST;
3161  Variable nv = TCST;
3162  Pvecteur pv;
3163 
3164  /* keep eq */
3166  sc_add_egalite(new_ps, new_eq);
3167 
3168  /* use eq to eliminate a variable */
3169 
3170  /* Let's use a variable with coefficient 1 if
3171  * possible. Among such variables,
3172  * choose the lexicographically minimal one.
3173  */
3174  v1 = TCST;
3175  v2 = TCST;
3176  for( pv = contrainte_vecteur(eq);
3177  !VECTEUR_NUL_P(pv);
3178  pv = vecteur_succ(pv)) {
3179  if(!term_cst(pv)) {
3180  nv = vecteur_var(pv);
3181  v2 = (v2==TCST)? nv : v2;
3182  if (value_one_p(vecteur_val(pv))) {
3183  if(v1==TCST) {
3184  v1 = nv;
3185  }
3186  else {
3187  /* v1 = TCST; */
3188  v1 =
3189  (strcmp(variable_name(v1),
3190  variable_name(nv))>=0)
3191  ? nv : v1;
3192  }
3193  }
3194  }
3195  }
3196  v = (v1==TCST)? v2 : v1;
3197  /* because of the !CONTRAINTE_NULLE_P() test */
3198  assert(v!=TCST);
3199 
3200  /* eq itself is going to be modified in ps.
3201  * use a copy!
3202  */
3203  def = contrainte_copy(eq);
3204  ps =
3205  sc_simple_variable_substitution_with_eq_ofl_ctrl
3206  (ps, def, v, NO_OFL_CTRL);
3207  contrainte_rm(def);
3208  }
3209  else {
3210  /* too early to use this equation eq */
3211  /* If there any hope to use it in the future?
3212  * Yes, if its dimension is no more than nvar+1
3213  * because one of its variable might be substituted.
3214  * If more variable are substituted, it's dimension
3215  * is going to go down and it will be counted later...
3216  * Well this is not true, it will be lost:-(
3217  */
3218  if(d<=nvar+1) {
3219  neq++;
3220  }
3221  else {
3222  /* to be on the safe side till I find a better idea... */
3223  neq++;
3224  }
3225  }
3226  }
3227  }
3228  else {
3229  /* The system is not feasible. Stop */
3230  feasible_p = false;
3231  break;
3232  }
3233 
3234  /* This reaaly generates a lot of about on real life system! */
3235  /*
3236  if_debug_sc_strong_normalize_and_check_feasibility2 {
3237  fprintf(stderr,
3238  "Print the two systems at each elimination step:\n");
3239  fprintf(stderr, "[sc_strong_normalize_and_check_feasibility2]: Input system %x\n",
3240  (unsigned int) ps);
3241  sc_default_dump(ps);
3242  fprintf(stderr, "[sc_strong_normalize_and_check_feasibility2]: New system %x\n",
3243  (unsigned int) new_ps);
3244  sc_default_dump(new_ps);
3245  }
3246  */
3247 
3248  /* This is a much too much expensive transformation
3249  * in an innermost loop!
3250  *
3251  * It cannot be used as a convergence test.
3252  */
3253  /* feasible_p = (!SC_EMPTY_P(ps = sc_normalize(ps))); */
3254 
3255  }
3256 
3258  fprintf(stderr,
3259  "Print the two systems at each nvar=%d step:\n", nvar);
3260  fprintf(stderr, "[sc_strong_normalize_and_check_feasibility2]: Input system %p\n",
3261  ps);
3262  sc_default_dump(ps);
3263  fprintf(stderr, "[sc_strong_normalize_and_check_feasibility2]: New system %p\n",
3264  new_ps);
3265  sc_default_dump(new_ps);
3266  }
3267  }
3268  sc_elim_empty_constraints(new_ps,true);
3269  sc_elim_empty_constraints(ps,true);
3270  assert(!feasible_p ||
3272 
3273  /* Check the inequalities */
3274  assert(check_feasibility != (Psysteme (*)(Psysteme)) NULL);
3275 
3276  feasible_p = feasible_p && !SC_EMPTY_P(ps = check_feasibility(ps));
3277 
3279  fprintf(stderr,
3280  "Print the three systems after inequality normalization:\n");
3281  fprintf(stderr, "[sc_strong_normalize_and_check_feasibility2]: Input system %p\n",
3282  ps);
3283  sc_default_dump(ps);
3284  fprintf(stderr, "[sc_strong_normalize_and_check_feasibility2]: New system %p\n",
3285  new_ps);
3286  sc_default_dump(new_ps);
3287  }
3288  }
3289 
3290  if(!feasible_p) {
3291  sc_rm(new_ps);
3292  new_ps = SC_EMPTY;
3293  }
3294  else {
3295  base_rm(sc_base(new_ps));
3296  sc_base(new_ps) = base_copy(sc_base(ps));
3297  sc_dimension(new_ps) = sc_dimension(ps);
3298  /* copy projected inequalities left in ps */
3299  new_ps = sc_safe_append(new_ps, ps);
3300  /* sc_base(ps) = BASE_UNDEFINED; */
3301  if (!sc_weak_consistent_p(new_ps))
3302  {
3303  fprintf(stderr,
3304  "[sc_strong_normalize_and_check_feasibility2]: "
3305  "Input system %p\n", ps);
3306  sc_default_dump(ps);
3307  fprintf(stderr,
3308  "[sc_strong_normalize_and_check_feasibility2]: "
3309  "New system %p\n", new_ps);
3310  sc_default_dump(new_ps);
3311  /* assert(sc_weak_consistent_p(new_ps)); */
3312  assert(false);
3313  }
3314  }
3315 
3316  sc_rm(ps);
3317  sc_rm(ps_backup);
3319  {
3320  fprintf(stderr,
3321  "[sc_strong_normalize_and_check_feasibility2]: Final value of new system %p:\n",
3322  new_ps);
3323  sc_default_dump(new_ps);
3324  fprintf(stderr, "[sc_strong_normalize_and_check_feasibility2]: End\n");
3325  }
3326 
3328  }
3329  return new_ps;
3330 }
3331 
3332 
3333 /* sc_gcd_normalize(ps)
3334  *
3335  * Normalization by gcd's of equalities and inequalities
3336  */
3338 {
3339  Pcontrainte eq1,ineq1;
3340 
3341  if (!SC_UNDEFINED_P(ps)) {
3342 
3343  /* Normalization by gcd's */
3344 
3345  for (eq1 = ps->egalites; eq1 != NULL; eq1 = eq1->succ) {
3346  vect_normalize(eq1->vecteur);
3347  }
3348 
3349  for (ineq1 = ps->inegalites; ineq1 != NULL;ineq1 = ineq1->succ) {
3350  (void) contrainte_normalize(ineq1, false);
3351  }
3352  }
3353 }
float a2sf[2] __attribute__((aligned(16)))
USER generates a user error (i.e., non fatal) by printing the given MSG according to the FMT.
Definition: 3dnow.h:3
static int count
Definition: SDG.c:519
#define CATCH(what)
@ overflow_error
#define UNCATCH(what)
#define TRY
#define value_pos_p(val)
#define VALUE_ZERO
#define modulo(a, b)
#define value_mone_p(val)
#define value_minus(v1, v2)
#define value_gt(v1, v2)
#define value_min(v1, v2)
#define value_pdiv(v1, v2)
#define value_le(v1, v2)
#define value_notzero_p(val)
#define value_uminus(val)
unary operators on values
void const char const char const int
#define value_one_p(val)
#define value_negz_p(val)
#define value_direct_multiply(v1, v2)
#define VALUE_MIN
#define VALUE_MONE
#define value_ne(v1, v2)
#define value_assign(ref, val)
assigments
#define value_zero_p(val)
int Value
#define value_addto(ref, val)
#define value_eq(v1, v2)
bool operators on values
#define VALUE_MAX
#define value_plus(v1, v2)
binary operators on values
#define VALUE_ONE
#define value_abs(val)
#define value_mult(v, w)
whether the default is protected or not this define makes no sense any more...
#define value_mod(v1, v2)
#define value_lt(v1, v2)
#define VALUE_NAN
#define value_ge(v1, v2)
#define value_neg_p(val)
#define value_div(v1, v2)
#define value_posz_p(val)
Pbase make_base_from_vect(Pvecteur pv)
Definition: base.c:109
int rank_of_variable(Pbase base, Variable var)
this function returns the rank of the variable var in the base 0 encodes TCST, but I do not know why,...
Definition: base.c:497
bool base_contains_variable_p(Pbase b, Variable v)
bool base_contains_variable_p(Pbase b, Variable v): returns true if variable v is one of b's elements...
Definition: base.c:136
#define CONTRAINTE_UNDEFINED_P(c)
#define CONTRAINTE_NULLE_P(c)
contrainte nulle (non contrainte 0 == 0 ou 0 <= 0)
#define contrainte_succ(c)
#define contrainte_vecteur(c)
passage au champ vecteur d'une contrainte "a la Newgen"
#define CONTRAINTE_UNDEFINED
#define contrainte_rm(c)
the standard xxx_rm does not return a value
Pcontrainte contraintes_make(Pvecteur pv,...)
Convert a list of vectors into a list of constraints.
Definition: alloc.c:99
Pcontrainte contrainte_make(Pvecteur pv)
Pcontrainte contrainte_make(Pvecteur pv): allocation et initialisation d'une contrainte avec un vecte...
Definition: alloc.c:73
Pcontrainte contrainte_copy(Pcontrainte c_in)
Have a look at contrainte_dup and contraintes_dup which reverse the order of the list This copy versi...
Definition: alloc.c:254
Pcontrainte contrainte_make_1D(Value a, Variable x, Value b, bool less_p)
Generate a constraint a x <= b or a x >= b, according to less_p, or ax==b, regardless of less_p.
Definition: alloc.c:86
Pcontrainte contrainte_append(Pcontrainte c1, Pcontrainte c2)
Pcontrainte contrainte_append(c1, c2) Pcontrainte c1, c2;.
Definition: binaires.c:267
void eq_set_vect_nul(Pcontrainte)
void_eq_set_vect_nul(Pcontrainte c): transformation d'une contrainte en une contrainte triviale 0 == ...
Definition: unaires.c:84
bool egalite_normalize(Pcontrainte)
bool egalite_normalize(Pcontrainte eg): reduction d'une equation diophantienne par le pgcd de ses coe...
Definition: normalize.c:136
bool cyclic_constraint_list_p(Pcontrainte)
Check if list l contains a cycle.
Definition: listes.c:141
bool contrainte_constante_p(Pcontrainte)
bool contrainte_constante_p(Pcontrainte c): test de contrainte triviale sans variables (ie du type 0<...
Definition: predicats.c:192
bool contrainte_normalize(Pcontrainte, bool)
normalize.c
Definition: normalize.c:56
bool inegalite_normalize(Pcontrainte)
bool inegalite_normalize(Pcontrainte ineg): normalisation d'une inegalite a variables entieres; voir ...
Definition: normalize.c:156
void inegalites_dump(Pcontrainte)
Definition: io.c:220
bool contrainte_verifiee(Pcontrainte, bool)
bool contrainte_verifiee(Pcontrainte ineg, bool eq_p): test de faisabilite d'inegalite (eq_p == false...
Definition: predicats.c:234
static bool(* bound_p)(entity)
void vect_dump(Pvecteur v)
void vect_dump(Pvecteur v): print sparse vector v on stderr.
Definition: io.c:304
void vect_fprint(FILE *f, Pvecteur v, get_variable_name_t variable_name)
void vect_fprint(FILE * f, Pvecteur v, char * (*variable_name)()): impression d'un vecteur creux v su...
Definition: io.c:124
int vect_dimension(Pvecteur v)
int vect_dimension(Pvecteur v): calcul du nombre de composantes non nulles et non constantes d'un vec...
Definition: reductions.c:64
int vect_size(Pvecteur v)
package vecteur - reductions
Definition: reductions.c:47
char *(* variable_debug_name)(Variable)
Debug support: pointer to the function used by debug print outs.
Definition: variable.c:114
#define abort()
Definition: misc-local.h:53
#define assert(ex)
Definition: newgen_assert.h:41
bool sc_consistent_p(Psysteme sc)
bool sc_consistent_p(Psysteme sc): check that sc is well defined, that the numbers of equalities and ...
Definition: sc.c:282
Psysteme sc_make(Pcontrainte leg, Pcontrainte lineg)
Psysteme sc_make(Pcontrainte leg, Pcontrainte lineg): allocation et initialisation d'un systeme d'equ...
Definition: sc.c:78
bool sc_weak_consistent_p(Psysteme sc)
check that sc is well defined, that the numbers of equalities and inequalities are consistent with th...
Definition: sc.c:362
bool sc_rn_p(Psysteme sc)
bool sc_rn_p(Psysteme sc): check if the set associated to sc is the whole space, rn
Definition: sc_alloc.c:369
Psysteme sc_empty(Pbase b)
Psysteme sc_empty(Pbase b): build a Psysteme with one unfeasible constraint to define the empty subsp...
Definition: sc_alloc.c:319
void sc_rm(Psysteme ps)
void sc_rm(Psysteme ps): liberation de l'espace memoire occupe par le systeme de contraintes ps;
Definition: sc_alloc.c:277
void sc_add_egalite(Psysteme p, Pcontrainte e)
void sc_add_egalite(Psysteme p, Pcontrainte e): macro ajoutant une egalite e a un systeme p; la base ...
Definition: sc_alloc.c:389
void sc_add_inegalites(Psysteme p, Pcontrainte i)
Definition: sc_alloc.c:432
bool sc_empty_p(Psysteme sc)
bool sc_empty_p(Psysteme sc): check if the set associated to sc is the constant sc_empty or not.
Definition: sc_alloc.c:350
void sc_add_inegalite(Psysteme p, Pcontrainte i)
void sc_add_inegalite(Psysteme p, Pcontrainte i): macro ajoutant une inegalite i a un systeme p; la b...
Definition: sc_alloc.c:406
void sc_add_egalites(Psysteme p, Pcontrainte i)
Definition: sc_alloc.c:415
Psysteme sc_copy(Psysteme ps)
Psysteme sc_copy(Psysteme ps): duplication d'un systeme (allocation et copie complete des champs sans...
Definition: sc_alloc.c:230
Psysteme sc_safe_kill_db_eg(Psysteme ps)
same as above, but returns an empty system if the system is not feasible
Definition: sc_elim_eq.c:191
void sc_rm_empty_constraints(Psysteme ps, bool process_equalities)
package sc: elimination de redondance simple
Definition: sc_elim_eq.c:56
bool sc_elim_simple_redund_with_ineq(Psysteme ps, Pcontrainte ineg)
bool sc_elim_simple_redund_with_ineq(Psysteme ps, Pcontrainte ineg): elimination des contraintes redo...
Psysteme sc_elim_double_constraints(Psysteme ps)
Psysteme sc_elim_double_constraints(Psysteme ps): elimination des egalites et des inegalites identiqu...
void sc_elim_empty_constraints(Psysteme ps, bool process_equalities)
void sc_elim_empty_constraints(Psysteme ps, bool process_equalities): elimination des "fausses" contr...
bool sc_elim_simple_redund_with_eq(Psysteme ps, Pcontrainte eg)
package sc
int sc_check_inequality_redundancy(Pcontrainte ineq, Psysteme ps)
int sc_check_inequality_redundancy(Pcontrainte ineq, Psysteme ps) Check if an inequality ineq,...
#define level
bool sc_rational_feasibility_ofl_ctrl(Psysteme sc, int ofl_ctrl, bool ofl_res)
Pcontrainte eq
element du vecteur colonne du systeme donne par l'analyse
Definition: sc_gram.c:108
Psysteme sc_safe_append(Psysteme s1, Psysteme s2)
Psysteme sc_safe_append(Psysteme s1, Psysteme s2) input : output : calcul de l'intersection des polye...
void sc_default_dump(Psysteme sc)
void sc_default_dump(Psysteme sc): dump to stderr
Definition: sc_io.c:170
int fprintf()
test sc_min : ce test s'appelle par : programme fichier1.data fichier2.data ...
Psysteme sc_add_normalize_ineq(Psysteme ps, Pcontrainte ineq)
static Pvecteur compute_x_and_y_bounds(Pvecteur v, Pvecteur l, Pvecteur lb, Pvecteur u, Pvecteur ub, Variable *px, Variable *py, Value *px_min, Value *px_max, int *pcb)
v is supposed to be the equation of a line in a 2-D space.
Definition: sc_normalize.c:327
Psysteme sc_normalize2(volatile Psysteme ps)
Psysteme sc_normalize2(Psysteme ps): normalisation d'un systeme d'equation et d'inequations lineaires...
static bool eligible_for_coefficient_reduction_with_bounding_box_p(Pvecteur v, Pvecteur l, Pvecteur lb, Pvecteur u, Pvecteur ub)
Is it possible to reduce the magnitude of at least one constraint coefficient because it is larger th...
Definition: sc_normalize.c:462
Psysteme sc_strong_normalize3(Psysteme ps)
static Pcontrainte reduce_coefficients_with_bounding_box(Pvecteur v, Pvecteur l, Pvecteur lb, Pvecteur u, Pvecteur ub)
If at least one of the coefficients of constraint v == ax+by<=c are greater that the intervals of the...
Psysteme sc_strong_normalize5(Psysteme ps, char *(*variable_name)(Variable))
static void check_coefficient_reduction(Pvecteur v, Pcontrainte ineq, Variable x, Variable y, Value x_min, Value x_max)
debug function: check that all 2-D constraints c in ineq are equivalent to contraint v on interval [x...
static Pvecteur new_constraint_for_coefficient_reduction_with_bounding_box(Pvecteur v, int *pcb, Variable x, Variable y, Value *px_min, Value *px_max, Value *py_min, Value *py_max)
Compute a normalized version of the constraint v and the corresponding change of basis.
Definition: sc_normalize.c:572
static void swap_values(Value *p1, Value *p2)
Definition: sc_normalize.c:57
#define MAX_NUMBER_OF_CONSTRAINTS
Psysteme sc_strong_normalize_and_check_feasibility2(volatile Psysteme ps, Psysteme(*check_feasibility)(Psysteme), char *(*variable_name)(Variable), int level)
Psysteme sc_strong_normalize_and_check_feasibility2 (Psysteme ps, Psysteme (*check_feasibility)(Psyst...
static void update_lower_or_upper_bound(Pvecteur *bound_p, Pvecteur *bound_base_p, Variable var, Value nb, bool lower_p)
Bounding box (not really a box most of the time)
Definition: sc_normalize.c:122
static bool small_slope_and_first_quadrant_p(Pvecteur v)
Check that the coefficients on the first and second variables, x and y, define a increasing line.
Definition: sc_normalize.c:531
static Value eval_2D_vecteur(Pvecteur v, Variable x, Variable y, Value xv, Value yv)
FI: a bit too specific for vecteur library?
Definition: sc_normalize.c:894
static Psysteme sc_rational_feasibility(Psysteme sc)
Psysteme sc_strong_normalize4(Psysteme ps, char *(*variable_name)(Variable))
Psysteme sc_strong_normalize4(Psysteme ps, char * (*variable_name)(Variable))
Pcontrainte find_intermediate_constraints_recursively(Pvecteur v, Variable x, Variable y, Value lmpx, Value lmpy, Value rmpx, Value rmpy)
Find a set ineq of 2-D constraints equivalent to 2-D constraint v==ax+by+c over the interval [lmpx,...
Definition: sc_normalize.c:995
Psysteme sc_strong_normalize_and_check_feasibility(volatile Psysteme ps, Psysteme(*check_feasibility)(Psysteme))
static void swap_value_intervals(Value *px_min, Value *px_max, Value *py_min, Value *py_max)
Definition: sc_normalize.c:64
void sc_gcd_normalize(Psysteme ps)
sc_gcd_normalize(ps)
Psysteme sc_strong_normalize2(volatile Psysteme ps)
Psysteme sc_strong_normalize2(Psysteme ps)
static Pcontrainte small_positive_slope_reduce_coefficients_with_bounding_box(Pvecteur v, Variable x, Value x_min, Value x_max, Variable y, Value y_min __attribute__((unused)), Value y_max __attribute__((unused)))
Replace 2-D constraint v by a set of constraints when possible because variable x is bounded by [x_mi...
static Psysteme add_bounding_box_constraints(Psysteme ps, Pbase cb, Pbase lb, Pbase ub, Pvecteur l, Pvecteur u)
Add the constraints defined by cb, lb and ub in Psysteme ps.
Psysteme sc_add_normalize_eq(Psysteme ps, Pcontrainte eq)
static bool find_integer_point_to_the_left(Value x0, Value y0, Pvecteur up, Pvecteur low, Variable x, Variable y, Value xf, Value yf, Value *pfx, Value *pfy)
Definition: sc_normalize.c:879
#define if_debug_sc_strong_normalize_and_check_feasibility2
static void update_coefficient_signs_in_vector(Pvecteur v, int cb, Variable x, Variable y)
Perform a reverse change of base to go back into the source code frame.
static bool find_integer_point_to_the_right(Value x0, Value y0, Pvecteur up, Pvecteur low, Variable x, Variable y, Value xf, Value yf, Value *pfx, Value *pfy)
Definition: sc_normalize.c:865
Psysteme sc_safe_normalize(Psysteme ps)
Psysteme sc_safe_normalize(Psysteme ps) output : ps, normalized.
Psysteme sc_normalize(Psysteme ps)
Psysteme sc_normalize(Psysteme ps): normalisation d'un systeme d'equation et d'inequations lineaires ...
static void update_coefficient_signs_in_constraints(Pcontrainte eq, int cb, Variable x, Variable y, Value *x_min, Value *x_max, Value *y_min, Value *y_max)
Perform the inverse change of basis and update the intervals for later checks.
static bool find_first_integer_point_in_between(Value x0, Value y0, Pvecteur up_c, Pvecteur low_c, Variable xv, Variable yv, Value dx, Value dy, Value xf, Value yf __attribute__((unused)), Value *pfx, Value *pfy)
Find the first significant integer point (*pfx, *pfy) starting from (x0,y0) moving by (dx,...
Definition: sc_normalize.c:705
#define if_debug_sc_strong_normalize_2
Psysteme sc_bounded_normalization(Psysteme ps)
Eliminate trivially redundant integer constraint using a O(n x d^2) algorithm, where n is the number ...
static Pcontrainte build_convex_constraints_from_vertices(Variable x, Variable y, int ni, int eni, Value ilmpx[ni+2], Value ilmpy[ni+2])
Use the first eni+2 points in ilmpx and ilmpy to build at most eni+1 convex constraints,...
Definition: sc_normalize.c:916
Psysteme sc_strong_normalize(Psysteme ps)
Psysteme sc_strong_normalize(Psysteme ps)
Pcontrainte find_intermediate_constraints(Pvecteur v, Variable x, Variable y, Value lmpx, Value lmpy, Value rmpx, Value rmpy)
Find a set ineq of 2-D constraints equivalent to 2-D constraint v==ax+by+c over the interval [lmpx,...
static void simplify_constraint_with_bounding_box(Pcontrainte eq, Pbase cb, Pvecteur l, bool is_inequality_p __attribute__((unused)))
Use constants imposed by the bounding box to eliminate constant terms from constraint eq.
Definition: sc_normalize.c:251
static void negate_value_interval(Value *pmin, Value *pmax)
package sc
Definition: sc_normalize.c:50
static bool update_lower_and_upper_bounds(Pvecteur *ubound_p, Pvecteur *ubound_base_p, Pvecteur *lbound_p, Pvecteur *lbound_base_p, Variable var, Value nb)
Updates upper and lower bounds, (ubound_p, ubound_base_p) and (lbound_p, lbound_base_p),...
Definition: sc_normalize.c:169
static Pvecteur vect_make_line(Variable x, Variable y, Value x0, Value y0, Value x1, Value y1)
FI: Could be moved in vecteur library...
Definition: sc_normalize.c:671
char * variable_name(Variable v)
polynome_ri.c
Definition: polynome_ri.c:73
Pvecteur vect_multiply(Pvecteur v, Value x)
Pvecteur vect_multiply(Pvecteur v, Value x): multiplication du vecteur v par le scalaire x,...
Definition: scalaires.c:123
static char * x
Definition: split_file.c:159
static string new_eq()
Definition: splitc.c:543
Pvecteur vecteur
struct Scontrainte * succ
Pcontrainte inegalites
Definition: sc-local.h:71
Pcontrainte egalites
Definition: sc-local.h:70
le type des coefficients dans les vecteurs: Value est defini dans le package arithmetique
Definition: vecteur-local.h:89
#define VARIABLE_DEFINED_P(v)
Definition: vecteur-local.h:66
#define TCST
VARIABLE REPRESENTANT LE TERME CONSTANT.
#define vecteur_val(v)
#define vecteur_var(v)
#define VECTEUR_NUL
DEFINITION DU VECTEUR NUL.
#define NO_OFL_CTRL
#define VECTEUR_UNDEFINED
#define vecteur_succ(v)
#define VECTEUR_NUL_P(v)
#define base_rm(b)
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 VARIABLE_UNDEFINED_P(v)
Definition: vecteur-local.h:65
#define BASE_UNDEFINED
#define VARIABLE_UNDEFINED
Definition: vecteur-local.h:64
#define term_cst(varval)
#define base_dimension(b)
#define BASE_NULLE
MACROS SUR LES BASES.
#define OFL_CTRL
I do thing that overflows are managed in a very poor manner.
#define VECTEUR_UNDEFINED_P(v)
#define base_add_dimension(b, v)
Pvecteur vect_make(Pvecteur v, Variable var, Value val,...)
Pvecteur vect_make(v, [var, val,]* 0, val) Pvecteur v; // may be NULL, use assigne anyway Variable va...
Definition: alloc.c:165
Pbase vect_copy(Pvecteur b)
direct duplication.
Definition: alloc.c:240
Pvecteur vect_new(Variable var, Value coeff)
Pvecteur vect_new(Variable var,Value coeff): allocation d'un vecteur colineaire au vecteur de base va...
Definition: alloc.c:110
Pbase base_copy(Pbase b)
Direct duplication.
Definition: alloc.c:300
void vect_rm(Pvecteur v)
void vect_rm(Pvecteur v): desallocation des couples de v;
Definition: alloc.c:78
Pvecteur vect_add(Pvecteur v1, Pvecteur v2)
package vecteur - operations binaires
Definition: binaires.c:53
void vect_add_elem(Pvecteur *pvect, Variable var, Value val)
void vect_add_elem(Pvecteur * pvect, Variable var, Value val): addition d'un vecteur colineaire au ve...
Definition: unaires.c:72
Value vect_coeff(Variable var, Pvecteur vect)
Variable vect_coeff(Variable var, Pvecteur vect): coefficient de coordonnee var du vecteur vect —> So...
Definition: unaires.c:228
void vect_chg_coeff(Pvecteur *ppv, Variable var, Value val)
void vect_chg_coeff(Pvecteur *ppv, Variable var, Value val): mise de la coordonnee var du vecteur *pp...
Definition: unaires.c:143
void vect_normalize(Pvecteur v)
void vect_normalize(Pvecteur v): division de tous les coefficients de v par leur pgcd; "normalisation...
Definition: unaires.c:59