Main Page | Class List | File List | Class Members | File Members

polyhedron.c

Go to the documentation of this file.
00001 /* polyhedron.c
00002      COPYRIGHT
00003           Both this software and its documentation are
00004 
00005               Copyright 1993 by IRISA /Universite de Rennes I - France,
00006               Copyright 1995,1996 by BYU, Provo, Utah
00007                          all rights reserved.
00008 
00009           Permission is granted to copy, use, and distribute
00010           for any commercial or noncommercial purpose under the terms
00011           of the GNU General Public license, version 2, June 1991
00012           (see file : LICENSING).
00013 */
00014 
00015 /*
00016 
00017 1997/12/02 - Olivier Albiez
00018   Ce fichier contient les fonctions de la polylib de l'IRISA,
00019   passees en 64bits.
00020   La structure de la polylib a donc ete modifie pour permettre 
00021   le passage aux Value. La fonction Chernikova a ete reecrite.
00022 
00023 */
00024 
00025 /*
00026 
00027 1998/26/02 - Vincent Loechner
00028   Ajout de nombreuses fonctions, a la fin de ce fichier,
00029   pour les polyedres parametres 64 bits.
00030 1998/16/03
00031   #define DEBUG  printf
00032   tests out of memory
00033   compatibilite avec la version de doran
00034 
00035 */
00036 
00037 #undef POLY_DEBUG               /* debug printf: general functions */
00038 #undef POLY_RR_DEBUG            /* debug printf: Remove Redundants */
00039 #undef POLY_CH_DEBUG            /* debug printf: Chernikova */
00040 
00041 #include <stdio.h>
00042 #include <stdlib.h>
00043 #include <string.h>
00044 #include <assert.h>
00045 #include <polylib/polylib.h>
00046 
00047 #ifdef MAC_OS
00048   #define abs __abs
00049 #endif
00050 
00051 /* WSIZE is the number of bits in a word or int type */ 
00052 #define WSIZE (8*sizeof(int)) 
00053 
00054 #define bexchange(a, b, l)\
00055 {\
00056   char *t = (char *)malloc(l*sizeof(char));\
00057   memcpy((t), (char *)(a), (int)(l));\
00058   memcpy((char *)(a), (char *)(b), (int)(l));\
00059   memcpy((char *)(b), (t), (int)(l));\
00060   free(t); \
00061 }
00062 
00063 #define exchange(a, b, t)\
00064 { (t)=(a); (a)=(b); (b)=(t); }
00065 
00066 /*  errormsg1 is an external function which is usually supplied by the
00067     calling program (e.g. Domlib.c, ReadAlpha, etc...).
00068     See errormsg.c for an example of such a function.  */
00069 
00070 void errormsg1(char *f , char *msgname, char *msg);
00071 
00072 int Pol_status;                    /* error status after operations */
00073 
00074 /*
00075  * The Saturation matrix is defined to be an integer (int type) matrix.
00076  * It is a boolean matrix which has a row for every constraint and a column
00077  * for every line or ray. The bits in the binary format of each integer in 
00078  * the stauration matrix stores the information whether the corresponding
00079  * constraint is saturated by ray(line) or not.   
00080  */
00081 
00082 typedef struct {
00083   unsigned int NbRows;
00084   unsigned int NbColumns;
00085   int **p;
00086   int *p_init;
00087 } SatMatrix;
00088 
00089 /*
00090  * Allocate memory space for a saturation matrix. 
00091  */
00092 static SatMatrix *SMAlloc(int rows,int cols) {
00093   
00094   int **q, *p, i;
00095   SatMatrix *result;
00096   
00097   result = (SatMatrix *) malloc (sizeof(SatMatrix));
00098   if(!result) { 
00099     errormsg1("SMAlloc", "outofmem", "out of memory space");
00100     return 0;
00101   }
00102   result->NbRows = rows;
00103   result->NbColumns = cols;
00104   if(rows == 0 || cols == 0) {
00105     result->p = NULL;
00106     return result;
00107   }
00108   result->p = q = (int **)malloc(rows * sizeof(int *));
00109   if(!result->p) {
00110     errormsg1("SMAlloc", "outofmem", "out of memory space");
00111     return 0;
00112   }
00113   result->p_init = p = (int *)malloc (rows * cols * sizeof (int));
00114   if(!result->p_init) {
00115     errormsg1("SMAlloc", "outofmem", "out of memory space");
00116     return 0;
00117   }
00118   for (i=0; i<rows; i++) {
00119     *q++ = p;
00120     p += cols;
00121   }
00122   return result;
00123 } /* SMAlloc */
00124 
00125 /* 
00126  * Free the memory space occupied by saturation matrix. 
00127  */ 
00128 static void SMFree (SatMatrix **matrix) {
00129   SatMatrix *SM = *matrix;
00130 
00131   if (SM) { 
00132     if (SM->p) {
00133       free ((char *) SM->p_init);
00134       free ((char *) SM->p);
00135     }
00136     free ((char *) SM);
00137     *matrix = NULL;
00138   }
00139 } /* SMFree */
00140 
00141 /*
00142  * Print the contents of a saturation matrix.
00143  * This function is defined only for debugging purpose. 
00144  */
00145 static void SMPrint (SatMatrix *matrix) {
00146   
00147   int *p;
00148   int i, j;
00149   unsigned NbRows, NbColumns;
00150   
00151   fprintf(stderr,"%d %d\n",NbRows=matrix->NbRows, NbColumns=matrix->NbColumns);
00152   for (i=0;i<NbRows;i++) {
00153     p = *(matrix->p+i);
00154     for (j=0;j<NbColumns;j++)
00155       fprintf(stderr, " %10X ", *p++);
00156     fprintf(stderr, "\n");
00157   }  
00158 } /* SMPrint */
00159 
00160 /* 
00161  * Compute the bitwise OR of two saturation matrices.
00162  */
00163 static void SatVector_OR(int *p1,int *p2,int *p3,unsigned length) {
00164   
00165   int *cp1, *cp2, *cp3;
00166   int i;
00167   
00168   cp1=p1;
00169   cp2=p2;
00170   cp3=p3;
00171   for (i=0;i<length;i++) {
00172     *cp3 = *cp1 | *cp2;
00173     cp3++;
00174     cp1++;
00175     cp2++;
00176   }
00177 } /* SatVector_OR */
00178 
00179 /* 
00180  * Copy a saturation matrix to another (macro definition). 
00181  */
00182 #define SMVector_Copy(p1, p2, length) \
00183   memcpy((char *)(p2), (char *)(p1), (int)((length)*sizeof(int)))
00184 
00185 /*
00186  * Initialize a saturation matrix with zeros (macro definition) 
00187  */
00188 #define SMVector_Init(p1, length) \
00189   memset((char *)(p1), 0, (int)((length)*sizeof(int)))
00190 
00191 /*
00192  * Defining operations on polyhedron --
00193  */
00194 
00195 /* 
00196  * Vector p3 is a linear combination of two vectors (p1 and p2) such that 
00197  * p3[pos] is zero. First element of each vector (p1,p2,p3) is a status 
00198  * element and is not changed in p3. The value of 'pos' may be 0 however.
00199  * The parameter 'length' does not include status element one. 
00200  */
00201 static void Combine(Value *p1, Value *p2, Value *p3, int pos, unsigned length) { 
00202 
00203   Value a1, a2, gcd;
00204   Value abs_a1,abs_a2,neg_a1;
00205 
00206   /* Initialize all the 'Value' variables */
00207   value_init(a1); value_init(a2); value_init(gcd);
00208   value_init(abs_a1); value_init(abs_a2); value_init(neg_a1);
00209   
00210   /* a1 = p1[pos] */
00211   value_assign(a1,p1[pos]); 
00212 
00213   /* a2 = p2[pos] */
00214   value_assign(a2,p2[pos]); 
00215 
00216   /* a1_abs = |a1| */
00217   value_absolute(abs_a1,a1);
00218   
00219   /* a2_abs = |a2| */
00220   value_absolute(abs_a2,a2);
00221 
00222   /* gcd  = Gcd(abs(a1), abs(a2)) */
00223   Gcd(abs_a1,abs_a2,&gcd);
00224 
00225   /* a1 = a1/gcd */
00226   value_division (a1,a1,gcd);
00227 
00228   /* a2 = a2/gcd */
00229   value_division (a2,a2,gcd);
00230 
00231   /* neg_a1 = -(a1) */
00232   value_oppose(neg_a1,a1);
00233 
00234   Vector_Combine(p1+1,p2+1,p3+1,a2,neg_a1,length);
00235   Vector_Normalize(p3+1,length);
00236 
00237   /* Clear all the 'Value' variables */
00238   value_clear(a1); value_clear(a2); value_clear(gcd);
00239   value_clear(abs_a1); value_clear(abs_a2); value_clear(neg_a1);    
00240   
00241   return;
00242 } /* Combine */
00243 
00244 /* 
00245  * Return the transpose of the saturation matrix 'Sat'. 'Mat' is a matrix
00246  * of constraints and 'Ray' is a matrix of ray vectors and 'Sat' is the 
00247  * corresponding saturation matrix. 
00248  */
00249 static SatMatrix *TransformSat(Matrix *Mat, Matrix *Ray, SatMatrix *Sat) { 
00250   
00251   int i, j, sat_nbcolumns;
00252   unsigned jx1, jx2, bx1, bx2;
00253   SatMatrix *result;
00254 
00255   if (Mat->NbRows != 0) 
00256     sat_nbcolumns = (Mat->NbRows-1) /(sizeof(int)*8) + 1;
00257   else                  
00258     sat_nbcolumns = 0;
00259 
00260   result = SMAlloc(Ray->NbRows, sat_nbcolumns);
00261   SMVector_Init(result->p_init, Ray->NbRows * sat_nbcolumns);
00262 
00263   for(i=0,jx1=0,bx1=MSB; i<Ray->NbRows; i++) { 
00264     for(j=0,jx2=0,bx2=MSB; j<Mat->NbRows; j++) { 
00265       if (Sat->p[j][jx1] & bx1) 
00266         result->p[i][jx2] |= bx2;
00267       NEXT(jx2,bx2);
00268     }
00269     NEXT(jx1, bx1);
00270   }
00271   return result;
00272 } /* TransformSat */
00273 
00274 /* 
00275  * Sort the rays (Ray, Sat) into three tiers as used in 'Chernikova' function:
00276  * NbBid         <= i <  equal_bound    : saturates the constraint
00277  * equal_bound   <= i <  sup_bound      : verifies the constraint
00278  * sup_bound     <= i <  NbRay          : does not verify 
00279  *
00280  * 'Ray' is the matrix of rays and 'Sat' is the corresponding saturation 
00281  * matrix. (jx,bx) pair specify the constraint in the saturation matrix. The
00282  * status element of the 'Ray' matrix holds the saturation value w.r.t the 
00283  * constraint specified by (jx,bx). Thus
00284  * Ray->p[i][0]  = 0 -> ray(i) saturates the constraint
00285  * Ray->p[i][0]  > 0 -> ray(i) verifies  the constraint
00286  * Ray->p[i][0]  < 0 -> ray(i) doesn't verify the constraint  
00287  */  
00288 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) {                     
00289 
00290   int inf_bound;
00291   Value **uni_eq, **uni_sup, **uni_inf;
00292   int **inc_eq, **inc_sup, **inc_inf;
00293 
00294   /* 'uni_eq' points to the first ray in the ray matrix which verifies a
00295    * constraint, 'inc_eq' is the corresponding pointer in saturation 
00296    * matrix. 'uni_inf' points to the first ray (from top) which doesn't 
00297    * verify a constraint, 'inc_inf' is the corresponding pointer in 
00298    * saturation matrix. 'uni_sup' scans the ray matrix and 'inc_sup' is 
00299    * the corresponding pointer in saturation matrix. 'inf_bound' holds the 
00300    * number of the first ray which does not verify the constraints. 
00301    */
00302 
00303   *sup_bound = *equal_bound = NbBid;
00304   uni_sup = uni_eq = Ray->p+NbBid;
00305   inc_sup = inc_eq = Sat->p+NbBid;
00306   inf_bound = NbRay;
00307   uni_inf = Ray->p+NbRay;
00308   inc_inf = Sat->p+NbRay;
00309   
00310   while (inf_bound>*sup_bound) {
00311     if (value_zero_p(**uni_sup)) {               /* status = satisfy */
00312       Vector_Exchange(*uni_eq,*uni_sup,RowSize1);
00313       bexchange(*inc_eq,*inc_sup,RowSize2);
00314       (*equal_bound)++; uni_eq++; inc_eq++;
00315       (*sup_bound)++; uni_sup++; inc_sup++;
00316     }
00317     else {
00318       *((*inc_sup)+jx)|=bx;
00319       
00320       /* if (**uni_sup<0) */
00321       if (value_neg_p(**uni_sup)) {             /* Status != verify  */
00322         inf_bound--; uni_inf--; inc_inf--;
00323         Vector_Exchange(*uni_inf,*uni_sup,RowSize1);
00324         bexchange(*inc_inf,*inc_sup,RowSize2);
00325       }
00326       else {                                     /* status == verify */
00327          (*sup_bound)++; uni_sup++; inc_sup++;
00328       } 
00329     }
00330   }
00331 } /* RaySort */ 
00332 
00333 static void SatMatrix_Extend(SatMatrix *Sat, Matrix* Mat, unsigned rows)
00334 {
00335   int i;
00336   unsigned cols;
00337   cols = (Mat->NbRows - 1)/(sizeof(int)*8) + 1;
00338 
00339   Sat->p = (int **)realloc(Sat->p, rows * sizeof(int *));
00340   if(!Sat->p) {
00341     errormsg1("SatMatrix_Extend", "outofmem", "out of memory space");
00342     return;
00343   }
00344   Sat->p_init = (int *)realloc(Sat->p_init, rows * cols * sizeof (int));
00345   if(!Sat->p_init) {
00346     errormsg1("SatMatrix_Extend", "outofmem", "out of memory space");
00347     return;
00348   }
00349   for (i = 0; i < rows; ++i)
00350     Sat->p[i] = Sat->p_init + (i * cols);
00351   Sat->NbRows = rows;
00352 }
00353 
00354 static void Matrix_Extend(Matrix *Mat, unsigned NbRows)
00355 {
00356   Value *p, **q;
00357   unsigned rows = Mat->p_Init_size / Mat->NbColumns;
00358   int i,j;
00359 
00360   q = (Value **)realloc(Mat->p, NbRows * sizeof(*q));
00361   if(!q) {
00362     errormsg1("Matrix_Extend", "outofmem", "out of memory space");
00363     return;
00364   }
00365   Mat->p = q;
00366   p = (Value *)realloc(Mat->p_Init, NbRows * Mat->NbColumns * sizeof(Value));
00367   if(!p) {
00368     errormsg1("Matrix_Extend", "outofmem", "out of memory space");
00369     return;
00370   }
00371   Mat->p_Init = p;
00372   for (i=0;i<NbRows;i++) {
00373     Mat->p[i] = Mat->p_Init + (i * Mat->NbColumns);
00374     if (i < rows)
00375       continue;
00376     for (j=0;j<Mat->NbColumns;j++)   
00377       value_init(Mat->p[i][j]);
00378   }
00379   Mat->p_Init_size = Mat->NbColumns*NbRows;
00380   Mat->NbRows = NbRows;
00381 }
00382 
00383 /* 
00384  * Compute the dual of matrix 'Mat' and place it in matrix 'Ray'.'Mat' 
00385  * contains the constraints (equalities and inequalities) in rows and 'Ray' 
00386  * contains the ray space (lines and rays) in its rows. 'Sat' is a boolean 
00387  * saturation matrix defined as Sat(i,j)=0 if ray(i) saturates constraint(j),
00388  *  otherwise 1. The constraints in the 'Mat' matrix are processed starting at
00389  * 'FirstConstraint', 'Ray' and 'Sat' matrices are changed accordingly.'NbBid'
00390  * is the number of lines in the ray matrix and 'NbMaxRays' is the maximum 
00391  * number of rows (rays) permissible in the 'Ray' and 'Sat' matrix. Return 0 
00392  * if successful, otherwise return 1.  
00393  */     
00394 static int Chernikova (Matrix *Mat,Matrix *Ray,SatMatrix *Sat, unsigned NbBid, unsigned NbMaxRays, unsigned FirstConstraint,unsigned dual) {
00395 
00396   unsigned NbRay, Dimension, NbConstraints, RowSize1, RowSize2, sat_nbcolumns;
00397   int sup_bound, equal_bound, index_non_zero, bound;
00398   int i, j, k, l, redundant, rayonly, nbcommonconstraints;
00399   int *Temp, aux;
00400   int *ip1, *ip2;
00401   unsigned bx, m, jx;
00402   Value tmp;
00403   Value *p1, *p2, *p3;
00404 
00405 #ifdef POLY_CH_DEBUG
00406   fprintf(stderr, "[Chernikova: Input]\nRay = ");
00407   Matrix_Print(stderr,0,Ray);
00408   fprintf(stderr, "\nConstraints = ");
00409   Matrix_Print(stderr,0,Mat);
00410   fprintf(stderr, "\nSat = ");
00411   SMPrint(Sat);
00412 #endif
00413   
00414   value_init(tmp);
00415   NbConstraints=Mat->NbRows;
00416   NbRay = Ray->NbRows;
00417   Dimension = Mat->NbColumns-1;         /* Homogeneous Dimension */
00418   sat_nbcolumns=Sat->NbColumns;
00419   
00420   RowSize1=(Dimension+1);
00421   RowSize2=sat_nbcolumns * sizeof(int);
00422 
00423   Temp=(int *)malloc(RowSize2);
00424   if(!Temp) {   
00425     errormsg1("Chernikova", "outofmem", "out of memory space");
00426     value_clear(tmp);
00427     return 0;
00428   }
00429   CATCH(any_exception_error) {
00430 
00431   /* 
00432    * In case of overflow, free the allocated memory!
00433    * Rethrow upwards the stack to forward the exception.
00434    */
00435     value_clear(tmp);
00436     free(Temp);
00437     RETHROW();
00438   }
00439   TRY {
00440     jx = FirstConstraint/WSIZE;    
00441     bx = MSB; bx >>= FirstConstraint%WSIZE;
00442     for (k=FirstConstraint; k<NbConstraints; k++) {
00443       
00444       /* Set the status word of each ray[i] to ray[i] dot constraint[k] */
00445       /* This is equivalent to evaluating each ray by the constraint[k] */
00446       /* 'index_non_zero' is assigned the smallest ray index which does */
00447       /* not saturate the constraint.                                   */
00448       
00449       index_non_zero = NbRay;
00450       for (i=0; i<NbRay; i++) { 
00451         p1 = Ray->p[i]+1;
00452         p2 = Mat->p[k]+1;
00453         p3 = Ray->p[i];
00454         
00455         /* *p3 = *p1 * *p2 */     
00456         value_multiply(*p3,*p1,*p2);
00457         p1++; p2++;
00458         for (j=1; j<Dimension; j++) {   
00459           
00460           /* *p3 +=  *p1 * *p2 */
00461           value_multiply(tmp,*p1,*p2);
00462           value_addto(*p3,*p3,tmp);
00463           p1++; p2++;
00464         }
00465         if (value_notzero_p(*p3) && (i<index_non_zero)) 
00466           index_non_zero=i;
00467       }
00468       
00469 #ifdef POLY_CH_DEBUG
00470       fprintf(stderr, "[Chernikova: A]\nRay = ");
00471       Matrix_Print(stderr,0,Ray);
00472       fprintf(stderr, "\nConstraints = ");
00473       Matrix_Print(stderr,0,Mat);
00474       fprintf(stderr, "\nSat = ");
00475       SMPrint (Sat);
00476 #endif
00477       
00478       /* Find a bidirectional ray z such that cz <> 0 */  
00479       if (index_non_zero<NbBid) {
00480         
00481         /* Discard index_non_zero bidirectional ray */    
00482         NbBid--;
00483         if (NbBid!=index_non_zero) 
00484           Vector_Exchange(Ray->p[index_non_zero],Ray->p[NbBid],RowSize1);       
00485 
00486 #ifdef POLY_CH_DEBUG    
00487         fprintf(stderr,"************\n");
00488         for(i=0;i<RowSize1;i++) {
00489           value_print(stderr,P_VALUE_FMT,Ray->p[index_non_zero][i]);
00490         }  
00491         fprintf(stderr,"\n******\n");
00492         for(i=0;i<RowSize1;i++) {
00493           value_print(stderr,P_VALUE_FMT,Ray->p[NbBid][i]);
00494         }
00495         fprintf(stderr,"\n*******\n");
00496 #endif
00497 
00498         /* Compute the new lineality space */    
00499         for (i=0; i<NbBid; i++)
00500           if (value_notzero_p(Ray->p[i][0]))
00501             Combine(Ray->p[i],Ray->p[NbBid],Ray->p[i],0,Dimension);
00502 
00503         /* Add the positive part of index_non_zero bidirectional ray to  */
00504         /* the set of unidirectional rays                                */
00505         
00506         if (value_neg_p(Ray->p[NbBid][0])) {
00507           p1=Ray->p[NbBid]; 
00508           for (j=0;j<Dimension+1; j++) { 
00509             
00510             /* *p1 = - *p1 */   
00511             value_oppose(*p1,*p1);
00512             p1++; 
00513           }
00514         }
00515         
00516 #ifdef POLY_CH_DEBUG
00517         fprintf(stderr, "[Chernikova: B]\nRay = ");
00518         Ray->NbRows=NbRay;
00519         Matrix_Print(stderr,0,Ray);
00520         fprintf(stderr, "\nConstraints = ");
00521         Matrix_Print(stderr,0,Mat);
00522         fprintf(stderr, "\nSat = ");
00523         SMPrint(Sat);
00524 #endif
00525         
00526         /* Compute the new pointed cone */
00527         for (i=NbBid+1; i<NbRay; i++)
00528           if (value_notzero_p(Ray->p[i][0]))
00529             Combine(Ray->p[i],Ray->p[NbBid],Ray->p[i],0,Dimension);
00530         
00531         /* Add the new ray */
00532         if (value_notzero_p(Mat->p[k][0])) { /* Constraint is an inequality */ 
00533           for (j=0;j<sat_nbcolumns;j++) {
00534             Sat->p[NbBid][j] = 0;     /* Saturation vec for new ray */
00535           }
00536           /* The new ray saturates everything except last inequality */
00537           Sat->p[NbBid][jx] |= bx;
00538         }
00539         else {                        /* Constraint is an equality */
00540           NbRay--;
00541           Vector_Copy(Ray->p[NbRay],Ray->p[NbBid],Dimension+1);
00542           SMVector_Copy(Sat->p[NbRay],Sat->p[NbBid],sat_nbcolumns);
00543         }
00544 
00545 #ifdef POLY_CH_DEBUG
00546         fprintf(stderr, "[Chernikova: C]\nRay = ");
00547         Ray->NbRows=NbRay;
00548         Matrix_Print(stderr,0,Ray);
00549         fprintf(stderr, "\nConstraints = ");
00550         Matrix_Print(stderr,0,Mat);
00551         fprintf(stderr, "\nSat = ");
00552         SMPrint (Sat);
00553 #endif
00554 
00555       } 
00556       else {  /* If the new constraint satisfies all the rays */
00557         RaySort(Ray, Sat, NbBid, NbRay, &equal_bound, &sup_bound,
00558                 RowSize1, RowSize2,bx,jx);
00559         
00560         /* Sort the unidirectional rays into R0, R+, R- */
00561         /* Ray 
00562            NbRay-> bound-> ________
00563                            |  R-  |    R- ==> ray.eq < 0  (outside domain)
00564                      sup-> |------|
00565                            |  R+  |    R+ ==> ray.eq > 0  (inside domain)
00566                    equal-> |------|
00567                            |  R0  |    R0 ==> ray.eq = 0  (on face of domain)
00568                    NbBid-> |______|
00569         */
00570 
00571 #ifdef POLY_CH_DEBUG
00572         fprintf(stderr, "[Chernikova: D]\nRay = ");
00573         Ray->NbRows=NbRay;
00574         Matrix_Print(stderr,0,Ray);
00575         fprintf(stderr, "\nConstraints = ");
00576         Matrix_Print(stderr,0,Mat);
00577         fprintf(stderr, "\nSat = ");
00578         SMPrint (Sat);
00579 #endif
00580 
00581         /* Compute only the new pointed cone */
00582         bound=NbRay;
00583         for (i=equal_bound; i<sup_bound; i++) /* for all pairs of R- and R+ */
00584           for(j=sup_bound; j<bound; j++) {    
00585             
00586           /*--------------------------------------------------------------*/
00587           /* Count the set of constraints saturated by R+ and R- */
00588           /* Includes equalities, inequalities and the positivity constraint */
00589           /*-----------------------------------------------------------------*/
00590             
00591             nbcommonconstraints = 0;
00592             for (l=0; l<jx; l++) {
00593               aux = Temp[l] = Sat->p[i][l] | Sat->p[j][l];
00594               for (m=MSB; m!=0; m>>=1) 
00595                 if (!(aux&m)) 
00596                   nbcommonconstraints++;
00597             }
00598             aux = Temp[jx] =  Sat->p[i][jx] | Sat->p[j][jx];
00599             for (m=MSB; m!=bx; m>>=1) 
00600               if (!(aux&m)) 
00601                 nbcommonconstraints++;      
00602             rayonly = (value_zero_p(Ray->p[i][Dimension])  && 
00603                        value_zero_p(Ray->p[j][Dimension]) && 
00604                        (dual == 0));                
00605             if(rayonly)
00606               nbcommonconstraints++;      /* account for pos constr */
00607 
00608           /*-----------------------------------------------------------------*/
00609           /* Adjacency Test : is combination [R-,R+] a non redundant ray?    */
00610           /*-----------------------------------------------------------------*/
00611           
00612             if (nbcommonconstraints+NbBid>=Dimension-2) { /* Dimensionality check*/
00613               /* Check whether a ray m saturates the same set of constraints */
00614               redundant=0;
00615               for (m=NbBid; m<bound; m++) 
00616                 if ((m!=i)&&(m!=j)) {
00617                   
00618                   /* Two rays (r+ r-) are never made redundant by a vertex */
00619                   /* because the positivity constraint saturates both rays */
00620                   /* but not the vertex                                    */
00621                   
00622                   if (rayonly && value_notzero_p(Ray->p[m][Dimension]))
00623                     continue;
00624 
00625                   /* (r+ r-) is redundant if there doesn't exist an equation */
00626                   /* which saturates both r+ and r- but not rm.              */
00627                   
00628                   ip1 = Temp;
00629                   ip2 = Sat->p[m];
00630                   for (l=0; l<=jx; l++,ip2++,ip1++)
00631                     if (*ip2 & ~*ip1) 
00632                       break;
00633                   if (l>jx) { 
00634                     redundant=1;
00635                     break;
00636                   }
00637                 }
00638 
00639 #ifdef POLY_CH_DEBUG
00640               fprintf(stderr, "[Chernikova: E]\nRay = ");
00641               Ray->NbRows=NbRay;
00642               Matrix_Print(stderr,0,Ray);
00643               fprintf(stderr, "\nConstraints = ");
00644               Matrix_Print(stderr,0,Mat);
00645               fprintf(stderr, "\nSat = ");
00646               SMPrint (Sat);
00647 #endif
00648               
00649               /*------------------------------------------------------------*/
00650               /* Add new ray generated by [R+,R-]                           */
00651               /*------------------------------------------------------------*/
00652             
00653               if (!redundant) {
00654                 if (NbRay==NbMaxRays) {
00655                   NbMaxRays *= 2;
00656                   Matrix_Extend(Ray, NbMaxRays);
00657                   SatMatrix_Extend(Sat, Mat, NbMaxRays);
00658                 }
00659                 
00660                 /* Compute the new ray */
00661                 Combine(Ray->p[j],Ray->p[i],Ray->p[NbRay],0,Dimension);
00662                 SatVector_OR(Sat->p[j],Sat->p[i],Sat->p[NbRay],sat_nbcolumns);
00663                 Sat->p[NbRay][jx] &= ~bx;
00664                 NbRay++;
00665               }
00666             }
00667           }
00668 
00669 #ifdef POLY_CH_DEBUG
00670         fprintf(stderr, 
00671                 "[Chernikova: F]\n"
00672                 "sup_bound=%d\n"
00673                 "equal_bound=%d\n"
00674                 "bound=%d\n"
00675                 "NbRay=%d\n"
00676                 "Dimension = %d\n"
00677                 "Ray = ",sup_bound,equal_bound,bound,NbRay,Dimension);
00678 #endif
00679 #ifdef POLY_CH_DEBUG
00680         Ray->NbRows=NbRay;
00681         fprintf(stderr, "[Chernikova: F]:\nRay = ");
00682         Matrix_Print(stderr,0,Ray);
00683 #endif
00684         
00685         /* Eliminates all non extremal rays */
00686         /* j = (Mat->p[k][0]) ? */
00687         
00688         j = (value_notzero_p(Mat->p[k][0])) ? 
00689           sup_bound : equal_bound;
00690         
00691         i = NbRay;
00692 #ifdef POLY_CH_DEBUG
00693         fprintf(stderr, "i = %d\nj = %d \n", i, j);
00694 #endif
00695         while ((j<bound)&&(i>bound)) {
00696           i--;
00697           Vector_Copy(Ray->p[i],Ray->p[j],Dimension+1);
00698           SMVector_Copy(Sat->p[i],Sat->p[j],sat_nbcolumns);
00699           j++;
00700         }
00701 
00702 #ifdef POLY_CH_DEBUG
00703         fprintf(stderr, "i = %d\nj = %d \n", i, j);
00704         fprintf(stderr, 
00705                 "[Chernikova: F]\n"
00706                 "sup_bound=%d\n"
00707                 "equal_bound=%d\n"
00708                 "bound=%d\n"
00709                 "NbRay=%d\n"
00710                 "Dimension = %d\n"
00711                 "Ray = ",sup_bound,equal_bound,bound,NbRay, Dimension);
00712 #endif
00713 #ifdef POLY_CH_DEBUG
00714         Ray->NbRows=NbRay;
00715         fprintf(stderr, "[Chernikova: G]\nRay = "); 
00716         Matrix_Print(stderr,0,Ray);
00717 #endif  
00718         if (j==bound) 
00719           NbRay=i;
00720         else 
00721           NbRay=j;
00722       }
00723       NEXT(jx,bx);
00724     }    
00725     Ray->NbRows=NbRay;
00726     Sat->NbRows=NbRay;
00727     
00728   } /* End of TRY */
00729 
00730   UNCATCH(any_exception_error);
00731   free(Temp);
00732   
00733 #ifdef POLY_CH_DEBUG
00734   fprintf(stderr, "[Chernikova: Output]\nRay = ");
00735   Matrix_Print(stderr,0,Ray);
00736   fprintf(stderr, "\nConstraints = ");
00737   Matrix_Print(stderr,0,Mat);
00738   fprintf(stderr, "\nSat = ");
00739   SMPrint (Sat);
00740 #endif
00741   
00742   value_clear(tmp);
00743   return 0;
00744 } /* Chernikova */
00745 
00746 static int Gauss4(Value **p, int NbEq, int NbRows, int Dimension)
00747 {
00748   int i, j, k, pivot, Rank;
00749   int *column_index = NULL;
00750   Value gcd,tmp,*cp;
00751 
00752   value_init(gcd); value_init(tmp);
00753   column_index=(int *)malloc(Dimension * sizeof(int));
00754   if(!column_index) {   
00755     errormsg1("Gauss","outofmem","out of memory space");
00756     value_clear(gcd); value_clear(tmp);
00757     return 0;
00758   }
00759   Rank=0;
00760   
00761   CATCH(any_exception_error) {
00762     if (column_index)
00763       free(column_index);
00764     value_clear(gcd); value_clear(tmp);
00765     RETHROW();
00766   }
00767   TRY {
00768     
00769     for (j=1; j<=Dimension; j++) {   /* for each column (except status) */  
00770       for (i=Rank; i<NbEq; i++)      /* starting at diagonal, look down */
00771         
00772         /* if (Mat->p[i][j] != 0) */
00773         if (value_notzero_p(p[i][j])) 
00774           break;                    /* Find the first non zero element  */    
00775       if (i!=NbEq) {                /* If a non-zero element is found?  */
00776         if (i!=Rank)                /* If it is found below the diagonal*/
00777           Vector_Exchange(p[Rank]+1,p[i]+1,Dimension);
00778         
00779         /* Normalize the pivot row by dividing it by the gcd */      
00780         /* gcd = Vector_Gcd(p[Rank]+1,Dimension) */
00781         Vector_Gcd(p[Rank]+1,Dimension,&gcd);
00782         
00783         /* if (gcd >= 2) */
00784         value_set_si(tmp,2);
00785         if (value_ge(gcd,tmp)) { 
00786           cp = &p[Rank][1];
00787           for (k=0; k<Dimension; k++) {
00788             value_division (*cp,*cp,gcd);       /* *cp /= gcd */    
00789             cp++;
00790           }
00791         }
00792         
00793         /* if (Mat->p[Rank][j] < 0) */
00794         if (value_neg_p(p[Rank][j])) { 
00795           cp = p[Rank]+1;       
00796           for (k=0; k<Dimension; k++) { 
00797             value_set_si(tmp,-1);
00798             value_multiply (*cp,*cp,tmp); /* *cp *= -1 */ 
00799             cp++;
00800           }
00801         }
00802         /* End of normalize */
00803         
00804         pivot=i;
00805         for (i=pivot+1; i<NbEq; i++) {  /* Zero out the rest of the column */
00806           
00807           /* if (Mat->p[i][j] != 0) */
00808           if (value_notzero_p(p[i][j]))
00809             Combine(p[i],p[Rank],p[i],j,Dimension);
00810         }
00811         
00812         /* For each row with non-zero entry Mat->p[Rank], store the column */
00813         /* number 'j' in 'column_index[Rank]'. This information will be    */
00814         /* useful in performing Gaussian elimination backward step.        */
00815         
00816         column_index[Rank]=j;
00817         Rank++;
00818       }
00819     } /* end of Gaussian elimination forward step */
00820     
00821     /* Back Substitution -- normalize the system of equations */
00822     for (k=Rank-1; k>=0; k--) { 
00823       j = column_index[k];
00824 
00825       /* Normalize the equations */
00826       for (i=0; i<k; i++) { 
00827         
00828         /* if (Mat->p[i][j] != 0) */
00829         if (value_notzero_p(p[i][j]))
00830           Combine(p[i],p[k],p[i],j,Dimension);
00831       }
00832       
00833       /* Normalize the inequalities */
00834       for (i=NbEq;i<NbRows;i++) { 
00835         
00836         /* if (Mat->p[i][j] != 0) */
00837         if (value_notzero_p(p[i][j]))
00838           Combine(p[i],p[k],p[i],j,Dimension);
00839       }
00840     }
00841   } /* end of TRY */
00842   
00843   UNCATCH(any_exception_error);
00844   free(column_index), column_index = NULL;
00845   
00846   value_clear(gcd); value_clear(tmp);
00847   return Rank;
00848 } /* Gauss */
00849 
00850 /*  
00851  * Compute a minimal system of equations using Gausian elimination method.
00852  * 'Mat' is a matrix of constraints in which the first 'Nbeq' constraints
00853  * are equations. The dimension of the homogenous system is 'Dimension'. 
00854  * The function returns the rank of the matrix 'Mat'. 
00855  */
00856 int Gauss(Matrix *Mat, int NbEq, int Dimension)
00857 {
00858   int Rank;
00859 
00860 #ifdef POLY_DEBUG
00861   fprintf(stderr, "[Gauss : Input]\nRay =");
00862   Matrix_Print(stderr,0,Mat);
00863 #endif
00864 
00865   Rank = Gauss4(Mat->p, NbEq, Mat->NbRows, Dimension);
00866 
00867 #ifdef POLY_DEBUG
00868   fprintf(stderr, "[Gauss : Output]\nRay =");
00869   Matrix_Print(stderr,0,Mat);
00870 #endif
00871 
00872   return Rank;
00873 }
00874 
00875 /*
00876  * Given 'Mat' - a matrix of equations and inequalities, 'Ray' - a matrix of 
00877  * lines and rays, 'Sat' - the corresponding saturation matrix, and 'Filter'
00878  * - an array to mark (with 1) the non-redundant equalities and inequalities, 
00879  * compute a polyhedron composed of 'Mat' as constraint matrix and 'Ray' as 
00880  * ray matrix after reductions. This function is usually called as a follow
00881  * up to 'Chernikova' to remove redundant constraints or rays.
00882  * Note: (1) 'Chernikova' ensures that there are no redundant lines and rays. 
00883  *       (2) The same function can be used with constraint and ray matrix used
00884   interchangbly.
00885  */ 
00886 static Polyhedron *Remove_Redundants(Matrix *Mat,Matrix *Ray,SatMatrix *Sat,unsigned *Filter) { 
00887   
00888   int i, j, k;
00889   unsigned Dimension, sat_nbcolumns, NbRay, NbConstraints, RowSize1, RowSize2, 
00890            *Trace = NULL, *bx = NULL, *jx = NULL, Dim_RaySpace, b;
00891   unsigned NbBid, NbUni, NbEq, NbIneq;
00892   unsigned NbBid2, NbUni2, NbEq2, NbIneq2;
00893   int Redundant;
00894   int aux, *temp2 = NULL;
00895   Polyhedron *Pol = NULL;
00896   Value *temp1 = NULL;
00897   Value *p, *q;
00898   Value Status,tmp1,tmp2,tmp3;
00899   
00900   Dimension = Mat->NbColumns-1;     /* Homogeneous Dimension */
00901   NbRay = Ray->NbRows;
00902   sat_nbcolumns = Sat->NbColumns;
00903   NbConstraints = Mat->NbRows;
00904   RowSize1=(Dimension+1);
00905   RowSize2=sat_nbcolumns * sizeof(int);
00906   
00907   temp1=(Value *)malloc(RowSize1*sizeof(Value));
00908   if(!temp1) {  
00909     errormsg1("Remove_Redundants", "outofmem", "out of memory space");
00910     return 0;
00911   }
00912 
00913   /* Initialize all the 'Value' variables */
00914   value_init(Status); value_init(tmp1);
00915   value_init(tmp2); value_init(tmp3);
00916   
00917   for(i=0;i<RowSize1;i++)
00918     value_init(temp1[i]);
00919 
00920   temp2=(int *)malloc(RowSize2);
00921   if(!temp2) {
00922     errormsg1("Remove_Redundants", "outofmem", "out of memory space");
00923     
00924     /* Clear all the 'Value' variables */
00925     value_clear(Status); value_clear(tmp1);
00926     value_clear(tmp2); value_clear(tmp3);
00927     for(i=0;i<RowSize1;i++)
00928       value_clear(temp1[i]);
00929     free(temp1);
00930     return 0;
00931   }
00932   
00933   /* Introduce indirections into saturation matrix 'Sat' to simplify */
00934   /* processing with 'Sat' and allow easy exchanges of columns.      */
00935   bx = (unsigned *)malloc(NbConstraints * sizeof(unsigned));
00936   if(!bx) {
00937     errormsg1("Remove_Redundants", "outofmem", "out of memory space");
00938     
00939     /* Clear all the 'Value' variables */
00940     value_clear(Status); value_clear(tmp1);
00941     value_clear(tmp2); value_clear(tmp3);
00942     for(i=0;i<RowSize1;i++)
00943       value_clear(temp1[i]);
00944     free(temp1); free(temp2);
00945     return 0;
00946   }
00947   jx = (unsigned *)malloc(NbConstraints * sizeof(unsigned));
00948   if(!jx) {
00949     errormsg1("Remove_Redundants", "outofmem", "out of memory space");
00950     
00951     /* Clear all the 'Value' variables */
00952     value_clear(Status); value_clear(tmp1);
00953     value_clear(tmp2); value_clear(tmp3);
00954     for(i=0;i<RowSize1;i++)
00955       value_clear(temp1[i]);
00956     free(temp1); free(temp2); free(bx);
00957     return 0;
00958   }
00959   CATCH(any_exception_error) {  
00960     
00961     if (temp1) {           
00962       for(i=0;i<RowSize1;i++)
00963         value_clear(temp1[i]);
00964       free(temp1);
00965     }  
00966     if (temp2) free(temp2);
00967     if (bx) free(bx);
00968     if (jx) free(jx);
00969     if (Trace) free(Trace);
00970     if (Pol) Polyhedron_Free(Pol);
00971 
00972     /* Clear all the 'Value' variables */
00973     value_clear(Status); value_clear(tmp1);
00974     value_clear(tmp2); value_clear(tmp3);
00975     
00976     RETHROW();
00977   }
00978   TRY {
00979     
00980     /* For each constraint 'j' following mapping is defined to facilitate  */
00981     /* data access from saturation matrix 'Sat' :-                         */
00982     /* (1) jx[j] -> floor[j/(8*sizeof(int))]                               */
00983     /* (2) bx[j] -> bin(00..10..0) where position of 1 = j%(8*sizeof(int)) */
00984     
00985     i = 0;
00986     b = MSB;
00987     for (j=0; j<NbConstraints; j++) { 
00988       jx[j] = i;
00989       bx[j] = b;
00990       NEXT(i,b);
00991     }
00992     
00993     /* 
00994      * STEP(0): Count the number of vertices among the rays while initializing
00995      * the ray status count to 0. If no vertices are found, quit the procedure
00996      * and return an empty polyhedron as the result. 
00997      */            
00998     
00999     /* Reset the status element of each ray to zero. Store the number of  */
01000     /* vertices in 'aux'.                                                 */
01001     aux = 0;
01002     for (i=0; i<NbRay; i++) {  
01003       
01004       /* Ray->p[i][0] = 0 */
01005       value_set_si(Ray->p[i][0],0);
01006       
01007       /* If ray(i) is a vertex of the Inhomogenous system */
01008       if (value_notzero_p(Ray->p[i][Dimension]))
01009         aux++;              
01010     }
01011     
01012     /* If no vertices, return an empty polyhedron. */
01013     if (!aux) { 
01014       
01015       /* Clear all the 'Value' variables */
01016       value_clear(Status); value_clear(tmp1);
01017       value_clear(tmp2); value_clear(tmp3);
01018       for(i=0;i<RowSize1;i++)
01019         value_clear(temp1[i]);
01020       
01021       /* Return an empty polyhedron */
01022       free(temp1); free(temp2); free(jx); free(bx);
01023       UNCATCH(any_exception_error);
01024       return Empty_Polyhedron(Dimension-1);
01025     }
01026     
01027 #ifdef POLY_RR_DEBUG
01028     fprintf(stderr, "[Remove_redundants : Init]\nConstraints =");
01029     Matrix_Print(stderr,0,Mat);
01030     fprintf(stderr, "\nRays =");
01031     Matrix_Print(stderr,0,Ray);
01032 #endif
01033     
01034     /* 
01035      * STEP(1): Compute status counts for both rays and inequalities. For each
01036      * constraint, count the number of vertices/rays saturated by that 
01037      * constraint, and put the result in the status words. At the same time, 
01038      * for each vertex/ray, count the number of constraints saturated by it.
01039      * Delete any positivity constraints, but give rays credit in their status
01040      * counts for saturating the positivity constraint.
01041      */
01042     
01043     NbEq=0;
01044  #ifdef JUNK
01045     /* JUNK is a temporary flag, the code in the JUNK part, should probably
01046        be removed (see with Fabien and Doran) */
01047    memset((char *)temp2, 0, RowSize2);       
01048 #endif
01049     
01050 #ifdef POLY_RR_DEBUG
01051     fprintf (stderr, " j = ");
01052 #endif
01053     
01054     for (j=0; j<NbConstraints; j++) {
01055       
01056 #ifdef POLY_RR_DEBUG
01057       fprintf (stderr, " %i ", j);
01058       fflush (stderr);
01059 #endif
01060       
01061 #ifdef JUNK
01062       /* If constraint(j) is an equality, mark '1' in array 'temp2' */
01063       if (Filter && value_zero_p(Mat->p[j][0]))  
01064         temp2[jx[j]] |= bx[j]; 
01065 #endif
01066       /* Reset the status element of each constraint to zero */
01067       value_set_si(Mat->p[j][0],0);
01068       
01069       /* Identify and remove the positivity constraint 1>=0 */
01070       for (i=1, p = &Mat->p[j][1]; i<Dimension; i++) { 
01071         
01072         /* if (*p) */
01073         if (value_notzero_p(*p)) {
01074           p++; 
01075           break;
01076         }
01077         else 
01078           p++;
01079       }
01080       
01081 #ifdef POLY_RR_DEBUG
01082       fprintf(stderr, "[Remove_redundants : IntoStep1]\nConstraints =");
01083       Matrix_Print(stderr,0,Mat);
01084       fprintf (stderr, " j = %i \n", j);
01085 #endif
01086       
01087       /* Check if constraint(j) is a positivity constraint, 1 >= 0, or if it */
01088       /* is 1==0. If constraint(j) saturates all the rays of the matrix 'Ray'*/
01089       /* then it is an equality. in this case, return an empty polyhedron.   */
01090       
01091       if (i==Dimension) { 
01092         for (i=0; i<NbRay; i++)
01093           if (!(Sat->p[i][jx[j]]&bx[j])) {
01094             
01095             /* Mat->p[j][0]++ */
01096             value_increment(Mat->p[j][0],Mat->p[j][0]);
01097           }
01098         
01099         /* if ((Mat->p[j][0] == NbRay) &&   : it is an equality
01100            (Mat->p[j][Dimension] != 0)) : and its not 0=0 */
01101         value_set_si(tmp1,NbRay);
01102         if ((value_eq(Mat->p[j][0],tmp1)) &&  
01103             (value_notzero_p(Mat->p[j][Dimension]))) {
01104           
01105           /* Clear all the 'Value' variables */
01106           value_clear(Status); value_clear(tmp1);
01107           value_clear(tmp2); value_clear(tmp3);
01108           for(i=0;i<RowSize1;i++)
01109             value_clear(temp1[i]);
01110           
01111           /* Return an empty polyhedron */
01112           free(temp1); free(temp2); free(jx); free(bx);
01113           UNCATCH(any_exception_error);
01114           return Empty_Polyhedron(Dimension-1);
01115         }
01116         
01117         /* Delete the positivity constraint */
01118         NbConstraints--;
01119         if (j==NbConstraints) continue;
01120         Vector_Exchange(Mat->p[j], Mat->p[NbConstraints],RowSize1);
01121         exchange(jx[j], jx[NbConstraints], aux);
01122         exchange(bx[j], bx[NbConstraints], aux);
01123         j--; continue;
01124       }
01125       
01126       /* Count the number of vertices/rays saturated by each constraint. At  */
01127       /* the same time, count the number of constraints saturated by each ray*/
01128       for (i=0; i<NbRay; i++) 
01129         if (!(Sat->p[i][jx[j]]&bx[j])) {  
01130           
01131           /* Mat->p[j][0]++ */
01132           value_increment(Mat->p[j][0],Mat->p[j][0]);
01133           
01134           /* Ray->p[i][0]++ */
01135           value_increment (Ray->p[i][0],Ray->p[i][0]);
01136         }
01137       
01138       /* if (Mat->p[j][0]==NbRay) then increment the number of eq. count */
01139       value_set_si(tmp1,NbRay);
01140       if (value_eq(Mat->p[j][0],tmp1)) 
01141         NbEq++;    /* all vertices/rays are saturated */
01142     }
01143     Mat->NbRows = NbConstraints;
01144     
01145     NbBid=0;
01146     for (i=0; i<NbRay; i++) {
01147       
01148       /* Give rays credit for saturating the positivity constraint */
01149       if (value_zero_p(Ray->p[i][Dimension]))   
01150         
01151         /* Ray->p[i][0]++ */
01152         value_increment(Ray->p[i][0],Ray->p[i][0]);
01153       
01154       /* If ray(i) saturates all the constraints including positivity  */
01155       /* constraint then it is a bi-directional ray or line. Increment */
01156       /* 'NbBid' by one.                                               */
01157       
01158       /* if (Ray->p[i][0]==NbConstraints+1) */
01159       value_set_si(tmp1,(NbConstraints+1));
01160       if (value_eq(Ray->p[i][0],tmp1))
01161         NbBid++;
01162     }
01163     
01164 #ifdef POLY_RR_DEBUG
01165     fprintf(stderr, "[Remove_redundants : Step1]\nConstraints =");
01166     Matrix_Print(stderr,0,Mat);
01167     fprintf(stderr, "\nRay =");
01168     Matrix_Print(stderr,0,Ray);
01169 #endif
01170     
01171     /* 
01172      * STEP(2): Sort equalities to the top of constraint matrix 'Mat'. Detect
01173      * implicit equations such as y>=3; y<=3. Keep Inequalities in same 
01174      * relative order. (Note: Equalities are constraints which saturate all of
01175      * the rays)              
01176      */
01177     
01178     for (i=0; i<NbEq; i++) {
01179       
01180       /* If constraint(i) doesn't saturate some ray, then it is an inequality*/
01181       value_set_si(tmp1,NbRay);
01182       if (value_ne(Mat->p[i][0],tmp1)) { 
01183         
01184         value_set_si(tmp1,NbRay);
01185         /* Skip over inequalities and find an equality */
01186         for (k=i+1;value_ne(Mat->p[k][0],tmp1) && k<NbConstraints;k++);
01187         if (k==NbConstraints) /* If none found then error */ break;
01188         
01189         /* Slide inequalities down the array 'Mat' and move equality up to */
01190         /* position 'i'.                                                   */
01191         Vector_Copy(Mat->p[k], temp1,RowSize1);
01192         aux = jx[k];
01193         j   = bx[k];
01194         for (;k>i;k--) {  
01195           Vector_Copy(Mat->p[k-1],Mat->p[k],RowSize1);
01196           jx[k] = jx[k-1];
01197           bx[k] = bx[k-1];
01198         }
01199         Vector_Copy(temp1,Mat->p[i],RowSize1);
01200         jx[i] = aux;
01201         bx[i] = j;
01202       }
01203     }
01204 
01205 #ifdef JUNK
01206     if (Filter)                     /* for SIMPLIFY */
01207       for (i=0; i<NbEq; i++) {
01208         
01209         /* Detect implicit constraints such as y>=3 and y<=3 */
01210         Redundant = 0;
01211         for (j=i+1; j<NbEq; j++) {
01212           for (k=0, p=&Mat->p[i][1], q=&Mat->p[j][1]; k<Dimension; k++,p++,q++) {  
01213             /* if (*p!=*q) */
01214             if (value_ne(*p, *q)) 
01215               break;
01216           }
01217           
01218           /* Redundant if both are same `and' constraint(j) was equality. */
01219           /* That is, 'temp2' has entry 1                                 */
01220           if (k==Dimension && (temp2[jx[j]] & bx[j])) { 
01221             Redundant=1; 
01222             break;
01223           }
01224         }
01225         
01226         /* Set 'Filter' entry to 1 corresponding to the irredundant equality*/
01227         if (!Redundant) Filter[jx[i]] |= bx[i];  /* set flag */
01228       }
01229 
01230 #endif
01231 #ifdef POLY_RR_DEBUG
01232     fprintf(stderr, "[Remove_redundants : Step2]\nConstraints =");
01233     Matrix_Print(stderr,0,Mat);
01234     fprintf(stderr, "\nRay =");
01235     Matrix_Print(stderr,0,Ray);
01236 #endif
01237     
01238     /* 
01239      * STEP(3): Perform Gaussian elimiation on the list of equalities. Obtain
01240      * a minimal basis by solving for as many variables as possible. Use this 
01241      * solution to reduce the inequalities by eliminating as many variables as
01242      * possible. Set NbEq2 to the rank of the system of equalities.
01243      */
01244     
01245     NbEq2 = Gauss(Mat,NbEq,Dimension);
01246     
01247     /* If number of equalities is not less then the homogenous dimension, */
01248     /* return an empty polyhedron.                                        */
01249     
01250     if (NbEq2>=Dimension) {             
01251       
01252       /* Clear all the 'Value' variables */
01253       value_clear(Status); value_clear(tmp1);
01254       value_clear(tmp2); value_clear(tmp3);
01255       for(i=0;i<RowSize1;i++)
01256         value_clear(temp1[i]);
01257       
01258       free(temp1); free(temp2); free(jx); free(bx);
01259       UNCATCH(any_exception_error);
01260       return Empty_Polyhedron(Dimension-1);
01261     }
01262     
01263 #ifdef POLY_RR_DEBUG
01264     fprintf(stderr, "[Remove_redundants : Step3]\nConstraints =");
01265     Matrix_Print(stderr,0,Mat);
01266     fprintf(stderr, "\nRay =");
01267     Matrix_Print(stderr,0,Ray);
01268 #endif
01269     
01270     /*
01271      * STEP(4): Sort lines to the top of ray matrix 'Ray', leaving rays
01272      * afterwards. Detect implicit lines such as ray(1,2) and ray(-1,-2). 
01273      * (Note: Lines are rays which saturate all of the constraints including
01274      * the positivity constraint 1>=0. 
01275      */
01276     
01277     
01278     for (i=0, k=NbRay; i<NbBid && k>i; i++) {
01279       value_set_si(tmp1,(NbConstraints+1));
01280       
01281       /* If ray(i) doesn't saturate some constraint then it is not a line */
01282       if (value_ne(Ray->p[i][0],tmp1)) { 
01283         
01284         value_set_si(tmp1,(NbConstraints+1));
01285         /* Skip over rays and vertices and find a line (bi-directional rays) */
01286         while (--k >i && value_ne(Ray->p[k][0],tmp1)) ;
01287         
01288         /* Exchange positions of ray(i) and line(k), thus sorting lines to */
01289         /* the top of matrix 'Ray'.                                        */
01290         Vector_Exchange(Ray->p[i], Ray->p[k], RowSize1);
01291         bexchange(Sat->p[i], Sat->p[k], RowSize2);
01292       }     
01293     }   
01294 
01295 #ifdef POLY_RR_DEBUG
01296     fprintf(stderr, "[Remove_redundants : Step4]\nConstraints =");
01297     Matrix_Print(stderr,0,Mat);
01298     fprintf(stderr, "\nRay =");
01299     Matrix_Print(stderr,0,Ray);
01300 #endif
01301     
01302     /* 
01303      * STEP(5): Perform Gaussian elimination on the lineality space to obtain
01304      * a minimal basis of lines. Use this basis to reduce the representation
01305      * of the uniderectional rays. Set 'NbBid2' to the rank of the system of 
01306      * lines. 
01307      */
01308     
01309     NbBid2 = Gauss(Ray, NbBid, Dimension);
01310     
01311 #ifdef POLY_RR_DEBUG
01312     fprintf(stderr, "[Remove_redundants : After Gauss]\nRay =");
01313     Matrix_Print(stderr,0,Ray);
01314 #endif
01315     
01316     /* If number of lines is not less then the homogenous dimension, return */
01317     /* an empty polyhedron.                                                 */
01318     if (NbBid2>=Dimension) {
01319       errormsg1("RemoveRedundants", "rmrdt", "dimension error");
01320       
01321       /* Clear all the 'Value' variables */
01322       value_clear(Status); value_clear(tmp1);
01323       value_clear(tmp2); value_clear(tmp3);
01324       for(i=0;i<RowSize1;i++)
01325         value_clear(temp1[i]);
01326       
01327       free(temp1); free(temp2); free(jx); free(bx);
01328       UNCATCH(any_exception_error);
01329       return Empty_Polyhedron(Dimension-1);
01330     }
01331     
01332     /* Compute dimension of non-homogenous ray space */
01333     Dim_RaySpace = Dimension-1-NbEq2-NbBid2;  
01334     
01335 #ifdef POLY_RR_DEBUG
01336     fprintf(stderr, "[Remove_redundants : Step5]\nConstraints =");
01337     Matrix_Print(stderr,0,Mat);
01338     fprintf(stderr, "\nRay =");
01339     Matrix_Print(stderr,0,Ray);
01340 #endif
01341     
01342     /* 
01343      * STEP(6): Do a first pass filter of inequalities and equality identifi-
01344      * cation. New positivity constraints may have been created by step(3). 
01345      * Check for and eliminate them. Count the irredundant inequalities and 
01346      * store count in 'NbIneq'.  
01347      */
01348  
01349     value_set_si(tmp2,Dim_RaySpace);
01350     value_set_si(tmp3,NbRay);
01351     NbIneq=0;
01352     for (j=0; j<NbConstraints; j++) {
01353       
01354       /* Identify and remove the positivity constraint 1>=0 */
01355       for (i=1, p = &Mat->p[j][1]; i<Dimension; i++)
01356         if (value_notzero_p (*p)) {
01357           p++; 
01358           break;
01359         }
01360         else
01361           p++;
01362       
01363       /* Check if constraint(j) is a positivity constraint, 1>= 0, or if it */
01364       /* is 1==0.                                                           */
01365       if (i==Dimension) {  
01366         
01367         value_set_si(tmp1,NbRay);
01368         
01369         /* if ((Mat->p[j][0]==NbRay) &&   : it is an equality 
01370            (Mat->p[j][Dimension]!=0))    : and its not 0=0 */
01371         if ((value_eq (Mat->p[j][0],tmp1)) &&
01372             (value_notzero_p(Mat->p[j][Dimension]))) {
01373           
01374           /* Clear all the 'Value' variables */
01375           value_clear(Status); value_clear(tmp1);
01376           value_clear(tmp2); value_clear(tmp3);
01377           for(i=0;i<RowSize1;i++)
01378             value_clear(temp1[i]);
01379           
01380           /* Return an empty polyhedron */
01381           free(temp1); free(temp2); free(jx); free(bx);
01382           UNCATCH(any_exception_error);
01383           return Empty_Polyhedron(Dimension-1);
01384         }       
01385         
01386         /* Set the positivity constraint redundant by setting status element */
01387         /* equal to 2.                                                       */
01388         value_set_si(Mat->p[j][0],2);
01389         continue;
01390       }
01391       
01392       /* Status = Mat->p[j][0] */
01393       value_assign(Status, Mat->p[j][0]);
01394       
01395       /* if (Status == 0) then constraint is redundant */
01396       if (value_zero_p(Status))         
01397         
01398         /* Mat->p[j][0]=2 : redundant */
01399         value_set_si(Mat->p[j][0],2);   
01400       
01401       /* else if (Status<Dim_RaySpace) then constraint is redundant */   
01402       else if (value_lt(Status,tmp2))   
01403         
01404         /* Mat->p[j][0]=2 : redundant */
01405         value_set_si(Mat->p[j][0],2);   
01406       
01407       /* else if (Status==NbRay) then constraint is an equality */
01408       else if (value_eq(Status,tmp3))   
01409         
01410         /* Mat->p[j][0]=0 : equality */
01411         value_set_si(Mat->p[j][0],0);
01412       
01413       /* else constraint is an irredundant inequality */ 
01414       else { 
01415         NbIneq++;       
01416         
01417         /* Mat->p[j][0]=1 : inequality */
01418         value_set_si(Mat->p[j][0],1);
01419       }
01420     }
01421     
01422 #ifdef POLY_RR_DEBUG
01423     fprintf(stderr, "[Remove_redundants : Step6]\nConstraints =");
01424     Matrix_Print(stderr,0,Mat);
01425     fprintf(stderr, "\nRay =");
01426     Matrix_Print(stderr,0,Ray);
01427 #endif
01428     
01429     /* 
01430      * STEP(7): Do a first pass filter of rays and identification of lines.
01431      * Count the irredundant Rays and store count in 'NbUni'. 
01432      */
01433     
01434     value_set_si(tmp2,Dim_RaySpace);
01435     value_set_si(tmp3,(NbConstraints+1));
01436     NbUni=0;
01437     for (j=0; j<NbRay; j++) { 
01438       
01439       /* Status = Ray->p[j][0] */
01440       value_assign(Status, Ray->p[j][0]);
01441       
01442       /* if (Status < Dim_RaySpace) the ray is redundant */
01443       if (value_lt(Status,tmp2))        
01444         
01445         /* Ray->p[j][0]=2 : redundant */
01446         value_set_si(Ray->p[j][0],2);   
01447       
01448       /* else if (Status == (NbConstraints+1)) then ray is a line */
01449       else if (value_eq(Status,tmp3)) 
01450         
01451         /* Ray->p[j][0]=0 : line */
01452         value_set_si(Ray->p[j][0],0);
01453       
01454       /* else ray is an irredundant unidirectional ray. */
01455       else {
01456         NbUni++; 
01457         
01458         /* Ray->p[j][0]=1 : ray */
01459         value_set_si(Ray->p[j][0],1);
01460       }
01461     }
01462     
01463     /*
01464      * STEP(8): Create the polyhedron (using approximate sizes).
01465      * Number of constraints = NbIneq + NbEq2 + 1
01466      * Number of rays = NbUni + NbBid2 
01467      * Partially fill the polyhedron structure with the lines computed in step
01468      * 3 and the equalities computed in step 5. 
01469      */
01470     
01471     Pol = Polyhedron_Alloc(Dimension-1, NbIneq+NbEq2+1, NbUni+NbBid2);
01472     if (!Pol) {
01473       errormsg1("Remove_redundants", "outofmem", "out of memory space");
01474       
01475       /* Clear all the 'Value' variables */
01476       value_clear(Status); value_clear(tmp1);
01477       value_clear(tmp2); value_clear(tmp3);
01478       for(i=0;i<RowSize1;i++)
01479         value_clear(temp1[i]);
01480       
01481       free(temp1); free(temp2); free(jx); free(bx);
01482       UNCATCH(any_exception_error);
01483       return 0;
01484     }
01485     Pol->NbBid = NbBid2;
01486     Pol->NbEq  = NbEq2;
01487     
01488     /* Partially fill the polyhedron structure */
01489     if (NbBid2) Vector_Copy(Ray->p[0], Pol->Ray[0], (Dimension+1)*NbBid2);
01490     if (NbEq2)  Vector_Copy(Mat->p[0], Pol->Constraint[0], (Dimension+1)*NbEq2);
01491     
01492 #ifdef POLY_RR_DEBUG
01493     fprintf(stderr, "[Remove_redundants : Step7]\nConstraints =");
01494     Matrix_Print(stderr,0,Mat);
01495     fprintf(stderr, "\nRay =");
01496     Matrix_Print(stderr,0,Ray);
01497 #endif
01498     
01499     /* 
01500      * STEP(9): Final Pass filter of inequalities and detection of redundant
01501      * inequaties. Redundant inequalities include: 
01502      * (1) Inequalities which are always true, such as 1>=0, 
01503      * (2) Redundant inequalities such as y>=4 given y>=3, or x>=1 given x=2. 
01504      * (3) Redundant inequalities such as x+y>=5 given x>=3 and y>=2.
01505      * Every 'good' inequality must saturate at least 'Dimension' rays and be 
01506      * unique.
01507      */
01508     
01509     /* 'Trace' is a (1 X sat_nbcolumns) row matrix to hold the union of all */
01510     /* rows (corresponding to irredundant rays) of saturation matrix 'Sat'  */
01511     /* which saturate some constraint 'j'. See figure below:-               */
01512     Trace=(unsigned *)malloc(sat_nbcolumns * sizeof(unsigned));
01513     if(!Trace) {
01514       errormsg1("Remove_Redundants", "outofmem", "out of memory space");
01515       
01516       /* Clear all the 'Value' variables */
01517       value_clear(Status); value_clear(tmp1);
01518       value_clear(tmp2); value_clear(tmp3);
01519       for(i=0;i<RowSize1;i++)
01520         value_clear(temp1[i]);
01521       
01522       free(temp1); free(temp2); free(jx); free(bx);
01523       UNCATCH(any_exception_error);
01524       return 0;
01525     }
01526     
01527     /*                         NbEq      NbConstraints
01528                                |----------->
01529                                 ___________j____
01530                                |           |   |
01531                                |      Mat  |   |
01532                                |___________|___|
01533                                            |                  
01534      NbRay  ^ ________         ____________|____
01535             | |-------|--------|-----------0---|t1
01536             |i|-------|--------|-----------0---|t2
01537             | | Ray   |        |    Sat        |
01538      NbBid  - |-------|--------|-----------0---|tk
01539               |_______|        |_______________|
01540                                            |
01541                                            |
01542                                       -OR- (of rows t1,t2,...,tk)
01543                                ________|___|____
01544                                |_____Trace_0___|
01545                                
01546     */
01547     
01548     NbIneq2 = 0;
01549     for (j=NbEq; j<NbConstraints; j++) {
01550       
01551       /* if (Mat->p[j][0]==1) : non-redundant inequality */
01552       if (value_one_p (Mat->p[j][0])) { 
01553         for (k=0; k<sat_nbcolumns; k++) Trace[k]=0;  /* init Trace */
01554         
01555         /* Compute Trace: the union of all rows of Sat where constraint(j) */
01556         /* is saturated.                                                   */
01557         for (i=NbBid; i<NbRay; i++) 
01558           
01559           /* if (Ray->p[i][0]==1) */
01560           if (value_one_p(Ray->p[i][0])) { 
01561             if (!(Sat->p[i][jx[j]]&bx[j])) 
01562               for (k=0; k<sat_nbcolumns; k++) Trace[k] |= Sat->p[i][k];
01563           }
01564         
01565         /* Only constraint(j) should saturate this set of vertices/rays. */
01566         /* If another non-redundant constraint also saturates this set,  */
01567         /* then constraint(j) is redundant                               */
01568         Redundant=0;
01569         for (i=NbEq; i<NbConstraints; i++) {
01570           
01571           /* if ((Mat->p[i][0] ==1) && (i!=j) && !(Trace[jx[i]] & bx[i]) ) */
01572           if (value_one_p(Mat->p[i][0]) && (i!=j) && !(Trace[jx[i]] & bx[i])) {
01573             Redundant=1;
01574             break;
01575           }
01576         }
01577         if (Redundant) {
01578           value_set_si(Mat->p[j][0],2);
01579         }       
01580         else {
01581           Vector_Copy(Mat->p[j], Pol->Constraint[NbEq2+NbIneq2], Dimension+1);
01582           if (Filter) Filter[jx[j]] |= bx[j];           /* for SIMPLIFY */
01583           NbIneq2++;
01584         }
01585       }
01586     }
01587     free(Trace), Trace = NULL;
01588     
01589 #ifdef POLY_RR_DEBUG
01590     fprintf(stderr, "[Remove_redundants : Step8]\nConstraints =");
01591     Matrix_Print(stderr,0,Mat);
01592     fprintf(stderr, "\nRay =");
01593     Matrix_Print(stderr,0,Ray);
01594 #endif
01595     
01596     /* 
01597      * Step(10): Final pass filter of rays and detection of redundant rays.
01598      * The final list of rays is written to polyhedron.                     
01599      */
01600     
01601     /* Trace is a (NbRay x 1) column matrix to hold the union of all columns */
01602     /* (corresponding to irredundant inequalities) of saturation matrix 'Sat'*/
01603     /* which saturate some ray 'i'. See figure below:-                       */
01604     
01605     Trace=(unsigned *)malloc(NbRay * sizeof(unsigned));
01606     if(!Trace) {
01607       errormsg1("Remove_Redundants", "outofmem", "out of memory space");
01608       
01609       /* Clear all the 'Value' variables */
01610       value_clear(Status); value_clear(tmp1);
01611       value_clear(tmp2); value_clear(tmp3);
01612       for(i=0;i<RowSize1;i++)
01613         value_clear(temp1[i]);
01614       
01615       free(bx); free(jx); free(temp2); free(temp1);
01616       UNCATCH(any_exception_error);
01617       return 0;
01618     }
01619     
01620     /*                     NbEq     NbConstraints
01621                              |---------->
01622                         ___________j_____
01623                         |      | |   |  |
01624                         |      Mat   |  |
01625                         |______|_|___|__|
01626                                | |   |
01627 NbRay ^ _________       _______|_|___|__   ___
01628       | |       |       |      | |   |  |  |T|
01629       | |  Ray  |       |   Sat| |   |  |  |r|
01630       | |       |       |      | |   |  |  |a|  Trace = Union[col(t1,t2,..,tk)]
01631       |i|-------|------>i      0 0   0  |  |c|
01632 NbBid - |       |       |      | |   |  |  |e|
01633         |_______|       |______|_|___|__|  |_|
01634                               t1 t2  tk
01635     */    
01636   
01637     NbUni2 = 0;
01638     
01639     /* Let 'aux' be the number of rays not vertices */ 
01640     aux = 0;     
01641     for (i=NbBid; i<NbRay; i++) {
01642       
01643       /* if (Ray->p[i][0]==1) */
01644       if (value_one_p (Ray->p[i][0])) { 
01645         
01646         /* if (Ray->p[i][Dimension]!=0) : vertex */
01647         if (value_notzero_p (Ray->p[i][Dimension]))
01648           for (k=NbBid; k<NbRay; k++) Trace[k]=0;         /* init Trace */
01649         else /* for ray */
01650           
01651           /* Include the positivity constraint incidences for rays. The */
01652           /* positivity constraint saturates all rays and no vertices   */
01653           
01654           for (k=NbBid; k<NbRay; k++)
01655             
01656             /* Trace[k]=(Ray->p[k][Dimension]!=0); */
01657             Trace[k] = (value_notzero_p (Ray->p[k][Dimension]));
01658         
01659         /* Compute Trace: the union of all columns of Sat where ray(i) is  */
01660         /* saturated.                                                      */
01661         for (j=NbEq; j<NbConstraints; j++)
01662           
01663           /* if (Mat->p[j][0]==1) : inequality */
01664           if (value_one_p (Mat->p[j][0])) { 
01665             if (!(Sat->p[i][jx[j]]&bx[j]))
01666               for (k=NbBid; k<NbRay; k++) Trace[k] |= Sat->p[k][jx[j]]&bx[j];
01667           }
01668         
01669         /* If ray i does not saturate any inequalities (other than the   */
01670         /* the positivity constraint, then it is the case that there is  */
01671         /* only one inequality and that ray is its orthogonal            */
01672         
01673         /* only ray(i) should saturate this set of inequalities. If      */
01674         /* another non-redundant ray also saturates this set, then ray(i)*/
01675         /* is redundant                                                  */
01676         
01677         Redundant = 0;
01678         for (j=NbBid; j<NbRay; j++) { 
01679           
01680           /* if ( (Ray->p[j][0]==1) && (i!=j) && !Trace[j] ) */
01681           if (value_one_p (Ray->p[j][0]) && (i!=j) && !Trace[j]) { 
01682             Redundant=1;
01683             break;
01684           }
01685         }
01686         if (Redundant) 
01687           value_set_si(Ray->p[i][0],2); 
01688         else {
01689           Vector_Copy(Ray->p[i], Pol->Ray[NbBid2+NbUni2], Dimension+1);
01690           NbUni2++;  /* Increment number of uni-directional rays */
01691           
01692           /* if (Ray->p[i][Dimension]==0) */ 
01693           if (value_zero_p (Ray->p[i][Dimension]))
01694             aux++; /* Increment number of rays which are not vertices */
01695         }
01696       }
01697     }
01698     
01699     /* Include the positivity constraint */
01700     if (aux>=Dim_RaySpace) {
01701       Vector_Set(Pol->Constraint[NbEq2+NbIneq2],0,Dimension+1);
01702       value_set_si(Pol->Constraint[NbEq2+NbIneq2][0],1);
01703       value_set_si(Pol->Constraint[NbEq2+NbIneq2][Dimension],1);
01704       NbIneq2++;
01705     }   
01706   } /* end of TRY */
01707   
01708   UNCATCH(any_exception_error);
01709   
01710 #ifdef POLY_RR_DEBUG
01711   fprintf(stderr, "[Remove_redundants : Step9]\nConstraints =");
01712   Matrix_Print(stderr,0,Mat);
01713   fprintf(stderr, "\nRay =");
01714   Matrix_Print(stderr,0,Ray);
01715 #endif
01716   
01717   free(Trace);
01718   free(bx);
01719   free(jx);
01720   free(temp2);
01721   
01722   Pol->NbConstraints = NbEq2 + NbIneq2;
01723   Pol->NbRays = NbBid2 + NbUni2;
01724   
01725   /* Clear all the 'Value' variables */
01726   value_clear(Status); value_clear(tmp1);
01727   value_clear(tmp2); value_clear(tmp3);
01728   for(i=0;i<RowSize1;i++)
01729     value_clear(temp1[i]);
01730   free(temp1);
01731   return Pol;
01732 } /* Remove_Redundants */
01733 
01734 /*
01735  * Allocate memory space for polyhedron. 
01736  */
01737 Polyhedron* Polyhedron_Alloc(unsigned Dimension,unsigned NbConstraints,unsigned NbRays) { 
01738   
01739   Polyhedron *Pol;
01740   unsigned NbRows,NbColumns;
01741   int i,j;
01742   Value *p, **q; 
01743 
01744   Pol=(Polyhedron *)malloc(sizeof(Polyhedron));
01745   if(!Pol) {
01746     errormsg1("Polyhedron_Alloc", "outofmem", "out of memory space");
01747     return 0;
01748   }
01749   
01750   Pol->next          = (Polyhedron *)0;
01751   Pol->Dimension     = Dimension;
01752   Pol->NbConstraints = NbConstraints;
01753   Pol->NbRays        = NbRays;
01754   Pol->NbEq          = 0;
01755   Pol->NbBid         = 0;
01756   NbRows             = NbConstraints + NbRays;
01757   NbColumns          = Dimension + 2;
01758   
01759   q = (Value **)malloc(NbRows * sizeof(Value *));
01760   if(!q) {
01761     errormsg1("Polyhedron_Alloc", "outofmem", "out of memory space");
01762     return 0;
01763   }
01764   p = (Value *)malloc(NbRows * NbColumns * sizeof(Value));
01765   if(!p) {
01766     free(q);
01767     errormsg1("Polyhedron_Alloc", "outofmem", "out of memory space");
01768     return 0;
01769   }
01770   Pol->Constraint    = q;
01771   Pol->Ray           = q + NbConstraints;
01772   Pol->p_Init        = p;
01773   for (i=0;i<NbRows;i++) {
01774     *q++ = p;
01775     for(j=0;j<NbColumns;j++) 
01776       value_init(*(p+j));
01777     p += NbColumns;
01778   }
01779   Pol->p_Init_size   = NbRows*NbColumns;
01780   return Pol;
01781 } /* Polyhedron_Alloc */
01782 
01783 /*    
01784  * Free the memory space occupied by the single polyhedron.
01785  */
01786 void Polyhedron_Free(Polyhedron *Pol) {
01787   
01788   int i,size;
01789   Value *p;
01790   
01791   if(!Pol)
01792     return;
01793   size = Pol->p_Init_size;
01794   p = Pol->p_Init;
01795   for(i=0;i<size;i++)
01796     value_clear(p[i]); 
01797   free(Pol->p_Init);
01798   free(Pol->Constraint);
01799   free(Pol);
01800   return;
01801 } /* Polyhedron_Free */
01802 
01803 /*
01804  * Free the memory space occupied by the domain. 
01805  */
01806 void Domain_Free(Polyhedron *Pol)
01807 {
01808   Polyhedron *Next;
01809   
01810   for (; Pol; Pol = Next) {
01811     Next = Pol->next;
01812     Polyhedron_Free(Pol);
01813   }
01814   return;
01815 } /* Domain_Free */
01816 
01817 /*
01818  * Print the contents of a polyhedron. 
01819  */
01820 void Polyhedron_Print(FILE *Dst,char *Format,Polyhedron *Pol) { 
01821 
01822   unsigned Dimension, NbConstraints, NbRays;
01823   int      i, j;
01824   Value    *p;
01825   
01826   if (!Pol) { 
01827     fprintf(Dst, "<null polyhedron>\n");
01828     return;
01829   }
01830   
01831   Dimension     = Pol->Dimension + 2;  /* Homogenous Dimension + status */
01832   NbConstraints = Pol->NbConstraints;
01833   NbRays        = Pol->NbRays;
01834   fprintf(Dst, "POLYHEDRON Dimension:%d\n", Pol->Dimension);
01835   fprintf(Dst,"           Constraints:%d  Equations:%d  Rays:%d  Lines:%d\n",
01836           Pol->NbConstraints, Pol->NbEq, Pol->NbRays, Pol->NbBid);
01837   fprintf(Dst,"Constraints %d %d\n", NbConstraints, Dimension);
01838   
01839   for (i=0;i<NbConstraints;i++) {
01840     p=Pol->Constraint[i];
01841     
01842     /* if (*p) */
01843     if (value_notzero_p (*p))
01844       fprintf(Dst,"Inequality: [");
01845     else      
01846       fprintf(Dst,"Equality:   [");
01847     p++;
01848     for (j=1;j<Dimension;j++) {
01849       value_print(Dst,Format,*p++);
01850     }  
01851     (void)fprintf(Dst," ]\n");
01852   }
01853 
01854   (void)fprintf(Dst, "Rays %d %d\n", NbRays, Dimension);
01855   for (i=0;i<NbRays;i++) {
01856     p=Pol->Ray[i];
01857     
01858     /* if (*p) */
01859     if (value_notzero_p (*p)) {   
01860       p++;
01861       
01862       /* if ( p[Dimension-2] ) */
01863       if (value_notzero_p (p[Dimension-2]))
01864         fprintf(Dst, "Vertex: [");
01865       else                  
01866         fprintf(Dst, "Ray:    [");
01867     }
01868     else {
01869       p++;
01870       fprintf(Dst, "Line:   [");
01871     }
01872     for (j=1; j < Dimension-1; j++) {
01873       value_print(Dst,Format,*p++);  
01874     }  
01875     
01876     /* if (*p) */
01877     if (value_notzero_p (*p)) {
01878       fprintf( Dst, " ]/" );
01879       value_print(Dst,VALUE_FMT,*p);
01880       fprintf( Dst, "\n" );
01881     }
01882     else    
01883       fprintf(Dst, " ]\n");
01884   }
01885   if (Pol->next) {  
01886     fprintf(Dst, "UNION ");
01887     Polyhedron_Print(Dst,Format,Pol->next);
01888   }
01889 } /* Polyhedron_Print */
01890 
01891 /* 
01892  * Print the contents of a polyhedron 'Pol' (used for debugging purpose).
01893  */
01894 void PolyPrint (Polyhedron *Pol) {
01895   Polyhedron_Print(stderr,"%4d",Pol);
01896 } /* PolyPrint */
01897 
01898 /* 
01899  * Create and return an empty polyhedron of non-homogenous dimension 
01900  * 'Dimension'. An empty polyhedron is characterized by :-
01901  *  (a) The dimension of the ray-space is -1.  
01902  *  (b) There is an over-constrained system of equations given by:
01903  *      x=0, y=0, ...... z=0, 1=0
01904  */
01905 Polyhedron *Empty_Polyhedron(unsigned Dimension) {
01906 
01907   Polyhedron *Pol;
01908   int i;
01909 
01910   Pol = Polyhedron_Alloc(Dimension, Dimension+1, 0);
01911   if (!Pol) {
01912     errormsg1("Empty_Polyhedron", "outofmem", "out of memory space");
01913     return 0;
01914   }
01915   Vector_Set(Pol->Constraint[0],0,(Dimension+1)*(Dimension+2));
01916   for (i=0; i<=Dimension; i++) {
01917     
01918     /* Pol->Constraint[i][i+1]=1 */
01919     value_set_si(Pol->Constraint[i][i+1],1);
01920   }
01921   Pol->NbEq = Dimension+1;
01922   Pol->NbBid = 0;
01923   return Pol;
01924 } /* Empty_Polyhedron */
01925 
01926 /* 
01927  * Create and return a universe polyhedron of non-homogenous dimension
01928  * 'Dimension'. A universe polyhedron is characterized by :-
01929  * (a) The dimension of rayspace is zero. 
01930  * (b) The dimension of lineality space is the dimension of the polyhedron.
01931  * (c) There is only one constraint (positivity constraint) in the constraint
01932  *     set given by : 1 >= 0. 
01933  * (d) The bi-directional ray set is the canonical set of vectors. 
01934  * (e) The only vertex is the origin (0,0,0,....0).  
01935  */
01936 Polyhedron *Universe_Polyhedron(unsigned Dimension) { 
01937   
01938   Polyhedron *Pol;
01939   int i;
01940   
01941   Pol = Polyhedron_Alloc(Dimension,1,Dimension+1);
01942   if (!Pol) {
01943     errormsg1("Universe_Polyhedron", "outofmem", "out of memory space");
01944     return 0;
01945   }
01946   Vector_Set(Pol->Constraint[0],0,(Dimension+2));
01947   
01948   /* Pol->Constraint[0][0] = 1 */
01949   value_set_si(Pol->Constraint[0][0],1);
01950   
01951   /* Pol->Constraint[0][Dimension+1] = 1 */
01952   value_set_si(Pol->Constraint[0][Dimension+1],1);
01953   Vector_Set(Pol->Ray[0],0,(Dimension+1)*(Dimension+2));
01954   for (i=0;i<=Dimension;i++) {
01955     
01956     /* Pol->Ray[i][i+1]=1 */
01957     value_set_si(Pol->Ray[i][i+1],1);
01958   }  
01959   
01960   /* Pol->Ray[Dimension][0] = 1 :  vertex status */
01961   value_set_si(Pol->Ray[Dimension][0],1);
01962   Pol->NbEq = 0;
01963   Pol->NbBid = Dimension;
01964   return Pol;
01965 } /* Universe_Polyhedron */
01966 
01967 /**
01968 
01969 Given a matrix of constraints ('Constraints'), construct and return a 
01970 polyhedron.
01971 
01972 @param Constraints Constraints (may be modified!)
01973 @param NbMaxRays Estimated number of rays in the ray matrix of the
01974 polyhedron.
01975 @return newly allocated Polyhedron
01976 
01977 */ 
01978 Polyhedron *Constraints2Polyhedron(Matrix *Constraints,unsigned NbMaxRays) {
01979   
01980   Polyhedron *Pol = NULL;
01981   Matrix *Ray = NULL;
01982   SatMatrix *Sat = NULL;
01983   unsigned Dimension, nbcolumns;
01984   int i;
01985 
01986   Dimension = Constraints->NbColumns - 1;  /* Homogeneous Dimension */
01987   if (Dimension < 1) {
01988     errormsg1("Constraints2Polyhedron","invalidpoly","invalid polyhedron dimension");
01989     return 0;
01990   }
01991   
01992   if (Dimension > NbMaxRays)
01993     NbMaxRays = Dimension;
01994     
01995   /* If there is no constraint in the constraint matrix, return universe */
01996   /* polyhderon.                                                         */
01997   if (Constraints->NbRows==0) {  
01998     Pol = Universe_Polyhedron(Dimension-1);
01999     return Pol;
02000   }
02001 
02002   /*
02003    * Rather than adding a 'positivity constraint', it is better to
02004    * initialize the lineality space with line in each of the index
02005    * dimensions, but no line in the lambda dimension. Then initialize
02006    * the ray space with an origin at 0.  This is what you get anyway,
02007    * after the positivity constraint has been processed by Chernikova
02008    * function.
02009    */
02010 
02011   /* Allocate and initialize the Ray Space */
02012   Ray = Matrix_Alloc(NbMaxRays, Dimension+1);
02013   if(!Ray) {
02014     errormsg1("Constraints2Polyhedron","outofmem","out of memory space");
02015     return 0;
02016   }
02017   Vector_Set(Ray->p_Init,0, NbMaxRays * (Dimension+1));
02018   for (i=0; i<Dimension; i++) {    
02019     
02020     /* Ray->p[i][i+1] = 1 */
02021     value_set_si(Ray->p[i][i+1],1);
02022   }
02023 
02024   /* Ray->p[Dimension-1][0] = 1 : mark for ray */
02025   value_set_si(Ray->p[Dimension-1][0],1);
02026   Ray->NbRows = Dimension; 
02027 
02028   /* Initialize the Sat Matrix */
02029   nbcolumns = (Constraints->NbRows - 1)/(sizeof(int)*8) + 1;
02030   Sat = SMAlloc(NbMaxRays, nbcolumns);
02031   SMVector_Init(Sat->p_init,Dimension*nbcolumns);
02032   Sat->NbRows = Dimension;
02033 
02034   CATCH(any_exception_error) {
02035 
02036     /* In case of overflow, free the allocated memory and forward. */    
02037     if (Sat) SMFree(&Sat);
02038     if (Ray) Matrix_Free(Ray);
02039     if (Pol) Polyhedron_Free(Pol);
02040     RETHROW();
02041   }
02042   TRY {
02043 
02044     /* Create ray matrix 'Ray' from constraint matrix 'Constraints' */
02045     Chernikova(Constraints,Ray,Sat,Dimension-1,NbMaxRays,0,0);
02046 
02047 #ifdef POLY_DEBUG
02048     fprintf(stderr, "[constraints2polyhedron]\nConstraints = ");
02049     Matrix_Print(stderr,0,Constraints);
02050     fprintf(stderr, "\nRay = ");
02051     Matrix_Print(stderr,0,Ray);
02052     fprintf(stderr, "\nSat = ");
02053     SMPrint(Sat);
02054 #endif
02055     
02056     /* Remove the redundant constraints and create the polyhedron */
02057     Pol = Remove_Redundants(Constraints,Ray,Sat,0);
02058   } /* end of TRY */
02059 
02060   UNCATCH(any_exception_error);
02061   
02062 #ifdef POLY_DEBUG
02063   fprintf(stderr, "\nPol = ");
02064   Polyhedron_Print(stderr,"%4d",Pol);
02065 #endif
02066   
02067   SMFree(&Sat), Sat = NULL;
02068   Matrix_Free(Ray), Ray = NULL; 
02069   return Pol;
02070 } /* Constraints2Polyhedron */
02071 
02072 #undef POLY_DEBUG
02073 
02074 /* 
02075  * Given a polyhedron 'Pol', return a matrix of constraints. 
02076  */
02077 Matrix *Polyhedron2Constraints(Polyhedron *Pol) {
02078   
02079   Matrix     *Mat;
02080   unsigned NbConstraints,Dimension;
02081   
02082   NbConstraints = Pol->NbConstraints;
02083   Dimension     = Pol->Dimension+2;
02084   Mat = Matrix_Alloc(NbConstraints,Dimension);
02085   if(!Mat) {
02086     errormsg1("Polyhedron2Constraints", "outofmem", "out of memory space");
02087     return 0;
02088   }
02089   Vector_Copy(Pol->Constraint[0],Mat->p_Init,NbConstraints * Dimension);
02090   return Mat;
02091 } /* Polyhedron2Constraints */
02092 
02093 /** 
02094 
02095 Given a matrix of rays 'Ray', create and return a polyhedron. 
02096 
02097 @param Ray Rays (may be modified!)
02098 @param NbMaxRays Estimated number of constraints in the polyhedron.
02099 @return newly allocated Polyhedron
02100 
02101 */ 
02102 Polyhedron *Rays2Polyhedron(Matrix *Ray,unsigned NbMaxConstrs) {
02103   
02104   Polyhedron *Pol = NULL;
02105   Matrix *Mat = NULL;
02106   SatMatrix *Sat = NULL, *SatTranspose = NULL;
02107   unsigned Dimension, nbcolumns;
02108   int i;
02109   
02110   Dimension = Ray->NbColumns-1;        /* Homogeneous Dimension */
02111   Sat = NULL;
02112   SatTranspose = NULL;
02113   Mat = NULL;
02114   
02115   if (Ray->NbRows==0) {  
02116     
02117     /* If there is no ray in the matrix 'Ray', return an empty polyhedron */
02118     Pol = Empty_Polyhedron(Dimension-1);
02119     return(Pol);
02120   }
02121 
02122   if (Dimension > NbMaxConstrs)
02123     NbMaxConstrs = Dimension;
02124   
02125   /* Allocate space for constraint matrix 'Mat' */
02126   Mat = Matrix_Alloc(NbMaxConstrs,Dimension+1);
02127   if(!Mat) {
02128     errormsg1("Rays2Polyhedron","outofmem","out of memory space");
02129     return 0;
02130   }
02131   
02132   /* Initialize the constraint matrix 'Mat' */
02133   Vector_Set(Mat->p_Init,0,NbMaxConstrs * (Dimension+1));
02134   for (i=0; i<Dimension; i++) {
02135     
02136     /* Mat->p[i][i+1]=1 */
02137     value_set_si(Mat->p[i][i+1],1);
02138   }
02139   
02140   /* Allocate and assign the saturation matrix. Remember we are using a */
02141   /* transposed saturation matrix referenced by (constraint,ray) pair.  */
02142   Mat->NbRows = Dimension;
02143   nbcolumns = (Ray->NbRows -1)/(sizeof(int)*8) + 1;
02144   SatTranspose = SMAlloc(NbMaxConstrs,nbcolumns);
02145   SMVector_Init(SatTranspose->p[0],Dimension * nbcolumns);
02146   SatTranspose->NbRows = Dimension;
02147   
02148 #ifdef POLY_DEBUG
02149   fprintf(stderr, "[ray2polyhedron: Before]\nRay = ");
02150   Matrix_Print(stderr,0,Ray);
02151   fprintf(stderr, "\nConstraints = ");
02152   Matrix_Print(stderr,0,Mat);
02153   fprintf(stderr, "\nSatTranspose = ");
02154   SMPrint (SatTranspose);
02155 #endif
02156   
02157   CATCH(any_exception_error) {
02158     
02159     /* In case of overflow, free the allocated memory before forwarding
02160      * the exception. 
02161      */
02162     if (SatTranspose) SMFree(&SatTranspose);
02163     if (Sat) SMFree(&Sat);
02164     if (Mat) Matrix_Free(Mat);
02165     if (Pol) Polyhedron_Free(Pol);
02166     RETHROW();
02167   }
02168   TRY {
02169     
02170     /* Create constraint matrix 'Mat' from ray matrix 'Ray' */ 
02171     Chernikova(Ray,Mat,SatTranspose,Dimension,NbMaxConstrs,0,1);
02172     
02173 #ifdef POLY_DEBUG
02174     fprintf(stderr, "[ray2polyhedron: After]\nRay = ");
02175     Matrix_Print(stderr,0,Ray);
02176     fprintf(stderr, "\nConstraints = ");
02177     Matrix_Print(stderr,0,Mat);
02178     fprintf(stderr, "\nSatTranspose = ");
02179     SMPrint (SatTranspose);
02180 #endif
02181     
02182     /* Transform the saturation matrix 'SatTranspose' in the standard  */
02183     /* format, that is, ray X constraint format.                       */
02184     Sat = TransformSat(Mat,Ray,SatTranspose);
02185     
02186 #ifdef POLY_DEBUG
02187     fprintf(stderr, "\nSat =");
02188     SMPrint(Sat);
02189 #endif
02190     
02191     SMFree(&SatTranspose), SatTranspose = NULL;
02192     
02193     /* Remove redundant rays from the ray matrix 'Ray' */
02194     Pol = Remove_Redundants(Mat,Ray,Sat,0);
02195   } /* of TRY */
02196   
02197   UNCATCH(any_exception_error);
02198   
02199 #ifdef POLY_DEBUG
02200   fprintf(stderr, "\nPol = ");
02201   Polyhedron_Print(stderr,"%4d",Pol);
02202 #endif
02203   
02204   SMFree(&Sat);
02205   Matrix_Free(Mat);
02206   return Pol;
02207 } /* Rays2Polyhedron */
02208 
02209 /*   
02210  * Build a saturation matrix from constraint matrix 'Mat' and ray matrix 
02211  * 'Ray'. Only 'NbConstraints' constraint of matrix 'Mat' are considered 
02212  * in creating the saturation matrix. 'NbMaxRays' is the maximum number 
02213  * of rows (rays) allowed in the saturation matrix.
02214  * Vin100's stuff, for the polyparam vertices to work.
02215  */
02216 static SatMatrix *BuildSat(Matrix *Mat,Matrix *Ray,unsigned NbConstraints,unsigned NbMaxRays) {
02217   
02218   SatMatrix *Sat = NULL;
02219   int i, j, k, jx;
02220   Value *p1, *p2, *p3;
02221   Value tmp;
02222   unsigned Dimension, NbRay, bx, nbcolumns;
02223   
02224   value_init(tmp);
02225   
02226   CATCH(any_exception_error) {
02227     if (Sat) 
02228       SMFree(&Sat);
02229     value_clear(tmp);
02230     RETHROW();
02231   }
02232   TRY {
02233     NbRay = Ray->NbRows;
02234     Dimension = Mat->NbColumns-1;   /* Homogeneous Dimension */
02235     
02236     /* Build the Sat matrix */
02237     nbcolumns = (Mat->NbRows - 1)/(sizeof(int)*8) + 1;
02238     Sat = SMAlloc(NbMaxRays,nbcolumns);
02239     Sat->NbRows = NbRay;
02240     SMVector_Init(Sat->p_init, nbcolumns * NbRay);
02241     jx=0; bx=MSB;
02242     for (k=0; k<NbConstraints; k++) {
02243       for (i=0; i<NbRay; i++) {
02244         
02245         /* Compute the dot product of ray(i) and constraint(k) and */
02246         /* store in the status element of ray(i).                  */
02247         p1 = Ray->p[i]+1;
02248         p2 = Mat->p[k]+1;
02249         p3 = Ray->p[i];
02250         value_set_si(*p3,0);
02251         for (j=0; j<Dimension; j++) {
02252           value_multiply(tmp,*p1,*p2);
02253           value_addto(*p3,*p3,tmp);
02254           p1++; p2++;
02255         }
02256       }
02257       for (j=0; j<NbRay; j++) {
02258         
02259         /* Set 1 in the saturation matrix if the ray doesn't saturate */
02260         /* the constraint, otherwise the entry is 0.                  */
02261         if (value_notzero_p(Ray->p[j][0]))
02262           Sat->p[j][jx]|=bx;
02263       }
02264       NEXT(jx, bx);
02265     }
02266   } /* end of TRY */
02267   
02268   UNCATCH(any_exception_error);
02269   value_clear(tmp);
02270   return Sat;
02271 } /* BuildSat */
02272 
02273 /* 
02274  * Add 'Nbconstraints' new constraints to polyhedron 'Pol'. Constraints are 
02275  * pointed by 'Con' and the maximum allowed rays in the new polyhedron is
02276  * 'NbMaxRays'.   
02277  */
02278 Polyhedron *AddConstraints(Value *Con,unsigned NbConstraints,Polyhedron *Pol,unsigned NbMaxRays) {
02279 
02280   Polyhedron *NewPol = NULL;
02281   Matrix   *Mat = NULL, *Ray = NULL;
02282   SatMatrix *Sat = NULL;
02283   unsigned NbRay, NbCon, Dimension;
02284 
02285   if (NbConstraints == 0)
02286     return Polyhedron_Copy(Pol);
02287   
02288   CATCH(any_exception_error) {
02289     if (NewPol) Polyhedron_Free(NewPol);
02290     if (Mat) Matrix_Free(Mat);
02291     if (Ray) Matrix_Free(Ray);
02292     if (Sat) SMFree(&Sat);
02293     RETHROW();
02294   }
02295   TRY {
02296     NbRay       = Pol->NbRays;
02297     NbCon       = Pol->NbConstraints + NbConstraints;
02298     Dimension   = Pol->Dimension + 2;   /* Homogeneous Dimension + Status */
02299 
02300     if (NbRay > NbMaxRays)
02301       NbMaxRays = NbRay;
02302     
02303     Mat = Matrix_Alloc(NbCon, Dimension);
02304     if(!Mat) {
02305       errormsg1("AddConstraints", "outofmem", "out of memory space");
02306       UNCATCH(any_exception_error);
02307       return 0;
02308     }
02309     
02310     /* Copy constraints of polyhedron 'Pol' to matrix 'Mat' */
02311     Vector_Copy(Pol->Constraint[0], Mat->p[0], Pol->NbConstraints * Dimension);
02312     
02313     /* Add the new constraints pointed by 'Con' to matrix 'Mat' */
02314     Vector_Copy(Con, Mat->p[Pol->NbConstraints], NbConstraints * Dimension);  
02315     
02316     /* Allocate space for ray matrix 'Ray' */
02317     Ray = Matrix_Alloc(NbMaxRays, Dimension);
02318     if(!Ray) {
02319       errormsg1("AddConstraints", "outofmem", "out of memory space");
02320       UNCATCH(any_exception_error);
02321       return 0;
02322     }
02323     Ray->NbRows = NbRay;
02324 
02325     /* Copy rays of polyhedron 'Pol' to matrix 'Ray' */
02326     if (NbRay)
02327         Vector_Copy(Pol->Ray[0], Ray->p[0], NbRay * Dimension);  
02328     
02329     /* Create the saturation matrix 'Sat' from constraint matrix 'Mat' and */
02330     /* ray matrix 'Ray' .                                                  */ 
02331     Sat = BuildSat(Mat, Ray, Pol->NbConstraints, NbMaxRays);
02332     
02333     /* Create the ray matrix 'Ray' from the constraint matrix 'Mat' */
02334     Pol_status = Chernikova(Mat, Ray, Sat, Pol->NbBid, NbMaxRays, Pol->NbConstraints,0);
02335     
02336     /* Remove redundant constraints from matrix 'Mat' */
02337     NewPol = Remove_Redundants(Mat, Ray, Sat, 0);
02338     
02339   } /* end of TRY */
02340   
02341   UNCATCH(any_exception_error);  
02342   SMFree(&Sat);
02343   Matrix_Free(Ray);
02344   Matrix_Free(Mat);  
02345   return NewPol;
02346 } /* AddConstraints */
02347 
02348 /* 
02349  * Return 1 if 'Pol1' includes (covers) 'Pol2', 0 otherwise. 
02350  * Polyhedron 'A' includes polyhedron 'B' if the rays of 'B' saturate
02351  * the equalities and verify the inequalities of 'A'. Both 'Pol1' and 
02352  * 'Pol2' have same dimensions. 
02353  */
02354 int PolyhedronIncludes(Polyhedron *Pol1,Polyhedron *Pol2) {
02355         
02356   int Dimension = Pol1->Dimension + 1;   /* Homogenous Dimension */
02357   int i, j, k;
02358   Value *p1, *p2, p3, tmp;
02359   
02360   value_init(p3); value_init(tmp);
02361   for (k=0; k<Pol1->NbConstraints; k++) {
02362     for (i=0;i<Pol2->NbRays;i++) {
02363       
02364       /* Compute the dot product of ray(i) and constraint(k) and store in p3 */
02365       p1 = Pol2->Ray[i]+1;
02366       p2 = Pol1->Constraint[k]+1;
02367       value_set_si(p3,0);
02368       for(j=0;j<Dimension;j++) {
02369         value_multiply(tmp,*p1,*p2);
02370         value_addto(p3,p3,tmp);
02371         p1++; p2++;
02372       }
02373      
02374       /* If (p3 < 0) or (p3 > 0 and (constraint(k) is equality
02375                                      or ray(i) is a line)), return 0 */
02376       if(value_neg_p(p3) ||
02377           (value_notzero_p(p3)
02378              && (value_zero_p(Pol1->Constraint[k][0]) || (value_zero_p(Pol2->Ray[i][0]))   ) )) {
02379         value_clear(p3); value_clear(tmp);
02380         return 0;
02381       }
02382     }
02383   } 
02384   value_clear(p3); value_clear(tmp);
02385   return 1;
02386 } /* PolyhedronIncludes */
02387 
02388 /*
02389  * Add Polyhedron 'Pol' to polhedral domain 'PolDomain'. If 'Pol' covers
02390  * some polyhedron in the domain 'PolDomain', it is removed from the list.
02391  * On the other hand if some polyhedron in the domain covers polyhedron 
02392  * 'Pol' then 'Pol' is not included in the domain.   
02393  */
02394 Polyhedron *AddPolyToDomain(Polyhedron *Pol,Polyhedron *PolDomain) {
02395   
02396   Polyhedron *p, *pnext, *p_domain_end = (Polyhedron *) 0;
02397   int Redundant;
02398   
02399   if (!Pol) 
02400     return PolDomain;
02401   if (!PolDomain)       
02402     return Pol;
02403   
02404   /* Check for emptiness of polyhedron 'Pol' */
02405   if (emptyQ(Pol)) {
02406     Polyhedron_Free(Pol);
02407     return PolDomain;
02408   }
02409   
02410   /* Check for emptiness of polyhedral domain 'PolDomain' */
02411   if (emptyQ(PolDomain)) {
02412     Polyhedron_Free(PolDomain);
02413     return Pol;
02414   }
02415   
02416   /* Test 'Pol' against the domain 'PolDomain' */
02417   Redundant = 0;
02418   for (p=PolDomain,PolDomain=(Polyhedron *)0; p; p=pnext) {
02419     
02420     /* If 'Pol' covers 'p' */    
02421     if (PolyhedronIncludes(Pol, p))
02422     {
02423        /* free p */
02424                  pnext = p->next;
02425        Polyhedron_Free( p );
02426        continue;
02427     }
02428 
02429     /* Add polyhedron p to the new domain list */
02430     if (!PolDomain) PolDomain = p; else p_domain_end->next = p;
02431     p_domain_end = p;
02432     
02433     /* If p covers Pol */
02434     if (PolyhedronIncludes(p,Pol)) {
02435       Redundant = 1;
02436       break;
02437     }
02438     pnext = p->next;
02439   }
02440   if (!Redundant) {  
02441     
02442     /* The whole list has been checked. Add new polyhedron 'Pol' to the */
02443     /* new domain list.                                                 */ 
02444     if (!PolDomain) PolDomain = Pol; else p_domain_end->next = Pol;
02445   }
02446   else {
02447     
02448     /* The rest of the list is just inherited from p */
02449     Polyhedron_Free(Pol);
02450   }
02451   return PolDomain;
02452 } /* AddPolyToDomain */
02453 
02454 /* 
02455  * Given a polyhedra 'Pol' and a single constraint 'Con' and an integer 'Pass' 
02456  * whose value ranges from 0 to 3, add the inverse of constraint 'Con' to the 
02457  * constraint set of 'Pol' and return the new polyhedron. 'NbMaxRays' is the 
02458  * maximum allowed rays in the new generated polyhedron. 
02459  * If Pass == 0, add ( -constraint -1) >= 0
02460  * If Pass == 1, add ( +constraint -1) >= 0
02461  * If Pass == 2, add ( -constraint   ) >= 0
02462  * If Pass == 3, add ( +constraint   ) >= 0
02463  */
02464 Polyhedron *SubConstraint(Value *Con,Polyhedron *Pol,unsigned NbMaxRays,int Pass) {
02465   
02466   Polyhedron *NewPol = NULL;
02467   Matrix   *Mat = NULL, *Ray = NULL;
02468   SatMatrix *Sat = NULL;
02469   unsigned NbRay, NbCon, NbEle1, Dimension;
02470   int i;
02471   
02472   CATCH(any_exception_error) {
02473     if (NewPol) Polyhedron_Free(NewPol);
02474     if (Mat) Matrix_Free(Mat);
02475     if (Ray) Matrix_Free(Ray);
02476     if (Sat) SMFree(&Sat);
02477     RETHROW();
02478   }
02479   TRY {
02480     
02481     /* If 'Con' is the positivity constraint, return Null */
02482     Dimension  = Pol->Dimension+1;      /* Homogeneous Dimension */
02483     for (i=1; i<Dimension; i++)
02484       if (value_notzero_p(Con[i])) break;
02485     if (i==Dimension) {
02486       UNCATCH(any_exception_error);
02487       return (Polyhedron *) 0;
02488     }
02489     
02490     NbRay     = Pol->NbRays;
02491     NbCon     = Pol->NbConstraints;
02492     Dimension = Pol->Dimension+2;       /* Homogeneous Dimension + Status */
02493     NbEle1    = NbCon * Dimension;
02494     
02495     if (NbRay > NbMaxRays)
02496       NbMaxRays = NbRay;
02497     
02498     Mat = Matrix_Alloc(NbCon + 1, Dimension);
02499     if(!Mat) {
02500       errormsg1("SubConstraint", "outofmem", "out of memory space");
02501       UNCATCH(any_exception_error);
02502       return 0;
02503     }
02504     
02505     /* Set the constraints of Pol */
02506     Vector_Copy(Pol->Constraint[0], Mat->p[0], NbEle1);
02507     
02508     /* Add the new constraint */
02509     value_set_si(Mat->p[NbCon][0],1);
02510     if (!(Pass&1))
02511       for(i=1; i<Dimension; i++) 
02512         value_oppose(Mat->p[NbCon][i],Con[i]);
02513     else
02514       for(i=1; i<Dimension; i++)
02515         value_assign(Mat->p[NbCon][i],Con[i]);
02516     if (!(Pass&2))
02517       value_decrement(Mat->p[NbCon][Dimension-1],Mat->p[NbCon][Dimension-1]);
02518    
02519     /* Allocate the ray matrix. */
02520     Ray = Matrix_Alloc(NbMaxRays, Dimension);
02521     if(!Ray) {
02522       errormsg1("SubConstraint", "outofmem", "out of memory space");
02523       UNCATCH(any_exception_error);
02524       return 0;
02525     }
02526     
02527     /* Initialize the ray matrix with the rays of polyhedron 'Pol' */
02528     Ray->NbRows = NbRay;
02529     if (NbRay)
02530         Vector_Copy(Pol->Ray[0], Ray->p[0], NbRay * Dimension);   
02531     
02532     /* Create the saturation matrix from the constraint matrix 'mat' and */
02533     /* ray matrix 'Ray'.                                                 */
02534     Sat = BuildSat(Mat, Ray, NbCon, NbMaxRays);
02535     
02536     /* Create the ray matrix 'Ray' from consraint matrix 'Mat'           */
02537     Pol_status = Chernikova(Mat, Ray, Sat, Pol->NbBid, NbMaxRays, NbCon,0);
02538     
02539     /* Remove redundant constraints from matrix 'Mat' */ 
02540     NewPol = Remove_Redundants(Mat, Ray, Sat, 0);
02541     
02542   } /* end of TRY */
02543   
02544   UNCATCH(any_exception_error);
02545   
02546   SMFree(&Sat);
02547   Matrix_Free(Ray);
02548   Matrix_Free(Mat);
02549   return NewPol;
02550 } /* SubConstraint */
02551 
02552 /*
02553  * Return the intersection of two polyhedral domains 'Pol1' and 'Pol2'. 
02554  * The maximum allowed rays in the new polyhedron generated is 'NbMaxRays'. 
02555  */
02556 Polyhedron *DomainIntersection(Polyhedron *Pol1,Polyhedron *Pol2,unsigned NbMaxRays) {
02557   
02558   Polyhedron *p1, *p2, *p3, *d;
02559   
02560   if (!Pol1 || !Pol2) return (Polyhedron*) 0;
02561   if (Pol1->Dimension != Pol2->Dimension) {
02562     errormsg1( "DomainIntersection", "diffdim",
02563                "operation on different dimensions");
02564     return (Polyhedron*) 0;
02565   }
02566   
02567   /* For every polyhedron pair (p1,p2) where p1 belongs to domain Pol1 and */
02568   /* p2 belongs to domain Pol2, compute the intersection and add it to the */
02569   /* new domain 'd'.                                                       */
02570   d = (Polyhedron *)0;
02571   for (p1=Pol1; p1; p1=p1->next) {
02572     for (p2=Pol2; p2; p2=p2->next) {
02573       p3 = AddConstraints(p2->Constraint[0],
02574                           p2->NbConstraints, p1, NbMaxRays);      
02575       d = AddPolyToDomain(p3,d);
02576     }
02577   }
02578   if (!d)
02579     return Empty_Polyhedron(Pol1->Dimension);
02580   else
02581     return d;
02582   
02583 } /* DomainIntersection */
02584 
02585 /*
02586  * Given a polyhedron 'Pol', return a matrix of rays. 
02587  */
02588 Matrix *Polyhedron2Rays(Polyhedron *Pol) {
02589   
02590   Matrix     *Ray;
02591   unsigned NbRays, Dimension;
02592   
02593   NbRays    = Pol->NbRays;
02594   Dimension = Pol->Dimension+2;         /* Homogeneous Dimension + Status */
02595   Ray = Matrix_Alloc(NbRays, Dimension);
02596   if(!Ray) {
02597     errormsg1("Polyhedron2Rays", "outofmem", "out of memory space");
02598     return 0;
02599   }
02600   Vector_Copy(Pol->Ray[0], Ray->p_Init, NbRays*Dimension);
02601   return Ray;
02602 } /* Polyhedron2Rays */
02603 
02604 /*
02605  * Add 'NbAddedRays' rays to polyhedron 'Pol'. Rays are pointed by 'AddedRays'
02606  * and the maximum allowed constraints in the new polyhedron is 'NbMaxConstrs'.
02607  */ 
02608 Polyhedron *AddRays(Value *AddedRays,unsigned NbAddedRays,Polyhedron *Pol,unsigned NbMaxConstrs) {
02609 
02610   Polyhedron *NewPol = NULL;
02611   Matrix   *Mat = NULL, *Ray = NULL;
02612   SatMatrix *Sat = NULL, *SatTranspose = NULL;
02613   unsigned NbCon, NbRay,NbEle1, Dimension;
02614   
02615   CATCH(any_exception_error) {
02616     if (NewPol) Polyhedron_Free(NewPol);
02617     if (Mat) Matrix_Free(Mat);
02618     if (Ray) Matrix_Free(Ray);
02619     if (Sat) SMFree(&Sat);
02620     if (SatTranspose) SMFree(&SatTranspose);
02621     RETHROW();
02622   }
02623   TRY {
02624     
02625     NbCon      = Pol->NbConstraints;
02626     NbRay      = Pol->NbRays;
02627     Dimension  = Pol->Dimension + 2;    /* Homogeneous Dimension + Status */
02628     NbEle1     = NbRay * Dimension;
02629     
02630     Ray = Matrix_Alloc(NbAddedRays + NbRay, Dimension);
02631     if(!Ray) {
02632       errormsg1("AddRays", "outofmem", "out of memory space");
02633       UNCATCH(any_exception_error);
02634       return 0;
02635     }
02636     
02637     /* Copy rays of polyhedron 'Pol' to matrix 'Ray' */
02638     if (NbRay)
02639       Vector_Copy(Pol->Ray[0], Ray->p_Init, NbEle1);
02640     
02641     /* Add the new rays pointed by 'AddedRays' to matrix 'Ray' */
02642     Vector_Copy(AddedRays, Ray->p_Init+NbEle1, NbAddedRays * Dimension);
02643     
02644     /* We need at least NbCon rows */
02645     if (NbMaxConstrs < NbCon)
02646         NbMaxConstrs = NbCon;
02647 
02648     /* Allocate space for constraint matrix 'Mat' */
02649     Mat = Matrix_Alloc(NbMaxConstrs, Dimension);
02650     if(!Mat) {
02651       errormsg1("AddRays", "outofmem", "out of memory space");
02652       UNCATCH(any_exception_error);
02653       return 0;
02654     }
02655     Mat->NbRows = NbCon;
02656     
02657     /* Copy constraints of polyhedron 'Pol' to matrix 'Mat' */
02658     Vector_Copy(Pol->Constraint[0], Mat->p_Init, NbCon*Dimension);
02659 
02660     /* Create the saturation matrix 'SatTranspose' from constraint matrix */
02661     /* 'Mat' and ray matrix 'Ray'. Remember the saturation matrix is      */
02662     /* referenced by (constraint,ray) pair                                */ 
02663     SatTranspose = BuildSat(Ray, Mat, NbRay, NbMaxConstrs);
02664     
02665     /* Create the constraint matrix 'Mat' from the ray matrix 'Ray' */
02666     Pol_status = Chernikova(Ray, Mat, SatTranspose, Pol->NbEq, NbMaxConstrs, NbRay,1);
02667     
02668     /* Transform the saturation matrix 'SatTranspose' in the standard format */
02669     /* , that is, (ray X constraint) format.                                 */
02670     Sat = TransformSat(Mat, Ray, SatTranspose);
02671     SMFree(&SatTranspose), SatTranspose = NULL;
02672     
02673     /* Remove redundant rays from the ray matrix 'Ray' */
02674     NewPol = Remove_Redundants(Mat, Ray, Sat, 0);
02675     
02676     SMFree(&Sat), Sat = NULL;
02677     Matrix_Free(Mat), Mat = NULL;
02678     Matrix_Free(Ray), Ray = NULL;  
02679   } /* end of TRY */
02680   
02681   UNCATCH(any_exception_error);  
02682   return NewPol;
02683 } /* AddRays */
02684 
02685 /* 
02686  * Add rays pointed by 'Ray' to each and every polyhedron in the polyhedral 
02687  * domain 'Pol'. 'NbMaxConstrs' is maximum allowed constraints in the 
02688  * constraint set of a polyhedron.                         
02689  */ 
02690 Polyhedron *DomainAddRays(Polyhedron *Pol,Matrix *Ray,unsigned NbMaxConstrs) {
02691   
02692   Polyhedron *PolA, *PolEndA, *p1, *p2, *p3;
02693   int Redundant;
02694   
02695   if (!Pol) return (Polyhedron*) 0;
02696   if (!Ray ) return Pol;
02697   if (Pol->Dimension != Ray->NbColumns-2) {
02698     errormsg1(
02699               "DomainAddRays", "diffdim", "operation on different dimensions");
02700     return (Polyhedron*) 0;
02701   }
02702   
02703   /* Copy Pol to PolA */
02704   PolA = PolEndA = (Polyhedron *)0;
02705   for (p1=Pol; p1; p1=p1->next) {
02706     p3 = AddRays(Ray->p[0], Ray->NbRows, p1, NbMaxConstrs);
02707     
02708     /* Does any component of PolA cover 'p3' ? */
02709     Redundant = 0;
02710     for (p2=PolA; p2; p2=p2->next) {
02711       if (PolyhedronIncludes(p2, p3)) { /* If p2 covers p3 */
02712         Redundant = 1;
02713         break;
02714       }
02715     }
02716     
02717     /* If the new polyheron is not redundant, add it ('p3') to the list */
02718     if (!Redundant) { 
02719       if (!PolEndA)
02720         PolEndA = PolA = p3;
02721       else {
02722         PolEndA->next = p3;
02723         PolEndA = PolEndA->next;
02724       }
02725     }
02726   }
02727   return PolA;
02728 } /* DomainAddRays */
02729 
02730 /*
02731  * Create a copy of the polyhedron 'Pol' 
02732  */
02733 Polyhedron *Polyhedron_Copy(Polyhedron *Pol) {
02734   
02735   Polyhedron *Pol1;
02736   
02737   if (!Pol) return (Polyhedron *)0;
02738   
02739   /* Allocate space for the new polyhedron */
02740   Pol1 = Polyhedron_Alloc(Pol->Dimension, Pol->NbConstraints, Pol->NbRays);
02741   if (!Pol1) {
02742     errormsg1("Polyhedron_Copy", "outofmem", "out of memory space");
02743     return 0;
02744   }
02745   if( Pol->NbConstraints )
02746     Vector_Copy(Pol->Constraint[0], Pol1->Constraint[0],
02747               Pol->NbConstraints*(Pol->Dimension+2));
02748   if( Pol->NbRays )
02749     Vector_Copy(Pol->Ray[0], Pol1->Ray[0],
02750               Pol->NbRays*(Pol->Dimension+2));
02751   Pol1->NbBid = Pol->NbBid;
02752   Pol1->NbEq = Pol->NbEq;
02753   return Pol1;
02754 } /* Polyhedron_Copy */
02755 
02756 /* 
02757  * Create a copy of a polyhedral domain. 
02758  */
02759 Polyhedron *Domain_Copy(Polyhedron *Pol) {
02760   
02761   Polyhedron *Pol1;
02762   
02763   if (!Pol) return (Polyhedron *) 0;
02764   Pol1 = Polyhedron_Copy(Pol);
02765   if (Pol->next) Pol1->next = Domain_Copy(Pol->next);
02766   return Pol1;
02767 } /* Domain_Copy */
02768 
02769 /*
02770  * Given constraint number 'k' of a polyhedron, and an array 'Filter' to store
02771  * the non-redundant constraints of the polyhedron in bit-wise notation, and
02772  * a Matrix 'Sat', add the constraint 'k' in 'Filter' array. tmpR[i] stores the
02773  * number of constraints, other than those in 'Filter', which ray(i) saturates 
02774  * or verifies. In case, ray(i) does not saturate or verify a constraint in
02775  * array 'Filter', it is assigned to -1. Similarly, tmpC[j] stores the number
02776  * of rays which constraint(j), if it doesn't belong to Filter, saturates or 
02777  * verifies. If constraint(j) belongs to 'Filter', then tmpC[j] is assigned to
02778  * -1. 'NbConstraints' is the number of constraints in the constraint matrix of
02779  * the polyhedron. 
02780  * NOTE: (1) 'Sat' is not the saturation matrix of the polyhedron. In fact, 
02781  *           entry in 'Sat' is set to 1 if ray(i) of polyhedron1 verifies or 
02782  *           saturates the constraint(j) of polyhedron2 and otherwise it is set
02783  *           to 0. So here the difference with saturation matrix is in terms 
02784  *           definition and entries(1<->0) of the matrix 'Sat'.    
02785  *       
02786  * ALGORITHM:->
02787  * (1) Include constraint(k) in array 'Filter'. 
02788  * (2) Set tmpC[k] to -1.
02789  * (3) For all ray(i) {
02790  *        If ray(i) saturates or verifies constraint(k) then --(tmpR[i])
02791  *        Else {
02792  *           Discard ray(i) by assigning tmpR[i] = -1
02793  *           Decrement tmpC[j] for all constraint(j) not in array 'Filter'.
02794  *        }
02795  *     }
02796  */
02797 static void addToFilter(int k, unsigned *Filter, SatMatrix *Sat,Value *tmpR,Value *tmpC,int NbRays,int NbConstraints) {
02798   
02799   int kj, i,j, jx;
02800   unsigned kb, bx;
02801   
02802   /* Remove constraint k */
02803   kj =   k/WSIZE; kb = MSB; kb >>= k%WSIZE;
02804   Filter[kj]|=kb;
02805   value_set_si(tmpC[k],-1);
02806   
02807   /* Remove rays excluded by constraint k */
02808   for(i=0; i<NbRays; i++)
02809     if (value_posz_p(tmpR[i])) {
02810       if (Sat->p[i][kj]&kb)
02811         value_decrement(tmpR[i],tmpR[i]);  /* adjust included ray */
02812       else {
02813         
02814         /* Constraint k excludes ray i -- delete ray i */
02815         value_set_si(tmpR[i],-1);
02816         
02817         /* Adjust non-deleted constraints */
02818         jx=0; bx=MSB;
02819         for(j=0; j<NbConstraints; j++) {
02820           if (value_posz_p(tmpC[j]) && (Sat->p[i][jx]&bx) )
02821             value_decrement(tmpC[j],tmpC[j]);
02822           NEXT(jx,bx);
02823         }
02824       }
02825     } 
02826 } /* addToFilter */
02827 
02828 /*
02829  * Given polyhedra 'P1' and 'P2' such that their intersection is an empty
02830  * polyhedron, find the minimal set of constraints of 'P1' which contradict
02831  * all of the constraints of 'P2'. This is believed to be an NP-hard problem
02832  * and so a heuristic is employed to solve it in worst case. The heuristic is 
02833  * to select in every turn that constraint of 'P1' which excludes most rays of
02834  * 'P2'. A bit in the binary format of an element of array 'Filter' is set to
02835  * 1 if the corresponding constraint is to be included in the minimal set of 
02836  * constraints otherwise it is set to 0.
02837  */
02838 static void FindSimple(Polyhedron *P1,Polyhedron *P2,unsigned *Filter,unsigned NbMaxRays) {
02839   
02840   Matrix *Mat = NULL;
02841   SatMatrix *Sat = NULL;
02842   int i, j, k, jx, found;
02843   Value *p1, *p2, p3;
02844   unsigned Dimension, NbRays, NbConstraints, bx, nc;
02845   Value NbConstraintsLeft, tmp;
02846   Value *tmpC = NULL, *tmpR = NULL;
02847   Polyhedron *Pol = NULL, *Pol2 = NULL;
02848   
02849   /* Initialize all the 'Value' variables */
02850   value_init(p3); value_init(NbConstraintsLeft);
02851   value_init(tmp);
02852  
02853   CATCH(any_exception_error) {
02854     if (tmpC) free(tmpC);
02855     if (tmpR) free(tmpR);
02856     if (Mat) Matrix_Free(Mat);
02857     if (Sat) SMFree(&Sat);
02858     if (Pol2 && Pol2!=P2) Polyhedron_Free(Pol2);
02859     if (Pol && Pol!=Pol2 && Pol!=P2) Polyhedron_Free(Pol);
02860     
02861     /* Clear all the 'Value' variables */
02862     value_clear(p3); value_clear(NbConstraintsLeft);
02863     value_clear(tmp);
02864     RETHROW();
02865   }
02866   TRY {
02867     
02868     Dimension = P1->Dimension+2;       /* status + homogeneous Dimension */
02869     Mat = Matrix_Alloc(P1->NbConstraints, Dimension);
02870     if(!Mat) {
02871       errormsg1("FindSimple", "outofmem", "out of memory space");
02872       UNCATCH(any_exception_error);
02873       
02874       /* Clear all the 'Value' variables */
02875       value_clear(p3); value_clear(NbConstraintsLeft); value_clear(tmp);  
02876       return;
02877     }
02878     
02879     /* Post constraints in P1 already included by Filter */
02880     jx = 0; bx = MSB; Mat->NbRows=0;
02881     value_set_si(NbConstraintsLeft,0);
02882     for (k=0; k<P1->NbConstraints; k++) {
02883       if (Filter[jx]&bx) {
02884         Vector_Copy(P1->Constraint[k], Mat->p[Mat->NbRows], Dimension);
02885         Mat->NbRows++;
02886       }
02887       else
02888         value_increment(NbConstraintsLeft,NbConstraintsLeft);
02889       NEXT(jx,bx);
02890     }
02891     Pol2 = P2;
02892     
02893     for (;;) {
02894       if (Mat->NbRows==0)
02895         Pol = Polyhedron_Copy(Pol2);
02896       else {
02897         Pol = AddConstraints(Mat->p_Init, Mat->NbRows, Pol2, NbMaxRays);
02898         if (Pol2 != P2) Polyhedron_Free(Pol2), Pol2 = NULL;
02899       }
02900       if (emptyQ(Pol)) {
02901         Matrix_Free(Mat), Mat = NULL;
02902         Polyhedron_Free(Pol), Pol = NULL;
02903         UNCATCH(any_exception_error);
02904         
02905         /* Clear all the 'Value' variables */
02906         value_clear(p3); value_clear(NbConstraintsLeft); value_clear(tmp);
02907         return;
02908       }
02909       Mat->NbRows = 0;        /* Reset Mat */
02910       Pol2 = Pol;
02911       
02912       /* Its not enough-- find some more constraints */
02913       Dimension         = Pol->Dimension+1;       /* homogeneous Dimension */
02914       NbRays            = Pol->NbRays;
02915       NbConstraints     = P1->NbConstraints;
02916       tmpR = (Value *)malloc(NbRays*sizeof(Value));
02917       if(!tmpR) {
02918         errormsg1("FindSimple", "outofmem", "out of memory space");
02919         UNCATCH(any_exception_error);
02920         
02921         /* Clear all the 'Value' variables */
02922         value_clear(p3); value_clear(NbConstraintsLeft); value_clear(tmp);  
02923         return;
02924       }
02925       for(i=0;i<NbRays;i++)
02926         value_init(tmpR[i]);
02927       tmpC = (Value *)malloc(NbConstraints*sizeof(Value));
02928       if(!tmpC) {
02929         errormsg1("FindSimple", "outofmem", "out of memory space");
02930         UNCATCH(any_exception_error);
02931         
02932         /* Clear all the 'Value' variables */
02933         value_clear(p3); value_clear(NbConstraintsLeft);
02934         for(i=0;i<NbRays;i++)
02935           value_clear(tmpR[i]);
02936         free(tmpR);
02937         return;
02938       }
02939       for(i=0;i<NbConstraints;i++)
02940         value_init(tmpC[i]);
02941       Vector_Set(tmpR,0,NbRays);
02942       Vector_Set(tmpC,0,NbConstraints);
02943       
02944       /* Build the Sat matrix */
02945       nc      = (NbConstraints - 1) / (sizeof(int)*8) + 1;
02946       Sat     = SMAlloc(NbRays, nc);
02947       Sat->NbRows = NbRays;
02948       SMVector_Init(Sat->p_init, nc*NbRays);
02949       
02950       jx=0; bx=MSB;
02951       for (k=0; k<NbConstraints; k++) {
02952         if (Filter[jx]&bx)
02953           value_set_si(tmpC[k],-1);
02954         else
02955           for (i=0; i<NbRays; i++) {
02956             p1 = Pol->Ray[i]+1;
02957             p2 = P1->Constraint[k]+1;
02958             value_set_si(p3,0);
02959             for (j=0; j<Dimension; j++) {
02960               value_multiply(tmp,*p1,*p2);
02961               value_addto(p3,p3,tmp);
02962               p1++; p2++;
02963             }
02964             if(value_zero_p(p3) ||
02965                (value_pos_p(p3) && value_notzero_p(P1->Constraint[k][0]))) {
02966               Sat->p[i][jx]|=bx;  /* constraint includes ray, set flag */
02967               value_increment(tmpR[i],tmpR[i]);
02968               value_increment(tmpC[k],tmpC[k]);
02969             }
02970           }
02971         NEXT(jx, bx);
02972       }
02973       
02974       do { /* find all of the essential constraints */
02975         found = 0;
02976         for(i=0; i<NbRays; i++)
02977           if(value_posz_p(tmpR[i])) {
02978             value_add_int(tmp,tmpR[i],1);
02979             if(value_eq(tmp,NbConstraintsLeft)) {
02980               
02981               /* Ray i is excluded by only one constraint... find it */
02982               jx = 0; bx = MSB;
02983               for(k=0; k<NbConstraints; k++) {
02984                 if(value_posz_p(tmpC[k]) && ((Sat->p[i][jx]&bx)==0)) {
02985                   addToFilter(k, Filter, Sat, tmpR, tmpC,
02986                               NbRays, NbConstraints);
02987                   Vector_Copy(P1->Constraint[k],
02988                               Mat->p[Mat->NbRows],Dimension+1);
02989                   Mat->NbRows++;
02990                   value_decrement(NbConstraintsLeft,NbConstraintsLeft);
02991                   found=1;
02992                   break;
02993                 }
02994                 NEXT(jx,bx);
02995               }
02996               break;
02997             }
02998           }
02999       }
03000       while (found);
03001      
03002       if (!Mat->NbRows) { /* Well then, just use a stupid heuristic */
03003         /* find the constraint which excludes the most */
03004         Value cmax;
03005         value_init(cmax);
03006         
03007 #ifndef LINEAR_VALUE_IS_CHARS
03008         
03009         /* the typechecking arithmetic lib does (of course) not
03010            recognize this one... */
03011         //value_assign(cmax,~((Value)1<<(sizeof(Value)*8-1)));
03012         value_set_si(cmax,(NbRays * NbConstraints+1));
03013 #else
03014         value_set_si(cmax,1);
03015 #endif
03016         
03017         j = -1;
03018         for(k=0; k<NbConstraints; k++)
03019           if (value_posz_p(tmpC[k])) {
03020             if (value_gt(cmax,tmpC[k])) {
03021               value_assign(cmax,tmpC[k]);
03022               j = k;
03023             }
03024           }
03025         value_clear(cmax);
03026         if (j<0) {
03027           errormsg1("DomSimplify","logerror","logic error");
03028         }
03029         else {
03030           addToFilter(j, Filter, Sat, tmpR, tmpC, NbRays, NbConstraints);
03031           Vector_Copy(P1->Constraint[j],Mat->p[Mat->NbRows],Dimension+1);
03032           Mat->NbRows++;
03033           value_decrement(NbConstraintsLeft,NbConstraintsLeft);
03034         }
03035       }
03036       SMFree(&Sat), Sat = NULL;
03037       free(tmpC), tmpC = NULL;
03038       free(tmpR), tmpR = NULL;
03039     }   
03040   } /* end of TRY */
03041   
03042   /* Clear all the 'Value' variables */
03043   value_clear(p3); value_clear(NbConstraintsLeft);
03044   value_clear(tmp);
03045   for(i=0;i<NbRays;i++)
03046     value_clear(tmpR[i]);
03047   for(i=0;i<NbRays;i++)
03048     value_clear(tmpC[i]);
03049   
03050   UNCATCH(any_exception_error);
03051 } /* FindSimple */
03052 
03053 /* 
03054  * Return 0 if the intersection of Pol1 and Pol2 is empty, otherwise return 1.
03055  * If the intersection is non-empty, store the non-redundant constraints in 
03056  * 'Filter' array. If the intersection is empty then store the smallest set of
03057  * constraints of 'Pol1' which on intersection with 'Pol2' gives empty set, in
03058  * 'Filter' array. 'NbMaxRays' is the maximum allowed rays in the intersection
03059  *  of 'Pol1' and 'Pol2'.   
03060  */
03061 static int SimplifyConstraints(Polyhedron *Pol1,Polyhedron *Pol2,unsigned *Filter,unsigned NbMaxRays) {
03062   
03063   Polyhedron *Pol = NULL;
03064   Matrix   *Mat = NULL, *Ray = NULL;
03065   SatMatrix *Sat = NULL;
03066   unsigned NbRay, NbCon, NbCon1, NbCon2, NbEle1, Dimension, notempty;
03067 
03068   CATCH(any_exception_error) {
03069     if (Pol) Polyhedron_Free(Pol);
03070     if (Mat) Matrix_Free(Mat);
03071     if (Ray) Matrix_Free(Ray);
03072     if (Sat) SMFree(&Sat);
03073     RETHROW();
03074   }
03075   TRY {
03076 
03077     NbRay         = Pol1->NbRays;
03078     NbCon1        = Pol1->NbConstraints;
03079     NbCon2        = Pol2->NbConstraints;
03080     NbCon         = NbCon1 + NbCon2;
03081     Dimension     = Pol1->Dimension+2;    /* Homogeneous Dimension + Status */
03082     NbEle1        = NbCon1*Dimension;
03083 
03084     if (NbRay > NbMaxRays)
03085       NbMaxRays = NbRay;
03086 
03087     /* Allocate space for constraint matrix 'Mat' */
03088     Mat = Matrix_Alloc(NbCon, Dimension);
03089     if(!Mat) {
03090       errormsg1("SimplifyConstraints", "outofmem", "out of memory space");
03091       UNCATCH(any_exception_error);
03092       return 0;
03093     }
03094 
03095     /* Copy constraints of 'Pol1' to matrix 'Mat' */
03096     Vector_Copy(Pol1->Constraint[0], Mat->p_Init, NbEle1);
03097     
03098     /* Add constraints of 'Pol2' to matrix 'Mat'*/
03099     Vector_Copy(Pol2->Constraint[0], Mat->p_Init+NbEle1, NbCon2*Dimension);
03100 
03101     /* Allocate space for ray matrix 'Ray' */
03102     Ray = Matrix_Alloc(NbMaxRays, Dimension);
03103     if(!Ray) {
03104       errormsg1("SimplifyConstraints", "outofmem", "out of memory space");
03105       UNCATCH(any_exception_error);
03106       return 0;
03107     }
03108     Ray->NbRows = NbRay;
03109         
03110     /* Copy rays of polyhedron 'Pol1' to matrix 'Ray' */
03111     Vector_Copy(Pol1->Ray[0], Ray->p_Init, NbRay*Dimension);
03112 
03113     /* Create saturation matrix from constraint matrix 'Mat' and ray matrix */
03114     /* 'Ray'.                                                               */
03115     Sat = BuildSat(Mat, Ray, NbCon1, NbMaxRays);
03116 
03117     /* Create the ray matrix 'Ray' from the constraint matrix 'Mat' */
03118     Pol_status = Chernikova(Mat, Ray, Sat, Pol1->NbBid, NbMaxRays, NbCon1,0);
03119 
03120     /* Remove redundant constraints from the constraint matrix 'Mat' */
03121     Pol = Remove_Redundants(Mat, Ray, Sat, Filter);
03122     notempty = 1;
03123     if (Filter && emptyQ(Pol)) {
03124       notempty = 0;
03125       FindSimple(Pol1, Pol2, Filter, NbMaxRays);
03126     }
03127     /* Polyhedron_Print(stderr,"%4d",Pol1); */
03128 
03129     Polyhedron_Free(Pol), Pol = NULL;
03130     SMFree(&Sat), Sat = NULL;
03131     Matrix_Free(Ray), Ray = NULL;
03132     Matrix_Free(Mat), Mat = NULL;
03133     
03134   } /* end of TRY */
03135 
03136   UNCATCH(any_exception_error);  
03137   return notempty;
03138 } /* SimplifyConstraints */
03139 
03140 /* 
03141  * Eliminate equations of Pol1 using equations of Pol2. Mark as needed, 
03142  * equations of Pol1 that are not eliminated. Or info into Filter vector. 
03143  */
03144 static void SimplifyEqualities(Polyhedron *Pol1, Polyhedron *Pol2, unsigned *Filter) {
03145 
03146   int i,j;
03147   unsigned ix, bx, NbEqn, NbEqn1, NbEqn2, NbEle2, Dimension;
03148   Matrix   *Mat;
03149 
03150   NbEqn1        = Pol1->NbEq;
03151   NbEqn2        = Pol2->NbEq;
03152   NbEqn         = NbEqn1 + NbEqn2;
03153   Dimension     = Pol1->Dimension+2;    /* Homogeneous Dimension + Status */
03154   NbEle2        = NbEqn2*Dimension;
03155 
03156   Mat = Matrix_Alloc(NbEqn, Dimension);
03157   if (!Mat) {
03158     errormsg1("SimplifyEqualities", "outofmem", "out of memory space");
03159     Pol_status = 1;
03160     return;
03161   }
03162 
03163   /* Set the equalities of Pol2 */
03164   Vector_Copy(Pol2->Constraint[0], Mat->p_Init, NbEle2);
03165 
03166   /* Add the equalities of Pol1 */
03167   Vector_Copy(Pol1->Constraint[0], Mat->p_Init+NbEle2, NbEqn1*Dimension);
03168 
03169   Gauss(Mat, NbEqn2, Dimension-1);
03170 
03171   ix = 0;
03172   bx = MSB;
03173   for (i=NbEqn2; i<NbEqn; i++) {
03174     for (j=1; j<Dimension; j++) {
03175       if (value_notzero_p(Mat->p[i][j])) { 
03176         /* If any coefficient of the equation is non-zero */    
03177         /* Set the filter bit for the equation */
03178         
03179         Filter[ix] |= bx;
03180         break;
03181       }
03182     }
03183     NEXT(ix,bx);
03184   }
03185   Matrix_Free(Mat);
03186   return;
03187 } /* SimplifyEqualities */
03188 
03189  
03190 /* 
03191  * Given two polyhedral domains 'Pol1' and 'Pol2', find the largest domain
03192  * set (or the smallest list of non-redundant constraints), that when 
03193  * intersected with polyhedral domain 'Pol2' equals (Pol1)intersect(Pol2).
03194  * The output is a polyhedral domain with the "redundant" constraints removed.
03195  * 'NbMaxRays' is the maximium allowed rays in the new polyhedra. 
03196  */
03197 Polyhedron *DomainSimplify(Polyhedron *Pol1, Polyhedron *Pol2, unsigned NbMaxRays) {
03198   
03199   Polyhedron *p1, *p2, *p3, *d;
03200   unsigned k, jx, bx, nbentries, NbConstraints, Dimension, NbCon, empty;
03201   unsigned *Filter;
03202   Matrix *Constraints;
03203   
03204 
03205   if (!Pol1 || !Pol2) return Pol1;
03206   if (Pol1->Dimension != Pol2->Dimension) {
03207     errormsg1("DomSimplify","diffdim","operation on different dimensions");
03208     Pol_status = 1;
03209     return 0;
03210   }
03211   if (emptyQ(Pol1)||emptyQ(Pol2)) 
03212     return Empty_Polyhedron(Pol1->Dimension);
03213 
03214   /* Find the maximum number of constraints over all polyhedron in the  */
03215   /* polyhedral domain 'Pol2' and store in 'NbCon'.                     */
03216   NbCon = 0;
03217   for (p2=Pol2; p2; p2=p2->next)
03218     if (p2->NbConstraints > NbCon) 
03219       NbCon = p2->NbConstraints;
03220   
03221   Dimension = Pol1->Dimension+2;     /* Homogenous Dimension + Status  */
03222   d = (Polyhedron *)0;
03223   for (p1=Pol1; p1; p1=p1->next) { 
03224     
03225     /* Filter is an array of integers, each bit in an element of Filter */
03226     /* array corresponds to a constraint. The bit is marked 1 if the    */
03227     /* corresponding constraint is non-redundant and is 0 if it is      */
03228     /* redundant.                                                       */
03229     
03230     NbConstraints = p1->NbConstraints;
03231     nbentries = (NbConstraints + NbCon - 1) / (sizeof(int)*8) + 1;
03232 
03233     /* Allocate space for array 'Filter' */
03234     Filter  = (unsigned *)malloc(nbentries * sizeof(int));
03235     if (!Filter) {
03236       errormsg1("DomSimplify", "outofmem", "out of memory space\n");
03237       Pol_status = 1;
03238       return 0;
03239     } 
03240     
03241     /* Initialize 'Filter' with zeros */
03242     SMVector_Init(Filter, nbentries);
03243     
03244     /* Filter the constraints of p1 in context of polyhedra p2(s) */
03245     empty = 1;
03246     for (p2=Pol2; p2; p2=p2->next) {
03247       
03248       /* Store the non-redundant constraints in array 'Filter'. With    */
03249       /* successive loops, the array 'Filter' holds the union of all    */
03250       /* non-redundant constraints. 'empty' is set to zero if the       */
03251       /* intersection of two polyhedra is non-empty and Filter is !Null */
03252       
03253       SimplifyEqualities(p1, p2, Filter);
03254       if (SimplifyConstraints(p1, p2, Filter, NbMaxRays)) 
03255         empty=0;      
03256             
03257       /* takes the union of all non redundant constraints */
03258     }
03259 
03260     if (!empty) {
03261       
03262       /* Copy all non-redundant constraints to matrix 'Constraints' */
03263       Constraints = Matrix_Alloc(NbConstraints, Dimension);
03264       if (!Constraints) {
03265         errormsg1("DomSimplify", "outofmem", "out of memory space\n");
03266         Pol_status = 1;
03267         return 0;
03268       }
03269       Constraints->NbRows = 0;
03270       for (k=0, jx=0, bx=MSB; k<NbConstraints; k++) {
03271 
03272         /* If a bit entry in Filter[jx] is marked 1, copy the correspond- */
03273         /* ing constraint in matrix 'Constraints'.                        */
03274         if (Filter[jx]&bx) { 
03275           Vector_Copy(p1->Constraint[k],
03276                       Constraints->p[Constraints->NbRows],
03277                       Dimension);
03278           Constraints->NbRows++;
03279         }
03280         NEXT(jx,bx);
03281       }
03282       
03283       /* Create the polyhedron 'p3' corresponding to the constraints in   */
03284       /* matrix 'Constraints'.                                            */
03285       p3 = Constraints2Polyhedron(Constraints,NbMaxRays);
03286       Matrix_Free(Constraints);
03287       
03288       /* Add polyhedron 'p3' in the domain 'd'. */
03289       d = AddPolyToDomain (p3, d);
03290       p3 = NULL;
03291     }
03292     free(Filter);
03293   }
03294   if (!d) 
03295     return Empty_Polyhedron(Pol1->Dimension); 
03296   else return d;
03297 
03298 } /* DomainSimplify */
03299 
03300 /*
03301  * Domain Simplify as defined in Strasborg Polylib version. 
03302  */
03303 Polyhedron *Stras_DomainSimplify(Polyhedron *Pol1,Polyhedron *Pol2,unsigned NbMaxRays) {
03304 
03305   Polyhedron *p1, *p2, *p3 = NULL, *d = NULL;
03306   unsigned k, jx, bx, nbentries, NbConstraints, Dimension, NbCon, empty;
03307   unsigned  *Filter = NULL;
03308   Matrix *Constraints = NULL;
03309   
03310   CATCH(any_exception_error) {
03311     if (Constraints) Matrix_Free(Constraints);
03312     if (Filter) free(Filter);
03313     if (d) Polyhedron_Free(d);
03314     if (p2) Polyhedron_Free(p3);
03315     RETHROW();
03316   }
03317   TRY {
03318     if (!Pol1 || !Pol2) {
03319       UNCATCH(any_exception_error);
03320       return Pol1;
03321     }
03322     if (Pol1->Dimension != Pol2->Dimension) {
03323       errormsg1("DomainSimplify","diffdim","operation on different dimensions");
03324       UNCATCH(any_exception_error);
03325       return 0;
03326     }
03327     if (emptyQ(Pol1)||emptyQ(Pol2)) {
03328       UNCATCH(any_exception_error);
03329       return Empty_Polyhedron(Pol1->Dimension);
03330     }
03331     
03332     /* Find the maximum number of constraints over all polyhedron in the  */
03333     /* polyhedral domain 'Pol2' and store in 'NbCon'.                     */
03334     NbCon = 0;
03335     for (p2=Pol2; p2; p2=p2->next)
03336       if (p2->NbConstraints > NbCon)
03337         NbCon = p2->NbConstraints;
03338     
03339     Dimension = Pol1->Dimension+2;      /* Homogenous Dimension + Status  */
03340     d = (Polyhedron *)0;
03341     for (p1=Pol1; p1; p1=p1->next) { 
03342 
03343       /* Filter is an array of integers, each bit in an element of Filter */
03344       /* array corresponds to a constraint. The bit is marked 1 if the    */
03345       /* corresponding constraint is non-redundant and is 0 if it is      */
03346       /* redundant.                                                       */
03347       
03348       NbConstraints = p1->NbConstraints;
03349       nbentries = (NbConstraints + NbCon - 1)/(sizeof(int)*8) + 1;
03350       
03351       /* Allocate space for array 'Filter' */
03352       Filter  = (unsigned *)malloc(nbentries * sizeof(int));
03353       if(!Filter) {
03354         errormsg1("DomainSimplify", "outofmem", "out of memory space");
03355         UNCATCH(any_exception_error);
03356         return 0;
03357       }
03358       
03359       /* Initialize 'Filter' with zeros */
03360       SMVector_Init(Filter, nbentries);
03361       
03362       /* Filter the constraints of p1 in context to the polyhedra p2(s)   */
03363       empty = 1;
03364       for (p2=Pol2; p2; p2=p2->next) {
03365         
03366         /* Store the non-redundant constraints in array 'Filter'. With    */
03367         /* successive loops, the array 'Filter' holds the union of all    */
03368         /* non-redundant constraints. 'empty' is set to zero if the       */
03369         /* intersection of two polyhedra is non-empty and Filter is !Null */
03370    
03371         if (SimplifyConstraints(p1, p2, Filter, NbMaxRays))
03372           empty=0;
03373       }
03374       
03375       if (!empty) {
03376         
03377         /* Copy all non-redundant constraints to matrix 'Constraints' */
03378         Constraints = Matrix_Alloc(NbConstraints,Dimension);
03379         if(!Constraints) {
03380           errormsg1("DomainSimplify", "outofmem", "out of memory space");
03381           UNCATCH(any_exception_error);
03382           return 0;
03383         }
03384         Constraints->NbRows = 0;
03385         for (k=0, jx=0, bx=MSB; k<NbConstraints; k++) {
03386           
03387           /* If a bit entry in Filter[jx] is marked 1, copy the correspond- */
03388           /* ing constraint in matrix 'Constraints'.                        */
03389           if (Filter[jx]&bx) { 
03390             Vector_Copy(p1->Constraint[k],
03391                         Constraints->p[Constraints->NbRows],
03392                         Dimension);
03393             Constraints->NbRows++;
03394           }
03395           NEXT(jx,bx);
03396         }
03397         
03398         /* Create the polyhedron 'p3' corresponding to the constraints in   */
03399         /* matrix 'Constraints'.                                            */
03400         p3 = Constraints2Polyhedron(Constraints,NbMaxRays);
03401         Matrix_Free(Constraints), Constraints = NULL;
03402         
03403         /* Add polyhedron 'p3' in the domain 'd'. */
03404         d = AddPolyToDomain (p3, d);
03405         p3 = NULL;
03406       }
03407       free(Filter), Filter = NULL;
03408     }
03409   } /* end of TRY */
03410         
03411   UNCATCH(any_exception_error);  
03412   if (!d)
03413     return Empty_Polyhedron(Pol1->Dimension);
03414   else
03415     return d;
03416 } /* DomainSimplify */
03417 
03418 /*
03419  * Return the Union of two polyhedral domains 'Pol1' and Pol2'. The result is
03420  * a new polyhedral domain.
03421  */
03422 Polyhedron *DomainUnion(Polyhedron *Pol1,Polyhedron *Pol2,unsigned NbMaxRays) {
03423 
03424   Polyhedron *PolA, *PolEndA, *PolB, *PolEndB, *p1, *p2;
03425   int Redundant;
03426   
03427   if (!Pol1 || !Pol2) return (Polyhedron *) 0;
03428   if (Pol1->Dimension != Pol2->Dimension) {
03429     errormsg1("DomainUnion","diffdim","operation on different dimensions");
03430     return (Polyhedron*) 0;
03431   }
03432 
03433 
03434 
03435 
03436 
03437 
03438   /* Copy 'Pol1' to 'PolA' */
03439   PolA = PolEndA = (Polyhedron *)0;
03440   for (p1=Pol1; p1; p1=p1->next) {
03441     
03442     /* Does any component of 'Pol2' cover 'p1' ? */
03443     Redundant = 0;
03444     for (p2=Pol2; p2; p2=p2->next) {
03445       if (PolyhedronIncludes(p2, p1) ) { /* p2 covers p1 */ 
03446         Redundant = 1;
03447         
03448 
03449         break;
03450 
03451       }
03452     }
03453     if (!Redundant) {
03454       
03455       /* Add 'p1' to 'PolA' */
03456       if (!PolEndA)
03457         PolEndA = PolA = Polyhedron_Copy(p1);
03458       else {
03459         PolEndA->next = Polyhedron_Copy(p1);
03460         PolEndA = PolEndA->next;
03461       }
03462 
03463     }
03464   }
03465 
03466   /* Copy 'Pol2' to PolB */
03467   PolB = PolEndB = (Polyhedron *)0;
03468   for (p2=Pol2; p2; p2=p2->next) {
03469 
03470     /* Does any component of PolA cover 'p2' ? */
03471     Redundant = 0;
03472     for (p1=PolA; p1; p1=p1->next) {
03473       if (PolyhedronIncludes(p1, p2)) { /* p1 covers p2 */
03474         Redundant = 1;
03475         break;
03476       }
03477     }
03478     if (!Redundant) {
03479       
03480       /* Add 'p2' to 'PolB' */
03481       if (!PolEndB)
03482         PolEndB = PolB = Polyhedron_Copy(p2);
03483       else {
03484         PolEndB->next = Polyhedron_Copy(p2);
03485         PolEndB = PolEndB->next;
03486       }
03487 
03488 
03489     }
03490   }
03491 
03492   if (!PolA) return PolB;
03493   PolEndA->next = PolB;
03494   return PolA;
03495 } /* DomainUnion */
03496 
03497 /* 
03498  * Given a polyhedral domain 'Pol', concatenate the lists of rays and lines 
03499  * of the two (or more) polyhedra in the domain into one combined list, and 
03500  * find the set of constraints which tightly bound all of those objects. 
03501  * 'NbMaxConstrs' is the maximum allowed constraints in the new polyhedron. 
03502  */ 
03503 Polyhedron *DomainConvex(Polyhedron *Pol,unsigned NbMaxConstrs) {
03504   
03505   Polyhedron *p, *q, *NewPol = NULL;
03506   
03507   CATCH(any_exception_error) {
03508     if (NewPol) Polyhedron_Free(NewPol);
03509     RETHROW();
03510   }
03511   TRY {
03512     
03513     if (!Pol) {
03514       UNCATCH(any_exception_error);
03515       return (Polyhedron*) 0;
03516     }
03517     
03518     NewPol = Polyhedron_Copy(Pol);
03519     for (p=Pol->next; p; p=p->next) {
03520       q = AddRays(p->Ray[0], p->NbRays, NewPol, NbMaxConstrs);
03521       Polyhedron_Free(NewPol);
03522       NewPol = q;
03523     }
03524   } /* end of TRY */
03525   
03526   UNCATCH(any_exception_error);
03527   
03528   return NewPol;
03529 } /* DomainConvex */
03530 
03531 /*
03532  * Given polyhedral domains 'Pol1' and 'Pol2', create a new polyhedral 
03533  * domain which is mathematically the differnce of the two domains. 
03534  */
03535 Polyhedron *DomainDifference(Polyhedron *Pol1,Polyhedron *Pol2,unsigned NbMaxRays) {
03536 
03537   Polyhedron *p1, *p2, *p3, *d;
03538   int i;
03539   
03540   if (!Pol1 || !Pol2) return (Polyhedron*) 0;
03541   if (Pol1->Dimension != Pol2->Dimension) {
03542     errormsg1("DomainDifference", 
03543               "diffdim", "operation on different dimensions");
03544     return (Polyhedron*) 0;
03545   }
03546   if (emptyQ(Pol1) || emptyQ(Pol2))
03547     return (Domain_Copy(Pol1));
03548   d = (Polyhedron *)0;
03549   for (p2=Pol2; p2; p2=p2->next) {
03550     for (p1=Pol1; p1; p1=p1->next) {
03551       for (i=0; i<p2->NbConstraints; i++) {
03552         
03553         /* Add the constraint ( -p2->constraint[i] -1) >= 0 in 'p1' */
03554         /* and create the new polyhedron 'p3'.                      */
03555         p3 = SubConstraint(p2->Constraint[i], p1, NbMaxRays,0);
03556         
03557         /* Add 'p3' in the new domain 'd' */
03558         d = AddPolyToDomain (p3, d);
03559         
03560         /* If the constraint p2->constraint[i][0] is an equality, then  */
03561         /* add the constraint ( +p2->constraint[i] -1) >= 0  in 'p1' and*/
03562         /* create the new polyhedron 'p3'.                              */
03563         
03564         if( value_notzero_p(p2->Constraint[i][0]) ) /* Inequality */
03565           continue;  
03566         p3 = SubConstraint(p2->Constraint[i], p1, NbMaxRays,1);
03567         
03568         /* Add 'p3' in the new domain 'd' */
03569         d = AddPolyToDomain (p3, d);
03570       }
03571     }
03572     if (p2 != Pol2)
03573         Domain_Free(Pol1);
03574     Pol1 = d;
03575     d = (Polyhedron *)0;
03576   }
03577   if (!Pol1)
03578     return Empty_Polyhedron(Pol2->Dimension);
03579   else
03580     return Pol1;
03581 } /* DomainDifference */
03582 
03583 /*
03584  * Given a polyhedral domain 'Pol', convert it to a new polyhedral domain 
03585  * with dimension expanded to 'align_dimension'. 'NbMaxRays' is the maximum
03586  * allowed rays in the new polyhedra.
03587  */
03588 Polyhedron *align_context(Polyhedron *Pol,int align_dimension,int NbMaxRays) {
03589   
03590   int i, j, k;
03591   Polyhedron *p = NULL, *q, *result = NULL;
03592   Matrix *Mat = NULL;
03593 
03594   CATCH(any_exception_error) {
03595     if (Mat) Matrix_Free(Mat);
03596     if (result) Polyhedron_Free(result);
03597     RETHROW();
03598   }
03599   TRY {
03600     
03601     if (!Pol) return Pol;
03602     if (align_dimension < Pol->Dimension) {
03603       errormsg1("align_context", "diffdim", "context dimension exceeds data");
03604       UNCATCH(any_exception_error);
03605       return Pol;
03606     }
03607     if (align_dimension == Pol->Dimension) {
03608       UNCATCH(any_exception_error);
03609       return Polyhedron_Copy(Pol);
03610     }
03611 
03612     /* 'k' is the dimension increment */
03613     k = align_dimension - Pol->Dimension;
03614     result = NULL;
03615     p = NULL;
03616 
03617     /* Expand the dimension of all polyhedron in the polyhedral domain 'Pol' */
03618     for (; Pol; Pol=Pol->next) {
03619       q = p;
03620       
03621       /* Allocate space for the new constraint matrix with dimension expanded*/
03622       /* to align_dimension.                                                 */
03623       Mat = Matrix_Alloc(Pol->NbConstraints, align_dimension + 2);
03624       if(!Mat) {
03625         errormsg1("align_context", "outofmem", "out of memory space");
03626         UNCATCH(any_exception_error);
03627         return 0;
03628       }
03629       
03630       /* Initialize the constraint matrix 'Mat' with zeros. */         
03631       Vector_Set(Mat->p[0],0,(Pol->NbConstraints) * (align_dimension + 2));
03632       
03633       /* Each constraint in 'Pol' is mapped to k-zeros followed by the */
03634       /* constraint and is stored in constraint matrix 'Mat'.          */ 
03635       for (i=0; i<Pol->NbConstraints; i++) {
03636         for (j=1; j<=Pol->Dimension+1;j++) {
03637           value_assign(Mat->p[i][k+j], Pol->Constraint[i][j]);
03638         }
03639         value_assign(Mat->p[i][0], Pol->Constraint[i][0]);  /* Status bit */
03640       }
03641       
03642       /* Convert the constraint matrix 'Mat' into an equivalent polyhedron. */
03643       p = Constraints2Polyhedron(Mat, NbMaxRays);
03644       if (q) q->next = p; else result = p;
03645       Matrix_Free(Mat), Mat = NULL;
03646     }
03647   } /* end of TRY */
03648   
03649   UNCATCH(any_exception_error); 
03650   return result;
03651 } /* align_context */
03652 
03653 /*----------------------------------------------------------------------*/
03654 /* Polyhedron *Polyhedron_Scan(D, C, NbMaxRays)                         */
03655 /*       D : Domain to be scanned (single polyhedron only)              */
03656 /*       C : Context domain                                             */
03657 /*       NbMaxRays : Workspace size                                     */
03658 /* Returns a linked list of scan domains, outer loop first              */
03659 /*----------------------------------------------------------------------*/
03660 Polyhedron *Polyhedron_Scan(Polyhedron *D, Polyhedron *C,unsigned NbMaxRays) {
03661   
03662   int i, j, dim ;
03663   Matrix *Mat;
03664   Polyhedron *C1, *C2, *D1, *D2;
03665   Polyhedron *res, *last, *tmp;
03666   
03667   dim = D->Dimension - C->Dimension;
03668   res = last = (Polyhedron *) 0;
03669   if (dim==0) return (Polyhedron *)0;
03670   
03671   /* Allocate space for constraint matrix. */
03672   Mat   = Matrix_Alloc(D->Dimension, D->Dimension+2);
03673   if(!Mat) {
03674     errormsg1("Polyhedron_Scan", "outofmem", "out of memory space");
03675     return 0;
03676   }
03677   C1  = align_context(C,D->Dimension,NbMaxRays);
03678   if(!C1) {
03679     return 0;
03680   }
03681   /* Vin100, aug 16, 2001:  The context is intersected with D */
03682   D2 = DomainIntersection( C1, D, NbMaxRays);
03683 
03684   for (i=0; i<dim; i++)
03685   {
03686     Vector_Set(Mat->p_Init,0,D2->Dimension*(D2->Dimension + 2));
03687     for (j=i+1; j<dim; j++) {
03688       value_set_si(Mat->p[j-i-1][j+1],1);
03689     }
03690     Mat->NbRows = dim-i-1;
03691     D1 = Mat->NbRows ? DomainAddRays(D2, Mat, NbMaxRays) : D2;
03692     tmp = DomainSimplify(D1, C1, NbMaxRays);
03693     if (!last) res = last = tmp;
03694     else { last->next = tmp; last = tmp; }
03695     C2 = DomainIntersection(C1, D1, NbMaxRays);
03696     Domain_Free(C1);
03697     C1 = C2;
03698     if (Mat->NbRows) Domain_Free(D1);
03699   }
03700   Domain_Free(D2);
03701   Domain_Free(C1);
03702   Matrix_Free(Mat);
03703   return res;
03704 } /* Polyhedron_Scan */
03705 
03706 /*---------------------------------------------------------------------*/
03707 /* int lower_upper_bounds(pos,P,context,LBp,UBp)                       */
03708 /*    pos : index position of current loop index (1..hdim-1)           */
03709 /*    P: loop domain                                                   */
03710 /*    context : context values for fixed indices                       */
03711 /*              notice that context[hdim] must be 1                    */
03712 /*    LBp, UBp : pointers to resulting bounds                          */
03713 /* returns the flag = (UB_INFINITY, LB_INFINITY)                       */
03714 /*---------------------------------------------------------------------*/
03715 int lower_upper_bounds(int pos,Polyhedron *P,Value *context,Value *LBp,Value *UBp) {
03716   
03717   Value LB, UB;
03718   int flag, i;
03719   Value n, n1, d, tmp;
03720   
03721   /* Initialize all the 'Value' variables */
03722   value_init(LB); value_init(UB); value_init(tmp);
03723   value_init(n); value_init(n1); value_init(d);
03724   
03725   value_set_si(LB,0);
03726   value_set_si(UB,0);
03727   
03728   /* Compute Upper Bound and Lower Bound for current loop */
03729   flag = LB_INFINITY | UB_INFINITY;
03730   for (i=0; i<P->NbConstraints; i++) {
03731     value_assign(d,P->Constraint[i][pos]);
03732     if (value_zero_p(d)) continue;    
03733     Inner_Product(&context[1],&(P->Constraint[i][1]),P->Dimension+1,&n);
03734     value_oppose(n,n);
03735     
03736     /*---------------------------------------------------*/
03737     /* Compute n/d        n/d<0              n/d>0       */
03738     /*---------------------------------------------------*/
03739     /*  n%d == 0    floor   = n/d      floor   = n/d     */
03740     /*              ceiling = n/d      ceiling = n/d     */
03741     /*---------------------------------------------------*/
03742     /*  n%d != 0    floor   = n/d - 1  floor   = n/d     */
03743     /*              ceiling = n/d      ceiling = n/d + 1 */
03744     /*---------------------------------------------------*/
03745 
03746     /* Check to see if constraint is inequality */
03747     /* if constraint is equality, both upper and lower bounds are fixed */
03748     if(value_zero_p(P->Constraint[i][0])) {     /* Equality */
03749       value_modulus(tmp,n,d);
03750       
03751       /* if not integer, return 0; */
03752       if(value_notzero_p(tmp)) {
03753         value_set_si(*LBp,1);
03754         value_set_si(*UBp,0);   /* empty loop */
03755         
03756         /* Clear all the 'Value' variables */
03757         value_clear(LB); value_clear(UB); value_clear(tmp);
03758         value_clear(n); value_clear(n1); value_clear(d);
03759         return 0;
03760       }
03761       value_division(n1,n,d);
03762       
03763       /* Upper and Lower bounds found */
03764       if((flag&LB_INFINITY) || value_gt(n1,LB))
03765         value_assign(LB,n1);
03766       if((flag&UB_INFINITY) || value_lt(n1,UB))
03767         value_assign(UB,n1);
03768       flag = 0;
03769     }
03770     
03771     if (value_pos_p(d)) {  /* Lower Bound */
03772       value_modulus(tmp,n,d);
03773       
03774       /* n1 = ceiling(n/d) */
03775       if (value_pos_p(n) && value_notzero_p(tmp)) {
03776         value_division(n1,n,d);
03777         value_add_int(n1,n1,1);
03778       }
03779       else
03780         value_division(n1,n,d);
03781       if (flag&LB_INFINITY) {
03782         value_assign(LB,n1); 
03783         flag^=LB_INFINITY; 
03784       }
03785       else if(value_gt(n1,LB))
03786         value_assign(LB,n1);
03787     }
03788     
03789     if (value_neg_p(d)) {   /* Upper Bound */
03790       value_modulus(tmp,n,d);
03791       
03792       /* n1 = floor(n/d) */
03793       if (value_pos_p(n) && value_notzero_p(tmp)) {
03794         value_division(n1,n,d);
03795         value_sub_int(n1,n1,1);
03796       }
03797       else
03798         value_division(n1,n,d);
03799       
03800       if (flag&UB_INFINITY) {
03801         value_assign(UB,n1); 
03802         flag^=UB_INFINITY; 
03803       }
03804       else if (value_lt(n1,UB))
03805         value_assign(UB, n1);
03806     }
03807   }
03808   if ((flag & LB_INFINITY)==0) value_assign(*LBp,LB);
03809   if ((flag & UB_INFINITY)==0) value_assign(*UBp,UB);
03810   
03811   /* Clear all the 'Value' variables */
03812   value_clear(LB); value_clear(UB); value_clear(tmp);
03813   value_clear(n); value_clear(n1); value_clear(d);
03814   return flag;
03815 } /* lower_upper_bounds */
03816 
03817 /*
03818  *  C = A x B
03819  */
03820 static void Rays_Mult(Value **A, Matrix *B, Value **C, unsigned NbRays)
03821 {
03822   int i, j, k;
03823   unsigned Dimension1, Dimension2;
03824   Value Sum, tmp;
03825 
03826   value_init(Sum); value_init(tmp);
03827 
03828   CATCH(any_exception_error) {
03829     value_clear(Sum); value_clear(tmp);
03830     RETHROW();
03831   }
03832   TRY {
03833     Dimension1 = B->NbRows;
03834     Dimension2 = B->NbColumns;
03835 
03836     for (i=0; i<NbRays; i++) {
03837       value_assign(C[i][0],A[i][0]);
03838       for (j=0; j<Dimension2; j++) {
03839         value_set_si(Sum,0);
03840         for (k=0; k<Dimension1; k++) {
03841           
03842           /* Sum+=A[i][k+1] * B->p[k][j]; */
03843           value_multiply(tmp,A[i][k+1],B->p[k][j]);
03844           value_addto(Sum,Sum,tmp);
03845         }
03846         value_assign(C[i][j+1],Sum);
03847       }
03848       Vector_Gcd(C[i]+1, Dimension2, &tmp);
03849       if (value_notone_p(tmp))
03850           Vector_AntiScale(C[i]+1, C[i]+1, tmp, Dimension2);
03851     }
03852   }
03853   UNCATCH(any_exception_error);
03854   value_clear(Sum); value_clear(tmp);
03855 }
03856 
03857 /*
03858  *  C = A x B^T
03859  */
03860 static void Rays_Mult_Transpose(Value **A, Matrix *B, Value **C, 
03861                                 unsigned NbRays)
03862 {
03863   int i, j, k;
03864   unsigned Dimension1, Dimension2;
03865   Value Sum, tmp;
03866 
03867   value_init(Sum); value_init(tmp);
03868 
03869   CATCH(any_exception_error) {
03870     value_clear(Sum); value_clear(tmp);
03871     RETHROW();
03872   }
03873   TRY {
03874     Dimension1 = B->NbColumns;
03875     Dimension2 = B->NbRows;
03876 
03877     for (i=0; i<NbRays; i++) {
03878       value_assign(C[i][0],A[i][0]);
03879       for (j=0; j<Dimension2; j++) {
03880         value_set_si(Sum,0);
03881         for (k=0; k<Dimension1; k++) {
03882           
03883           /* Sum+=A[i][k+1] * B->p[j][k]; */
03884           value_multiply(tmp,A[i][k+1],B->p[j][k]);
03885           value_addto(Sum,Sum,tmp);
03886         }
03887         value_assign(C[i][j+1],Sum);
03888       }
03889       Vector_Gcd(C[i]+1, Dimension2, &tmp);
03890       if (value_notone_p(tmp))
03891           Vector_AntiScale(C[i]+1, C[i]+1, tmp, Dimension2);
03892     }
03893   }
03894   UNCATCH(any_exception_error);
03895   value_clear(Sum); value_clear(tmp);
03896 }
03897 
03898 /*
03899  * Given a polyhedron 'Pol' and a transformation matrix 'Func', return the 
03900  * polyhedron which when transformed by mapping function 'Func' gives 'Pol'. 
03901  * 'NbMaxRays' is the maximum number of rays that can be in the ray matrix 
03902  * of the resulting polyhedron.
03903  */
03904 Polyhedron *Polyhedron_Preimage(Polyhedron *Pol,Matrix *Func,unsigned NbMaxRays) {
03905 
03906   Matrix *Constraints = NULL;
03907   Polyhedron *NewPol = NULL;
03908   unsigned NbConstraints, Dimension1, Dimension2;
03909   
03910   CATCH(any_exception_error) {
03911     if (Constraints) Matrix_Free(Constraints);
03912     if (NewPol) Polyhedron_Free(NewPol);
03913     RETHROW();
03914   }
03915   TRY {
03916     
03917     NbConstraints = Pol->NbConstraints;
03918     Dimension1    = Pol->Dimension+1;   /* Homogeneous Dimension */
03919     Dimension2    = Func->NbColumns;    /* Homogeneous Dimension */
03920     if (Dimension1!=(Func->NbRows)) {
03921       errormsg1("Polyhedron_Preimage", "dimincomp", "incompatable dimensions");
03922       UNCATCH(any_exception_error);
03923       return Empty_Polyhedron(Dimension2-1);
03924     }
03925     
03926     /*            Dim1           Dim2            Dim2
03927                   __k__          __j__           __j__  
03928             NbCon |   |  X   Dim1|   |  =  NbCon |   |
03929               i   |___|       k  |___|       i   |___|
03930             Pol->Constraints Function        Constraints
03931     */
03932   
03933     /* Allocate space for the resultant constraint matrix */
03934     Constraints = Matrix_Alloc(NbConstraints, Dimension2+1);
03935     if (!Constraints) { 
03936       errormsg1("Polyhedron_Preimage", "outofmem", "out of memory space\n");
03937       Pol_status = 1;
03938       UNCATCH(any_exception_error);
03939       return 0;
03940     }
03941     
03942     /* The new constraint matrix is the product of constraint matrix of the */
03943     /* polyhedron and the function matrix.                                  */
03944     Rays_Mult(Pol->Constraint, Func, Constraints->p, NbConstraints);
03945     NewPol = Constraints2Polyhedron(Constraints, NbMaxRays);
03946     Matrix_Free(Constraints), Constraints = NULL;
03947     
03948   } /* end of TRY */
03949   
03950   UNCATCH(any_exception_error);
03951   
03952   return NewPol;
03953 } /* Polyhedron_Preimage */
03954 
03955 /*
03956  * Given a polyhedral domain 'Pol' and a transformation matrix 'Func', return 
03957  * the polyhedral domain which when transformed by mapping function 'Func' 
03958  * gives 'Pol'. 'NbMaxRays' is the maximum number of rays that can be in the 
03959  * ray matrix of the resulting domain.
03960  */
03961 Polyhedron *DomainPreimage(Polyhedron *Pol,Matrix *Func,unsigned NbMaxRays) {
03962   
03963   Polyhedron *p, *q, *d = NULL;
03964   
03965   CATCH(any_exception_error) {
03966     if (d) Polyhedron_Free(d);
03967     RETHROW();
03968   }
03969   TRY {
03970     if (!Pol || !Func) {
03971       UNCATCH(any_exception_error);
03972       return (Polyhedron *) 0;
03973     }
03974     d = (Polyhedron *) 0;
03975     for (p=Pol; p; p=p->next) {
03976       q = Polyhedron_Preimage(p, Func, NbMaxRays);
03977       d = AddPolyToDomain (q, d);
03978     } 
03979   } /* end of TRY */
03980   UNCATCH(any_exception_error);
03981   return d;
03982 } /* DomainPreimage */
03983 
03984 /*
03985  * Transform a polyhedron 'Pol' into another polyhedron according to a given
03986  * affine mapping function 'Func'. 'NbMaxConstrs' is the maximum number of 
03987  * constraints that can be in the constraint matrix of the new polyhedron. 
03988  */
03989 Polyhedron *Polyhedron_Image(Polyhedron *Pol, Matrix *Func,unsigned NbMaxConstrs) {
03990   
03991   Matrix *Rays = NULL;
03992   Polyhedron *NewPol = NULL;
03993   unsigned NbRays, Dimension1, Dimension2;
03994   
03995   CATCH(any_exception_error) {
03996     if (Rays) Matrix_Free(Rays);
03997     if (NewPol) Polyhedron_Free(NewPol);
03998     RETHROW();
03999   }
04000   TRY {
04001   
04002     NbRays     = Pol->NbRays;
04003     Dimension1 = Pol->Dimension+1;      /* Homogeneous Dimension */
04004     Dimension2 = Func->NbRows;          /* Homogeneous Dimension */
04005     if (Dimension1!=Func->NbColumns) {
04006       errormsg1("Polyhedron_Image", "dimincomp", "incompatable dimensions");
04007       UNCATCH(any_exception_error);
04008       return Empty_Polyhedron(Dimension2-1);
04009     }
04010     
04011     /*   
04012         Dim1     /      Dim1  \Transpose      Dim2
04013         __k__    |      __k__ |              __j__
04014   NbRays|   |  X | Dim2 |   | |     =  NbRays|   |
04015     i   |___|    |   j  |___| |          i   |___|
04016      Pol->Rays  \       Func /               Rays
04017 
04018     */
04019 
04020     if (Dimension1 == Dimension2) {
04021         Matrix *M, *M2;
04022         int ok;
04023         M = Matrix_Copy(Func);
04024         M2 = Matrix_Alloc(Dimension2, Dimension1);
04025         if (!M2) {
04026           errormsg1("Polyhedron_Image", "outofmem", "out of memory space\n");
04027           UNCATCH(any_exception_error);
04028           return 0;
04029         }
04030 
04031         ok = Matrix_Inverse(M, M2);
04032         Matrix_Free(M);
04033         if (ok) {
04034             NewPol = Polyhedron_Alloc(Pol->Dimension, Pol->NbConstraints,
04035                                       Pol->NbRays);
04036             if (!NewPol) {
04037               errormsg1("Polyhedron_Image", "outofmem", 
04038                         "out of memory space\n");
04039               UNCATCH(any_exception_error);
04040               return 0;
04041             }
04042             Rays_Mult_Transpose(Pol->Ray, Func, NewPol->Ray, NbRays);
04043             Rays_Mult(Pol->Constraint, M2, NewPol->Constraint, 
04044                       Pol->NbConstraints);
04045             NewPol->NbEq = Pol->NbEq;
04046             NewPol->NbBid = Pol->NbBid;
04047             if (NewPol->NbEq)
04048               Gauss4(NewPol->Constraint, NewPol->NbEq, NewPol->NbConstraints,
04049                      NewPol->Dimension+1);
04050             if (NewPol->NbBid)
04051               Gauss4(NewPol->Ray, NewPol->NbBid, NewPol->NbRays,
04052                      NewPol->Dimension+1);
04053         }
04054         Matrix_Free(M2);
04055     }
04056     
04057     
04058     if (!NewPol) {
04059         /* Allocate space for the resultant ray matrix */
04060         Rays = Matrix_Alloc(NbRays, Dimension2+1);
04061         if (!Rays) {
04062           errormsg1("Polyhedron_Image", "outofmem", "out of memory space\n");
04063           UNCATCH(any_exception_error);
04064           return 0;
04065         }
04066         
04067         /* The new ray space is the product of ray matrix of the polyhedron and */
04068         /* the transpose matrix of the mapping function.                        */
04069         Rays_Mult_Transpose(Pol->Ray, Func, Rays->p, NbRays);
04070         NewPol = Rays2Polyhedron(Rays, NbMaxConstrs);
04071         Matrix_Free(Rays), Rays = NULL;
04072     }
04073     
04074   } /* end of TRY */
04075 
04076   UNCATCH(any_exception_error);
04077   return NewPol;
04078 } /* Polyhedron_Image */
04079 
04080 /* 
04081  *Transform a polyhedral domain 'Pol' into another domain according to a given
04082  * affine mapping function 'Func'. 'NbMaxConstrs' is the maximum number of 
04083  * constraints that can be in the constraint matrix of the resulting domain. 
04084  */
04085 Polyhedron *DomainImage(Polyhedron *Pol,Matrix *Func,unsigned NbMaxConstrs) {
04086 
04087   Polyhedron *p, *q, *d = NULL;
04088 
04089   CATCH(any_exception_error) {
04090     if (d) Polyhedron_Free(d);
04091     RETHROW();
04092   }
04093   TRY {
04094     
04095     if (!Pol || !Func) {
04096       UNCATCH(any_exception_error);
04097       return (Polyhedron *) 0;
04098     }
04099     d = (Polyhedron *) 0;
04100     for (p=Pol; p; p=p->next) { 
04101       q = Polyhedron_Image(p, Func, NbMaxConstrs);
04102       d = AddPolyToDomain (q, d);
04103     }
04104   } /* end of TRY */
04105   
04106   UNCATCH(any_exception_error);
04107   
04108   return d;
04109 } /* DomainImage */
04110 
04111 /* 
04112  * Given a polyhedron 'Pol' and an affine cost function 'Cost', compute the 
04113  * maximum and minimum value of the function over set of points representing
04114  * polyhedron. 
04115  * Note: If Polyhedron 'Pol' is empty, then there is no feasible solution. 
04116  * Otherwise, if there is a bidirectional ray with Sum[cost(i)*ray(i)] != 0 or
04117  * a unidirectional ray with Sum[cost(i)*ray(i)] >0, then the maximum is un-
04118  * bounded else the finite optimal solution occurs at one of the vertices of
04119  * the polyhderon. 
04120  */
04121 Interval *DomainCost(Polyhedron *Pol,Value *Cost) {
04122   
04123   int i, j, NbRay, Dim;
04124   Value *p1, *p2, p3, d, status;
04125   Value tmp1, tmp2, tmp3;
04126   Value **Ray;
04127   Interval *I = NULL;
04128 
04129   value_init(p3); value_init(d); value_init(status);
04130   value_init(tmp1); value_init(tmp2); value_init(tmp3);
04131 
04132   CATCH(any_exception_error) {
04133     if (I) free(I);
04134     RETHROW();
04135     value_clear(p3); value_clear(d); value_clear(status);
04136     value_clear(tmp1); value_clear(tmp2); value_clear(tmp3);
04137   }
04138   TRY {
04139     
04140     Ray = Pol->Ray;
04141     NbRay = Pol->NbRays;
04142     Dim = Pol->Dimension+1;             /* Homogenous Dimension */
04143     I = (Interval *) malloc (sizeof(Interval));
04144     if (!I) {
04145       errormsg1("DomainCost", "outofmem", "out of memory space\n");
04146       UNCATCH(any_exception_error);
04147       value_clear(p3); value_clear(d); value_clear(status);
04148       value_clear(tmp1); value_clear(tmp2); value_clear(tmp3);
04149       return 0;
04150     }
04151     
04152     /* The maximum and minimum values of the cost function over polyhedral  */
04153     /* domain is stored in 'I'. I->MaxN and I->MaxD store the numerator and */
04154     /* denominator of the maximum value. Likewise,I->MinN and I->MinD store */
04155     /* the numerator and denominator of the minimum value. I->MaxI and      */
04156     /* I->MinI store the ray indices corresponding to the max and min values*/
04157     /* of the function.                                                     */
04158     
04159     value_set_si(I->MaxN,-1);
04160     value_set_si(I->MaxD,0);          /* Actual cost is MaxN/MaxD */
04161     I->MaxI = -1;
04162     value_set_si(I->MinN,1);
04163     value_set_si(I->MinD,0);
04164     I->MinI = -1;
04165     
04166     /* Compute the cost of each ray[i] */
04167     for (i=0; i<NbRay; i++) {
04168       p1 = Ray[i];
04169       value_assign(status, *p1);
04170       p1++;
04171       p2 = Cost;
04172       
04173       /* p3 = *p1++ * *p2++; */
04174       value_multiply(p3,*p1,*p2);
04175       p1++; p2++;
04176       for (j=1; j<Dim; j++) {
04177         value_multiply(tmp1,*p1,*p2);
04178         
04179         /* p3 += *p1++ * *p2++; */
04180         value_addto(p3,p3,tmp1);
04181         p1++; p2++;
04182       }
04183       
04184       /* d = *--p1; */
04185       p1--;
04186       value_assign(d,*p1); /* d == 0 for lines and ray, non-zero for vertex */
04187       value_multiply(tmp1,p3,I->MaxD); 
04188       value_multiply(tmp2,I->MaxN,d);
04189       value_set_si(tmp3,1);
04190       
04191       /* Compare p3/d with MaxN/MaxD to assign new maximum cost value */
04192       if (I->MaxI==-1 ||
04193           value_gt(tmp1,tmp2) ||
04194           (value_eq(tmp1,tmp2) &&
04195            value_eq(d,tmp3) && value_ne(I->MaxD,tmp3))) {
04196         value_assign(I->MaxN,p3);
04197         value_assign(I->MaxD,d);
04198         I->MaxI = i;
04199       }
04200       value_multiply(tmp1,p3,I->MinD);
04201       value_multiply(tmp2,I->MinN,d);
04202       value_set_si(tmp3,1);
04203       
04204       /* Compare p3/d with MinN/MinD to assign new minimum cost value */
04205       if (I->MinI==-1 ||
04206           value_lt(tmp1,tmp2) ||
04207           (value_eq(tmp1,tmp2) &&
04208            value_eq(d,tmp3) && value_ne(I->MinD,tmp3))) {
04209         value_assign(I->MinN, p3);
04210         value_assign(I->MinD, d);
04211         I->MinI = i;
04212       }
04213       value_multiply(tmp1,p3,I->MaxD);
04214       value_set_si(tmp2,0);
04215       
04216       /* If there is a line, assign max to +infinity and min to -infinity */
04217       if (value_zero_p(status)) { /* line , d is 0 */
04218         if (value_lt(tmp1,tmp2)) {
04219           value_oppose(I->MaxN,p3);
04220           value_set_si(I->MaxD,0);
04221           I->MaxI = i;
04222         }
04223         value_multiply(tmp1,p3,I->MinD);
04224         value_set_si(tmp2,0);
04225 
04226         if (value_gt(tmp1,tmp2)) {
04227           value_oppose(I->MinN,p3);
04228           value_set_si(I->MinD,0);
04229           I->MinI = i;
04230         }
04231       }
04232     }
04233   } /* end of TRY */
04234   
04235   UNCATCH(any_exception_error);
04236   value_clear(p3); value_clear(d); value_clear(status);
04237   value_clear(tmp1); value_clear(tmp2); value_clear(tmp3);
04238   return I;
04239 } /* DomainCost */
04240 
04241 /* 
04242  * Add constraints pointed by 'Mat' to each and every polyhedron in the 
04243  * polyhedral domain 'Pol'. 'NbMaxRays' is maximum allowed rays in the ray 
04244  * matrix of a polyhedron.
04245  */
04246 Polyhedron *DomainAddConstraints(Polyhedron *Pol,Matrix *Mat,unsigned NbMaxRays) {
04247 
04248   Polyhedron *PolA, *PolEndA, *p1, *p2, *p3;
04249   int Redundant;
04250   
04251   if (!Pol) return (Polyhedron*) 0;
04252   if (!Mat) return Pol;
04253   if (Pol->Dimension != Mat->NbColumns-2) {
04254     errormsg1("DomainAddConstraints",
04255               "diffdim", "operation on different dimensions");
04256     return (Polyhedron*) 0;
04257   }
04258   
04259   /* Copy 'Pol' to 'PolA' */
04260   PolA = PolEndA = (Polyhedron *)0;
04261   for (p1=Pol; p1; p1=p1->next) {
04262     p3 = AddConstraints(Mat->p_Init, Mat->NbRows, p1, NbMaxRays);
04263     
04264     /* Does any component of 'PolA' cover 'p3' */
04265     Redundant = 0;
04266     for (p2=PolA; p2; p2=p2->next) {
04267       if (PolyhedronIncludes(p2, p3)) { /* 'p2' covers 'p3' */
04268         Redundant = 1;
04269         break;
04270       }
04271     }
04272     
04273     /* If the new polyhedron 'p3' is not redundant, add it to the domain */
04274     if (!Redundant) { 
04275       
04276       /* Add 'p3' to 'PolA' */
04277       if (!PolEndA)
04278         PolEndA = PolA = p3;
04279       else {
04280         PolEndA->next = p3;
04281         PolEndA = PolEndA->next;
04282       }
04283     }
04284   }
04285   return PolA;
04286 } /* DomainAddConstraints */
04287 
04288 
04289 /* 
04290  * Computes the disjoint union of a union of polyhedra.
04291  * If flag = 0 the result is such that there are no intersections
04292  *                   between the resulting polyhedra,
04293  * if flag = 1 it computes a joint union, the resulting polyhedra are
04294  *                   adjacent (they have their facets in common).
04295  *
04296  * WARNING: if all polyhedra are not of same geometrical dimension
04297  *          duplicates may appear.
04298  */
04299 Polyhedron *Disjoint_Domain( Polyhedron *P, int flag, unsigned NbMaxRays )
04300 {
04301         Polyhedron *lP, *tmp, *Result, *lR, *prec, *reste;
04302         Polyhedron *p1, *p2, *p3, *Pol1, *dx, *d1, *d2, *pi, *newpi;
04303         int i;
04304 
04305         if( flag!=0 && flag!=1 )
04306         {
04307                 errormsg1("Disjoint_Domain",
04308                         "invalidarg", "flag should be equal to 0 or 1");
04309                 return (Polyhedron*) 0;
04310         }
04311         if(!P) return (Polyhedron*) 0;
04312         if(!P->next) return Polyhedron_Copy(P);
04313 
04314         Result = (Polyhedron *)0;
04315 
04316         for(lP=P;lP;lP=lP->next)
04317         {
04318                 reste = Polyhedron_Copy(lP);
04319                 prec = (Polyhedron *)0; /* preceeding lR */
04320                 /* Intersection with each polyhedron of the current Result */
04321                 lR=Result;
04322                 while( lR && reste )
04323                 {
04324                         /* dx = DomainIntersection(reste,lR->P,WS); */
04325                         dx = (Polyhedron *)0;
04326                         for( p1=reste; p1; p1=p1->next )
04327                         {
04328                                 p3 = AddConstraints(lR->Constraint[0], lR->NbConstraints, p1,
04329                                                 NbMaxRays);
04330                                 dx = AddPolyToDomain(p3,dx);
04331                         }
04332 
04333                         /* if empty intersection, continue */
04334                         if(!dx)
04335                         {       prec = lR;
04336                                 lR=lR->next;
04337                                 continue;
04338                         }
04339                         if (emptyQ(dx)) {       
04340                                 Domain_Free(dx);
04341                                 prec = lR;
04342                                 lR=lR->next;
04343                                 continue;
04344                 }
04345 
04346                         /* intersection is not empty, we need to compute the differences */
04347                         /* between the intersection and the two polyhedra, such that the */
04348                         /* results are disjoint unions (according to flag)               */
04349                         /* d1 = reste \ P = DomainDifference(reste,lR->P,WS);   */
04350                         /* d2 = P \ reste = DomainDifference(lR->P,reste,WS); */
04351 
04352                         /* compute d1 */
04353                         d1 = (Polyhedron *)0;
04354                         for (p1=reste; p1; p1=p1->next)
04355                         {
04356                                 pi = p1;
04357                                 for (i=0; i<P->NbConstraints && pi ; i++)
04358                                 {
04359 
04360                                         /* Add the constraint ( -P->constraint[i] [-1 if flag=0]) >= 0 in 'p1' */
04361                                         /* and create the new polyhedron 'p3'.                      */
04362                                         p3 = SubConstraint(P->Constraint[i], pi, NbMaxRays,2*flag);
04363                                         /* Add 'p3' in the new domain 'd1' */
04364                                         d1 = AddPolyToDomain (p3, d1);
04365 
04366                                         /* If the constraint P->constraint[i][0] is an equality, then add   */
04367                                         /* the constraint ( +P->constraint[i] [-1 if flag=0]) >= 0  in 'pi' */
04368                                         /* and create the new polyhedron 'p3'.                              */
04369                                         if( value_zero_p(P->Constraint[i][0]) ) /* Inequality */
04370                                         {
04371                                                 p3 = SubConstraint(P->Constraint[i], pi, NbMaxRays,1+2*flag);
04372                                                 /* Add 'p3' in the new domain 'd1' */
04373                                                 d1 = AddPolyToDomain (p3, d1);
04374 
04375                                                 /* newpi : add constraint P->constraint[i]==0 to pi */
04376                                                 newpi = AddConstraints( P->Constraint[i], 1, pi, NbMaxRays);
04377                                         }
04378                                         else
04379                                         {
04380                                                 /* newpi : add constraint +P->constraint[i] >= 0 in pi */
04381                                                 newpi = SubConstraint(P->Constraint[i], pi, NbMaxRays,3);
04382                                         }
04383                                         if( newpi && emptyQ( newpi ) )
04384                                         {
04385                                                 Domain_Free( newpi );
04386                                                 newpi = (Polyhedron *)0;
04387                                         }
04388                                         if( pi != p1 )
04389                                                 Domain_Free( pi );
04390                                         pi = newpi;
04391                                 }
04392                                 if( pi != p1 )
04393                                         Domain_Free( pi );
04394                         }
04395 
04396                         /* and now d2 */
04397                         Pol1 = Polyhedron_Copy( lR );
04398                         for (p2=reste; p2; p2=p2->next)
04399                         {
04400                                 d2 = (Polyhedron *)0;
04401                                 for (p1=Pol1; p1; p1=p1->next)
04402                                 {
04403                                         pi = p1;
04404                                         for (i=0; i<p2->NbConstraints && pi ; i++)
04405                                         {
04406 
04407                                                 /* Add the constraint ( -p2->constraint[i] [-1 if flag=0]) >= 0 in 'pi' */
04408                                                 /* and create the new polyhedron 'p3'.                      */
04409                                                 p3 = SubConstraint(p2->Constraint[i], pi, NbMaxRays,2*flag);
04410                                                 /* Add 'p3' in the new domain 'd2' */
04411                                                 d2 = AddPolyToDomain (p3, d2);
04412 
04413                                                 /* If the constraint p2->constraint[i][0] is an equality, then add   */
04414                                                 /* the constraint ( +p2->constraint[i] [-1 if flag=0]) >= 0  in 'pi' */
04415                                                 /* and create the new polyhedron 'p3'.                              */
04416                                                 if( value_zero_p(p2->Constraint[i][0]) ) /* Inequality */
04417                                                 {
04418                                                         p3 = SubConstraint(p2->Constraint[i], pi, NbMaxRays,1+2*flag);
04419                                                         /* Add 'p3' in the new domain 'd2' */
04420                                                         d2 = AddPolyToDomain (p3, d2);
04421 
04422                                                         /* newpi : add constraint p2->constraint[i]==0 to pi */
04423                                                         newpi = AddConstraints( p2->Constraint[i], 1, pi, NbMaxRays);
04424                                                 }
04425                                                 else
04426                                                 {
04427                                                         /* newpi : add constraint +p2->constraint[i] >= 0 in pi */
04428                                                         newpi = SubConstraint(p2->Constraint[i], pi, NbMaxRays,3);
04429                                                 }
04430                                                 if( newpi && emptyQ( newpi ) )
04431                                                 {
04432                                                         Domain_Free( newpi );
04433                                                         newpi = (Polyhedron *)0;
04434                                                 }
04435                                                 if( pi != p1 )
04436                                                         Domain_Free( pi );
04437                                                 pi = newpi;
04438                                         }
04439                                         if( pi && pi!=p1 )
04440                                                 Domain_Free( pi );
04441                                 }
04442                                 if( Pol1 )
04443                                         Domain_Free( Pol1 );
04444                                 Pol1 = d2;
04445                         }
04446                         /* ok, d1 and d2 are computed */
04447 
04448                         /* now, replace lR by d2+dx (at least dx is nonempty) and set reste to d1 */
04449                         if( d1 && emptyQ(d1) )
04450                         {
04451                                 Domain_Free( d1 );
04452                                 d1 = NULL;
04453                         }
04454                         if( d2 && emptyQ(d2) )
04455                         {
04456                                 Domain_Free( d2 );
04457                                 d2 = NULL;
04458                         }
04459 
04460                         /* set reste */
04461                         Domain_Free( reste );
04462                         reste = d1;
04463 
04464                         /* add d2 at beginning of Result */
04465                         if( d2 )
04466                         {
04467                                 for( tmp=d2 ; tmp->next ; tmp=tmp->next )
04468                                                 ;
04469                                 tmp->next = Result;
04470                                 Result = d2;
04471                                 if( !prec )
04472                                         prec = tmp;
04473                         }
04474 
04475                         /* add dx at beginning of Result */
04476 //                      if( dx )
04477                         {
04478                                 for( tmp=dx ; tmp->next ; tmp=tmp->next )
04479                                         ;
04480                                 tmp->next = Result;
04481                                 Result = dx;
04482                                 if( !prec )
04483                                         prec = tmp;
04484                         }
04485 
04486                         /* suppress current lR */
04487                         if( !prec )
04488                                 errormsg1( "Disjoint_Domain","internalerror","internal error");
04489                         prec->next = lR->next;
04490                         Polyhedron_Free( lR );
04491                         lR = prec->next;
04492                 } /* end for result */
04493 
04494                   /* if there is something left, add it to Result : */
04495                 if(reste)
04496                 {
04497                         if(emptyQ(reste))
04498                         {
04499                                 Domain_Free( reste );
04500                                 reste = NULL;
04501                         }
04502                         else
04503                         {
04504                                 Polyhedron *tnext;
04505                                 for( tmp=reste ; tmp ; tmp=tnext )
04506                                 {
04507                                         tnext = tmp->next;
04508                                         tmp->next = NULL;
04509                                         Result = AddPolyToDomain(tmp, Result);
04510                                 }
04511                 }
04512                 }
04513         }
04514 
04515         return( Result );
04516 }
04517 
04518 
04519 
04520 /* Procedure to print constraint matrix of a polyhedron */
04521 void Polyhedron_PrintConstraints(FILE *Dst,char *Format,Polyhedron *Pol)
04522 {
04523         int i,j;
04524 
04525         fprintf( Dst, "%d %d\n", Pol->NbConstraints, Pol->Dimension+2 );
04526         for( i=0 ; i<Pol->NbConstraints ; i++ )
04527         {
04528                 for( j=0 ; j<Pol->Dimension+2 ; j++ )
04529                         value_print( stdout, Format, Pol->Constraint[i][j] );
04530                 fprintf( Dst, "\n" );
04531         }
04532 
04533 }
04534 
04535 

Generated on Mon Sep 12 14:48:29 2005 for polylib by doxygen 1.3.5