corrected a bug in reading matrices on MacOS (fgets) and cleaned a bit the code
[polylib.git] / source / kernel / polyhedron.c
blob0a5a878d1b4fa46035907b086d500ebc7544354d
1 /*
2 This file is part of PolyLib.
4 PolyLib is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
9 PolyLib is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with PolyLib. If not, see <http://www.gnu.org/licenses/>.
18 /* polyhedron.c
19 COPYRIGHT
20 Both this software and its documentation are
22 Copyright 1993 by IRISA /Universite de Rennes I - France,
23 Copyright 1995,1996 by BYU, Provo, Utah
24 all rights reserved.
30 1997/12/02 - Olivier Albiez
31 Ce fichier contient les fonctions de la polylib de l'IRISA,
32 passees en 64bits.
33 La structure de la polylib a donc ete modifie pour permettre
34 le passage aux Value. La fonction Chernikova a ete reecrite.
40 1998/26/02 - Vincent Loechner
41 Ajout de nombreuses fonctions, a la fin de ce fichier,
42 pour les polyedres parametres 64 bits.
43 1998/16/03
44 #define DEBUG printf
45 tests out of memory
46 compatibilite avec la version de doran
50 #undef POLY_DEBUG /* debug printf: general functions */
51 #undef POLY_RR_DEBUG /* debug printf: Remove Redundants */
52 #undef POLY_CH_DEBUG /* debug printf: Chernikova */
54 #include <stdio.h>
55 #include <stdlib.h>
56 #include <string.h>
57 #include <assert.h>
58 #include <polylib/polylib.h>
60 #ifdef MAC_OS
61 #define abs __abs
62 #endif
64 /* WSIZE is the number of bits in a word or int type */
65 #define WSIZE (8*sizeof(int))
67 #define bexchange(a, b, l)\
69 char *t = (char *)malloc(l*sizeof(char));\
70 memcpy((t), (char *)(a), (int)(l));\
71 memcpy((char *)(a), (char *)(b), (int)(l));\
72 memcpy((char *)(b), (t), (int)(l));\
73 free(t); \
76 #define exchange(a, b, t)\
77 { (t)=(a); (a)=(b); (b)=(t); }
79 /* errormsg1 is an external function which is usually supplied by the
80 calling program (e.g. Domlib.c, ReadAlpha, etc...).
81 See errormsg.c for an example of such a function. */
83 void errormsg1(const char *f, const char *msgname, const char *msg);
85 int Pol_status; /* error status after operations */
88 * The Saturation matrix is defined to be an integer (int type) matrix.
89 * It is a boolean matrix which has a row for every constraint and a column
90 * for every line or ray. The bits in the binary format of each integer in
91 * the stauration matrix stores the information whether the corresponding
92 * constraint is saturated by ray(line) or not.
95 typedef struct {
96 unsigned int NbRows;
97 unsigned int NbColumns;
98 int **p;
99 int *p_init;
100 } SatMatrix;
103 * Allocate memory space for a saturation matrix.
105 static SatMatrix *SMAlloc(int rows,int cols) {
107 int **q, *p, i;
108 SatMatrix *result;
110 result = (SatMatrix *) malloc (sizeof(SatMatrix));
111 if(!result) {
112 errormsg1("SMAlloc", "outofmem", "out of memory space");
113 return 0;
115 result->NbRows = rows;
116 result->NbColumns = cols;
117 if(rows == 0 || cols == 0) {
118 result->p = NULL;
119 return result;
121 result->p = q = (int **)malloc(rows * sizeof(int *));
122 if(!result->p) {
123 errormsg1("SMAlloc", "outofmem", "out of memory space");
124 return 0;
126 result->p_init = p = (int *)malloc (rows * cols * sizeof (int));
127 if(!result->p_init) {
128 errormsg1("SMAlloc", "outofmem", "out of memory space");
129 return 0;
131 for (i=0; i<rows; i++) {
132 *q++ = p;
133 p += cols;
135 return result;
136 } /* SMAlloc */
139 * Free the memory space occupied by saturation matrix.
141 static void SMFree (SatMatrix **matrix) {
142 SatMatrix *SM = *matrix;
144 if (SM) {
145 if (SM->p) {
146 free ((char *) SM->p_init);
147 free ((char *) SM->p);
149 free ((char *) SM);
150 *matrix = NULL;
152 } /* SMFree */
155 * Print the contents of a saturation matrix.
156 * This function is defined only for debugging purpose.
158 static void SMPrint (SatMatrix *matrix) {
160 int *p;
161 int i, j;
162 unsigned NbRows, NbColumns;
164 fprintf(stderr,"%d %d\n",NbRows=matrix->NbRows, NbColumns=matrix->NbColumns);
165 for (i=0;i<NbRows;i++) {
166 p = *(matrix->p+i);
167 for (j=0;j<NbColumns;j++)
168 fprintf(stderr, " %10X ", *p++);
169 fprintf(stderr, "\n");
171 } /* SMPrint */
174 * Compute the bitwise OR of two saturation matrices.
176 static void SatVector_OR(int *p1,int *p2,int *p3,unsigned length) {
178 int *cp1, *cp2, *cp3;
179 int i;
181 cp1=p1;
182 cp2=p2;
183 cp3=p3;
184 for (i=0;i<length;i++) {
185 *cp3 = *cp1 | *cp2;
186 cp3++;
187 cp1++;
188 cp2++;
190 } /* SatVector_OR */
193 * Copy a saturation matrix to another (macro definition).
195 #define SMVector_Copy(p1, p2, length) \
196 memcpy((char *)(p2), (char *)(p1), (int)((length)*sizeof(int)))
199 * Initialize a saturation matrix with zeros (macro definition)
201 #define SMVector_Init(p1, length) \
202 memset((char *)(p1), 0, (int)((length)*sizeof(int)))
205 * Defining operations on polyhedron --
209 * Vector p3 is a linear combination of two vectors (p1 and p2) such that
210 * p3[pos] is zero. First element of each vector (p1,p2,p3) is a status
211 * element and is not changed in p3. The value of 'pos' may be 0 however.
212 * The parameter 'length' does not include status element one.
214 static void Combine(Value *p1, Value *p2, Value *p3, int pos, unsigned length) {
216 Value a1, a2, gcd;
217 Value abs_a1,abs_a2,neg_a1;
219 /* Initialize all the 'Value' variables */
220 value_init(a1); value_init(a2); value_init(gcd);
221 value_init(abs_a1); value_init(abs_a2); value_init(neg_a1);
223 /* a1 = p1[pos] */
224 value_assign(a1,p1[pos]);
226 /* a2 = p2[pos] */
227 value_assign(a2,p2[pos]);
229 /* a1_abs = |a1| */
230 value_absolute(abs_a1,a1);
232 /* a2_abs = |a2| */
233 value_absolute(abs_a2,a2);
235 /* gcd = Gcd(abs(a1), abs(a2)) */
236 value_gcd(gcd, abs_a1, abs_a2);
238 /* a1 = a1/gcd */
239 value_divexact(a1, a1, gcd);
241 /* a2 = a2/gcd */
242 value_divexact(a2, a2, gcd);
244 /* neg_a1 = -(a1) */
245 value_oppose(neg_a1,a1);
247 Vector_Combine(p1+1,p2+1,p3+1,a2,neg_a1,length);
248 Vector_Normalize(p3+1,length);
250 /* Clear all the 'Value' variables */
251 value_clear(a1); value_clear(a2); value_clear(gcd);
252 value_clear(abs_a1); value_clear(abs_a2); value_clear(neg_a1);
254 return;
255 } /* Combine */
258 * Return the transpose of the saturation matrix 'Sat'. 'Mat' is a matrix
259 * of constraints and 'Ray' is a matrix of ray vectors and 'Sat' is the
260 * corresponding saturation matrix.
262 static SatMatrix *TransformSat(Matrix *Mat, Matrix *Ray, SatMatrix *Sat) {
264 int i, j, sat_nbcolumns;
265 unsigned jx1, jx2, bx1, bx2;
266 SatMatrix *result;
268 if (Mat->NbRows != 0)
269 sat_nbcolumns = (Mat->NbRows-1) /(sizeof(int)*8) + 1;
270 else
271 sat_nbcolumns = 0;
273 result = SMAlloc(Ray->NbRows, sat_nbcolumns);
274 SMVector_Init(result->p_init, Ray->NbRows * sat_nbcolumns);
276 for(i=0,jx1=0,bx1=MSB; i<Ray->NbRows; i++) {
277 for(j=0,jx2=0,bx2=MSB; j<Mat->NbRows; j++) {
278 if (Sat->p[j][jx1] & bx1)
279 result->p[i][jx2] |= bx2;
280 NEXT(jx2,bx2);
282 NEXT(jx1, bx1);
284 return result;
285 } /* TransformSat */
288 * Sort the rays (Ray, Sat) into three tiers as used in 'Chernikova' function:
289 * NbBid <= i < equal_bound : saturates the constraint
290 * equal_bound <= i < sup_bound : verifies the constraint
291 * sup_bound <= i < NbRay : does not verify
293 * 'Ray' is the matrix of rays and 'Sat' is the corresponding saturation
294 * matrix. (jx,bx) pair specify the constraint in the saturation matrix. The
295 * status element of the 'Ray' matrix holds the saturation value w.r.t the
296 * constraint specified by (jx,bx). Thus
297 * Ray->p[i][0] = 0 -> ray(i) saturates the constraint
298 * Ray->p[i][0] > 0 -> ray(i) verifies the constraint
299 * Ray->p[i][0] < 0 -> ray(i) doesn't verify the constraint
301 static void RaySort(Matrix *Ray,SatMatrix *Sat,int NbBid,int NbRay,int *equal_bound,int *sup_bound,unsigned RowSize1, unsigned RowSize2, unsigned bx, unsigned jx) {
303 int inf_bound;
304 Value **uni_eq, **uni_sup, **uni_inf;
305 int **inc_eq, **inc_sup, **inc_inf;
307 /* 'uni_eq' points to the first ray in the ray matrix which verifies a
308 * constraint, 'inc_eq' is the corresponding pointer in saturation
309 * matrix. 'uni_inf' points to the first ray (from top) which doesn't
310 * verify a constraint, 'inc_inf' is the corresponding pointer in
311 * saturation matrix. 'uni_sup' scans the ray matrix and 'inc_sup' is
312 * the corresponding pointer in saturation matrix. 'inf_bound' holds the
313 * number of the first ray which does not verify the constraints.
316 *sup_bound = *equal_bound = NbBid;
317 uni_sup = uni_eq = Ray->p+NbBid;
318 inc_sup = inc_eq = Sat->p+NbBid;
319 inf_bound = NbRay;
320 uni_inf = Ray->p+NbRay;
321 inc_inf = Sat->p+NbRay;
323 while (inf_bound>*sup_bound) {
324 if (value_zero_p(**uni_sup)) { /* status = satisfy */
325 if (inc_eq != inc_sup) {
326 Vector_Exchange(*uni_eq,*uni_sup,RowSize1);
327 bexchange(*inc_eq,*inc_sup,RowSize2);
329 (*equal_bound)++; uni_eq++; inc_eq++;
330 (*sup_bound)++; uni_sup++; inc_sup++;
332 else {
333 *((*inc_sup)+jx)|=bx;
335 /* if (**uni_sup<0) */
336 if (value_neg_p(**uni_sup)) { /* Status != verify */
337 inf_bound--; uni_inf--; inc_inf--;
338 if (inc_inf != inc_sup) {
339 Vector_Exchange(*uni_inf,*uni_sup,RowSize1);
340 bexchange(*inc_inf,*inc_sup,RowSize2);
343 else { /* status == verify */
344 (*sup_bound)++; uni_sup++; inc_sup++;
348 } /* RaySort */
350 static void SatMatrix_Extend(SatMatrix *Sat, Matrix* Mat, unsigned rows)
352 int i;
353 unsigned cols;
354 cols = (Mat->NbRows - 1)/(sizeof(int)*8) + 1;
356 Sat->p = (int **)realloc(Sat->p, rows * sizeof(int *));
357 if(!Sat->p) {
358 errormsg1("SatMatrix_Extend", "outofmem", "out of memory space");
359 return;
361 Sat->p_init = (int *)realloc(Sat->p_init, rows * cols * sizeof (int));
362 if(!Sat->p_init) {
363 errormsg1("SatMatrix_Extend", "outofmem", "out of memory space");
364 return;
366 for (i = 0; i < rows; ++i)
367 Sat->p[i] = Sat->p_init + (i * cols);
368 Sat->NbRows = rows;
372 * Compute the dual of matrix 'Mat' and place it in matrix 'Ray'.'Mat'
373 * contains the constraints (equalities and inequalities) in rows and 'Ray'
374 * contains the ray space (lines and rays) in its rows. 'Sat' is a boolean
375 * saturation matrix defined as Sat(i,j)=0 if ray(i) saturates constraint(j),
376 * otherwise 1. The constraints in the 'Mat' matrix are processed starting at
377 * 'FirstConstraint', 'Ray' and 'Sat' matrices are changed accordingly.'NbBid'
378 * is the number of lines in the ray matrix and 'NbMaxRays' is the maximum
379 * number of rows (rays) permissible in the 'Ray' and 'Sat' matrix. Return 0
380 * if successful, otherwise return 1.
382 static int Chernikova (Matrix *Mat,Matrix *Ray,SatMatrix *Sat, unsigned NbBid, unsigned NbMaxRays, unsigned FirstConstraint,unsigned dual) {
384 unsigned NbRay, Dimension, NbConstraints, RowSize1, RowSize2, sat_nbcolumns;
385 int sup_bound, equal_bound, index_non_zero, bound;
386 int i, j, k, l, redundant, rayonly, nbcommonconstraints;
387 int *Temp, aux;
388 int *ip1, *ip2;
389 unsigned bx, m, jx;
390 Value *p1, *p2, *p3;
392 #ifdef POLY_CH_DEBUG
393 fprintf(stderr, "[Chernikova: Input]\nRay = ");
394 Matrix_Print(stderr,0,Ray);
395 fprintf(stderr, "\nConstraints = ");
396 Matrix_Print(stderr,0,Mat);
397 fprintf(stderr, "\nSat = ");
398 SMPrint(Sat);
399 #endif
401 NbConstraints=Mat->NbRows;
402 NbRay = Ray->NbRows;
403 Dimension = Mat->NbColumns-1; /* Homogeneous Dimension */
404 sat_nbcolumns=Sat->NbColumns;
406 RowSize1=(Dimension+1);
407 RowSize2=sat_nbcolumns * sizeof(int);
409 Temp=(int *)malloc(RowSize2);
410 if(!Temp) {
411 errormsg1("Chernikova", "outofmem", "out of memory space");
412 return 0;
414 CATCH(any_exception_error) {
417 * In case of overflow, free the allocated memory!
418 * Rethrow upwards the stack to forward the exception.
420 free(Temp);
421 RETHROW();
423 TRY {
424 jx = FirstConstraint/WSIZE;
425 bx = MSB; bx >>= FirstConstraint%WSIZE;
426 for (k=FirstConstraint; k<NbConstraints; k++) {
428 /* Set the status word of each ray[i] to ray[i] dot constraint[k] */
429 /* This is equivalent to evaluating each ray by the constraint[k] */
430 /* 'index_non_zero' is assigned the smallest ray index which does */
431 /* not saturate the constraint. */
433 index_non_zero = NbRay;
434 for (i=0; i<NbRay; i++) {
435 p1 = Ray->p[i]+1;
436 p2 = Mat->p[k]+1;
437 p3 = Ray->p[i];
439 /* *p3 = *p1 * *p2 */
440 value_multiply(*p3,*p1,*p2);
441 p1++; p2++;
442 for (j=1; j<Dimension; j++) {
444 /* *p3 += *p1 * *p2 */
445 value_addmul(*p3, *p1, *p2);
446 p1++; p2++;
448 if (value_notzero_p(*p3) && (i<index_non_zero))
449 index_non_zero=i;
452 #ifdef POLY_CH_DEBUG
453 fprintf(stderr, "[Chernikova: A]\nRay = ");
454 Matrix_Print(stderr,0,Ray);
455 fprintf(stderr, "\nConstraints = ");
456 Matrix_Print(stderr,0,Mat);
457 fprintf(stderr, "\nSat = ");
458 SMPrint (Sat);
459 #endif
461 /* Find a bidirectional ray z such that cz <> 0 */
462 if (index_non_zero<NbBid) {
464 /* Discard index_non_zero bidirectional ray */
465 NbBid--;
466 if (NbBid!=index_non_zero)
467 Vector_Exchange(Ray->p[index_non_zero],Ray->p[NbBid],RowSize1);
469 #ifdef POLY_CH_DEBUG
470 fprintf(stderr,"************\n");
471 for(i=0;i<RowSize1;i++) {
472 value_print(stderr,P_VALUE_FMT,Ray->p[index_non_zero][i]);
474 fprintf(stderr,"\n******\n");
475 for(i=0;i<RowSize1;i++) {
476 value_print(stderr,P_VALUE_FMT,Ray->p[NbBid][i]);
478 fprintf(stderr,"\n*******\n");
479 #endif
481 /* Compute the new lineality space */
482 for (i=0; i<NbBid; i++)
483 if (value_notzero_p(Ray->p[i][0]))
484 Combine(Ray->p[i],Ray->p[NbBid],Ray->p[i],0,Dimension);
486 /* Add the positive part of index_non_zero bidirectional ray to */
487 /* the set of unidirectional rays */
489 if (value_neg_p(Ray->p[NbBid][0])) {
490 p1=Ray->p[NbBid];
491 for (j=0;j<Dimension+1; j++) {
493 /* *p1 = - *p1 */
494 value_oppose(*p1,*p1);
495 p1++;
499 #ifdef POLY_CH_DEBUG
500 fprintf(stderr, "[Chernikova: B]\nRay = ");
501 Ray->NbRows=NbRay;
502 Matrix_Print(stderr,0,Ray);
503 fprintf(stderr, "\nConstraints = ");
504 Matrix_Print(stderr,0,Mat);
505 fprintf(stderr, "\nSat = ");
506 SMPrint(Sat);
507 #endif
509 /* Compute the new pointed cone */
510 for (i=NbBid+1; i<NbRay; i++)
511 if (value_notzero_p(Ray->p[i][0]))
512 Combine(Ray->p[i],Ray->p[NbBid],Ray->p[i],0,Dimension);
514 /* Add the new ray */
515 if (value_notzero_p(Mat->p[k][0])) { /* Constraint is an inequality */
516 for (j=0;j<sat_nbcolumns;j++) {
517 Sat->p[NbBid][j] = 0; /* Saturation vec for new ray */
519 /* The new ray saturates everything except last inequality */
520 Sat->p[NbBid][jx] |= bx;
522 else { /* Constraint is an equality */
523 if (--NbRay != NbBid) {
524 Vector_Copy(Ray->p[NbRay],Ray->p[NbBid],Dimension+1);
525 SMVector_Copy(Sat->p[NbRay],Sat->p[NbBid],sat_nbcolumns);
529 #ifdef POLY_CH_DEBUG
530 fprintf(stderr, "[Chernikova: C]\nRay = ");
531 Ray->NbRows=NbRay;
532 Matrix_Print(stderr,0,Ray);
533 fprintf(stderr, "\nConstraints = ");
534 Matrix_Print(stderr,0,Mat);
535 fprintf(stderr, "\nSat = ");
536 SMPrint (Sat);
537 #endif
540 else { /* If the new constraint satisfies all the rays */
541 RaySort(Ray, Sat, NbBid, NbRay, &equal_bound, &sup_bound,
542 RowSize1, RowSize2,bx,jx);
544 /* Sort the unidirectional rays into R0, R+, R- */
545 /* Ray
546 NbRay-> bound-> ________
547 | R- | R- ==> ray.eq < 0 (outside domain)
548 sup-> |------|
549 | R+ | R+ ==> ray.eq > 0 (inside domain)
550 equal-> |------|
551 | R0 | R0 ==> ray.eq = 0 (on face of domain)
552 NbBid-> |______|
555 #ifdef POLY_CH_DEBUG
556 fprintf(stderr, "[Chernikova: D]\nRay = ");
557 Ray->NbRows=NbRay;
558 Matrix_Print(stderr,0,Ray);
559 fprintf(stderr, "\nConstraints = ");
560 Matrix_Print(stderr,0,Mat);
561 fprintf(stderr, "\nSat = ");
562 SMPrint (Sat);
563 #endif
565 /* Compute only the new pointed cone */
566 bound=NbRay;
567 for (i=equal_bound; i<sup_bound; i++) /* for all pairs of R- and R+ */
568 for(j=sup_bound; j<bound; j++) {
570 /*--------------------------------------------------------------*/
571 /* Count the set of constraints saturated by R+ and R- */
572 /* Includes equalities, inequalities and the positivity constraint */
573 /*-----------------------------------------------------------------*/
575 nbcommonconstraints = 0;
576 for (l=0; l<jx; l++) {
577 aux = Temp[l] = Sat->p[i][l] | Sat->p[j][l];
578 for (m=MSB; m!=0; m>>=1)
579 if (!(aux&m))
580 nbcommonconstraints++;
582 aux = Temp[jx] = Sat->p[i][jx] | Sat->p[j][jx];
583 for (m=MSB; m!=bx; m>>=1)
584 if (!(aux&m))
585 nbcommonconstraints++;
586 rayonly = (value_zero_p(Ray->p[i][Dimension]) &&
587 value_zero_p(Ray->p[j][Dimension]) &&
588 (dual == 0));
589 if(rayonly)
590 nbcommonconstraints++; /* account for pos constr */
592 /*-----------------------------------------------------------------*/
593 /* Adjacency Test : is combination [R-,R+] a non redundant ray? */
594 /*-----------------------------------------------------------------*/
596 if (nbcommonconstraints+NbBid>=Dimension-2) { /* Dimensionality check*/
597 /* Check whether a ray m saturates the same set of constraints */
598 redundant=0;
599 for (m=NbBid; m<bound; m++)
600 if ((m!=i)&&(m!=j)) {
602 /* Two rays (r+ r-) are never made redundant by a vertex */
603 /* because the positivity constraint saturates both rays */
604 /* but not the vertex */
606 if (rayonly && value_notzero_p(Ray->p[m][Dimension]))
607 continue;
609 /* (r+ r-) is redundant if there doesn't exist an equation */
610 /* which saturates both r+ and r- but not rm. */
612 ip1 = Temp;
613 ip2 = Sat->p[m];
614 for (l=0; l<=jx; l++,ip2++,ip1++)
615 if (*ip2 & ~*ip1)
616 break;
617 if (l>jx) {
618 redundant=1;
619 break;
623 #ifdef POLY_CH_DEBUG
624 fprintf(stderr, "[Chernikova: E]\nRay = ");
625 Ray->NbRows=NbRay;
626 Matrix_Print(stderr,0,Ray);
627 fprintf(stderr, "\nConstraints = ");
628 Matrix_Print(stderr,0,Mat);
629 fprintf(stderr, "\nSat = ");
630 SMPrint (Sat);
631 #endif
633 /*------------------------------------------------------------*/
634 /* Add new ray generated by [R+,R-] */
635 /*------------------------------------------------------------*/
637 if (!redundant) {
638 if (NbRay==NbMaxRays) {
639 NbMaxRays *= 2;
640 Ray->NbRows = NbRay;
641 Matrix_Extend(Ray, NbMaxRays);
642 SatMatrix_Extend(Sat, Mat, NbMaxRays);
645 /* Compute the new ray */
646 Combine(Ray->p[j],Ray->p[i],Ray->p[NbRay],0,Dimension);
647 SatVector_OR(Sat->p[j],Sat->p[i],Sat->p[NbRay],sat_nbcolumns);
648 Sat->p[NbRay][jx] &= ~bx;
649 NbRay++;
654 #ifdef POLY_CH_DEBUG
655 fprintf(stderr,
656 "[Chernikova: F]\n"
657 "sup_bound=%d\n"
658 "equal_bound=%d\n"
659 "bound=%d\n"
660 "NbRay=%d\n"
661 "Dimension = %d\n"
662 "Ray = ",sup_bound,equal_bound,bound,NbRay,Dimension);
663 #endif
664 #ifdef POLY_CH_DEBUG
665 Ray->NbRows=NbRay;
666 fprintf(stderr, "[Chernikova: F]:\nRay = ");
667 Matrix_Print(stderr,0,Ray);
668 #endif
670 /* Eliminates all non extremal rays */
671 /* j = (Mat->p[k][0]) ? */
673 j = (value_notzero_p(Mat->p[k][0])) ?
674 sup_bound : equal_bound;
676 i = NbRay;
677 #ifdef POLY_CH_DEBUG
678 fprintf(stderr, "i = %d\nj = %d \n", i, j);
679 #endif
680 while ((j<bound)&&(i>bound)) {
681 i--;
682 Vector_Copy(Ray->p[i],Ray->p[j],Dimension+1);
683 SMVector_Copy(Sat->p[i],Sat->p[j],sat_nbcolumns);
684 j++;
687 #ifdef POLY_CH_DEBUG
688 fprintf(stderr, "i = %d\nj = %d \n", i, j);
689 fprintf(stderr,
690 "[Chernikova: F]\n"
691 "sup_bound=%d\n"
692 "equal_bound=%d\n"
693 "bound=%d\n"
694 "NbRay=%d\n"
695 "Dimension = %d\n"
696 "Ray = ",sup_bound,equal_bound,bound,NbRay, Dimension);
697 #endif
698 #ifdef POLY_CH_DEBUG
699 Ray->NbRows=NbRay;
700 fprintf(stderr, "[Chernikova: G]\nRay = ");
701 Matrix_Print(stderr,0,Ray);
702 #endif
703 if (j==bound)
704 NbRay=i;
705 else
706 NbRay=j;
708 NEXT(jx,bx);
710 Ray->NbRows=NbRay;
711 Sat->NbRows=NbRay;
713 } /* End of TRY */
715 UNCATCH(any_exception_error);
716 free(Temp);
718 #ifdef POLY_CH_DEBUG
719 fprintf(stderr, "[Chernikova: Output]\nRay = ");
720 Matrix_Print(stderr,0,Ray);
721 fprintf(stderr, "\nConstraints = ");
722 Matrix_Print(stderr,0,Mat);
723 fprintf(stderr, "\nSat = ");
724 SMPrint (Sat);
725 #endif
727 return 0;
728 } /* Chernikova */
730 static int Gauss4(Value **p, int NbEq, int NbRows, int Dimension)
732 int i, j, k, pivot, Rank;
733 int *column_index = NULL;
734 Value gcd;
736 value_init(gcd);
737 column_index=(int *)malloc(Dimension * sizeof(int));
738 if(!column_index) {
739 errormsg1("Gauss","outofmem","out of memory space");
740 value_clear(gcd);
741 return 0;
743 Rank=0;
745 CATCH(any_exception_error) {
746 if (column_index)
747 free(column_index);
748 value_clear(gcd);
749 RETHROW();
751 TRY {
753 for (j=1; j<=Dimension; j++) { /* for each column (except status) */
754 for (i=Rank; i<NbEq; i++) /* starting at diagonal, look down */
756 /* if (Mat->p[i][j] != 0) */
757 if (value_notzero_p(p[i][j]))
758 break; /* Find the first non zero element */
759 if (i!=NbEq) { /* If a non-zero element is found? */
760 if (i!=Rank) /* If it is found below the diagonal*/
761 Vector_Exchange(p[Rank]+1,p[i]+1,Dimension);
763 /* Normalize the pivot row by dividing it by the gcd */
764 /* gcd = Vector_Gcd(p[Rank]+1,Dimension) */
765 Vector_Gcd(p[Rank]+1,Dimension,&gcd);
767 if (value_cmp_si(gcd, 2) >= 0)
768 Vector_AntiScale(p[Rank]+1, p[Rank]+1, gcd, Dimension);
770 if (value_neg_p(p[Rank][j]))
771 Vector_Oppose(p[Rank]+1, p[Rank]+1, Dimension);
773 pivot=i;
774 for (i=pivot+1; i<NbEq; i++) { /* Zero out the rest of the column */
776 /* if (Mat->p[i][j] != 0) */
777 if (value_notzero_p(p[i][j]))
778 Combine(p[i],p[Rank],p[i],j,Dimension);
781 /* For each row with non-zero entry Mat->p[Rank], store the column */
782 /* number 'j' in 'column_index[Rank]'. This information will be */
783 /* useful in performing Gaussian elimination backward step. */
785 column_index[Rank]=j;
786 Rank++;
788 } /* end of Gaussian elimination forward step */
790 /* Back Substitution -- normalize the system of equations */
791 for (k=Rank-1; k>=0; k--) {
792 j = column_index[k];
794 /* Normalize the equations */
795 for (i=0; i<k; i++) {
797 /* if (Mat->p[i][j] != 0) */
798 if (value_notzero_p(p[i][j]))
799 Combine(p[i],p[k],p[i],j,Dimension);
802 /* Normalize the inequalities */
803 for (i=NbEq;i<NbRows;i++) {
805 /* if (Mat->p[i][j] != 0) */
806 if (value_notzero_p(p[i][j]))
807 Combine(p[i],p[k],p[i],j,Dimension);
810 } /* end of TRY */
812 UNCATCH(any_exception_error);
813 free(column_index), column_index = NULL;
815 value_clear(gcd);
816 return Rank;
817 } /* Gauss */
820 * Compute a minimal system of equations using Gausian elimination method.
821 * 'Mat' is a matrix of constraints in which the first 'Nbeq' constraints
822 * are equations. The dimension of the homogenous system is 'Dimension'.
823 * The function returns the rank of the matrix 'Mat'.
825 int Gauss(Matrix *Mat, int NbEq, int Dimension)
827 int Rank;
829 #ifdef POLY_DEBUG
830 fprintf(stderr, "[Gauss : Input]\nRay =");
831 Matrix_Print(stderr,0,Mat);
832 #endif
834 Rank = Gauss4(Mat->p, NbEq, Mat->NbRows, Dimension);
836 #ifdef POLY_DEBUG
837 fprintf(stderr, "[Gauss : Output]\nRay =");
838 Matrix_Print(stderr,0,Mat);
839 #endif
841 return Rank;
845 * Given 'Mat' - a matrix of equations and inequalities, 'Ray' - a matrix of
846 * lines and rays, 'Sat' - the corresponding saturation matrix, and 'Filter'
847 * - an array to mark (with 1) the non-redundant equalities and inequalities,
848 * compute a polyhedron composed of 'Mat' as constraint matrix and 'Ray' as
849 * ray matrix after reductions. This function is usually called as a follow
850 * up to 'Chernikova' to remove redundant constraints or rays.
851 * Note: (1) 'Chernikova' ensures that there are no redundant lines and rays.
852 * (2) The same function can be used with constraint and ray matrix used
853 interchangbly.
855 static Polyhedron *Remove_Redundants(Matrix *Mat,Matrix *Ray,SatMatrix *Sat,unsigned *Filter) {
857 int i, j, k;
858 unsigned Dimension, sat_nbcolumns, NbRay, NbConstraints, RowSize2,
859 *Trace = NULL, *bx = NULL, *jx = NULL, Dim_RaySpace, b;
860 unsigned NbBid, NbUni, NbEq, NbIneq;
861 unsigned NbBid2, NbUni2, NbEq2, NbIneq2;
862 int Redundant;
863 int aux, *temp2 = NULL;
864 Polyhedron *Pol = NULL;
865 Vector *temp1 = NULL;
866 unsigned Status;
868 Dimension = Mat->NbColumns-1; /* Homogeneous Dimension */
869 NbRay = Ray->NbRows;
870 sat_nbcolumns = Sat->NbColumns;
871 NbConstraints = Mat->NbRows;
872 RowSize2=sat_nbcolumns * sizeof(int);
874 temp1 = Vector_Alloc(Dimension+1);
875 if (!temp1) {
876 errormsg1("Remove_Redundants", "outofmem", "out of memory space");
877 return 0;
880 if (Filter) {
881 temp2 = (int *)calloc(sat_nbcolumns, sizeof(int));
882 if (!temp2)
883 goto oom;
886 /* Introduce indirections into saturation matrix 'Sat' to simplify */
887 /* processing with 'Sat' and allow easy exchanges of columns. */
888 bx = (unsigned *)malloc(NbConstraints * sizeof(unsigned));
889 if (!bx)
890 goto oom;
891 jx = (unsigned *)malloc(NbConstraints * sizeof(unsigned));
892 if (!jx)
893 goto oom;
894 CATCH(any_exception_error) {
896 Vector_Free(temp1);
897 if (temp2) free(temp2);
898 if (bx) free(bx);
899 if (jx) free(jx);
900 if (Trace) free(Trace);
901 if (Pol) Polyhedron_Free(Pol);
903 RETHROW();
905 TRY {
907 /* For each constraint 'j' following mapping is defined to facilitate */
908 /* data access from saturation matrix 'Sat' :- */
909 /* (1) jx[j] -> floor[j/(8*sizeof(int))] */
910 /* (2) bx[j] -> bin(00..10..0) where position of 1 = j%(8*sizeof(int)) */
912 i = 0;
913 b = MSB;
914 for (j=0; j<NbConstraints; j++) {
915 jx[j] = i;
916 bx[j] = b;
917 NEXT(i,b);
921 * STEP(0): Count the number of vertices among the rays while initializing
922 * the ray status count to 0. If no vertices are found, quit the procedure
923 * and return an empty polyhedron as the result.
926 /* Reset the status element of each ray to zero. Store the number of */
927 /* vertices in 'aux'. */
928 aux = 0;
929 for (i=0; i<NbRay; i++) {
931 /* Ray->p[i][0] = 0 */
932 value_set_si(Ray->p[i][0],0);
934 /* If ray(i) is a vertex of the Inhomogenous system */
935 if (value_notzero_p(Ray->p[i][Dimension]))
936 aux++;
939 /* If no vertices, return an empty polyhedron. */
940 if (!aux)
941 goto empty;
943 #ifdef POLY_RR_DEBUG
944 fprintf(stderr, "[Remove_redundants : Init]\nConstraints =");
945 Matrix_Print(stderr,0,Mat);
946 fprintf(stderr, "\nRays =");
947 Matrix_Print(stderr,0,Ray);
948 #endif
951 * STEP(1): Compute status counts for both rays and inequalities. For each
952 * constraint, count the number of vertices/rays saturated by that
953 * constraint, and put the result in the status words. At the same time,
954 * for each vertex/ray, count the number of constraints saturated by it.
955 * Delete any positivity constraints, but give rays credit in their status
956 * counts for saturating the positivity constraint.
959 NbEq=0;
961 #ifdef POLY_RR_DEBUG
962 fprintf (stderr, " j = ");
963 #endif
965 for (j=0; j<NbConstraints; j++) {
967 #ifdef POLY_RR_DEBUG
968 fprintf (stderr, " %i ", j);
969 fflush (stderr);
970 #endif
972 /* If constraint(j) is an equality, mark '1' in array 'temp2' */
973 if (Filter && value_zero_p(Mat->p[j][0]))
974 temp2[jx[j]] |= bx[j];
975 /* Reset the status element of each constraint to zero */
976 value_set_si(Mat->p[j][0],0);
978 /* Identify and remove the positivity constraint 1>=0 */
979 i = First_Non_Zero(Mat->p[j]+1, Dimension-1);
981 #ifdef POLY_RR_DEBUG
982 fprintf(stderr, "[Remove_redundants : IntoStep1]\nConstraints =");
983 Matrix_Print(stderr,0,Mat);
984 fprintf (stderr, " j = %i \n", j);
985 #endif
987 /* Check if constraint(j) is a positivity constraint, 1 >= 0, or if it */
988 /* is 1==0. If constraint(j) saturates all the rays of the matrix 'Ray'*/
989 /* then it is an equality. in this case, return an empty polyhedron. */
991 if (i == -1) {
992 for (i=0; i<NbRay; i++)
993 if (!(Sat->p[i][jx[j]]&bx[j])) {
995 /* Mat->p[j][0]++ */
996 value_increment(Mat->p[j][0],Mat->p[j][0]);
999 /* if ((Mat->p[j][0] == NbRay) && : it is an equality
1000 (Mat->p[j][Dimension] != 0)) : and its not 0=0 */
1001 if ((value_cmp_si(Mat->p[j][0], NbRay) == 0) &&
1002 (value_notzero_p(Mat->p[j][Dimension])))
1003 goto empty;
1005 /* Delete the positivity constraint */
1006 NbConstraints--;
1007 if (j==NbConstraints) continue;
1008 Vector_Exchange(Mat->p[j], Mat->p[NbConstraints], temp1->Size);
1009 exchange(jx[j], jx[NbConstraints], aux);
1010 exchange(bx[j], bx[NbConstraints], aux);
1011 j--; continue;
1014 /* Count the number of vertices/rays saturated by each constraint. At */
1015 /* the same time, count the number of constraints saturated by each ray*/
1016 for (i=0; i<NbRay; i++)
1017 if (!(Sat->p[i][jx[j]]&bx[j])) {
1019 /* Mat->p[j][0]++ */
1020 value_increment(Mat->p[j][0],Mat->p[j][0]);
1022 /* Ray->p[i][0]++ */
1023 value_increment (Ray->p[i][0],Ray->p[i][0]);
1026 /* if (Mat->p[j][0]==NbRay) then increment the number of eq. count */
1027 if (value_cmp_si(Mat->p[j][0], NbRay) == 0)
1028 NbEq++; /* all vertices/rays are saturated */
1030 Mat->NbRows = NbConstraints;
1032 NbBid=0;
1033 for (i=0; i<NbRay; i++) {
1035 /* Give rays credit for saturating the positivity constraint */
1036 if (value_zero_p(Ray->p[i][Dimension]))
1038 /* Ray->p[i][0]++ */
1039 value_increment(Ray->p[i][0],Ray->p[i][0]);
1041 /* If ray(i) saturates all the constraints including positivity */
1042 /* constraint then it is a bi-directional ray or line. Increment */
1043 /* 'NbBid' by one. */
1045 /* if (Ray->p[i][0]==NbConstraints+1) */
1046 if (value_cmp_si(Ray->p[i][0], NbConstraints+1) == 0)
1047 NbBid++;
1050 #ifdef POLY_RR_DEBUG
1051 fprintf(stderr, "[Remove_redundants : Step1]\nConstraints =");
1052 Matrix_Print(stderr,0,Mat);
1053 fprintf(stderr, "\nRay =");
1054 Matrix_Print(stderr,0,Ray);
1055 #endif
1058 * STEP(2): Sort equalities to the top of constraint matrix 'Mat'. Detect
1059 * implicit equations such as y>=3; y<=3. Keep Inequalities in same
1060 * relative order. (Note: Equalities are constraints which saturate all of
1061 * the rays)
1064 for (i=0; i<NbEq; i++) {
1066 /* If constraint(i) doesn't saturate some ray, then it is an inequality*/
1067 if (value_cmp_si(Mat->p[i][0], NbRay) != 0) {
1069 /* Skip over inequalities and find an equality */
1070 for (k=i+1; k < NbConstraints && value_cmp_si(Mat->p[k][0], NbRay) != 0 ; k++)
1072 if (k>=NbConstraints) /* If none found then error */ break;
1074 /* Slide inequalities down the array 'Mat' and move equality up to */
1075 /* position 'i'. */
1076 Vector_Copy(Mat->p[k], temp1->p, temp1->Size);
1077 aux = jx[k];
1078 j = bx[k];
1079 for (;k>i;k--) {
1080 Vector_Copy(Mat->p[k-1], Mat->p[k], temp1->Size);
1081 jx[k] = jx[k-1];
1082 bx[k] = bx[k-1];
1084 Vector_Copy(temp1->p, Mat->p[i], temp1->Size);
1085 jx[i] = aux;
1086 bx[i] = j;
1090 /* for SIMPLIFY */
1091 if (Filter) {
1092 Value mone;
1093 value_init(mone);
1094 value_set_si(mone, -1);
1095 /* Normalize equalities to have lexpositive coefficients to
1096 * be able to detect identical equalities.
1098 for (i = 0; i < NbEq; i++) {
1099 int pos = First_Non_Zero(Mat->p[i]+1, Dimension);
1100 if (pos == -1)
1101 continue;
1102 if (value_neg_p(Mat->p[i][1+pos]))
1103 Vector_Scale(Mat->p[i]+1, Mat->p[i]+1, mone, Dimension);
1105 value_clear(mone);
1106 for (i=0; i<NbEq; i++) {
1108 /* Detect implicit constraints such as y>=3 and y<=3 */
1109 Redundant = 0;
1110 for (j=i+1; j<NbEq; j++) {
1111 /* Only check equalities, i.e., 'temp2' has entry 1 */
1112 if (!(temp2[jx[j]] & bx[j]))
1113 continue;
1114 /* Redundant if both are same `and' constraint(j) was equality. */
1115 if (Vector_Equal(Mat->p[i]+1, Mat->p[j]+1, Dimension)) {
1116 Redundant=1;
1117 break;
1121 /* Set 'Filter' entry to 1 corresponding to the irredundant equality*/
1122 if (!Redundant) Filter[jx[i]] |= bx[i]; /* set flag */
1126 #ifdef POLY_RR_DEBUG
1127 fprintf(stderr, "[Remove_redundants : Step2]\nConstraints =");
1128 Matrix_Print(stderr,0,Mat);
1129 fprintf(stderr, "\nRay =");
1130 Matrix_Print(stderr,0,Ray);
1131 #endif
1134 * STEP(3): Perform Gaussian elimiation on the list of equalities. Obtain
1135 * a minimal basis by solving for as many variables as possible. Use this
1136 * solution to reduce the inequalities by eliminating as many variables as
1137 * possible. Set NbEq2 to the rank of the system of equalities.
1140 NbEq2 = Gauss(Mat,NbEq,Dimension);
1142 /* If number of equalities is not less then the homogenous dimension, */
1143 /* return an empty polyhedron. */
1145 if (NbEq2 >= Dimension)
1146 goto empty;
1148 #ifdef POLY_RR_DEBUG
1149 fprintf(stderr, "[Remove_redundants : Step3]\nConstraints =");
1150 Matrix_Print(stderr,0,Mat);
1151 fprintf(stderr, "\nRay =");
1152 Matrix_Print(stderr,0,Ray);
1153 #endif
1156 * STEP(4): Sort lines to the top of ray matrix 'Ray', leaving rays
1157 * afterwards. Detect implicit lines such as ray(1,2) and ray(-1,-2).
1158 * (Note: Lines are rays which saturate all of the constraints including
1159 * the positivity constraint 1>=0.
1163 for (i=0, k=NbRay; i<NbBid && k>i; i++) {
1164 /* If ray(i) doesn't saturate some constraint then it is not a line */
1165 if (value_cmp_si(Ray->p[i][0], NbConstraints+1) != 0) {
1167 /* Skip over rays and vertices and find a line (bi-directional rays) */
1168 while (--k > i && value_cmp_si(Ray->p[k][0], NbConstraints+1) != 0)
1171 /* Exchange positions of ray(i) and line(k), thus sorting lines to */
1172 /* the top of matrix 'Ray'. */
1173 Vector_Exchange(Ray->p[i], Ray->p[k], temp1->Size);
1174 bexchange(Sat->p[i], Sat->p[k], RowSize2);
1178 #ifdef POLY_RR_DEBUG
1179 fprintf(stderr, "[Remove_redundants : Step4]\nConstraints =");
1180 Matrix_Print(stderr,0,Mat);
1181 fprintf(stderr, "\nRay =");
1182 Matrix_Print(stderr,0,Ray);
1183 #endif
1186 * STEP(5): Perform Gaussian elimination on the lineality space to obtain
1187 * a minimal basis of lines. Use this basis to reduce the representation
1188 * of the uniderectional rays. Set 'NbBid2' to the rank of the system of
1189 * lines.
1192 NbBid2 = Gauss(Ray, NbBid, Dimension);
1194 #ifdef POLY_RR_DEBUG
1195 fprintf(stderr, "[Remove_redundants : After Gauss]\nRay =");
1196 Matrix_Print(stderr,0,Ray);
1197 #endif
1199 /* If number of lines is not less then the homogenous dimension, return */
1200 /* an empty polyhedron. */
1201 if (NbBid2>=Dimension) {
1202 errormsg1("RemoveRedundants", "rmrdt", "dimension error");
1203 goto empty;
1206 /* Compute dimension of non-homogenous ray space */
1207 Dim_RaySpace = Dimension-1-NbEq2-NbBid2;
1209 #ifdef POLY_RR_DEBUG
1210 fprintf(stderr, "[Remove_redundants : Step5]\nConstraints =");
1211 Matrix_Print(stderr,0,Mat);
1212 fprintf(stderr, "\nRay =");
1213 Matrix_Print(stderr,0,Ray);
1214 #endif
1217 * STEP(6): Do a first pass filter of inequalities and equality identifi-
1218 * cation. New positivity constraints may have been created by step(3).
1219 * Check for and eliminate them. Count the irredundant inequalities and
1220 * store count in 'NbIneq'.
1223 NbIneq=0;
1224 for (j=0; j<NbConstraints; j++) {
1226 /* Identify and remove the positivity constraint 1>=0 */
1227 i = First_Non_Zero(Mat->p[j]+1, Dimension-1);
1229 /* Check if constraint(j) is a positivity constraint, 1>= 0, or if it */
1230 /* is 1==0. */
1231 if (i == -1) {
1232 /* if ((Mat->p[j][0]==NbRay) && : it is an equality
1233 (Mat->p[j][Dimension]!=0)) : and its not 0=0 */
1234 if ((value_cmp_si(Mat->p[j][0], NbRay) == 0) &&
1235 (value_notzero_p(Mat->p[j][Dimension])))
1236 goto empty;
1238 /* Set the positivity constraint redundant by setting status element */
1239 /* equal to 2. */
1240 value_set_si(Mat->p[j][0],2);
1241 continue;
1244 Status = VALUE_TO_INT(Mat->p[j][0]);
1246 if (Status == 0)
1247 value_set_si(Mat->p[j][0], 2); /* constraint is redundant */
1248 else if (Status < Dim_RaySpace)
1249 value_set_si(Mat->p[j][0], 2); /* constraint is redundant */
1250 else if (Status == NbRay)
1251 value_set_si(Mat->p[j][0], 0); /* constraint is an equality */
1252 else {
1253 NbIneq++; /* constraint is an irredundant inequality */
1254 value_set_si(Mat->p[j][0], 1); /* inequality */
1258 #ifdef POLY_RR_DEBUG
1259 fprintf(stderr, "[Remove_redundants : Step6]\nConstraints =");
1260 Matrix_Print(stderr,0,Mat);
1261 fprintf(stderr, "\nRay =");
1262 Matrix_Print(stderr,0,Ray);
1263 #endif
1266 * STEP(7): Do a first pass filter of rays and identification of lines.
1267 * Count the irredundant Rays and store count in 'NbUni'.
1270 NbUni=0;
1271 for (j=0; j<NbRay; j++) {
1272 Status = VALUE_TO_INT(Ray->p[j][0]);
1274 if (Status < Dim_RaySpace)
1275 value_set_si(Ray->p[j][0], 2); /* ray is redundant */
1276 else if (Status == NbConstraints+1)
1277 value_set_si(Ray->p[j][0], 0); /* ray is a line */
1278 else {
1279 NbUni++; /* an irredundant unidirectional ray. */
1280 value_set_si(Ray->p[j][0], 1); /* ray */
1285 * STEP(8): Create the polyhedron (using approximate sizes).
1286 * Number of constraints = NbIneq + NbEq2 + 1
1287 * Number of rays = NbUni + NbBid2
1288 * Partially fill the polyhedron structure with the lines computed in step
1289 * 3 and the equalities computed in step 5.
1292 Pol = Polyhedron_Alloc(Dimension-1, NbIneq+NbEq2+1, NbUni+NbBid2);
1293 if (!Pol) {
1294 UNCATCH(any_exception_error);
1295 goto oom;
1297 Pol->NbBid = NbBid2;
1298 Pol->NbEq = NbEq2;
1300 /* Partially fill the polyhedron structure */
1301 if (NbBid2) Vector_Copy(Ray->p[0], Pol->Ray[0], (Dimension+1)*NbBid2);
1302 if (NbEq2) Vector_Copy(Mat->p[0], Pol->Constraint[0], (Dimension+1)*NbEq2);
1304 #ifdef POLY_RR_DEBUG
1305 fprintf(stderr, "[Remove_redundants : Step7]\nConstraints =");
1306 Matrix_Print(stderr,0,Mat);
1307 fprintf(stderr, "\nRay =");
1308 Matrix_Print(stderr,0,Ray);
1309 #endif
1312 * STEP(9): Final Pass filter of inequalities and detection of redundant
1313 * inequalities. Redundant inequalities include:
1314 * (1) Inequalities which are always true, such as 1>=0,
1315 * (2) Redundant inequalities such as y>=4 given y>=3, or x>=1 given x=2.
1316 * (3) Redundant inequalities such as x+y>=5 given x>=3 and y>=2.
1317 * Every 'good' inequality must saturate at least 'Dimension' rays and be
1318 * unique.
1321 /* 'Trace' is a (1 X sat_nbcolumns) row matrix to hold the union of all */
1322 /* rows (corresponding to irredundant rays) of saturation matrix 'Sat' */
1323 /* which saturate some constraint 'j'. See figure below:- */
1324 Trace=(unsigned *)malloc(sat_nbcolumns * sizeof(unsigned));
1325 if(!Trace) {
1326 UNCATCH(any_exception_error);
1327 goto oom;
1330 /* NbEq NbConstraints
1331 |----------->
1332 ___________j____
1333 | | |
1334 | Mat | |
1335 |___________|___|
1337 NbRay ^ ________ ____________|____
1338 | |-------|--------|-----------0---|t1
1339 |i|-------|--------|-----------0---|t2
1340 | | Ray | | Sat |
1341 NbBid - |-------|--------|-----------0---|tk
1342 |_______| |_______________|
1345 -OR- (of rows t1,t2,...,tk)
1346 ________|___|____
1347 |_____Trace_0___|
1351 NbIneq2 = 0;
1352 for (j=NbEq; j<NbConstraints; j++) {
1354 /* if (Mat->p[j][0]==1) : non-redundant inequality */
1355 if (value_one_p (Mat->p[j][0])) {
1356 for (k=0; k<sat_nbcolumns; k++) Trace[k]=0; /* init Trace */
1358 /* Compute Trace: the union of all rows of Sat where constraint(j) */
1359 /* is saturated. */
1360 for (i=NbBid; i<NbRay; i++)
1362 /* if (Ray->p[i][0]==1) */
1363 if (value_one_p(Ray->p[i][0])) {
1364 if (!(Sat->p[i][jx[j]]&bx[j]))
1365 for (k=0; k<sat_nbcolumns; k++) Trace[k] |= Sat->p[i][k];
1368 /* Only constraint(j) should saturate this set of vertices/rays. */
1369 /* If another non-redundant constraint also saturates this set, */
1370 /* then constraint(j) is redundant */
1371 Redundant=0;
1372 for (i=NbEq; i<NbConstraints; i++) {
1374 /* if ((Mat->p[i][0] ==1) && (i!=j) && !(Trace[jx[i]] & bx[i]) ) */
1375 if (value_one_p(Mat->p[i][0]) && (i!=j) && !(Trace[jx[i]] & bx[i])) {
1376 Redundant=1;
1377 break;
1380 if (Redundant) {
1381 value_set_si(Mat->p[j][0],2);
1383 else {
1384 Vector_Copy(Mat->p[j], Pol->Constraint[NbEq2+NbIneq2], Dimension+1);
1385 if (Filter) Filter[jx[j]] |= bx[j]; /* for SIMPLIFY */
1386 NbIneq2++;
1390 free(Trace), Trace = NULL;
1392 #ifdef POLY_RR_DEBUG
1393 fprintf(stderr, "[Remove_redundants : Step8]\nConstraints =");
1394 Matrix_Print(stderr,0,Mat);
1395 fprintf(stderr, "\nRay =");
1396 Matrix_Print(stderr,0,Ray);
1397 #endif
1400 * Step(10): Final pass filter of rays and detection of redundant rays.
1401 * The final list of rays is written to polyhedron.
1404 /* Trace is a (NbRay x 1) column matrix to hold the union of all columns */
1405 /* (corresponding to irredundant inequalities) of saturation matrix 'Sat'*/
1406 /* which saturate some ray 'i'. See figure below:- */
1408 Trace=(unsigned *)malloc(NbRay * sizeof(unsigned));
1409 if(!Trace) {
1410 UNCATCH(any_exception_error);
1411 goto oom;
1414 /* NbEq NbConstraints
1415 |---------->
1416 ___________j_____
1417 | | | | |
1418 | Mat | |
1419 |______|_|___|__|
1420 | | |
1421 NbRay ^ _________ _______|_|___|__ ___
1422 | | | | | | | | |T|
1423 | | Ray | | Sat| | | | |r|
1424 | | | | | | | | |a| Trace = Union[col(t1,t2,..,tk)]
1425 |i|-------|------>i 0 0 0 | |c|
1426 NbBid - | | | | | | | |e|
1427 |_______| |______|_|___|__| |_|
1428 t1 t2 tk
1431 NbUni2 = 0;
1433 /* Let 'aux' be the number of rays not vertices */
1434 aux = 0;
1435 for (i=NbBid; i<NbRay; i++) {
1437 /* if (Ray->p[i][0]==1) */
1438 if (value_one_p (Ray->p[i][0])) {
1440 /* if (Ray->p[i][Dimension]!=0) : vertex */
1441 if (value_notzero_p (Ray->p[i][Dimension]))
1442 for (k=NbBid; k<NbRay; k++) Trace[k]=0; /* init Trace */
1443 else /* for ray */
1445 /* Include the positivity constraint incidences for rays. The */
1446 /* positivity constraint saturates all rays and no vertices */
1448 for (k=NbBid; k<NbRay; k++)
1450 /* Trace[k]=(Ray->p[k][Dimension]!=0); */
1451 Trace[k] = (value_notzero_p (Ray->p[k][Dimension]));
1453 /* Compute Trace: the union of all columns of Sat where ray(i) is */
1454 /* saturated. */
1455 for (j=NbEq; j<NbConstraints; j++)
1457 /* if (Mat->p[j][0]==1) : inequality */
1458 if (value_one_p (Mat->p[j][0])) {
1459 if (!(Sat->p[i][jx[j]]&bx[j]))
1460 for (k=NbBid; k<NbRay; k++) Trace[k] |= Sat->p[k][jx[j]]&bx[j];
1463 /* If ray i does not saturate any inequalities (other than the */
1464 /* the positivity constraint, then it is the case that there is */
1465 /* only one inequality and that ray is its orthogonal */
1467 /* only ray(i) should saturate this set of inequalities. If */
1468 /* another non-redundant ray also saturates this set, then ray(i)*/
1469 /* is redundant */
1471 Redundant = 0;
1472 for (j=NbBid; j<NbRay; j++) {
1474 /* if ( (Ray->p[j][0]==1) && (i!=j) && !Trace[j] ) */
1475 if (value_one_p (Ray->p[j][0]) && (i!=j) && !Trace[j]) {
1476 Redundant=1;
1477 break;
1480 if (Redundant)
1481 value_set_si(Ray->p[i][0],2);
1482 else {
1483 Vector_Copy(Ray->p[i], Pol->Ray[NbBid2+NbUni2], Dimension+1);
1484 NbUni2++; /* Increment number of uni-directional rays */
1486 /* if (Ray->p[i][Dimension]==0) */
1487 if (value_zero_p (Ray->p[i][Dimension]))
1488 aux++; /* Increment number of rays which are not vertices */
1493 /* Include the positivity constraint */
1494 if (aux>=Dim_RaySpace) {
1495 Vector_Set(Pol->Constraint[NbEq2+NbIneq2],0,Dimension+1);
1496 value_set_si(Pol->Constraint[NbEq2+NbIneq2][0],1);
1497 value_set_si(Pol->Constraint[NbEq2+NbIneq2][Dimension],1);
1498 NbIneq2++;
1500 } /* end of TRY */
1502 UNCATCH(any_exception_error);
1504 #ifdef POLY_RR_DEBUG
1505 fprintf(stderr, "[Remove_redundants : Step9]\nConstraints =");
1506 Matrix_Print(stderr,0,Mat);
1507 fprintf(stderr, "\nRay =");
1508 Matrix_Print(stderr,0,Ray);
1509 #endif
1511 free(Trace);
1512 free(bx);
1513 free(jx);
1514 if (temp2)
1515 free(temp2);
1517 Pol->NbConstraints = NbEq2 + NbIneq2;
1518 Pol->NbRays = NbBid2 + NbUni2;
1520 Vector_Free(temp1);
1521 F_SET(Pol,
1522 POL_VALID | POL_INEQUALITIES | POL_FACETS | POL_POINTS | POL_VERTICES);
1523 return Pol;
1525 oom:
1526 errormsg1("Remove_Redundants", "outofmem", "out of memory space");
1528 Vector_Free(temp1);
1529 if (temp2)
1530 free(temp2);
1531 if (bx)
1532 free(bx);
1533 if (jx)
1534 free(jx);
1535 return NULL;
1537 empty:
1538 Vector_Free(temp1);
1539 if (temp2)
1540 free(temp2);
1541 if (bx)
1542 free(bx);
1543 if (jx)
1544 free(jx);
1545 UNCATCH(any_exception_error);
1546 return Empty_Polyhedron(Dimension-1);
1547 } /* Remove_Redundants */
1550 * Allocate memory space for polyhedron.
1552 Polyhedron* Polyhedron_Alloc(unsigned Dimension,unsigned NbConstraints,unsigned NbRays) {
1554 Polyhedron *Pol;
1555 unsigned NbRows,NbColumns;
1556 int i,j;
1557 Value *p, **q;
1559 Pol=(Polyhedron *)malloc(sizeof(Polyhedron));
1560 if(!Pol) {
1561 errormsg1("Polyhedron_Alloc", "outofmem", "out of memory space");
1562 return 0;
1565 Pol->next = (Polyhedron *)0;
1566 Pol->Dimension = Dimension;
1567 Pol->NbConstraints = NbConstraints;
1568 Pol->NbRays = NbRays;
1569 Pol->NbEq = 0;
1570 Pol->NbBid = 0;
1571 Pol->flags = 0;
1572 NbRows = NbConstraints + NbRays;
1573 NbColumns = Dimension + 2;
1575 q = (Value **)malloc(NbRows * sizeof(Value *));
1576 if(!q) {
1577 errormsg1("Polyhedron_Alloc", "outofmem", "out of memory space");
1578 return 0;
1580 p = value_alloc(NbRows*NbColumns, &Pol->p_Init_size);
1581 if(!p) {
1582 free(q);
1583 errormsg1("Polyhedron_Alloc", "outofmem", "out of memory space");
1584 return 0;
1586 Pol->Constraint = q;
1587 Pol->Ray = q + NbConstraints;
1588 Pol->p_Init = p;
1589 for (i=0;i<NbRows;i++) {
1590 *q++ = p;
1591 p += NbColumns;
1593 return Pol;
1594 } /* Polyhedron_Alloc */
1597 * Free the memory space occupied by the single polyhedron.
1599 void Polyhedron_Free(Polyhedron *Pol)
1601 if(!Pol)
1602 return;
1603 value_free(Pol->p_Init, Pol->p_Init_size);
1604 free(Pol->Constraint);
1605 free(Pol);
1606 return;
1607 } /* Polyhedron_Free */
1610 * Free the memory space occupied by the domain.
1612 void Domain_Free(Polyhedron *Pol)
1614 Polyhedron *Next;
1616 for (; Pol; Pol = Next) {
1617 Next = Pol->next;
1618 Polyhedron_Free(Pol);
1620 return;
1621 } /* Domain_Free */
1624 * Print the contents of a polyhedron.
1626 void Polyhedron_Print(FILE *Dst, const char *Format, const Polyhedron *Pol)
1628 unsigned Dimension, NbConstraints, NbRays;
1629 int i, j;
1630 Value *p;
1632 if (!Pol) {
1633 fprintf(Dst, "<null polyhedron>\n");
1634 return;
1637 Dimension = Pol->Dimension + 2; /* Homogenous Dimension + status */
1638 NbConstraints = Pol->NbConstraints;
1639 NbRays = Pol->NbRays;
1640 fprintf(Dst, "POLYHEDRON Dimension:%d\n", Pol->Dimension);
1641 fprintf(Dst," Constraints:%d Equations:%d Rays:%d Lines:%d\n",
1642 Pol->NbConstraints, Pol->NbEq, Pol->NbRays, Pol->NbBid);
1643 fprintf(Dst,"Constraints %d %d\n", NbConstraints, Dimension);
1645 for (i=0;i<NbConstraints;i++) {
1646 p=Pol->Constraint[i];
1648 /* if (*p) */
1649 if (value_notzero_p (*p))
1650 fprintf(Dst,"Inequality: [");
1651 else
1652 fprintf(Dst,"Equality: [");
1653 p++;
1654 for (j=1;j<Dimension;j++) {
1655 value_print(Dst,Format,*p++);
1657 (void)fprintf(Dst," ]\n");
1660 (void)fprintf(Dst, "Rays %d %d\n", NbRays, Dimension);
1661 for (i=0;i<NbRays;i++) {
1662 p=Pol->Ray[i];
1664 /* if (*p) */
1665 if (value_notzero_p (*p)) {
1666 p++;
1668 /* if ( p[Dimension-2] ) */
1669 if (value_notzero_p (p[Dimension-2]))
1670 fprintf(Dst, "Vertex: [");
1671 else
1672 fprintf(Dst, "Ray: [");
1674 else {
1675 p++;
1676 fprintf(Dst, "Line: [");
1678 for (j=1; j < Dimension-1; j++) {
1679 value_print(Dst,Format,*p++);
1682 /* if (*p) */
1683 if (value_notzero_p (*p)) {
1684 fprintf( Dst, " ]/" );
1685 value_print(Dst,VALUE_FMT,*p);
1686 fprintf( Dst, "\n" );
1688 else
1689 fprintf(Dst, " ]\n");
1691 if (Pol->next) {
1692 fprintf(Dst, "UNION ");
1693 Polyhedron_Print(Dst,Format,Pol->next);
1695 } /* Polyhedron_Print */
1698 * Print the contents of a polyhedron 'Pol' (used for debugging purpose).
1700 void PolyPrint (Polyhedron *Pol) {
1701 Polyhedron_Print(stderr,"%4d",Pol);
1702 } /* PolyPrint */
1705 * Create and return an empty polyhedron of non-homogenous dimension
1706 * 'Dimension'. An empty polyhedron is characterized by :-
1707 * (a) The dimension of the ray-space is -1.
1708 * (b) There is an over-constrained system of equations given by:
1709 * x=0, y=0, ...... z=0, 1=0
1711 Polyhedron *Empty_Polyhedron(unsigned Dimension) {
1713 Polyhedron *Pol;
1714 int i;
1716 Pol = Polyhedron_Alloc(Dimension, Dimension+1, 0);
1717 if (!Pol) {
1718 errormsg1("Empty_Polyhedron", "outofmem", "out of memory space");
1719 return 0;
1721 Vector_Set(Pol->Constraint[0],0,(Dimension+1)*(Dimension+2));
1722 for (i=0; i<=Dimension; i++) {
1724 /* Pol->Constraint[i][i+1]=1 */
1725 value_set_si(Pol->Constraint[i][i+1],1);
1727 Pol->NbEq = Dimension+1;
1728 Pol->NbBid = 0;
1729 F_SET(Pol,
1730 POL_VALID | POL_INEQUALITIES | POL_FACETS | POL_POINTS | POL_VERTICES);
1731 return Pol;
1732 } /* Empty_Polyhedron */
1735 * Create and return a universe polyhedron of non-homogenous dimension
1736 * 'Dimension'. A universe polyhedron is characterized by :-
1737 * (a) The dimension of rayspace is zero.
1738 * (b) The dimension of lineality space is the dimension of the polyhedron.
1739 * (c) There is only one constraint (positivity constraint) in the constraint
1740 * set given by : 1 >= 0.
1741 * (d) The bi-directional ray set is the canonical set of vectors.
1742 * (e) The only vertex is the origin (0,0,0,....0).
1744 Polyhedron *Universe_Polyhedron(unsigned Dimension) {
1746 Polyhedron *Pol;
1747 int i;
1749 Pol = Polyhedron_Alloc(Dimension,1,Dimension+1);
1750 if (!Pol) {
1751 errormsg1("Universe_Polyhedron", "outofmem", "out of memory space");
1752 return 0;
1754 Vector_Set(Pol->Constraint[0],0,(Dimension+2));
1756 /* Pol->Constraint[0][0] = 1 */
1757 value_set_si(Pol->Constraint[0][0],1);
1759 /* Pol->Constraint[0][Dimension+1] = 1 */
1760 value_set_si(Pol->Constraint[0][Dimension+1],1);
1761 Vector_Set(Pol->Ray[0],0,(Dimension+1)*(Dimension+2));
1762 for (i=0;i<=Dimension;i++) {
1764 /* Pol->Ray[i][i+1]=1 */
1765 value_set_si(Pol->Ray[i][i+1],1);
1768 /* Pol->Ray[Dimension][0] = 1 : vertex status */
1769 value_set_si(Pol->Ray[Dimension][0],1);
1770 Pol->NbEq = 0;
1771 Pol->NbBid = Dimension;
1772 F_SET(Pol,
1773 POL_VALID | POL_INEQUALITIES | POL_FACETS | POL_POINTS | POL_VERTICES);
1774 return Pol;
1775 } /* Universe_Polyhedron */
1779 Sort constraints and remove trivially redundant constraints.
1782 static void SortConstraints(Matrix *Constraints, unsigned NbEq)
1784 int i, j, k;
1785 for (i = NbEq; i < Constraints->NbRows; ++i) {
1786 int max = i;
1787 for (k = i+1; k < Constraints->NbRows; ++k) {
1788 for (j = 1; j < Constraints->NbColumns-1; ++j) {
1789 if (value_eq(Constraints->p[k][j],
1790 Constraints->p[max][j]))
1791 continue;
1792 if (value_abs_lt(Constraints->p[k][j],
1793 Constraints->p[max][j]))
1794 break;
1795 if (value_abs_eq(Constraints->p[k][j],
1796 Constraints->p[max][j]) &&
1797 value_pos_p(Constraints->p[max][j]))
1798 break;
1799 max = k;
1800 break;
1802 /* equal, except for possibly the constant
1803 * => remove constraint with biggest constant
1805 if (j == Constraints->NbColumns-1) {
1806 if (value_lt(Constraints->p[k][j], Constraints->p[max][j]))
1807 Vector_Exchange(Constraints->p[k],
1808 Constraints->p[max],
1809 Constraints->NbColumns);
1810 Constraints->NbRows--;
1811 if (k < Constraints->NbRows)
1812 Vector_Exchange(Constraints->p[k],
1813 Constraints->p[Constraints->NbRows],
1814 Constraints->NbColumns);
1815 k--;
1818 if (max != i)
1819 Vector_Exchange(Constraints->p[max], Constraints->p[i],
1820 Constraints->NbColumns);
1826 Search for trivial implicit equalities,
1827 assuming the constraints have been sorted.
1831 static int ImplicitEqualities(Matrix *Constraints, unsigned NbEq)
1833 int row, nrow, k;
1834 int found = 0;
1835 Value tmp;
1836 for (row = NbEq; row < Constraints->NbRows; ++row) {
1837 int d = First_Non_Zero(Constraints->p[row]+1, Constraints->NbColumns-2);
1838 if (d == -1) {
1839 /* -n >= 0 */
1840 if (value_neg_p(Constraints->p[row][Constraints->NbColumns-1])) {
1841 value_set_si(Constraints->p[row][0], 0);
1842 found = 1;
1844 break;
1846 if (value_neg_p(Constraints->p[row][1+d]))
1847 continue;
1848 for (nrow = row+1; nrow < Constraints->NbRows; ++nrow) {
1849 if (value_zero_p(Constraints->p[nrow][1+d]))
1850 break;
1851 if (value_pos_p(Constraints->p[nrow][1+d]))
1852 continue;
1853 for (k = d; k < Constraints->NbColumns-1; ++k) {
1854 if (value_abs_ne(Constraints->p[row][1+k],
1855 Constraints->p[nrow][1+k]))
1856 break;
1857 if (value_zero_p(Constraints->p[row][1+k]))
1858 continue;
1859 if (value_eq(Constraints->p[row][1+k], Constraints->p[nrow][1+k]))
1860 break;
1862 if (k == Constraints->NbColumns-1) {
1863 value_set_si(Constraints->p[row][0], 0);
1864 value_set_si(Constraints->p[nrow][0], 0);
1865 found = 1;
1866 break;
1868 if (k != Constraints->NbColumns-2)
1869 continue;
1870 /* if the constants are such that
1871 * the sum c1+c2 is negative then the constraints conflict
1873 value_init(tmp);
1874 value_addto(tmp, Constraints->p[row][1+k],
1875 Constraints->p[nrow][1+k]);
1876 if (value_sign(tmp) < 0) {
1877 Vector_Set(Constraints->p[row], 0, Constraints->NbColumns-1);
1878 Vector_Set(Constraints->p[nrow], 0, Constraints->NbColumns-1);
1879 value_set_si(Constraints->p[row][1+k], 1);
1880 value_set_si(Constraints->p[nrow][1+k], 1);
1881 found = 1;
1883 value_clear(tmp);
1884 if (found)
1885 break;
1888 return found;
1893 Given a matrix of constraints ('Constraints'), construct and return a
1894 polyhedron.
1896 @param Constraints Constraints (may be modified!)
1897 @param NbMaxRays Estimated number of rays in the ray matrix of the
1898 polyhedron.
1899 @return newly allocated Polyhedron
1902 Polyhedron *Constraints2Polyhedron(Matrix *Constraints,unsigned NbMaxRays) {
1904 Polyhedron *Pol = NULL;
1905 Matrix *Ray = NULL;
1906 SatMatrix *Sat = NULL;
1907 unsigned Dimension, nbcolumns;
1908 int i;
1910 Dimension = Constraints->NbColumns - 1; /* Homogeneous Dimension */
1911 if (Dimension < 1) {
1912 errormsg1("Constraints2Polyhedron","invalidpoly","invalid polyhedron dimension");
1913 return 0;
1916 /* If there is no constraint in the constraint matrix, return universe */
1917 /* polyhderon. */
1918 if (Constraints->NbRows==0) {
1919 Pol = Universe_Polyhedron(Dimension-1);
1920 return Pol;
1923 if (POL_ISSET(NbMaxRays, POL_NO_DUAL)) {
1924 unsigned NbEq;
1925 unsigned Rank;
1926 Value tmp;
1927 if (POL_ISSET(NbMaxRays, POL_INTEGER))
1928 value_init(tmp);
1929 do {
1930 NbEq = 0;
1931 /* Move equalities up */
1932 for (i = 0; i < Constraints->NbRows; ++i)
1933 if (value_zero_p(Constraints->p[i][0])) {
1934 if (POL_ISSET(NbMaxRays, POL_INTEGER) &&
1935 ConstraintSimplify(Constraints->p[i],
1936 Constraints->p[i], Dimension+1, &tmp)) {
1937 value_clear(tmp);
1938 return Empty_Polyhedron(Dimension-1);
1940 /* detect 1 == 0, possibly created by ImplicitEqualities */
1941 if (First_Non_Zero(Constraints->p[i]+1, Dimension-1) == -1 &&
1942 value_notzero_p(Constraints->p[i][Dimension])) {
1943 if (POL_ISSET(NbMaxRays, POL_INTEGER))
1944 value_clear(tmp);
1945 return Empty_Polyhedron(Dimension-1);
1947 if (i != NbEq)
1948 ExchangeRows(Constraints, i, NbEq);
1949 ++NbEq;
1951 Rank = Gauss(Constraints, NbEq, Dimension);
1952 if (POL_ISSET(NbMaxRays, POL_INTEGER))
1953 for (i = NbEq; i < Constraints->NbRows; ++i)
1954 ConstraintSimplify(Constraints->p[i],
1955 Constraints->p[i], Dimension+1, &tmp);
1956 SortConstraints(Constraints, NbEq);
1957 } while (ImplicitEqualities(Constraints, NbEq));
1958 if (POL_ISSET(NbMaxRays, POL_INTEGER))
1959 value_clear(tmp);
1960 Pol = Polyhedron_Alloc(Dimension-1, Constraints->NbRows - (NbEq-Rank), 0);
1961 if (Rank > 0)
1962 Vector_Copy(Constraints->p[0], Pol->Constraint[0],
1963 Rank * Constraints->NbColumns);
1964 if (Constraints->NbRows > NbEq)
1965 Vector_Copy(Constraints->p[NbEq], Pol->Constraint[Rank],
1966 (Constraints->NbRows - NbEq) * Constraints->NbColumns);
1967 Pol->NbEq = Rank;
1968 /* Make sure nobody accesses the rays by accident */
1969 Pol->Ray = 0;
1970 F_SET(Pol, POL_VALID | POL_INEQUALITIES);
1971 return Pol;
1974 if (Dimension > NbMaxRays)
1975 NbMaxRays = Dimension;
1978 * Rather than adding a 'positivity constraint', it is better to
1979 * initialize the lineality space with line in each of the index
1980 * dimensions, but no line in the lambda dimension. Then initialize
1981 * the ray space with an origin at 0. This is what you get anyway,
1982 * after the positivity constraint has been processed by Chernikova
1983 * function.
1986 /* Allocate and initialize the Ray Space */
1987 Ray = Matrix_Alloc(NbMaxRays, Dimension+1);
1988 if(!Ray) {
1989 errormsg1("Constraints2Polyhedron","outofmem","out of memory space");
1990 return 0;
1992 Vector_Set(Ray->p_Init,0, NbMaxRays * (Dimension+1));
1993 for (i=0; i<Dimension; i++) {
1995 /* Ray->p[i][i+1] = 1 */
1996 value_set_si(Ray->p[i][i+1],1);
1999 /* Ray->p[Dimension-1][0] = 1 : mark for ray */
2000 value_set_si(Ray->p[Dimension-1][0],1);
2001 Ray->NbRows = Dimension;
2003 /* Initialize the Sat Matrix */
2004 nbcolumns = (Constraints->NbRows - 1)/(sizeof(int)*8) + 1;
2005 Sat = SMAlloc(NbMaxRays, nbcolumns);
2006 SMVector_Init(Sat->p_init,Dimension*nbcolumns);
2007 Sat->NbRows = Dimension;
2009 CATCH(any_exception_error) {
2011 /* In case of overflow, free the allocated memory and forward. */
2012 if (Sat) SMFree(&Sat);
2013 if (Ray) Matrix_Free(Ray);
2014 if (Pol) Polyhedron_Free(Pol);
2015 RETHROW();
2017 TRY {
2019 /* Create ray matrix 'Ray' from constraint matrix 'Constraints' */
2020 Chernikova(Constraints,Ray,Sat,Dimension-1,NbMaxRays,0,0);
2022 #ifdef POLY_DEBUG
2023 fprintf(stderr, "[constraints2polyhedron]\nConstraints = ");
2024 Matrix_Print(stderr,0,Constraints);
2025 fprintf(stderr, "\nRay = ");
2026 Matrix_Print(stderr,0,Ray);
2027 fprintf(stderr, "\nSat = ");
2028 SMPrint(Sat);
2029 #endif
2031 /* Remove the redundant constraints and create the polyhedron */
2032 Pol = Remove_Redundants(Constraints,Ray,Sat,0);
2033 } /* end of TRY */
2035 UNCATCH(any_exception_error);
2037 #ifdef POLY_DEBUG
2038 fprintf(stderr, "\nPol = ");
2039 Polyhedron_Print(stderr,"%4d",Pol);
2040 #endif
2042 SMFree(&Sat), Sat = NULL;
2043 Matrix_Free(Ray), Ray = NULL;
2044 return Pol;
2045 } /* Constraints2Polyhedron */
2047 #undef POLY_DEBUG
2050 * Given a polyhedron 'Pol', return a matrix of constraints.
2052 Matrix *Polyhedron2Constraints(Polyhedron *Pol) {
2054 Matrix *Mat;
2055 unsigned NbConstraints,Dimension;
2057 POL_ENSURE_INEQUALITIES(Pol);
2059 NbConstraints = Pol->NbConstraints;
2060 Dimension = Pol->Dimension+2;
2061 Mat = Matrix_Alloc(NbConstraints,Dimension);
2062 if(!Mat) {
2063 errormsg1("Polyhedron2Constraints", "outofmem", "out of memory space");
2064 return 0;
2066 Vector_Copy(Pol->Constraint[0],Mat->p_Init,NbConstraints * Dimension);
2067 return Mat;
2068 } /* Polyhedron2Constraints */
2070 /**
2072 Given a matrix of rays 'Ray', create and return a polyhedron.
2074 @param Ray Rays (may be modified!)
2075 @param NbMaxConstrs Estimated number of constraints in the polyhedron.
2076 @return newly allocated Polyhedron
2079 Polyhedron *Rays2Polyhedron(Matrix *Ray,unsigned NbMaxConstrs) {
2081 Polyhedron *Pol = NULL;
2082 Matrix *Mat = NULL;
2083 SatMatrix *Sat = NULL, *SatTranspose = NULL;
2084 unsigned Dimension, nbcolumns;
2085 int i;
2087 Dimension = Ray->NbColumns-1; /* Homogeneous Dimension */
2088 Sat = NULL;
2089 SatTranspose = NULL;
2090 Mat = NULL;
2092 if (Ray->NbRows==0) {
2094 /* If there is no ray in the matrix 'Ray', return an empty polyhedron */
2095 Pol = Empty_Polyhedron(Dimension-1);
2096 return(Pol);
2099 /* Ignore for now */
2100 if (POL_ISSET(NbMaxConstrs, POL_NO_DUAL))
2101 NbMaxConstrs = 0;
2103 if (Dimension > NbMaxConstrs)
2104 NbMaxConstrs = Dimension;
2106 /* Allocate space for constraint matrix 'Mat' */
2107 Mat = Matrix_Alloc(NbMaxConstrs,Dimension+1);
2108 if(!Mat) {
2109 errormsg1("Rays2Polyhedron","outofmem","out of memory space");
2110 return 0;
2113 /* Initialize the constraint matrix 'Mat' */
2114 Vector_Set(Mat->p_Init,0,NbMaxConstrs * (Dimension+1));
2115 for (i=0; i<Dimension; i++) {
2117 /* Mat->p[i][i+1]=1 */
2118 value_set_si(Mat->p[i][i+1],1);
2121 /* Allocate and assign the saturation matrix. Remember we are using a */
2122 /* transposed saturation matrix referenced by (constraint,ray) pair. */
2123 Mat->NbRows = Dimension;
2124 nbcolumns = (Ray->NbRows -1)/(sizeof(int)*8) + 1;
2125 SatTranspose = SMAlloc(NbMaxConstrs,nbcolumns);
2126 SMVector_Init(SatTranspose->p[0],Dimension * nbcolumns);
2127 SatTranspose->NbRows = Dimension;
2129 #ifdef POLY_DEBUG
2130 fprintf(stderr, "[ray2polyhedron: Before]\nRay = ");
2131 Matrix_Print(stderr,0,Ray);
2132 fprintf(stderr, "\nConstraints = ");
2133 Matrix_Print(stderr,0,Mat);
2134 fprintf(stderr, "\nSatTranspose = ");
2135 SMPrint (SatTranspose);
2136 #endif
2138 CATCH(any_exception_error) {
2140 /* In case of overflow, free the allocated memory before forwarding
2141 * the exception.
2143 if (SatTranspose) SMFree(&SatTranspose);
2144 if (Sat) SMFree(&Sat);
2145 if (Mat) Matrix_Free(Mat);
2146 if (Pol) Polyhedron_Free(Pol);
2147 RETHROW();
2149 TRY {
2151 /* Create constraint matrix 'Mat' from ray matrix 'Ray' */
2152 Chernikova(Ray,Mat,SatTranspose,Dimension,NbMaxConstrs,0,1);
2154 #ifdef POLY_DEBUG
2155 fprintf(stderr, "[ray2polyhedron: After]\nRay = ");
2156 Matrix_Print(stderr,0,Ray);
2157 fprintf(stderr, "\nConstraints = ");
2158 Matrix_Print(stderr,0,Mat);
2159 fprintf(stderr, "\nSatTranspose = ");
2160 SMPrint (SatTranspose);
2161 #endif
2163 /* Transform the saturation matrix 'SatTranspose' in the standard */
2164 /* format, that is, ray X constraint format. */
2165 Sat = TransformSat(Mat,Ray,SatTranspose);
2167 #ifdef POLY_DEBUG
2168 fprintf(stderr, "\nSat =");
2169 SMPrint(Sat);
2170 #endif
2172 SMFree(&SatTranspose), SatTranspose = NULL;
2174 /* Remove redundant rays from the ray matrix 'Ray' */
2175 Pol = Remove_Redundants(Mat,Ray,Sat,0);
2176 } /* of TRY */
2178 UNCATCH(any_exception_error);
2180 #ifdef POLY_DEBUG
2181 fprintf(stderr, "\nPol = ");
2182 Polyhedron_Print(stderr,"%4d",Pol);
2183 #endif
2185 SMFree(&Sat);
2186 Matrix_Free(Mat);
2187 return Pol;
2188 } /* Rays2Polyhedron */
2191 * Compute the dual representation if P only contains one representation.
2192 * Currently only handles the case where only the equalities are known.
2194 void Polyhedron_Compute_Dual(Polyhedron *P)
2196 if (!F_ISSET(P, POL_VALID))
2197 return;
2199 if (F_ISSET(P, POL_FACETS | POL_VERTICES))
2200 return;
2202 if (F_ISSET(P, POL_INEQUALITIES)) {
2203 Matrix M;
2204 Polyhedron tmp, *Q;
2205 /* Pretend P is a Matrix for a second */
2206 M.NbRows = P->NbConstraints;
2207 M.NbColumns = P->Dimension+2;
2208 M.p_Init = P->p_Init;
2209 M.p = P->Constraint;
2210 Q = Constraints2Polyhedron(&M, 0);
2212 /* Switch contents of P and Q ... */
2213 tmp = *Q;
2214 *Q = *P;
2215 *P = tmp;
2216 /* ... but keep the next pointer */
2217 P->next = Q->next;
2218 Polyhedron_Free(Q);
2219 return;
2222 /* other cases not handled yet */
2223 assert(0);
2227 * Build a saturation matrix from constraint matrix 'Mat' and ray matrix
2228 * 'Ray'. Only 'NbConstraints' constraint of matrix 'Mat' are considered
2229 * in creating the saturation matrix. 'NbMaxRays' is the maximum number
2230 * of rows (rays) allowed in the saturation matrix.
2231 * Vin100's stuff, for the polyparam vertices to work.
2233 static SatMatrix *BuildSat(Matrix *Mat,Matrix *Ray,unsigned NbConstraints,unsigned NbMaxRays) {
2235 SatMatrix *Sat = NULL;
2236 int i, j, k, jx;
2237 Value *p1, *p2, *p3;
2238 unsigned Dimension, NbRay, bx, nbcolumns;
2240 CATCH(any_exception_error) {
2241 if (Sat)
2242 SMFree(&Sat);
2243 RETHROW();
2245 TRY {
2246 NbRay = Ray->NbRows;
2247 Dimension = Mat->NbColumns-1; /* Homogeneous Dimension */
2249 /* Build the Sat matrix */
2250 nbcolumns = (Mat->NbRows - 1)/(sizeof(int)*8) + 1;
2251 Sat = SMAlloc(NbMaxRays,nbcolumns);
2252 Sat->NbRows = NbRay;
2253 SMVector_Init(Sat->p_init, nbcolumns * NbRay);
2254 jx=0; bx=MSB;
2255 for (k=0; k<NbConstraints; k++) {
2256 for (i=0; i<NbRay; i++) {
2258 /* Compute the dot product of ray(i) and constraint(k) and */
2259 /* store in the status element of ray(i). */
2260 p1 = Ray->p[i]+1;
2261 p2 = Mat->p[k]+1;
2262 p3 = Ray->p[i];
2263 value_set_si(*p3,0);
2264 for (j=0; j<Dimension; j++) {
2265 value_addmul(*p3, *p1, *p2);
2266 p1++; p2++;
2269 for (j=0; j<NbRay; j++) {
2271 /* Set 1 in the saturation matrix if the ray doesn't saturate */
2272 /* the constraint, otherwise the entry is 0. */
2273 if (value_notzero_p(Ray->p[j][0]))
2274 Sat->p[j][jx]|=bx;
2276 NEXT(jx, bx);
2278 } /* end of TRY */
2280 UNCATCH(any_exception_error);
2281 return Sat;
2282 } /* BuildSat */
2285 * Add 'Nbconstraints' new constraints to polyhedron 'Pol'. Constraints are
2286 * pointed by 'Con' and the maximum allowed rays in the new polyhedron is
2287 * 'NbMaxRays'.
2289 Polyhedron *AddConstraints(Value *Con,unsigned NbConstraints,Polyhedron *Pol,unsigned NbMaxRays) {
2291 Polyhedron *NewPol = NULL;
2292 Matrix *Mat = NULL, *Ray = NULL;
2293 SatMatrix *Sat = NULL;
2294 unsigned NbRay, NbCon, Dimension;
2296 if (NbConstraints == 0)
2297 return Polyhedron_Copy(Pol);
2299 POL_ENSURE_INEQUALITIES(Pol);
2300 Dimension = Pol->Dimension + 2; /* Homogeneous Dimension + Status */
2302 if (POL_ISSET(NbMaxRays, POL_NO_DUAL)) {
2303 NbCon = Pol->NbConstraints + NbConstraints;
2305 Mat = Matrix_Alloc(NbCon, Dimension);
2306 if (!Mat) {
2307 errormsg1("AddConstraints", "outofmem", "out of memory space");
2308 return NULL;
2310 Vector_Copy(Pol->Constraint[0], Mat->p[0], Pol->NbConstraints * Dimension);
2311 Vector_Copy(Con, Mat->p[Pol->NbConstraints], NbConstraints * Dimension);
2312 NewPol = Constraints2Polyhedron(Mat, NbMaxRays);
2313 Matrix_Free(Mat);
2314 return NewPol;
2317 POL_ENSURE_VERTICES(Pol);
2319 CATCH(any_exception_error) {
2320 if (NewPol) Polyhedron_Free(NewPol);
2321 if (Mat) Matrix_Free(Mat);
2322 if (Ray) Matrix_Free(Ray);
2323 if (Sat) SMFree(&Sat);
2324 RETHROW();
2326 TRY {
2327 NbRay = Pol->NbRays;
2328 NbCon = Pol->NbConstraints + NbConstraints;
2330 if (NbRay > NbMaxRays)
2331 NbMaxRays = NbRay;
2333 Mat = Matrix_Alloc(NbCon, Dimension);
2334 if(!Mat) {
2335 errormsg1("AddConstraints", "outofmem", "out of memory space");
2336 UNCATCH(any_exception_error);
2337 return 0;
2340 /* Copy constraints of polyhedron 'Pol' to matrix 'Mat' */
2341 Vector_Copy(Pol->Constraint[0], Mat->p[0], Pol->NbConstraints * Dimension);
2343 /* Add the new constraints pointed by 'Con' to matrix 'Mat' */
2344 Vector_Copy(Con, Mat->p[Pol->NbConstraints], NbConstraints * Dimension);
2346 /* Allocate space for ray matrix 'Ray' */
2347 Ray = Matrix_Alloc(NbMaxRays, Dimension);
2348 if(!Ray) {
2349 errormsg1("AddConstraints", "outofmem", "out of memory space");
2350 UNCATCH(any_exception_error);
2351 return 0;
2353 Ray->NbRows = NbRay;
2355 /* Copy rays of polyhedron 'Pol' to matrix 'Ray' */
2356 if (NbRay)
2357 Vector_Copy(Pol->Ray[0], Ray->p[0], NbRay * Dimension);
2359 /* Create the saturation matrix 'Sat' from constraint matrix 'Mat' and */
2360 /* ray matrix 'Ray' . */
2361 Sat = BuildSat(Mat, Ray, Pol->NbConstraints, NbMaxRays);
2363 /* Create the ray matrix 'Ray' from the constraint matrix 'Mat' */
2364 Pol_status = Chernikova(Mat, Ray, Sat, Pol->NbBid, NbMaxRays, Pol->NbConstraints,0);
2366 /* Remove redundant constraints from matrix 'Mat' */
2367 NewPol = Remove_Redundants(Mat, Ray, Sat, 0);
2369 } /* end of TRY */
2371 UNCATCH(any_exception_error);
2372 SMFree(&Sat);
2373 Matrix_Free(Ray);
2374 Matrix_Free(Mat);
2375 return NewPol;
2376 } /* AddConstraints */
2379 * Return 1 if 'Pol1' includes (covers) 'Pol2', 0 otherwise.
2380 * Polyhedron 'A' includes polyhedron 'B' if the rays of 'B' saturate
2381 * the equalities and verify the inequalities of 'A'. Both 'Pol1' and
2382 * 'Pol2' have same dimensions.
2384 int PolyhedronIncludes(Polyhedron *Pol1,Polyhedron *Pol2) {
2386 int Dimension = Pol1->Dimension + 1; /* Homogenous Dimension */
2387 int i, j, k;
2388 Value *p1, *p2, p3;
2390 POL_ENSURE_FACETS(Pol1);
2391 POL_ENSURE_VERTICES(Pol1);
2392 POL_ENSURE_FACETS(Pol2);
2393 POL_ENSURE_VERTICES(Pol2);
2395 value_init(p3);
2396 for (k=0; k<Pol1->NbConstraints; k++) {
2397 for (i=0;i<Pol2->NbRays;i++) {
2399 /* Compute the dot product of ray(i) and constraint(k) and store in p3 */
2400 p1 = Pol2->Ray[i]+1;
2401 p2 = Pol1->Constraint[k]+1;
2402 value_set_si(p3,0);
2403 for(j=0;j<Dimension;j++) {
2404 value_addmul(p3, *p1,*p2);
2405 p1++; p2++;
2408 /* If (p3 < 0) or (p3 > 0 and (constraint(k) is equality
2409 or ray(i) is a line)), return 0 */
2410 if(value_neg_p(p3) ||
2411 (value_notzero_p(p3)
2412 && (value_zero_p(Pol1->Constraint[k][0]) || (value_zero_p(Pol2->Ray[i][0])) ) )) {
2413 value_clear(p3);
2414 return 0;
2418 value_clear(p3);
2419 return 1;
2420 } /* PolyhedronIncludes */
2423 * Add Polyhedron 'Pol' to polhedral domain 'PolDomain'. If 'Pol' covers
2424 * some polyhedron in the domain 'PolDomain', it is removed from the list.
2425 * On the other hand if some polyhedron in the domain covers polyhedron
2426 * 'Pol' then 'Pol' is not included in the domain.
2428 Polyhedron *AddPolyToDomain(Polyhedron *Pol,Polyhedron *PolDomain) {
2430 Polyhedron *p, *pnext, *p_domain_end = (Polyhedron *) 0;
2431 int Redundant;
2433 if (!Pol)
2434 return PolDomain;
2435 if (!PolDomain)
2436 return Pol;
2438 POL_ENSURE_FACETS(Pol);
2439 POL_ENSURE_VERTICES(Pol);
2441 /* Check for emptiness of polyhedron 'Pol' */
2442 if (emptyQ(Pol)) {
2443 Polyhedron_Free(Pol);
2444 return PolDomain;
2447 POL_ENSURE_FACETS(PolDomain);
2448 POL_ENSURE_VERTICES(PolDomain);
2450 /* Check for emptiness of polyhedral domain 'PolDomain' */
2451 if (emptyQ(PolDomain)) {
2452 Polyhedron_Free(PolDomain);
2453 return Pol;
2456 /* Test 'Pol' against the domain 'PolDomain' */
2457 Redundant = 0;
2458 for (p=PolDomain,PolDomain=(Polyhedron *)0; p; p=pnext) {
2460 /* If 'Pol' covers 'p' */
2461 if (PolyhedronIncludes(Pol, p))
2463 /* free p */
2464 pnext = p->next;
2465 Polyhedron_Free( p );
2466 continue;
2469 /* Add polyhedron p to the new domain list */
2470 if (!PolDomain) PolDomain = p; else p_domain_end->next = p;
2471 p_domain_end = p;
2473 /* If p covers Pol */
2474 if (PolyhedronIncludes(p,Pol)) {
2475 Redundant = 1;
2476 break;
2478 pnext = p->next;
2480 if (!Redundant) {
2482 /* The whole list has been checked. Add new polyhedron 'Pol' to the */
2483 /* new domain list. */
2484 if (!PolDomain) PolDomain = Pol; else p_domain_end->next = Pol;
2486 else {
2488 /* The rest of the list is just inherited from p */
2489 Polyhedron_Free(Pol);
2491 return PolDomain;
2492 } /* AddPolyToDomain */
2495 * Given a polyhedra 'Pol' and a single constraint 'Con' and an integer 'Pass'
2496 * whose value ranges from 0 to 3, add the inverse of constraint 'Con' to the
2497 * constraint set of 'Pol' and return the new polyhedron. 'NbMaxRays' is the
2498 * maximum allowed rays in the new generated polyhedron.
2499 * If Pass == 0, add ( -constraint -1) >= 0
2500 * If Pass == 1, add ( +constraint -1) >= 0
2501 * If Pass == 2, add ( -constraint ) >= 0
2502 * If Pass == 3, add ( +constraint ) >= 0
2504 Polyhedron *SubConstraint(Value *Con,Polyhedron *Pol,unsigned NbMaxRays,int Pass) {
2506 Polyhedron *NewPol = NULL;
2507 Matrix *Mat = NULL, *Ray = NULL;
2508 SatMatrix *Sat = NULL;
2509 unsigned NbRay, NbCon, NbEle1, Dimension;
2510 int i;
2512 POL_ENSURE_FACETS(Pol);
2513 POL_ENSURE_VERTICES(Pol);
2515 CATCH(any_exception_error) {
2516 if (NewPol) Polyhedron_Free(NewPol);
2517 if (Mat) Matrix_Free(Mat);
2518 if (Ray) Matrix_Free(Ray);
2519 if (Sat) SMFree(&Sat);
2520 RETHROW();
2522 TRY {
2524 /* If 'Con' is the positivity constraint, return Null */
2525 Dimension = Pol->Dimension+1; /* Homogeneous Dimension */
2526 for (i=1; i<Dimension; i++)
2527 if (value_notzero_p(Con[i])) break;
2528 if (i==Dimension) {
2529 UNCATCH(any_exception_error);
2530 return (Polyhedron *) 0;
2533 NbRay = Pol->NbRays;
2534 NbCon = Pol->NbConstraints;
2535 Dimension = Pol->Dimension+2; /* Homogeneous Dimension + Status */
2536 NbEle1 = NbCon * Dimension;
2538 /* Ignore for now */
2539 if (POL_ISSET(NbMaxRays, POL_NO_DUAL))
2540 NbMaxRays = 0;
2542 if (NbRay > NbMaxRays)
2543 NbMaxRays = NbRay;
2545 Mat = Matrix_Alloc(NbCon + 1, Dimension);
2546 if(!Mat) {
2547 errormsg1("SubConstraint", "outofmem", "out of memory space");
2548 UNCATCH(any_exception_error);
2549 return 0;
2552 /* Set the constraints of Pol */
2553 Vector_Copy(Pol->Constraint[0], Mat->p[0], NbEle1);
2555 /* Add the new constraint */
2556 value_set_si(Mat->p[NbCon][0],1);
2557 if (!(Pass&1))
2558 for(i=1; i<Dimension; i++)
2559 value_oppose(Mat->p[NbCon][i],Con[i]);
2560 else
2561 for(i=1; i<Dimension; i++)
2562 value_assign(Mat->p[NbCon][i],Con[i]);
2563 if (!(Pass&2))
2564 value_decrement(Mat->p[NbCon][Dimension-1],Mat->p[NbCon][Dimension-1]);
2566 /* Allocate the ray matrix. */
2567 Ray = Matrix_Alloc(NbMaxRays, Dimension);
2568 if(!Ray) {
2569 errormsg1("SubConstraint", "outofmem", "out of memory space");
2570 UNCATCH(any_exception_error);
2571 return 0;
2574 /* Initialize the ray matrix with the rays of polyhedron 'Pol' */
2575 Ray->NbRows = NbRay;
2576 if (NbRay)
2577 Vector_Copy(Pol->Ray[0], Ray->p[0], NbRay * Dimension);
2579 /* Create the saturation matrix from the constraint matrix 'mat' and */
2580 /* ray matrix 'Ray'. */
2581 Sat = BuildSat(Mat, Ray, NbCon, NbMaxRays);
2583 /* Create the ray matrix 'Ray' from consraint matrix 'Mat' */
2584 Pol_status = Chernikova(Mat, Ray, Sat, Pol->NbBid, NbMaxRays, NbCon,0);
2586 /* Remove redundant constraints from matrix 'Mat' */
2587 NewPol = Remove_Redundants(Mat, Ray, Sat, 0);
2589 } /* end of TRY */
2591 UNCATCH(any_exception_error);
2593 SMFree(&Sat);
2594 Matrix_Free(Ray);
2595 Matrix_Free(Mat);
2596 return NewPol;
2597 } /* SubConstraint */
2600 * Return the intersection of two polyhedral domains 'Pol1' and 'Pol2'.
2601 * The maximum allowed rays in the new polyhedron generated is 'NbMaxRays'.
2603 Polyhedron *DomainIntersection(Polyhedron *Pol1,Polyhedron *Pol2,unsigned NbMaxRays) {
2605 Polyhedron *p1, *p2, *p3, *d;
2607 if (!Pol1 || !Pol2) return (Polyhedron*) 0;
2608 if (Pol1->Dimension != Pol2->Dimension) {
2609 errormsg1( "DomainIntersection", "diffdim",
2610 "operation on different dimensions");
2611 return (Polyhedron*) 0;
2614 /* For every polyhedron pair (p1,p2) where p1 belongs to domain Pol1 and */
2615 /* p2 belongs to domain Pol2, compute the intersection and add it to the */
2616 /* new domain 'd'. */
2617 d = (Polyhedron *)0;
2618 for (p1=Pol1; p1; p1=p1->next) {
2619 for (p2=Pol2; p2; p2=p2->next) {
2620 p3 = AddConstraints(p2->Constraint[0],
2621 p2->NbConstraints, p1, NbMaxRays);
2622 d = AddPolyToDomain(p3,d);
2625 if (!d)
2626 return Empty_Polyhedron(Pol1->Dimension);
2627 else
2628 return d;
2630 } /* DomainIntersection */
2633 * Given a polyhedron 'Pol', return a matrix of rays.
2635 Matrix *Polyhedron2Rays(Polyhedron *Pol) {
2637 Matrix *Ray;
2638 unsigned NbRays, Dimension;
2640 POL_ENSURE_POINTS(Pol);
2642 NbRays = Pol->NbRays;
2643 Dimension = Pol->Dimension+2; /* Homogeneous Dimension + Status */
2644 Ray = Matrix_Alloc(NbRays, Dimension);
2645 if(!Ray) {
2646 errormsg1("Polyhedron2Rays", "outofmem", "out of memory space");
2647 return 0;
2649 Vector_Copy(Pol->Ray[0], Ray->p_Init, NbRays*Dimension);
2650 return Ray;
2651 } /* Polyhedron2Rays */
2654 * Add 'NbAddedRays' rays to polyhedron 'Pol'. Rays are pointed by 'AddedRays'
2655 * and the maximum allowed constraints in the new polyhedron is 'NbMaxConstrs'.
2657 Polyhedron *AddRays(Value *AddedRays,unsigned NbAddedRays,Polyhedron *Pol,unsigned NbMaxConstrs) {
2659 Polyhedron *NewPol = NULL;
2660 Matrix *Mat = NULL, *Ray = NULL;
2661 SatMatrix *Sat = NULL, *SatTranspose = NULL;
2662 unsigned NbCon, NbRay,NbEle1, Dimension;
2664 POL_ENSURE_FACETS(Pol);
2665 POL_ENSURE_VERTICES(Pol);
2667 CATCH(any_exception_error) {
2668 if (NewPol) Polyhedron_Free(NewPol);
2669 if (Mat) Matrix_Free(Mat);
2670 if (Ray) Matrix_Free(Ray);
2671 if (Sat) SMFree(&Sat);
2672 if (SatTranspose) SMFree(&SatTranspose);
2673 RETHROW();
2675 TRY {
2677 NbCon = Pol->NbConstraints;
2678 NbRay = Pol->NbRays;
2679 Dimension = Pol->Dimension + 2; /* Homogeneous Dimension + Status */
2680 NbEle1 = NbRay * Dimension;
2682 Ray = Matrix_Alloc(NbAddedRays + NbRay, Dimension);
2683 if(!Ray) {
2684 errormsg1("AddRays", "outofmem", "out of memory space");
2685 UNCATCH(any_exception_error);
2686 return 0;
2689 /* Copy rays of polyhedron 'Pol' to matrix 'Ray' */
2690 if (NbRay)
2691 Vector_Copy(Pol->Ray[0], Ray->p_Init, NbEle1);
2693 /* Add the new rays pointed by 'AddedRays' to matrix 'Ray' */
2694 Vector_Copy(AddedRays, Ray->p_Init+NbEle1, NbAddedRays * Dimension);
2696 /* Ignore for now */
2697 if (POL_ISSET(NbMaxConstrs, POL_NO_DUAL))
2698 NbMaxConstrs = 0;
2700 /* We need at least NbCon rows */
2701 if (NbMaxConstrs < NbCon)
2702 NbMaxConstrs = NbCon;
2704 /* Allocate space for constraint matrix 'Mat' */
2705 Mat = Matrix_Alloc(NbMaxConstrs, Dimension);
2706 if(!Mat) {
2707 errormsg1("AddRays", "outofmem", "out of memory space");
2708 UNCATCH(any_exception_error);
2709 return 0;
2711 Mat->NbRows = NbCon;
2713 /* Copy constraints of polyhedron 'Pol' to matrix 'Mat' */
2714 Vector_Copy(Pol->Constraint[0], Mat->p_Init, NbCon*Dimension);
2716 /* Create the saturation matrix 'SatTranspose' from constraint matrix */
2717 /* 'Mat' and ray matrix 'Ray'. Remember the saturation matrix is */
2718 /* referenced by (constraint,ray) pair */
2719 SatTranspose = BuildSat(Ray, Mat, NbRay, NbMaxConstrs);
2721 /* Create the constraint matrix 'Mat' from the ray matrix 'Ray' */
2722 Pol_status = Chernikova(Ray, Mat, SatTranspose, Pol->NbEq, NbMaxConstrs, NbRay,1);
2724 /* Transform the saturation matrix 'SatTranspose' in the standard format */
2725 /* , that is, (ray X constraint) format. */
2726 Sat = TransformSat(Mat, Ray, SatTranspose);
2727 SMFree(&SatTranspose), SatTranspose = NULL;
2729 /* Remove redundant rays from the ray matrix 'Ray' */
2730 NewPol = Remove_Redundants(Mat, Ray, Sat, 0);
2732 SMFree(&Sat), Sat = NULL;
2733 Matrix_Free(Mat), Mat = NULL;
2734 Matrix_Free(Ray), Ray = NULL;
2735 } /* end of TRY */
2737 UNCATCH(any_exception_error);
2738 return NewPol;
2739 } /* AddRays */
2742 * Add rays pointed by 'Ray' to each and every polyhedron in the polyhedral
2743 * domain 'Pol'. 'NbMaxConstrs' is maximum allowed constraints in the
2744 * constraint set of a polyhedron.
2746 Polyhedron *DomainAddRays(Polyhedron *Pol,Matrix *Ray,unsigned NbMaxConstrs) {
2748 Polyhedron *PolA, *PolEndA, *p1, *p2, *p3;
2749 int Redundant;
2751 if (!Pol) return (Polyhedron*) 0;
2752 if (!Ray || Ray->NbRows == 0)
2753 return Domain_Copy(Pol);
2754 if (Pol->Dimension != Ray->NbColumns-2) {
2755 errormsg1(
2756 "DomainAddRays", "diffdim", "operation on different dimensions");
2757 return (Polyhedron*) 0;
2760 /* Copy Pol to PolA */
2761 PolA = PolEndA = (Polyhedron *)0;
2762 for (p1=Pol; p1; p1=p1->next) {
2763 p3 = AddRays(Ray->p[0], Ray->NbRows, p1, NbMaxConstrs);
2765 /* Does any component of PolA cover 'p3' ? */
2766 Redundant = 0;
2767 for (p2=PolA; p2; p2=p2->next) {
2768 if (PolyhedronIncludes(p2, p3)) { /* If p2 covers p3 */
2769 Redundant = 1;
2770 break;
2774 /* If the new polyheron is not redundant, add it ('p3') to the list */
2775 if (Redundant)
2776 Polyhedron_Free(p3);
2777 else {
2778 if (!PolEndA)
2779 PolEndA = PolA = p3;
2780 else {
2781 PolEndA->next = p3;
2782 PolEndA = PolEndA->next;
2786 return PolA;
2787 } /* DomainAddRays */
2790 * Create a copy of the polyhedron 'Pol'
2792 Polyhedron *Polyhedron_Copy(Polyhedron *Pol) {
2794 Polyhedron *Pol1;
2796 if (!Pol) return (Polyhedron *)0;
2798 /* Allocate space for the new polyhedron */
2799 Pol1 = Polyhedron_Alloc(Pol->Dimension, Pol->NbConstraints, Pol->NbRays);
2800 if (!Pol1) {
2801 errormsg1("Polyhedron_Copy", "outofmem", "out of memory space");
2802 return 0;
2804 if( Pol->NbConstraints )
2805 Vector_Copy(Pol->Constraint[0], Pol1->Constraint[0],
2806 Pol->NbConstraints*(Pol->Dimension+2));
2807 if( Pol->NbRays )
2808 Vector_Copy(Pol->Ray[0], Pol1->Ray[0],
2809 Pol->NbRays*(Pol->Dimension+2));
2810 Pol1->NbBid = Pol->NbBid;
2811 Pol1->NbEq = Pol->NbEq;
2812 Pol1->flags = Pol->flags;
2813 return Pol1;
2814 } /* Polyhedron_Copy */
2817 * Create a copy of a polyhedral domain.
2819 Polyhedron *Domain_Copy(Polyhedron *Pol) {
2821 Polyhedron *Pol1;
2823 if (!Pol) return (Polyhedron *) 0;
2824 Pol1 = Polyhedron_Copy(Pol);
2825 if (Pol->next) Pol1->next = Domain_Copy(Pol->next);
2826 return Pol1;
2827 } /* Domain_Copy */
2830 * Given constraint number 'k' of a polyhedron, and an array 'Filter' to store
2831 * the non-redundant constraints of the polyhedron in bit-wise notation, and
2832 * a Matrix 'Sat', add the constraint 'k' in 'Filter' array. tmpR[i] stores the
2833 * number of constraints, other than those in 'Filter', which ray(i) saturates
2834 * or verifies. In case, ray(i) does not saturate or verify a constraint in
2835 * array 'Filter', it is assigned to -1. Similarly, tmpC[j] stores the number
2836 * of rays which constraint(j), if it doesn't belong to Filter, saturates or
2837 * verifies. If constraint(j) belongs to 'Filter', then tmpC[j] is assigned to
2838 * -1. 'NbConstraints' is the number of constraints in the constraint matrix of
2839 * the polyhedron.
2840 * NOTE: (1) 'Sat' is not the saturation matrix of the polyhedron. In fact,
2841 * entry in 'Sat' is set to 1 if ray(i) of polyhedron1 verifies or
2842 * saturates the constraint(j) of polyhedron2 and otherwise it is set
2843 * to 0. So here the difference with saturation matrix is in terms
2844 * definition and entries(1<->0) of the matrix 'Sat'.
2846 * ALGORITHM:->
2847 * (1) Include constraint(k) in array 'Filter'.
2848 * (2) Set tmpC[k] to -1.
2849 * (3) For all ray(i) {
2850 * If ray(i) saturates or verifies constraint(k) then --(tmpR[i])
2851 * Else {
2852 * Discard ray(i) by assigning tmpR[i] = -1
2853 * Decrement tmpC[j] for all constraint(j) not in array 'Filter'.
2857 static void addToFilter(int k, unsigned *Filter, SatMatrix *Sat,Value *tmpR,Value *tmpC,int NbRays,int NbConstraints) {
2859 int kj, i,j, jx;
2860 unsigned kb, bx;
2862 /* Remove constraint k */
2863 kj = k/WSIZE; kb = MSB; kb >>= k%WSIZE;
2864 Filter[kj]|=kb;
2865 value_set_si(tmpC[k],-1);
2867 /* Remove rays excluded by constraint k */
2868 for(i=0; i<NbRays; i++)
2869 if (value_posz_p(tmpR[i])) {
2870 if (Sat->p[i][kj]&kb)
2871 value_decrement(tmpR[i],tmpR[i]); /* adjust included ray */
2872 else {
2874 /* Constraint k excludes ray i -- delete ray i */
2875 value_set_si(tmpR[i],-1);
2877 /* Adjust non-deleted constraints */
2878 jx=0; bx=MSB;
2879 for(j=0; j<NbConstraints; j++) {
2880 if (value_posz_p(tmpC[j]) && (Sat->p[i][jx]&bx) )
2881 value_decrement(tmpC[j],tmpC[j]);
2882 NEXT(jx,bx);
2886 } /* addToFilter */
2889 * Given polyhedra 'P1' and 'P2' such that their intersection is an empty
2890 * polyhedron, find the minimal set of constraints of 'P1' which contradict
2891 * all of the constraints of 'P2'. This is believed to be an NP-hard problem
2892 * and so a heuristic is employed to solve it in worst case. The heuristic is
2893 * to select in every turn that constraint of 'P1' which excludes most rays of
2894 * 'P2'. A bit in the binary format of an element of array 'Filter' is set to
2895 * 1 if the corresponding constraint is to be included in the minimal set of
2896 * constraints otherwise it is set to 0.
2898 static void FindSimple(Polyhedron *P1,Polyhedron *P2,unsigned *Filter,unsigned NbMaxRays) {
2900 Matrix *Mat = NULL;
2901 SatMatrix *Sat = NULL;
2902 int i, j, k, jx, found;
2903 Value *p1, *p2, p3;
2904 unsigned Dimension, NbRays, NbConstraints, bx, nc;
2905 Value NbConstraintsLeft, tmp;
2906 Value *tmpC = NULL, *tmpR = NULL;
2907 Polyhedron *Pol = NULL, *Pol2 = NULL;
2909 /* Initialize all the 'Value' variables */
2910 value_init(p3); value_init(NbConstraintsLeft);
2911 value_init(tmp);
2913 CATCH(any_exception_error) {
2914 if (tmpC) free(tmpC);
2915 if (tmpR) free(tmpR);
2916 if (Mat) Matrix_Free(Mat);
2917 if (Sat) SMFree(&Sat);
2918 if (Pol2 && Pol2!=P2) Polyhedron_Free(Pol2);
2919 if (Pol && Pol!=Pol2 && Pol!=P2) Polyhedron_Free(Pol);
2921 /* Clear all the 'Value' variables */
2922 value_clear(p3); value_clear(NbConstraintsLeft);
2923 value_clear(tmp);
2924 RETHROW();
2926 TRY {
2928 Dimension = P1->Dimension+2; /* status + homogeneous Dimension */
2929 Mat = Matrix_Alloc(P1->NbConstraints, Dimension);
2930 if(!Mat) {
2931 errormsg1("FindSimple", "outofmem", "out of memory space");
2932 UNCATCH(any_exception_error);
2934 /* Clear all the 'Value' variables */
2935 value_clear(p3); value_clear(NbConstraintsLeft); value_clear(tmp);
2936 return;
2939 /* Post constraints in P1 already included by Filter */
2940 jx = 0; bx = MSB; Mat->NbRows=0;
2941 value_set_si(NbConstraintsLeft,0);
2942 for (k=0; k<P1->NbConstraints; k++) {
2943 if (Filter[jx]&bx) {
2944 Vector_Copy(P1->Constraint[k], Mat->p[Mat->NbRows], Dimension);
2945 Mat->NbRows++;
2947 else
2948 value_increment(NbConstraintsLeft,NbConstraintsLeft);
2949 NEXT(jx,bx);
2951 Pol2 = P2;
2953 for (;;) {
2954 if (Mat->NbRows==0)
2955 Pol = Polyhedron_Copy(Pol2);
2956 else {
2957 Pol = AddConstraints(Mat->p_Init, Mat->NbRows, Pol2, NbMaxRays);
2958 if (Pol2 != P2) Polyhedron_Free(Pol2), Pol2 = NULL;
2960 if (emptyQ(Pol)) {
2961 Matrix_Free(Mat), Mat = NULL;
2962 Polyhedron_Free(Pol), Pol = NULL;
2963 UNCATCH(any_exception_error);
2965 /* Clear all the 'Value' variables */
2966 value_clear(p3); value_clear(NbConstraintsLeft); value_clear(tmp);
2967 return;
2969 Mat->NbRows = 0; /* Reset Mat */
2970 Pol2 = Pol;
2972 /* Its not enough-- find some more constraints */
2973 Dimension = Pol->Dimension+1; /* homogeneous Dimension */
2974 NbRays = Pol->NbRays;
2975 NbConstraints = P1->NbConstraints;
2976 tmpR = (Value *)malloc(NbRays*sizeof(Value));
2977 if(!tmpR) {
2978 errormsg1("FindSimple", "outofmem", "out of memory space");
2979 UNCATCH(any_exception_error);
2981 /* Clear all the 'Value' variables */
2982 value_clear(p3); value_clear(NbConstraintsLeft); value_clear(tmp);
2983 return;
2985 for(i=0;i<NbRays;i++)
2986 value_init(tmpR[i]);
2987 tmpC = (Value *)malloc(NbConstraints*sizeof(Value));
2988 if(!tmpC) {
2989 errormsg1("FindSimple", "outofmem", "out of memory space");
2990 UNCATCH(any_exception_error);
2992 /* Clear all the 'Value' variables */
2993 value_clear(p3); value_clear(NbConstraintsLeft);
2994 for(i=0;i<NbRays;i++)
2995 value_clear(tmpR[i]);
2996 free(tmpR);
2997 return;
2999 for(i=0;i<NbConstraints;i++)
3000 value_init(tmpC[i]);
3001 Vector_Set(tmpR,0,NbRays);
3002 Vector_Set(tmpC,0,NbConstraints);
3004 /* Build the Sat matrix */
3005 nc = (NbConstraints - 1) / (sizeof(int)*8) + 1;
3006 Sat = SMAlloc(NbRays, nc);
3007 Sat->NbRows = NbRays;
3008 SMVector_Init(Sat->p_init, nc*NbRays);
3010 jx=0; bx=MSB;
3011 for (k=0; k<NbConstraints; k++) {
3012 if (Filter[jx]&bx)
3013 value_set_si(tmpC[k],-1);
3014 else
3015 for (i=0; i<NbRays; i++) {
3016 p1 = Pol->Ray[i]+1;
3017 p2 = P1->Constraint[k]+1;
3018 value_set_si(p3,0);
3019 for (j=0; j<Dimension; j++) {
3020 value_addmul(p3, *p1, *p2);
3021 p1++; p2++;
3023 if(value_zero_p(p3) ||
3024 (value_pos_p(p3) && value_notzero_p(P1->Constraint[k][0]))) {
3025 Sat->p[i][jx]|=bx; /* constraint includes ray, set flag */
3026 value_increment(tmpR[i],tmpR[i]);
3027 value_increment(tmpC[k],tmpC[k]);
3030 NEXT(jx, bx);
3033 do { /* find all of the essential constraints */
3034 found = 0;
3035 for(i=0; i<NbRays; i++)
3036 if(value_posz_p(tmpR[i])) {
3037 value_add_int(tmp,tmpR[i],1);
3038 if(value_eq(tmp,NbConstraintsLeft)) {
3040 /* Ray i is excluded by only one constraint... find it */
3041 jx = 0; bx = MSB;
3042 for(k=0; k<NbConstraints; k++) {
3043 if(value_posz_p(tmpC[k]) && ((Sat->p[i][jx]&bx)==0)) {
3044 addToFilter(k, Filter, Sat, tmpR, tmpC,
3045 NbRays, NbConstraints);
3046 Vector_Copy(P1->Constraint[k],
3047 Mat->p[Mat->NbRows],Dimension+1);
3048 Mat->NbRows++;
3049 value_decrement(NbConstraintsLeft,NbConstraintsLeft);
3050 found=1;
3051 break;
3053 NEXT(jx,bx);
3055 break;
3059 while (found);
3061 if (!Mat->NbRows) { /* Well then, just use a stupid heuristic */
3062 /* find the constraint which excludes the most */
3063 Value cmax;
3064 value_init(cmax);
3066 #ifndef LINEAR_VALUE_IS_CHARS
3067 value_set_si(cmax,(NbRays * NbConstraints+1));
3068 #else
3069 value_set_si(cmax,1);
3070 #endif
3072 j = -1;
3073 for(k=0; k<NbConstraints; k++)
3074 if (value_posz_p(tmpC[k])) {
3075 if (value_gt(cmax,tmpC[k])) {
3076 value_assign(cmax,tmpC[k]);
3077 j = k;
3080 value_clear(cmax);
3081 if (j<0) {
3082 errormsg1("DomSimplify","logerror","logic error");
3084 else {
3085 addToFilter(j, Filter, Sat, tmpR, tmpC, NbRays, NbConstraints);
3086 Vector_Copy(P1->Constraint[j],Mat->p[Mat->NbRows],Dimension+1);
3087 Mat->NbRows++;
3088 value_decrement(NbConstraintsLeft,NbConstraintsLeft);
3091 SMFree(&Sat), Sat = NULL;
3092 free(tmpC), tmpC = NULL;
3093 free(tmpR), tmpR = NULL;
3095 } /* end of TRY */
3097 /* Clear all the 'Value' variables */
3098 value_clear(p3); value_clear(NbConstraintsLeft);
3099 value_clear(tmp);
3100 for(i=0;i<NbRays;i++)
3101 value_clear(tmpR[i]);
3102 for(i=0;i<NbRays;i++)
3103 value_clear(tmpC[i]);
3105 UNCATCH(any_exception_error);
3106 } /* FindSimple */
3109 * Return 0 if the intersection of Pol1 and Pol2 is empty, otherwise return 1.
3110 * If the intersection is non-empty, store the non-redundant constraints in
3111 * 'Filter' array. If the intersection is empty then store the smallest set of
3112 * constraints of 'Pol1' which on intersection with 'Pol2' gives empty set, in
3113 * 'Filter' array. 'NbMaxRays' is the maximum allowed rays in the intersection
3114 * of 'Pol1' and 'Pol2'.
3116 static int SimplifyConstraints(Polyhedron *Pol1,Polyhedron *Pol2,unsigned *Filter,unsigned NbMaxRays) {
3118 Polyhedron *Pol = NULL;
3119 Matrix *Mat = NULL, *Ray = NULL;
3120 SatMatrix *Sat = NULL;
3121 unsigned NbRay, NbCon, NbCon1, NbCon2, NbEle1, Dimension, notempty;
3123 CATCH(any_exception_error) {
3124 if (Pol) Polyhedron_Free(Pol);
3125 if (Mat) Matrix_Free(Mat);
3126 if (Ray) Matrix_Free(Ray);
3127 if (Sat) SMFree(&Sat);
3128 RETHROW();
3130 TRY {
3132 NbRay = Pol1->NbRays;
3133 NbCon1 = Pol1->NbConstraints;
3134 NbCon2 = Pol2->NbConstraints;
3135 NbCon = NbCon1 + NbCon2;
3136 Dimension = Pol1->Dimension+2; /* Homogeneous Dimension + Status */
3137 NbEle1 = NbCon1*Dimension;
3139 /* Ignore for now */
3140 if (POL_ISSET(NbMaxRays, POL_NO_DUAL))
3141 NbMaxRays = 0;
3143 if (NbRay > NbMaxRays)
3144 NbMaxRays = NbRay;
3146 /* Allocate space for constraint matrix 'Mat' */
3147 Mat = Matrix_Alloc(NbCon, Dimension);
3148 if(!Mat) {
3149 errormsg1("SimplifyConstraints", "outofmem", "out of memory space");
3150 UNCATCH(any_exception_error);
3151 return 0;
3154 /* Copy constraints of 'Pol1' to matrix 'Mat' */
3155 Vector_Copy(Pol1->Constraint[0], Mat->p_Init, NbEle1);
3157 /* Add constraints of 'Pol2' to matrix 'Mat'*/
3158 Vector_Copy(Pol2->Constraint[0], Mat->p_Init+NbEle1, NbCon2*Dimension);
3160 /* Allocate space for ray matrix 'Ray' */
3161 Ray = Matrix_Alloc(NbMaxRays, Dimension);
3162 if(!Ray) {
3163 errormsg1("SimplifyConstraints", "outofmem", "out of memory space");
3164 UNCATCH(any_exception_error);
3165 return 0;
3167 Ray->NbRows = NbRay;
3169 /* Copy rays of polyhedron 'Pol1' to matrix 'Ray' */
3170 Vector_Copy(Pol1->Ray[0], Ray->p_Init, NbRay*Dimension);
3172 /* Create saturation matrix from constraint matrix 'Mat' and ray matrix */
3173 /* 'Ray'. */
3174 Sat = BuildSat(Mat, Ray, NbCon1, NbMaxRays);
3176 /* Create the ray matrix 'Ray' from the constraint matrix 'Mat' */
3177 Pol_status = Chernikova(Mat, Ray, Sat, Pol1->NbBid, NbMaxRays, NbCon1,0);
3179 /* Remove redundant constraints from the constraint matrix 'Mat' */
3180 Pol = Remove_Redundants(Mat, Ray, Sat, Filter);
3181 notempty = 1;
3182 if (Filter && emptyQ(Pol)) {
3183 notempty = 0;
3184 FindSimple(Pol1, Pol2, Filter, NbMaxRays);
3186 /* Polyhedron_Print(stderr,"%4d",Pol1); */
3188 Polyhedron_Free(Pol), Pol = NULL;
3189 SMFree(&Sat), Sat = NULL;
3190 Matrix_Free(Ray), Ray = NULL;
3191 Matrix_Free(Mat), Mat = NULL;
3193 } /* end of TRY */
3195 UNCATCH(any_exception_error);
3196 return notempty;
3197 } /* SimplifyConstraints */
3200 * Eliminate equations of Pol1 using equations of Pol2. Mark as needed,
3201 * equations of Pol1 that are not eliminated. Or info into Filter vector.
3203 static void SimplifyEqualities(Polyhedron *Pol1, Polyhedron *Pol2, unsigned *Filter) {
3205 int i,j;
3206 unsigned ix, bx, NbEqn, NbEqn1, NbEqn2, NbEle2, Dimension;
3207 Matrix *Mat;
3209 NbEqn1 = Pol1->NbEq;
3210 NbEqn2 = Pol2->NbEq;
3211 NbEqn = NbEqn1 + NbEqn2;
3212 Dimension = Pol1->Dimension+2; /* Homogeneous Dimension + Status */
3213 NbEle2 = NbEqn2*Dimension;
3215 Mat = Matrix_Alloc(NbEqn, Dimension);
3216 if (!Mat) {
3217 errormsg1("SimplifyEqualities", "outofmem", "out of memory space");
3218 Pol_status = 1;
3219 return;
3222 /* Set the equalities of Pol2 */
3223 Vector_Copy(Pol2->Constraint[0], Mat->p_Init, NbEle2);
3225 /* Add the equalities of Pol1 */
3226 Vector_Copy(Pol1->Constraint[0], Mat->p_Init+NbEle2, NbEqn1*Dimension);
3228 Gauss(Mat, NbEqn2, Dimension-1);
3230 ix = 0;
3231 bx = MSB;
3232 for (i=NbEqn2; i<NbEqn; i++) {
3233 for (j=1; j<Dimension; j++) {
3234 if (value_notzero_p(Mat->p[i][j])) {
3235 /* If any coefficient of the equation is non-zero */
3236 /* Set the filter bit for the equation */
3238 Filter[ix] |= bx;
3239 break;
3242 NEXT(ix,bx);
3244 Matrix_Free(Mat);
3245 return;
3246 } /* SimplifyEqualities */
3250 * Given two polyhedral domains 'Pol1' and 'Pol2', find the largest domain
3251 * set (or the smallest list of non-redundant constraints), that when
3252 * intersected with polyhedral domain 'Pol2' equals (Pol1)intersect(Pol2).
3253 * The output is a polyhedral domain with the "redundant" constraints removed.
3254 * 'NbMaxRays' is the maximium allowed rays in the new polyhedra.
3256 Polyhedron *DomainSimplify(Polyhedron *Pol1, Polyhedron *Pol2, unsigned NbMaxRays) {
3258 Polyhedron *p1, *p2, *p3, *d;
3259 unsigned k, jx, bx, nbentries, NbConstraints, Dimension, NbCon, empty;
3260 unsigned *Filter;
3261 Matrix *Constraints;
3264 if (!Pol1 || !Pol2) return Pol1;
3265 if (Pol1->Dimension != Pol2->Dimension) {
3266 errormsg1("DomSimplify","diffdim","operation on different dimensions");
3267 Pol_status = 1;
3268 return 0;
3270 POL_ENSURE_VERTICES(Pol1);
3271 POL_ENSURE_VERTICES(Pol2);
3272 if (emptyQ(Pol1)||emptyQ(Pol2))
3273 return Empty_Polyhedron(Pol1->Dimension);
3275 /* Find the maximum number of constraints over all polyhedron in the */
3276 /* polyhedral domain 'Pol2' and store in 'NbCon'. */
3277 NbCon = 0;
3278 for (p2=Pol2; p2; p2=p2->next)
3279 if (p2->NbConstraints > NbCon)
3280 NbCon = p2->NbConstraints;
3282 Dimension = Pol1->Dimension+2; /* Homogenous Dimension + Status */
3283 d = (Polyhedron *)0;
3284 for (p1=Pol1; p1; p1=p1->next) {
3286 POL_ENSURE_VERTICES(p1);
3288 /* Filter is an array of integers, each bit in an element of Filter */
3289 /* array corresponds to a constraint. The bit is marked 1 if the */
3290 /* corresponding constraint is non-redundant and is 0 if it is */
3291 /* redundant. */
3293 NbConstraints = p1->NbConstraints;
3294 nbentries = (NbConstraints + NbCon - 1) / (sizeof(int)*8) + 1;
3296 /* Allocate space for array 'Filter' */
3297 Filter = (unsigned *)malloc(nbentries * sizeof(int));
3298 if (!Filter) {
3299 errormsg1("DomSimplify", "outofmem", "out of memory space\n");
3300 Pol_status = 1;
3301 return 0;
3304 /* Initialize 'Filter' with zeros */
3305 SMVector_Init(Filter, nbentries);
3307 /* Filter the constraints of p1 in context of polyhedra p2(s) */
3308 empty = 1;
3309 for (p2=Pol2; p2; p2=p2->next) {
3311 POL_ENSURE_VERTICES(p2);
3313 /* Store the non-redundant constraints in array 'Filter'. With */
3314 /* successive loops, the array 'Filter' holds the union of all */
3315 /* non-redundant constraints. 'empty' is set to zero if the */
3316 /* intersection of two polyhedra is non-empty and Filter is !Null */
3318 SimplifyEqualities(p1, p2, Filter);
3319 if (SimplifyConstraints(p1, p2, Filter, NbMaxRays))
3320 empty=0;
3322 /* takes the union of all non redundant constraints */
3325 if (!empty) {
3327 /* Copy all non-redundant constraints to matrix 'Constraints' */
3328 Constraints = Matrix_Alloc(NbConstraints, Dimension);
3329 if (!Constraints) {
3330 errormsg1("DomSimplify", "outofmem", "out of memory space\n");
3331 Pol_status = 1;
3332 return 0;
3334 Constraints->NbRows = 0;
3335 for (k=0, jx=0, bx=MSB; k<NbConstraints; k++) {
3337 /* If a bit entry in Filter[jx] is marked 1, copy the correspond- */
3338 /* ing constraint in matrix 'Constraints'. */
3339 if (Filter[jx]&bx) {
3340 Vector_Copy(p1->Constraint[k],
3341 Constraints->p[Constraints->NbRows],
3342 Dimension);
3343 Constraints->NbRows++;
3345 NEXT(jx,bx);
3348 /* Create the polyhedron 'p3' corresponding to the constraints in */
3349 /* matrix 'Constraints'. */
3350 p3 = Constraints2Polyhedron(Constraints,NbMaxRays);
3351 Matrix_Free(Constraints);
3353 /* Add polyhedron 'p3' in the domain 'd'. */
3354 d = AddPolyToDomain (p3, d);
3355 p3 = NULL;
3357 free(Filter);
3359 if (!d)
3360 return Empty_Polyhedron(Pol1->Dimension);
3361 else return d;
3363 } /* DomainSimplify */
3366 * Domain Simplify as defined in Strasborg Polylib version.
3368 Polyhedron *Stras_DomainSimplify(Polyhedron *Pol1,Polyhedron *Pol2,unsigned NbMaxRays) {
3370 Polyhedron *p1, *p2, *p3 = NULL, *d = NULL;
3371 unsigned k, jx, bx, nbentries, NbConstraints, Dimension, NbCon, empty;
3372 unsigned *Filter = NULL;
3373 Matrix *Constraints = NULL;
3375 CATCH(any_exception_error) {
3376 if (Constraints) Matrix_Free(Constraints);
3377 if (Filter) free(Filter);
3378 if (d) Polyhedron_Free(d);
3379 if (p2) Polyhedron_Free(p3);
3380 RETHROW();
3382 TRY {
3383 if (!Pol1 || !Pol2) {
3384 UNCATCH(any_exception_error);
3385 return Pol1;
3387 if (Pol1->Dimension != Pol2->Dimension) {
3388 errormsg1("DomainSimplify","diffdim","operation on different dimensions");
3389 UNCATCH(any_exception_error);
3390 return 0;
3392 POL_ENSURE_VERTICES(Pol1);
3393 POL_ENSURE_VERTICES(Pol2);
3394 if (emptyQ(Pol1)||emptyQ(Pol2)) {
3395 UNCATCH(any_exception_error);
3396 return Empty_Polyhedron(Pol1->Dimension);
3399 /* Find the maximum number of constraints over all polyhedron in the */
3400 /* polyhedral domain 'Pol2' and store in 'NbCon'. */
3401 NbCon = 0;
3402 for (p2=Pol2; p2; p2=p2->next)
3403 if (p2->NbConstraints > NbCon)
3404 NbCon = p2->NbConstraints;
3406 Dimension = Pol1->Dimension+2; /* Homogenous Dimension + Status */
3407 d = (Polyhedron *)0;
3408 for (p1=Pol1; p1; p1=p1->next) {
3410 /* Filter is an array of integers, each bit in an element of Filter */
3411 /* array corresponds to a constraint. The bit is marked 1 if the */
3412 /* corresponding constraint is non-redundant and is 0 if it is */
3413 /* redundant. */
3415 NbConstraints = p1->NbConstraints;
3416 nbentries = (NbConstraints + NbCon - 1)/(sizeof(int)*8) + 1;
3418 /* Allocate space for array 'Filter' */
3419 Filter = (unsigned *)malloc(nbentries * sizeof(int));
3420 if(!Filter) {
3421 errormsg1("DomainSimplify", "outofmem", "out of memory space");
3422 UNCATCH(any_exception_error);
3423 return 0;
3426 /* Initialize 'Filter' with zeros */
3427 SMVector_Init(Filter, nbentries);
3429 /* Filter the constraints of p1 in context to the polyhedra p2(s) */
3430 empty = 1;
3431 for (p2=Pol2; p2; p2=p2->next) {
3433 /* Store the non-redundant constraints in array 'Filter'. With */
3434 /* successive loops, the array 'Filter' holds the union of all */
3435 /* non-redundant constraints. 'empty' is set to zero if the */
3436 /* intersection of two polyhedra is non-empty and Filter is !Null */
3438 if (SimplifyConstraints(p1, p2, Filter, NbMaxRays))
3439 empty=0;
3442 if (!empty) {
3444 /* Copy all non-redundant constraints to matrix 'Constraints' */
3445 Constraints = Matrix_Alloc(NbConstraints,Dimension);
3446 if(!Constraints) {
3447 errormsg1("DomainSimplify", "outofmem", "out of memory space");
3448 UNCATCH(any_exception_error);
3449 return 0;
3451 Constraints->NbRows = 0;
3452 for (k=0, jx=0, bx=MSB; k<NbConstraints; k++) {
3454 /* If a bit entry in Filter[jx] is marked 1, copy the correspond- */
3455 /* ing constraint in matrix 'Constraints'. */
3456 if (Filter[jx]&bx) {
3457 Vector_Copy(p1->Constraint[k],
3458 Constraints->p[Constraints->NbRows],
3459 Dimension);
3460 Constraints->NbRows++;
3462 NEXT(jx,bx);
3465 /* Create the polyhedron 'p3' corresponding to the constraints in */
3466 /* matrix 'Constraints'. */
3467 p3 = Constraints2Polyhedron(Constraints,NbMaxRays);
3468 Matrix_Free(Constraints), Constraints = NULL;
3470 /* Add polyhedron 'p3' in the domain 'd'. */
3471 d = AddPolyToDomain (p3, d);
3472 p3 = NULL;
3474 free(Filter), Filter = NULL;
3476 } /* end of TRY */
3478 UNCATCH(any_exception_error);
3479 if (!d)
3480 return Empty_Polyhedron(Pol1->Dimension);
3481 else
3482 return d;
3483 } /* DomainSimplify */
3486 * Return the Union of two polyhedral domains 'Pol1' and Pol2'. The result is
3487 * a new polyhedral domain.
3489 Polyhedron *DomainUnion(Polyhedron *Pol1,Polyhedron *Pol2,unsigned NbMaxRays) {
3491 Polyhedron *PolA, *PolEndA, *PolB, *PolEndB, *p1, *p2;
3492 int Redundant;
3494 if (!Pol1 || !Pol2) return (Polyhedron *) 0;
3495 if (Pol1->Dimension != Pol2->Dimension) {
3496 errormsg1("DomainUnion","diffdim","operation on different dimensions");
3497 return (Polyhedron*) 0;
3505 /* Copy 'Pol1' to 'PolA' */
3506 PolA = PolEndA = (Polyhedron *)0;
3507 for (p1=Pol1; p1; p1=p1->next) {
3509 /* Does any component of 'Pol2' cover 'p1' ? */
3510 Redundant = 0;
3511 for (p2=Pol2; p2; p2=p2->next) {
3512 if (PolyhedronIncludes(p2, p1) ) { /* p2 covers p1 */
3513 Redundant = 1;
3516 break;
3520 if (!Redundant) {
3522 /* Add 'p1' to 'PolA' */
3523 if (!PolEndA)
3524 PolEndA = PolA = Polyhedron_Copy(p1);
3525 else {
3526 PolEndA->next = Polyhedron_Copy(p1);
3527 PolEndA = PolEndA->next;
3533 /* Copy 'Pol2' to PolB */
3534 PolB = PolEndB = (Polyhedron *)0;
3535 for (p2=Pol2; p2; p2=p2->next) {
3537 /* Does any component of PolA cover 'p2' ? */
3538 Redundant = 0;
3539 for (p1=PolA; p1; p1=p1->next) {
3540 if (PolyhedronIncludes(p1, p2)) { /* p1 covers p2 */
3541 Redundant = 1;
3542 break;
3545 if (!Redundant) {
3547 /* Add 'p2' to 'PolB' */
3548 if (!PolEndB)
3549 PolEndB = PolB = Polyhedron_Copy(p2);
3550 else {
3551 PolEndB->next = Polyhedron_Copy(p2);
3552 PolEndB = PolEndB->next;
3559 if (!PolA) return PolB;
3560 PolEndA->next = PolB;
3561 return PolA;
3562 } /* DomainUnion */
3565 * Given a polyhedral domain 'Pol', concatenate the lists of rays and lines
3566 * of the two (or more) polyhedra in the domain into one combined list, and
3567 * find the set of constraints which tightly bound all of those objects.
3568 * 'NbMaxConstrs' is the maximum allowed constraints in the new polyhedron.
3570 Polyhedron *DomainConvex(Polyhedron *Pol,unsigned NbMaxConstrs) {
3572 Polyhedron *p, *q, *NewPol = NULL;
3574 CATCH(any_exception_error) {
3575 if (NewPol) Polyhedron_Free(NewPol);
3576 RETHROW();
3578 TRY {
3580 if (!Pol) {
3581 UNCATCH(any_exception_error);
3582 return (Polyhedron*) 0;
3585 POL_ENSURE_VERTICES(Pol);
3586 NewPol = Polyhedron_Copy(Pol);
3587 for (p=Pol->next; p; p=p->next) {
3588 POL_ENSURE_VERTICES(p);
3589 q = AddRays(p->Ray[0], p->NbRays, NewPol, NbMaxConstrs);
3590 Polyhedron_Free(NewPol);
3591 NewPol = q;
3593 } /* end of TRY */
3595 UNCATCH(any_exception_error);
3597 return NewPol;
3598 } /* DomainConvex */
3601 * Given polyhedral domains 'Pol1' and 'Pol2', create a new polyhedral
3602 * domain which is mathematically the differnce of the two domains.
3604 Polyhedron *DomainDifference(Polyhedron *Pol1,Polyhedron *Pol2,unsigned NbMaxRays) {
3606 Polyhedron *p1, *p2, *p3, *d;
3607 int i;
3609 if (!Pol1 || !Pol2) return (Polyhedron*) 0;
3610 if (Pol1->Dimension != Pol2->Dimension) {
3611 errormsg1("DomainDifference",
3612 "diffdim", "operation on different dimensions");
3613 return (Polyhedron*) 0;
3615 POL_ENSURE_FACETS(Pol1);
3616 POL_ENSURE_VERTICES(Pol1);
3617 POL_ENSURE_FACETS(Pol2);
3618 POL_ENSURE_VERTICES(Pol2);
3619 if (emptyQ(Pol1) || emptyQ(Pol2))
3620 return (Domain_Copy(Pol1));
3621 d = (Polyhedron *)0;
3622 for (p2=Pol2; p2; p2=p2->next) {
3623 for (p1=Pol1; p1; p1=p1->next) {
3624 for (i=0; i<p2->NbConstraints; i++) {
3626 /* Add the constraint ( -p2->constraint[i] -1) >= 0 in 'p1' */
3627 /* and create the new polyhedron 'p3'. */
3628 p3 = SubConstraint(p2->Constraint[i], p1, NbMaxRays,0);
3630 /* Add 'p3' in the new domain 'd' */
3631 d = AddPolyToDomain (p3, d);
3633 /* If the constraint p2->constraint[i][0] is an equality, then */
3634 /* add the constraint ( +p2->constraint[i] -1) >= 0 in 'p1' and*/
3635 /* create the new polyhedron 'p3'. */
3637 if( value_notzero_p(p2->Constraint[i][0]) ) /* Inequality */
3638 continue;
3639 p3 = SubConstraint(p2->Constraint[i], p1, NbMaxRays,1);
3641 /* Add 'p3' in the new domain 'd' */
3642 d = AddPolyToDomain (p3, d);
3645 if (p2 != Pol2)
3646 Domain_Free(Pol1);
3647 Pol1 = d;
3648 d = (Polyhedron *)0;
3650 if (!Pol1)
3651 return Empty_Polyhedron(Pol2->Dimension);
3652 else
3653 return Pol1;
3654 } /* DomainDifference */
3657 * Given a polyhedral domain 'Pol', convert it to a new polyhedral domain
3658 * with dimension expanded to 'align_dimension'. 'NbMaxRays' is the maximum
3659 * allowed rays in the new polyhedra.
3661 Polyhedron *align_context(Polyhedron *Pol,int align_dimension,int NbMaxRays) {
3663 int i, j, k;
3664 Polyhedron *p = NULL, **next, *result = NULL;
3665 unsigned dim;
3667 CATCH(any_exception_error) {
3668 if (result) Polyhedron_Free(result);
3669 RETHROW();
3671 TRY {
3673 if (!Pol) return Pol;
3674 dim = Pol->Dimension;
3675 if (align_dimension < Pol->Dimension) {
3676 errormsg1("align_context", "diffdim", "context dimension exceeds data");
3677 UNCATCH(any_exception_error);
3678 return NULL;
3680 if (align_dimension == Pol->Dimension) {
3681 UNCATCH(any_exception_error);
3682 return Domain_Copy(Pol);
3685 /* 'k' is the dimension increment */
3686 k = align_dimension - Pol->Dimension;
3687 next = &result;
3689 /* Expand the dimension of all polyhedra in the polyhedral domain 'Pol' */
3690 for (; Pol; Pol=Pol->next) {
3691 int have_cons = !F_ISSET(Pol, POL_VALID) || F_ISSET(Pol, POL_INEQUALITIES);
3692 int have_rays = !F_ISSET(Pol, POL_VALID) || F_ISSET(Pol, POL_POINTS);
3693 unsigned NbCons = have_cons ? Pol->NbConstraints : 0;
3694 unsigned NbRays = have_rays ? Pol->NbRays + k : 0;
3696 if (Pol->Dimension != dim) {
3697 Domain_Free(result);
3698 errormsg1("align_context", "diffdim", "context not of uniform dimension");
3699 UNCATCH(any_exception_error);
3700 return NULL;
3703 p = Polyhedron_Alloc(align_dimension, NbCons, NbRays);
3704 if (have_cons) {
3705 for (i = 0; i < NbCons; ++i) {
3706 value_assign(p->Constraint[i][0], Pol->Constraint[i][0]); /* Status bit */
3707 Vector_Copy(Pol->Constraint[i]+1, p->Constraint[i]+k+1, Pol->Dimension+1);
3709 p->NbEq = Pol->NbEq;
3712 if (have_rays) {
3713 for (i = 0; i < k; ++i)
3714 value_set_si(p->Ray[i][1+i], 1); /* A line */
3715 for (i = 0; i < Pol->NbRays; ++i) {
3716 value_assign(p->Ray[k+i][0], Pol->Ray[i][0]); /* Status bit */
3717 Vector_Copy(Pol->Ray[i]+1, p->Ray[i+k]+k+1, Pol->Dimension+1);
3719 p->NbBid = Pol->NbBid + k;
3721 p->flags = Pol->flags;
3723 *next = p;
3724 next = &p->next;
3726 } /* end of TRY */
3728 UNCATCH(any_exception_error);
3729 return result;
3730 } /* align_context */
3732 /*----------------------------------------------------------------------*/
3733 /* Polyhedron *Polyhedron_Scan(D, C, NbMaxRays) */
3734 /* D : Domain to be scanned (single polyhedron only) */
3735 /* C : Context domain */
3736 /* NbMaxRays : Workspace size */
3737 /* Returns a linked list of scan domains, outer loop first */
3738 /*----------------------------------------------------------------------*/
3739 Polyhedron *Polyhedron_Scan(Polyhedron *D, Polyhedron *C,unsigned NbMaxRays) {
3741 int i, j, dim ;
3742 Matrix *Mat;
3743 Polyhedron *C1, *C2, *D1, *D2;
3744 Polyhedron *res, *last, *tmp;
3746 dim = D->Dimension - C->Dimension;
3747 res = last = (Polyhedron *) 0;
3748 if (dim==0) return (Polyhedron *)0;
3750 assert(!D->next);
3752 POL_ENSURE_FACETS(D);
3753 POL_ENSURE_VERTICES(D);
3754 POL_ENSURE_FACETS(C);
3755 POL_ENSURE_VERTICES(C);
3757 /* Allocate space for constraint matrix. */
3758 Mat = Matrix_Alloc(D->Dimension, D->Dimension+2);
3759 if(!Mat) {
3760 errormsg1("Polyhedron_Scan", "outofmem", "out of memory space");
3761 return 0;
3763 C1 = align_context(C,D->Dimension,NbMaxRays);
3764 if(!C1) {
3765 return 0;
3767 /* Vin100, aug 16, 2001: The context is intersected with D */
3768 D2 = DomainIntersection( C1, D, NbMaxRays);
3770 for (i=0; i<dim; i++)
3772 Vector_Set(Mat->p_Init,0,D2->Dimension*(D2->Dimension + 2));
3773 for (j=i+1; j<dim; j++) {
3774 value_set_si(Mat->p[j-i-1][j+1],1);
3776 Mat->NbRows = dim-i-1;
3777 D1 = Mat->NbRows ? DomainAddRays(D2, Mat, NbMaxRays) : D2;
3778 tmp = DomainSimplify(D1, C1, NbMaxRays);
3779 if (!last) res = last = tmp;
3780 else { last->next = tmp; last = tmp; }
3781 C2 = DomainIntersection(C1, D1, NbMaxRays);
3782 Domain_Free(C1);
3783 C1 = C2;
3784 if (Mat->NbRows) Domain_Free(D1);
3786 Domain_Free(D2);
3787 Domain_Free(C1);
3788 Matrix_Free(Mat);
3789 return res;
3790 } /* Polyhedron_Scan */
3792 /*---------------------------------------------------------------------*/
3793 /* int lower_upper_bounds(pos,P,context,LBp,UBp) */
3794 /* pos : index position of current loop index (1..hdim-1) */
3795 /* P: loop domain */
3796 /* context : context values for fixed indices */
3797 /* notice that context[hdim] must be 1 */
3798 /* LBp, UBp : pointers to resulting bounds */
3799 /* returns the flag = (UB_INFINITY, LB_INFINITY) */
3800 /*---------------------------------------------------------------------*/
3801 int lower_upper_bounds(int pos,Polyhedron *P,Value *context,Value *LBp,Value *UBp) {
3803 Value LB, UB;
3804 int flag, i;
3805 Value n, n1, d, tmp;
3807 POL_ENSURE_FACETS(P);
3808 POL_ENSURE_VERTICES(P);
3810 /* Initialize all the 'Value' variables */
3811 value_init(LB); value_init(UB); value_init(tmp);
3812 value_init(n); value_init(n1); value_init(d);
3814 value_set_si(LB,0);
3815 value_set_si(UB,0);
3817 /* Compute Upper Bound and Lower Bound for current loop */
3818 flag = LB_INFINITY | UB_INFINITY;
3819 for (i=0; i<P->NbConstraints; i++) {
3820 value_assign(d,P->Constraint[i][pos]);
3821 Inner_Product(&context[1],&(P->Constraint[i][1]),P->Dimension+1,&n);
3822 if (value_zero_p(d)) {
3823 /* If context doesn't satisfy constraints, return empty loop. */
3824 if (value_neg_p(n) ||
3825 (value_zero_p(P->Constraint[i][0]) && value_notzero_p(n)))
3826 goto empty_loop;
3827 continue;
3829 value_oppose(n,n);
3831 /*---------------------------------------------------*/
3832 /* Compute n/d n/d<0 n/d>0 */
3833 /*---------------------------------------------------*/
3834 /* n%d == 0 floor = n/d floor = n/d */
3835 /* ceiling = n/d ceiling = n/d */
3836 /*---------------------------------------------------*/
3837 /* n%d != 0 floor = n/d - 1 floor = n/d */
3838 /* ceiling = n/d ceiling = n/d + 1 */
3839 /*---------------------------------------------------*/
3841 /* Check to see if constraint is inequality */
3842 /* if constraint is equality, both upper and lower bounds are fixed */
3843 if(value_zero_p(P->Constraint[i][0])) { /* Equality */
3844 value_modulus(tmp,n,d);
3846 /* if not integer, return 0; */
3847 if (value_notzero_p(tmp))
3848 goto empty_loop;
3850 value_division(n1,n,d);
3852 /* Upper and Lower bounds found */
3853 if((flag&LB_INFINITY) || value_gt(n1,LB))
3854 value_assign(LB,n1);
3855 if((flag&UB_INFINITY) || value_lt(n1,UB))
3856 value_assign(UB,n1);
3857 flag = 0;
3860 if (value_pos_p(d)) { /* Lower Bound */
3861 value_modulus(tmp,n,d);
3863 /* n1 = ceiling(n/d) */
3864 if (value_pos_p(n) && value_notzero_p(tmp)) {
3865 value_division(n1,n,d);
3866 value_add_int(n1,n1,1);
3868 else
3869 value_division(n1,n,d);
3870 if (flag&LB_INFINITY) {
3871 value_assign(LB,n1);
3872 flag^=LB_INFINITY;
3874 else if(value_gt(n1,LB))
3875 value_assign(LB,n1);
3878 if (value_neg_p(d)) { /* Upper Bound */
3879 value_modulus(tmp,n,d);
3881 /* n1 = floor(n/d) */
3882 if (value_pos_p(n) && value_notzero_p(tmp)) {
3883 value_division(n1,n,d);
3884 value_sub_int(n1,n1,1);
3886 else
3887 value_division(n1,n,d);
3889 if (flag&UB_INFINITY) {
3890 value_assign(UB,n1);
3891 flag^=UB_INFINITY;
3893 else if (value_lt(n1,UB))
3894 value_assign(UB, n1);
3897 if ((flag & LB_INFINITY)==0) value_assign(*LBp,LB);
3898 if ((flag & UB_INFINITY)==0) value_assign(*UBp,UB);
3900 if (0) {
3901 empty_loop:
3902 flag = 0;
3903 value_set_si(*LBp, 1);
3904 value_set_si(*UBp, 0); /* empty loop */
3907 /* Clear all the 'Value' variables */
3908 value_clear(LB); value_clear(UB); value_clear(tmp);
3909 value_clear(n); value_clear(n1); value_clear(d);
3910 return flag;
3911 } /* lower_upper_bounds */
3914 * C = A x B
3916 static void Rays_Mult(Value **A, Matrix *B, Value **C, unsigned NbRays)
3918 int i, j, k;
3919 unsigned Dimension1, Dimension2;
3920 Value Sum, tmp;
3922 value_init(Sum); value_init(tmp);
3924 CATCH(any_exception_error) {
3925 value_clear(Sum); value_clear(tmp);
3926 RETHROW();
3928 TRY {
3929 Dimension1 = B->NbRows;
3930 Dimension2 = B->NbColumns;
3932 for (i=0; i<NbRays; i++) {
3933 value_assign(C[i][0],A[i][0]);
3934 for (j=0; j<Dimension2; j++) {
3935 value_set_si(Sum,0);
3936 for (k=0; k<Dimension1; k++) {
3938 /* Sum+=A[i][k+1] * B->p[k][j]; */
3939 value_addmul(Sum, A[i][k+1], B->p[k][j]);
3941 value_assign(C[i][j+1],Sum);
3943 Vector_Gcd(C[i]+1, Dimension2, &tmp);
3944 if (value_notone_p(tmp))
3945 Vector_AntiScale(C[i]+1, C[i]+1, tmp, Dimension2);
3948 UNCATCH(any_exception_error);
3949 value_clear(Sum); value_clear(tmp);
3953 * C = A x B^T
3955 static void Rays_Mult_Transpose(Value **A, Matrix *B, Value **C,
3956 unsigned NbRays)
3958 int i, j, k;
3959 unsigned Dimension1, Dimension2;
3960 Value Sum, tmp;
3962 value_init(Sum); value_init(tmp);
3964 CATCH(any_exception_error) {
3965 value_clear(Sum); value_clear(tmp);
3966 RETHROW();
3968 TRY {
3969 Dimension1 = B->NbColumns;
3970 Dimension2 = B->NbRows;
3972 for (i=0; i<NbRays; i++) {
3973 value_assign(C[i][0],A[i][0]);
3974 for (j=0; j<Dimension2; j++) {
3975 value_set_si(Sum,0);
3976 for (k=0; k<Dimension1; k++) {
3978 /* Sum+=A[i][k+1] * B->p[j][k]; */
3979 value_addmul(Sum, A[i][k+1], B->p[j][k]);
3981 value_assign(C[i][j+1],Sum);
3983 Vector_Gcd(C[i]+1, Dimension2, &tmp);
3984 if (value_notone_p(tmp))
3985 Vector_AntiScale(C[i]+1, C[i]+1, tmp, Dimension2);
3988 UNCATCH(any_exception_error);
3989 value_clear(Sum); value_clear(tmp);
3993 * Given a polyhedron 'Pol' and a transformation matrix 'Func', return the
3994 * polyhedron which when transformed by mapping function 'Func' gives 'Pol'.
3995 * 'NbMaxRays' is the maximum number of rays that can be in the ray matrix
3996 * of the resulting polyhedron.
3998 Polyhedron *Polyhedron_Preimage(Polyhedron *Pol,Matrix *Func,unsigned NbMaxRays) {
4000 Matrix *Constraints = NULL;
4001 Polyhedron *NewPol = NULL;
4002 unsigned NbConstraints, Dimension1, Dimension2;
4004 POL_ENSURE_INEQUALITIES(Pol);
4006 CATCH(any_exception_error) {
4007 if (Constraints) Matrix_Free(Constraints);
4008 if (NewPol) Polyhedron_Free(NewPol);
4009 RETHROW();
4011 TRY {
4013 NbConstraints = Pol->NbConstraints;
4014 Dimension1 = Pol->Dimension+1; /* Homogeneous Dimension */
4015 Dimension2 = Func->NbColumns; /* Homogeneous Dimension */
4016 if (Dimension1!=(Func->NbRows)) {
4017 errormsg1("Polyhedron_Preimage", "dimincomp", "incompatible dimensions");
4018 UNCATCH(any_exception_error);
4019 return Empty_Polyhedron(Dimension2-1);
4022 /* Dim1 Dim2 Dim2
4023 __k__ __j__ __j__
4024 NbCon | | X Dim1| | = NbCon | |
4025 i |___| k |___| i |___|
4026 Pol->Constraints Function Constraints
4029 /* Allocate space for the resulting constraint matrix */
4030 Constraints = Matrix_Alloc(NbConstraints, Dimension2+1);
4031 if (!Constraints) {
4032 errormsg1("Polyhedron_Preimage", "outofmem", "out of memory space\n");
4033 Pol_status = 1;
4034 UNCATCH(any_exception_error);
4035 return 0;
4038 /* The new constraint matrix is the product of constraint matrix of the */
4039 /* polyhedron and the function matrix. */
4040 Rays_Mult(Pol->Constraint, Func, Constraints->p, NbConstraints);
4041 NewPol = Constraints2Polyhedron(Constraints, NbMaxRays);
4042 Matrix_Free(Constraints), Constraints = NULL;
4044 } /* end of TRY */
4046 UNCATCH(any_exception_error);
4048 return NewPol;
4049 } /* Polyhedron_Preimage */
4052 * Given a polyhedral domain 'Pol' and a transformation matrix 'Func', return
4053 * the polyhedral domain which when transformed by mapping function 'Func'
4054 * gives 'Pol'. 'NbMaxRays' is the maximum number of rays that can be in the
4055 * ray matrix of the resulting domain.
4057 Polyhedron *DomainPreimage(Polyhedron *Pol,Matrix *Func,unsigned NbMaxRays) {
4059 Polyhedron *p, *q, *d = NULL;
4061 CATCH(any_exception_error) {
4062 if (d) Polyhedron_Free(d);
4063 RETHROW();
4065 TRY {
4066 if (!Pol || !Func) {
4067 UNCATCH(any_exception_error);
4068 return (Polyhedron *) 0;
4070 d = (Polyhedron *) 0;
4071 for (p=Pol; p; p=p->next) {
4072 q = Polyhedron_Preimage(p, Func, NbMaxRays);
4073 d = AddPolyToDomain (q, d);
4075 } /* end of TRY */
4076 UNCATCH(any_exception_error);
4077 return d;
4078 } /* DomainPreimage */
4081 * Transform a polyhedron 'Pol' into another polyhedron according to a given
4082 * affine mapping function 'Func'. 'NbMaxConstrs' is the maximum number of
4083 * constraints that can be in the constraint matrix of the new polyhedron.
4085 Polyhedron *Polyhedron_Image(Polyhedron *Pol, Matrix *Func,unsigned NbMaxConstrs) {
4087 Matrix *Rays = NULL;
4088 Polyhedron *NewPol = NULL;
4089 unsigned NbRays, Dimension1, Dimension2;
4091 POL_ENSURE_FACETS(Pol);
4092 POL_ENSURE_VERTICES(Pol);
4094 CATCH(any_exception_error) {
4095 if (Rays) Matrix_Free(Rays);
4096 if (NewPol) Polyhedron_Free(NewPol);
4097 RETHROW();
4099 TRY {
4101 NbRays = Pol->NbRays;
4102 Dimension1 = Pol->Dimension+1; /* Homogeneous Dimension */
4103 Dimension2 = Func->NbRows; /* Homogeneous Dimension */
4104 if (Dimension1!=Func->NbColumns) {
4105 errormsg1("Polyhedron_Image", "dimincomp", "incompatible dimensions");
4106 UNCATCH(any_exception_error);
4107 return Empty_Polyhedron(Dimension2-1);
4111 Dim1 / Dim1 \Transpose Dim2
4112 __k__ | __k__ | __j__
4113 NbRays| | X | Dim2 | | | = NbRays| |
4114 i |___| | j |___| | i |___|
4115 Pol->Rays \ Func / Rays
4119 if (Dimension1 == Dimension2) {
4120 Matrix *M, *M2;
4121 int ok;
4122 M = Matrix_Copy(Func);
4123 M2 = Matrix_Alloc(Dimension2, Dimension1);
4124 if (!M2) {
4125 errormsg1("Polyhedron_Image", "outofmem", "out of memory space\n");
4126 UNCATCH(any_exception_error);
4127 return 0;
4130 ok = Matrix_Inverse(M, M2);
4131 Matrix_Free(M);
4132 if (ok) {
4133 NewPol = Polyhedron_Alloc(Pol->Dimension, Pol->NbConstraints,
4134 Pol->NbRays);
4135 if (!NewPol) {
4136 errormsg1("Polyhedron_Image", "outofmem",
4137 "out of memory space\n");
4138 UNCATCH(any_exception_error);
4139 return 0;
4141 Rays_Mult_Transpose(Pol->Ray, Func, NewPol->Ray, NbRays);
4142 Rays_Mult(Pol->Constraint, M2, NewPol->Constraint,
4143 Pol->NbConstraints);
4144 NewPol->NbEq = Pol->NbEq;
4145 NewPol->NbBid = Pol->NbBid;
4146 if (NewPol->NbEq)
4147 Gauss4(NewPol->Constraint, NewPol->NbEq, NewPol->NbConstraints,
4148 NewPol->Dimension+1);
4149 if (NewPol->NbBid)
4150 Gauss4(NewPol->Ray, NewPol->NbBid, NewPol->NbRays,
4151 NewPol->Dimension+1);
4153 Matrix_Free(M2);
4156 if (!NewPol) {
4157 /* Allocate space for the resulting ray matrix */
4158 Rays = Matrix_Alloc(NbRays, Dimension2+1);
4159 if (!Rays) {
4160 errormsg1("Polyhedron_Image", "outofmem", "out of memory space\n");
4161 UNCATCH(any_exception_error);
4162 return 0;
4165 /* The new ray space is the product of ray matrix of the polyhedron and */
4166 /* the transpose matrix of the mapping function. */
4167 Rays_Mult_Transpose(Pol->Ray, Func, Rays->p, NbRays);
4168 NewPol = Rays2Polyhedron(Rays, NbMaxConstrs);
4169 Matrix_Free(Rays), Rays = NULL;
4172 } /* end of TRY */
4174 UNCATCH(any_exception_error);
4175 return NewPol;
4176 } /* Polyhedron_Image */
4179 *Transform a polyhedral domain 'Pol' into another domain according to a given
4180 * affine mapping function 'Func'. 'NbMaxConstrs' is the maximum number of
4181 * constraints that can be in the constraint matrix of the resulting domain.
4183 Polyhedron *DomainImage(Polyhedron *Pol,Matrix *Func,unsigned NbMaxConstrs) {
4185 Polyhedron *p, *q, *d = NULL;
4187 CATCH(any_exception_error) {
4188 if (d) Polyhedron_Free(d);
4189 RETHROW();
4191 TRY {
4193 if (!Pol || !Func) {
4194 UNCATCH(any_exception_error);
4195 return (Polyhedron *) 0;
4197 d = (Polyhedron *) 0;
4198 for (p=Pol; p; p=p->next) {
4199 q = Polyhedron_Image(p, Func, NbMaxConstrs);
4200 d = AddPolyToDomain (q, d);
4202 } /* end of TRY */
4204 UNCATCH(any_exception_error);
4206 return d;
4207 } /* DomainImage */
4210 * Given a polyhedron 'Pol' and an affine cost function 'Cost', compute the
4211 * maximum and minimum value of the function over set of points representing
4212 * polyhedron.
4213 * Note: If Polyhedron 'Pol' is empty, then there is no feasible solution.
4214 * Otherwise, if there is a bidirectional ray with Sum[cost(i)*ray(i)] != 0 or
4215 * a unidirectional ray with Sum[cost(i)*ray(i)] >0, then the maximum is un-
4216 * bounded else the finite optimal solution occurs at one of the vertices of
4217 * the polyhderon.
4219 Interval *DomainCost(Polyhedron *Pol,Value *Cost) {
4221 int i, j, NbRay, Dim;
4222 Value *p1, *p2, p3, d, status;
4223 Value tmp1, tmp2, tmp3;
4224 Value **Ray;
4225 Interval *I = NULL;
4227 value_init(p3); value_init(d); value_init(status);
4228 value_init(tmp1); value_init(tmp2); value_init(tmp3);
4230 POL_ENSURE_FACETS(Pol);
4231 POL_ENSURE_VERTICES(Pol);
4233 CATCH(any_exception_error) {
4234 if (I) free(I);
4235 RETHROW();
4236 value_clear(p3); value_clear(d); value_clear(status);
4237 value_clear(tmp1); value_clear(tmp2); value_clear(tmp3);
4239 TRY {
4241 Ray = Pol->Ray;
4242 NbRay = Pol->NbRays;
4243 Dim = Pol->Dimension+1; /* Homogenous Dimension */
4244 I = (Interval *) malloc (sizeof(Interval));
4245 if (!I) {
4246 errormsg1("DomainCost", "outofmem", "out of memory space\n");
4247 UNCATCH(any_exception_error);
4248 value_clear(p3); value_clear(d); value_clear(status);
4249 value_clear(tmp1); value_clear(tmp2); value_clear(tmp3);
4250 return 0;
4253 /* The maximum and minimum values of the cost function over polyhedral */
4254 /* domain is stored in 'I'. I->MaxN and I->MaxD store the numerator and */
4255 /* denominator of the maximum value. Likewise,I->MinN and I->MinD store */
4256 /* the numerator and denominator of the minimum value. I->MaxI and */
4257 /* I->MinI store the ray indices corresponding to the max and min values*/
4258 /* of the function. */
4260 value_set_si(I->MaxN,-1);
4261 value_set_si(I->MaxD,0); /* Actual cost is MaxN/MaxD */
4262 I->MaxI = -1;
4263 value_set_si(I->MinN,1);
4264 value_set_si(I->MinD,0);
4265 I->MinI = -1;
4267 /* Compute the cost of each ray[i] */
4268 for (i=0; i<NbRay; i++) {
4269 p1 = Ray[i];
4270 value_assign(status, *p1);
4271 p1++;
4272 p2 = Cost;
4274 /* p3 = *p1++ * *p2++; */
4275 value_multiply(p3,*p1,*p2);
4276 p1++; p2++;
4277 for (j=1; j<Dim; j++) {
4278 value_multiply(tmp1,*p1,*p2);
4280 /* p3 += *p1++ * *p2++; */
4281 value_addto(p3,p3,tmp1);
4282 p1++; p2++;
4285 /* d = *--p1; */
4286 p1--;
4287 value_assign(d,*p1); /* d == 0 for lines and ray, non-zero for vertex */
4288 value_multiply(tmp1,p3,I->MaxD);
4289 value_multiply(tmp2,I->MaxN,d);
4290 value_set_si(tmp3,1);
4292 /* Compare p3/d with MaxN/MaxD to assign new maximum cost value */
4293 if (I->MaxI==-1 ||
4294 value_gt(tmp1,tmp2) ||
4295 (value_eq(tmp1,tmp2) &&
4296 value_eq(d,tmp3) && value_ne(I->MaxD,tmp3))) {
4297 value_assign(I->MaxN,p3);
4298 value_assign(I->MaxD,d);
4299 I->MaxI = i;
4301 value_multiply(tmp1,p3,I->MinD);
4302 value_multiply(tmp2,I->MinN,d);
4303 value_set_si(tmp3,1);
4305 /* Compare p3/d with MinN/MinD to assign new minimum cost value */
4306 if (I->MinI==-1 ||
4307 value_lt(tmp1,tmp2) ||
4308 (value_eq(tmp1,tmp2) &&
4309 value_eq(d,tmp3) && value_ne(I->MinD,tmp3))) {
4310 value_assign(I->MinN, p3);
4311 value_assign(I->MinD, d);
4312 I->MinI = i;
4314 value_multiply(tmp1,p3,I->MaxD);
4315 value_set_si(tmp2,0);
4317 /* If there is a line, assign max to +infinity and min to -infinity */
4318 if (value_zero_p(status)) { /* line , d is 0 */
4319 if (value_lt(tmp1,tmp2)) {
4320 value_oppose(I->MaxN,p3);
4321 value_set_si(I->MaxD,0);
4322 I->MaxI = i;
4324 value_multiply(tmp1,p3,I->MinD);
4325 value_set_si(tmp2,0);
4327 if (value_gt(tmp1,tmp2)) {
4328 value_oppose(I->MinN,p3);
4329 value_set_si(I->MinD,0);
4330 I->MinI = i;
4334 } /* end of TRY */
4336 UNCATCH(any_exception_error);
4337 value_clear(p3); value_clear(d); value_clear(status);
4338 value_clear(tmp1); value_clear(tmp2); value_clear(tmp3);
4339 return I;
4340 } /* DomainCost */
4343 * Add constraints pointed by 'Mat' to each and every polyhedron in the
4344 * polyhedral domain 'Pol'. 'NbMaxRays' is maximum allowed rays in the ray
4345 * matrix of a polyhedron.
4347 Polyhedron *DomainAddConstraints(Polyhedron *Pol,Matrix *Mat,unsigned NbMaxRays) {
4349 Polyhedron *PolA, *PolEndA, *p1, *p2, *p3;
4350 int Redundant;
4352 if (!Pol) return (Polyhedron*) 0;
4353 if (!Mat) return Pol;
4354 if (Pol->Dimension != Mat->NbColumns-2) {
4355 errormsg1("DomainAddConstraints",
4356 "diffdim", "operation on different dimensions");
4357 return (Polyhedron*) 0;
4360 /* Copy 'Pol' to 'PolA' */
4361 PolA = PolEndA = (Polyhedron *)0;
4362 for (p1=Pol; p1; p1=p1->next) {
4363 p3 = AddConstraints(Mat->p_Init, Mat->NbRows, p1, NbMaxRays);
4365 /* Does any component of 'PolA' cover 'p3' */
4366 Redundant = 0;
4367 for (p2=PolA; p2; p2=p2->next) {
4368 if (PolyhedronIncludes(p2, p3)) { /* 'p2' covers 'p3' */
4369 Redundant = 1;
4370 break;
4374 /* If the new polyhedron 'p3' is not redundant, add it to the domain */
4375 if (Redundant)
4376 Polyhedron_Free(p3);
4377 else {
4378 if (!PolEndA)
4379 PolEndA = PolA = p3;
4380 else {
4381 PolEndA->next = p3;
4382 PolEndA = PolEndA->next;
4386 return PolA;
4387 } /* DomainAddConstraints */
4391 * Computes the disjoint union of a union of polyhedra.
4392 * If flag = 0 the result is such that there are no intersections
4393 * between the resulting polyhedra,
4394 * if flag = 1 it computes a joint union, the resulting polyhedra are
4395 * adjacent (they have their facets in common).
4397 * WARNING: if all polyhedra are not of same geometrical dimension
4398 * duplicates may appear.
4400 Polyhedron *Disjoint_Domain( Polyhedron *P, int flag, unsigned NbMaxRays )
4402 Polyhedron *lP, *tmp, *Result, *lR, *prec, *reste;
4403 Polyhedron *p1, *p2, *p3, *Pol1, *dx, *d1, *d2, *pi, *newpi;
4404 int i;
4406 if( flag!=0 && flag!=1 )
4408 errormsg1("Disjoint_Domain",
4409 "invalidarg", "flag should be equal to 0 or 1");
4410 return (Polyhedron*) 0;
4412 if(!P) return (Polyhedron*) 0;
4413 if(!P->next) return Polyhedron_Copy(P);
4415 Result = (Polyhedron *)0;
4417 for(lP=P;lP;lP=lP->next)
4419 reste = Polyhedron_Copy(lP);
4420 prec = (Polyhedron *)0; /* preceeding lR */
4421 /* Intersection with each polyhedron of the current Result */
4422 lR=Result;
4423 while( lR && reste )
4425 /* dx = DomainIntersection(reste,lR->P,WS); */
4426 dx = (Polyhedron *)0;
4427 for( p1=reste; p1; p1=p1->next )
4429 p3 = AddConstraints(lR->Constraint[0], lR->NbConstraints, p1,
4430 NbMaxRays);
4431 dx = AddPolyToDomain(p3,dx);
4434 /* if empty intersection, continue */
4435 if(!dx)
4436 { prec = lR;
4437 lR=lR->next;
4438 continue;
4440 if (emptyQ(dx)) {
4441 Domain_Free(dx);
4442 prec = lR;
4443 lR=lR->next;
4444 continue;
4447 /* intersection is not empty, we need to compute the differences */
4448 /* between the intersection and the two polyhedra, such that the */
4449 /* results are disjoint unions (according to flag) */
4450 /* d1 = reste \ P = DomainDifference(reste,lR->P,WS); */
4451 /* d2 = P \ reste = DomainDifference(lR->P,reste,WS); */
4453 /* compute d1 */
4454 d1 = (Polyhedron *)0;
4455 for (p1=reste; p1; p1=p1->next)
4457 pi = p1;
4458 for (i=0; i<P->NbConstraints && pi ; i++)
4461 /* Add the constraint ( -P->constraint[i] [-1 if flag=0]) >= 0 in 'p1' */
4462 /* and create the new polyhedron 'p3'. */
4463 p3 = SubConstraint(P->Constraint[i], pi, NbMaxRays,2*flag);
4464 /* Add 'p3' in the new domain 'd1' */
4465 d1 = AddPolyToDomain (p3, d1);
4467 /* If the constraint P->constraint[i][0] is an equality, then add */
4468 /* the constraint ( +P->constraint[i] [-1 if flag=0]) >= 0 in 'pi' */
4469 /* and create the new polyhedron 'p3'. */
4470 if( value_zero_p(P->Constraint[i][0]) ) /* Inequality */
4472 p3 = SubConstraint(P->Constraint[i], pi, NbMaxRays,1+2*flag);
4473 /* Add 'p3' in the new domain 'd1' */
4474 d1 = AddPolyToDomain (p3, d1);
4476 /* newpi : add constraint P->constraint[i]==0 to pi */
4477 newpi = AddConstraints( P->Constraint[i], 1, pi, NbMaxRays);
4479 else
4481 /* newpi : add constraint +P->constraint[i] >= 0 in pi */
4482 newpi = SubConstraint(P->Constraint[i], pi, NbMaxRays,3);
4484 if( newpi && emptyQ( newpi ) )
4486 Domain_Free( newpi );
4487 newpi = (Polyhedron *)0;
4489 if( pi != p1 )
4490 Domain_Free( pi );
4491 pi = newpi;
4493 if( pi != p1 )
4494 Domain_Free( pi );
4497 /* and now d2 */
4498 Pol1 = Polyhedron_Copy( lR );
4499 for (p2=reste; p2; p2=p2->next)
4501 d2 = (Polyhedron *)0;
4502 for (p1=Pol1; p1; p1=p1->next)
4504 pi = p1;
4505 for (i=0; i<p2->NbConstraints && pi ; i++)
4508 /* Add the constraint ( -p2->constraint[i] [-1 if flag=0]) >= 0 in 'pi' */
4509 /* and create the new polyhedron 'p3'. */
4510 p3 = SubConstraint(p2->Constraint[i], pi, NbMaxRays,2*flag);
4511 /* Add 'p3' in the new domain 'd2' */
4512 d2 = AddPolyToDomain (p3, d2);
4514 /* If the constraint p2->constraint[i][0] is an equality, then add */
4515 /* the constraint ( +p2->constraint[i] [-1 if flag=0]) >= 0 in 'pi' */
4516 /* and create the new polyhedron 'p3'. */
4517 if( value_zero_p(p2->Constraint[i][0]) ) /* Inequality */
4519 p3 = SubConstraint(p2->Constraint[i], pi, NbMaxRays,1+2*flag);
4520 /* Add 'p3' in the new domain 'd2' */
4521 d2 = AddPolyToDomain (p3, d2);
4523 /* newpi : add constraint p2->constraint[i]==0 to pi */
4524 newpi = AddConstraints( p2->Constraint[i], 1, pi, NbMaxRays);
4526 else
4528 /* newpi : add constraint +p2->constraint[i] >= 0 in pi */
4529 newpi = SubConstraint(p2->Constraint[i], pi, NbMaxRays,3);
4531 if( newpi && emptyQ( newpi ) )
4533 Domain_Free( newpi );
4534 newpi = (Polyhedron *)0;
4536 if( pi != p1 )
4537 Domain_Free( pi );
4538 pi = newpi;
4540 if( pi && pi!=p1 )
4541 Domain_Free( pi );
4543 if( Pol1 )
4544 Domain_Free( Pol1 );
4545 Pol1 = d2;
4547 /* ok, d1 and d2 are computed */
4549 /* now, replace lR by d2+dx (at least dx is nonempty) and set reste to d1 */
4550 if( d1 && emptyQ(d1) )
4552 Domain_Free( d1 );
4553 d1 = NULL;
4555 if( d2 && emptyQ(d2) )
4557 Domain_Free( d2 );
4558 d2 = NULL;
4561 /* set reste */
4562 Domain_Free( reste );
4563 reste = d1;
4565 /* add d2 at beginning of Result */
4566 if( d2 )
4568 for( tmp=d2 ; tmp->next ; tmp=tmp->next )
4570 tmp->next = Result;
4571 Result = d2;
4572 if( !prec )
4573 prec = tmp;
4576 /* add dx at beginning of Result */
4577 for( tmp=dx ; tmp->next ; tmp=tmp->next )
4579 tmp->next = Result;
4580 Result = dx;
4581 if( !prec )
4582 prec = tmp;
4584 /* suppress current lR */
4585 if( !prec )
4586 errormsg1( "Disjoint_Domain","internalerror","internal error");
4587 prec->next = lR->next;
4588 Polyhedron_Free( lR );
4589 lR = prec->next;
4590 } /* end for result */
4592 /* if there is something left, add it to Result : */
4593 if(reste)
4595 if(emptyQ(reste))
4597 Domain_Free( reste );
4598 reste = NULL;
4600 else
4602 Polyhedron *tnext;
4603 for( tmp=reste ; tmp ; tmp=tnext )
4605 tnext = tmp->next;
4606 tmp->next = NULL;
4607 Result = AddPolyToDomain(tmp, Result);
4613 return( Result );
4618 /* Procedure to print constraint matrix of a polyhedron */
4619 void Polyhedron_PrintConstraints(FILE *Dst, const char *Format, Polyhedron *Pol)
4621 int i,j;
4623 fprintf( Dst, "%d %d\n", Pol->NbConstraints, Pol->Dimension+2 );
4624 for( i=0 ; i<Pol->NbConstraints ; i++ )
4626 for( j=0 ; j<Pol->Dimension+2 ; j++ )
4627 value_print( Dst, Format, Pol->Constraint[i][j] );
4628 fprintf( Dst, "\n" );
4633 /* Procedure to print constraint matrix of a domain */
4634 void Domain_PrintConstraints(FILE *Dst, const char *Format, Polyhedron *Pol)
4636 Polyhedron *Q;
4637 for (Q = Pol; Q; Q = Q->next)
4638 Polyhedron_PrintConstraints(Dst, Format, Q);
4641 static Polyhedron *p_simplify_constraints(Polyhedron *P, Vector *row,
4642 Value *g, unsigned MaxRays)
4644 Polyhedron *T, *R = P;
4645 int len = P->Dimension+2;
4646 int r;
4648 /* Also look at equalities.
4649 * If an equality can be "simplified" then there
4650 * are no integer solutions and we return an empty polyhedron
4652 for (r = 0; r < R->NbConstraints; ++r) {
4653 if (ConstraintSimplify(R->Constraint[r], row->p, len, g)) {
4654 T = R;
4655 if (value_zero_p(R->Constraint[r][0])) {
4656 R = Empty_Polyhedron(R->Dimension);
4657 r = R->NbConstraints;
4658 } else if (POL_ISSET(MaxRays, POL_NO_DUAL)) {
4659 R = Polyhedron_Copy(R);
4660 F_CLR(R, POL_FACETS | POL_VERTICES | POL_POINTS);
4661 Vector_Copy(row->p+1, R->Constraint[r]+1, R->Dimension+1);
4662 } else {
4663 R = AddConstraints(row->p, 1, R, MaxRays);
4664 r = -1;
4666 if (T != P)
4667 Polyhedron_Free(T);
4670 if (R != P)
4671 Polyhedron_Free(P);
4672 return R;
4676 * Replaces constraint a x >= c by x >= ceil(c/a)
4677 * where "a" is a common factor in the coefficients
4678 * Destroys P and returns a newly allocated Polyhedron
4679 * or just returns P in case no changes were made
4681 Polyhedron *DomainConstraintSimplify(Polyhedron *P, unsigned MaxRays)
4683 Polyhedron **prev;
4684 int len = P->Dimension+2;
4685 Vector *row = Vector_Alloc(len);
4686 Value g;
4687 Polyhedron *R = P, *N;
4688 value_set_si(row->p[0], 1);
4689 value_init(g);
4691 for (prev = &R; P; P = N) {
4692 Polyhedron *T;
4693 N = P->next;
4694 T = p_simplify_constraints(P, row, &g, MaxRays);
4696 if (emptyQ(T) && prev != &R) {
4697 Polyhedron_Free(T);
4698 *prev = NULL;
4699 continue;
4702 if (T != P)
4703 T->next = N;
4704 *prev = T;
4705 prev = &T->next;
4708 if (R->next && emptyQ(R)) {
4709 N = R->next;
4710 Polyhedron_Free(R);
4711 R = N;
4714 value_clear(g);
4715 Vector_Free(row);
4716 return R;