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

Generated on Mon Apr 23 19:23:53 2007 for polylib by doxygen 1.3.5