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

Generated on Mon Sep 12 15:15:11 2005 for polylib by doxygen 1.3.5