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

ehrhart.c

Go to the documentation of this file.
00001 /***********************************************************************/
00002 /*                Ehrhart V4.20                                        */
00003 /*                copyright 1997, Doran Wilde                          */
00004 /*                copyright 1997-2000, Vincent Loechner                */
00005 /*       Permission is granted to copy, use, and distribute            */
00006 /*       for any commercial or noncommercial purpose under the terms   */
00007 /*       of the GNU General Public license, version 2, June 1991       */
00008 /*       (see file : LICENSING).                                       */
00009 /***********************************************************************/
00010 
00011 #include <stdio.h>
00012 #include <stdlib.h>
00013 #include <ctype.h>
00014 #include <string.h>
00015 #include <unistd.h>
00016 #include <assert.h>
00017 
00018 #include <polylib/polylib.h>
00019 #include <polylib/homogenization.h>
00020 
00021 
00022 /*! \class Ehrhart
00023 
00024 The following are mainly for debug purposes. You shouldn't need to
00025 change anything for daily usage...
00026 
00027 <p>
00028 
00029 you may define each macro independently 
00030 <ol>
00031 <li> #define EDEBUG minimal debug 
00032 <li> #define EDEBUG1 prints enumeration points
00033 <li> #define EDEBUG11 prints number of points
00034 <li> #define EDEBUG2 prints domains
00035 <li> #define EDEBUG21 prints more domains
00036 <li> #define EDEBUG3 prints systems of equations that are solved
00037 <li> #define EDEBUG4 prints message for degree reduction
00038 <li> #define EDEBUG5 prints result before simplification 
00039 <li> #define EDEBUG6 prints domains in Preprocess 
00040 <li> #define EDEBUG61 prints even more in Preprocess
00041 <li> #define EDEBUG62 prints domains in Preprocess2
00042 </ol>
00043 */
00044 
00045 
00046 /** 
00047     
00048 define this to print all constraints on the validity domains if not
00049 defined, only new constraints (not in validity domain given by the
00050 user) are printed
00051 
00052 */
00053 #define EPRINT_ALL_VALIDITY_CONSTRAINTS
00054 
00055 /* #define EDEBUG       */              /* minimal debug */
00056 /* #define EDEBUG1      */              /* prints enumeration points */
00057 /* #define EDEBUG11     */              /* prints number of points */
00058 /* #define EDEBUG2      */              /* prints domains */
00059 /* #define EDEBUG21     */              /* prints more domains */
00060 /* #define EDEBUG3      */              /* prints systems of equations that are solved */
00061 /* #define EDEBUG4      */              /* prints message for degree reduction */
00062 /* #define EDEBUG5      */              /* prints result before simplification */
00063 /* #define EDEBUG6      */              /* prints domains in Preprocess */
00064 /* #define EDEBUG61     */              /* prints even more in Preprocess */
00065 /* #define EDEBUG62     */              /* prints domains in Preprocess2 */
00066 
00067 
00068 /**
00069  Reduce the degree of resulting polynomials
00070 */
00071 #define REDUCE_DEGREE
00072 
00073 /** 
00074 define this to print one warning message per domain overflow these
00075 overflows should no longer happen since version 4.20
00076 */
00077 #define ALL_OVERFLOW_WARNINGS
00078 
00079 /******************* -----------END USER #DEFS-------- *********************/
00080 
00081 int overflow_warning_flag = 1;
00082 
00083 /*-------------------------------------------------------------------*/
00084 /* EHRHART POLYNOMIAL SYMBOLIC ALGEBRA SYSTEM                        */
00085 /*-------------------------------------------------------------------*/ 
00086 /** 
00087 
00088 EHRHART POLYNOMIAL SYMBOLIC ALGEBRA SYSTEM. The newly allocated enode
00089 can be freed with a simple free(x)
00090 
00091 @param type : enode type
00092 @param size : degree+1 for polynomial, period for periodic
00093 @param pos  : 1..nb_param, position of parameter            
00094 @return a newly allocated enode 
00095 
00096 */
00097 enode *new_enode(enode_type type,int size,int pos) {
00098   
00099   enode *res;
00100   int i;
00101   
00102   if(size == 0) {
00103     fprintf(stderr, "Allocating enode of size 0 !\n" );
00104     return NULL;
00105   }
00106   res = (enode *) malloc(sizeof(enode) + (size-1)*sizeof(evalue));
00107   res->type = type;
00108   res->size = size;
00109   res->pos = pos;
00110   for(i=0; i<size; i++) {
00111     value_init(res->arr[i].d);
00112     value_set_si(res->arr[i].d,0);
00113     res->arr[i].x.p = 0;
00114   }
00115   return res;
00116 } /* new_enode */
00117 
00118 /**
00119 releases all memory referenced by e.  (recursive)        
00120 @param e pointer to an evalue
00121 */
00122 void free_evalue_refs(evalue *e) {
00123   
00124   enode *p;
00125   int i;
00126   
00127   if (value_notzero_p(e->d)) {
00128     
00129     /* 'e' stores a constant */
00130     value_clear(e->d);
00131     value_clear(e->x.n);
00132     return; 
00133   }  
00134   value_clear(e->d);
00135   p = e->x.p;
00136   if (!p) return;       /* null pointer */
00137   for (i=0; i<p->size; i++) {
00138     free_evalue_refs(&(p->arr[i]));
00139   }
00140   free(p);
00141   return;
00142 } /* free_evalue_refs */
00143 
00144 /**
00145 
00146 @param e pointer to an evalue 
00147 @return description
00148 
00149 */
00150 enode *ecopy(enode *e) {
00151   
00152   enode *res;
00153   int i;
00154   
00155   res = new_enode(e->type,e->size,e->pos);
00156   for(i=0;i<e->size;++i) {
00157     value_assign(res->arr[i].d,e->arr[i].d);
00158     if(value_zero_p(res->arr[i].d))
00159       res->arr[i].x.p = ecopy(e->arr[i].x.p);
00160     else {
00161       value_init(res->arr[i].x.n);
00162       value_assign(res->arr[i].x.n,e->arr[i].x.n);
00163     }
00164   }
00165   return(res);
00166 } /* ecopy */
00167 
00168 /**
00169 
00170 @param DST destination file
00171 @param e pointer to evalue to be printed
00172 @param pname array of strings, name of the parameters
00173 
00174 */
00175 void print_evalue(FILE *DST, evalue *e, const char **pname)
00176 {
00177   if(value_notzero_p(e->d)) {    
00178     if(value_notone_p(e->d)) {
00179       value_print(DST,VALUE_FMT,e->x.n);
00180       fprintf(DST,"/");
00181       value_print(DST,VALUE_FMT,e->d);
00182     }  
00183     else {
00184       value_print(DST,VALUE_FMT,e->x.n);
00185     }
00186   }  
00187   else
00188     print_enode(DST,e->x.p,pname);
00189   return;
00190 } /* print_evalue */
00191 
00192 /** prints the enode  to DST  
00193 
00194 @param DST destination file 
00195 @param p pointer to enode  to be printed 
00196 @param pname array of strings, name of the parameters
00197 
00198 */
00199 void print_enode(FILE *DST, enode *p, const char **pname)
00200 {
00201   int i;
00202   
00203   if (!p) {
00204     fprintf(DST, "NULL");
00205     return;
00206   }
00207   if (p->type == evector) {
00208     fprintf(DST, "{ ");
00209     for (i=0; i<p->size; i++) {
00210       print_evalue(DST, &p->arr[i], pname);
00211       if (i!=(p->size-1))
00212         fprintf(DST, ", ");
00213     }
00214     fprintf(DST, " }\n");
00215   }
00216   else if (p->type == polynomial) {
00217     fprintf(DST, "( ");
00218     for (i=p->size-1; i>=0; i--) {
00219       print_evalue(DST, &p->arr[i], pname);
00220       if (i==1) fprintf(DST, " * %s + ", pname[p->pos-1]);
00221       else if (i>1) 
00222         fprintf(DST, " * %s^%d + ", pname[p->pos-1], i);
00223     }
00224     fprintf(DST, " )\n");
00225   }
00226   else if (p->type == periodic) {
00227     fprintf(DST, "[ ");
00228     for (i=0; i<p->size; i++) {
00229       print_evalue(DST, &p->arr[i], pname);
00230       if (i!=(p->size-1)) fprintf(DST, ", ");
00231     }
00232     fprintf(DST," ]_%s", pname[p->pos-1]);
00233   }
00234   return;
00235 } /* print_enode */ 
00236 
00237 /**
00238 
00239 @param  e1 pointers to evalues
00240 @param  e2 pointers to evalues
00241 @return 1 (true) if they are equal, 0 (false) if not       
00242 
00243 */
00244 static int eequal(evalue *e1,evalue *e2) { 
00245  
00246     int i;
00247     enode *p1, *p2;
00248   
00249     if (value_ne(e1->d,e2->d))
00250         return 0;
00251   
00252     /* e1->d == e2->d */
00253     if (value_notzero_p(e1->d)) {    
00254         if (value_ne(e1->x.n,e2->x.n))
00255             return 0;
00256     
00257         /* e1->d == e2->d != 0  AND e1->n == e2->n */
00258         return 1;
00259     }
00260   
00261     /* e1->d == e2->d == 0 */
00262     p1 = e1->x.p;
00263     p2 = e2->x.p;
00264     if (p1->type != p2->type) return 0;
00265     if (p1->size != p2->size) return 0;
00266     if (p1->pos  != p2->pos) return 0;
00267     for (i=0; i<p1->size; i++)
00268         if (!eequal(&p1->arr[i], &p2->arr[i]) ) 
00269             return 0;
00270     return 1;
00271 } /* eequal */
00272 
00273 /** 
00274 
00275 @param e pointer to an evalue
00276 
00277 */
00278 void reduce_evalue (evalue *e) {
00279   
00280     enode *p;
00281     int i, j, k;
00282   
00283     if (value_notzero_p(e->d))
00284         return; /* a rational number, its already reduced */
00285     if(!(p = e->x.p))
00286         return; /* hum... an overflow probably occured */
00287   
00288     /* First reduce the components of p */
00289     for (i=0; i<p->size; i++)
00290         reduce_evalue(&p->arr[i]);
00291 
00292     if (p->type==periodic) {
00293     
00294         /* Try to reduce the period */
00295         for (i=1; i<=(p->size)/2; i++) {
00296             if ((p->size % i)==0) {
00297         
00298                 /* Can we reduce the size to i ? */
00299                 for (j=0; j<i; j++)
00300                     for (k=j+i; k<e->x.p->size; k+=i)
00301                         if (!eequal(&p->arr[j], &p->arr[k])) goto you_lose;
00302 
00303                 /* OK, lets do it */
00304                 for (j=i; j<p->size; j++) free_evalue_refs(&p->arr[j]);
00305                 p->size = i;
00306                 break;
00307 
00308             you_lose:   /* OK, lets not do it */
00309                 continue;
00310             }
00311         }
00312 
00313         /* Try to reduce its strength */
00314         if (p->size == 1) {
00315             value_clear(e->d);
00316             memcpy(e,&p->arr[0],sizeof(evalue));
00317             free(p);
00318         }
00319     }
00320     else if (p->type==polynomial) {
00321           
00322         /* Try to reduce the degree */
00323         for (i=p->size-1;i>=1;i--) {
00324             if (!(value_one_p(p->arr[i].d) && value_zero_p(p->arr[i].x.n)))
00325                 break;
00326             /* Zero coefficient */
00327             free_evalue_refs(&p->arr[i]);
00328         }
00329         if (i+1<p->size)
00330             p->size = i+1;
00331 
00332         /* Try to reduce its strength */
00333         if (p->size == 1) {
00334             value_clear(e->d);
00335             memcpy(e,&p->arr[0],sizeof(evalue));
00336             free(p);
00337         }
00338     }
00339 } /* reduce_evalue */
00340 
00341 
00342 /**
00343 
00344 multiplies two evalues and puts the result in res
00345 
00346 @param e1 pointer to an evalue
00347 @param e2 pointer to a constant evalue
00348 @param res  pointer to result evalue = e1 * e2
00349 
00350 */
00351 static void emul (evalue *e1,evalue *e2,evalue *res) {
00352   
00353     enode *p;
00354     int i;
00355     Value g;
00356 
00357     if (value_zero_p(e2->d)) {
00358         fprintf(stderr, "emul: ?expecting constant value\n");
00359         return;
00360     }  
00361     value_init(g);
00362     if (value_notzero_p(e1->d)) {
00363     
00364         value_init(res->x.n);
00365         /* Product of two rational numbers */
00366         value_multiply(res->d,e1->d,e2->d);
00367         value_multiply(res->x.n,e1->x.n,e2->x.n );
00368         value_gcd(g, res->x.n, res->d);
00369         if (value_notone_p(g)) {
00370             value_divexact(res->d, res->d, g);
00371             value_divexact(res->x.n, res->x.n, g);
00372         }
00373     }
00374     else { /* e1 is an expression */    
00375         value_set_si(res->d,0);
00376         p = e1->x.p;
00377         res->x.p = new_enode(p->type, p->size, p->pos);
00378         for (i=0; i<p->size; i++) {
00379             emul(&p->arr[i], e2, &(res->x.p->arr[i]) ); 
00380         }
00381     }
00382     value_clear(g);
00383     return;
00384 } /* emul */
00385 
00386 /**
00387 adds one evalue to evalue 'res. result = res + e1 
00388 
00389 @param e1 an evalue 
00390 @param res 
00391 
00392 */
00393 void eadd(evalue *e1,evalue *res) {
00394 
00395   int i;
00396   Value g,m1,m2;
00397  
00398   value_init(g);
00399   value_init(m1);
00400   value_init(m2);
00401   
00402   if (value_notzero_p(e1->d) && value_notzero_p(res->d)) {
00403     
00404     /* Add two rational numbers*/
00405     value_multiply(m1,e1->x.n,res->d);
00406     value_multiply(m2,res->x.n,e1->d);
00407     value_addto(res->x.n,m1,m2);
00408     value_multiply(res->d,e1->d,res->d);  
00409     value_gcd(g, res->x.n, res->d);
00410     if (value_notone_p(g)) {  
00411       value_divexact(res->d, res->d, g);
00412       value_divexact(res->x.n, res->x.n, g);
00413     }
00414     value_clear(g); value_clear(m1); value_clear(m2);
00415     return;
00416   }
00417   else if (value_notzero_p(e1->d) && value_zero_p(res->d)) {
00418     if (res->x.p->type==polynomial) {
00419       
00420       /* Add the constant to the constant term */
00421       eadd(e1, &res->x.p->arr[0]);
00422       value_clear(g); value_clear(m1); value_clear(m2);
00423       return;
00424     }
00425     else if (res->x.p->type==periodic) {
00426       
00427       /* Add the constant to all elements of periodic number */
00428       for (i=0; i<res->x.p->size; i++) { 
00429         eadd(e1, &res->x.p->arr[i]);
00430       }
00431       value_clear(g); value_clear(m1); value_clear(m2);
00432       return;
00433     }
00434     else {
00435       fprintf(stderr, "eadd: cannot add const with vector\n");
00436       value_clear(g); value_clear(m1); value_clear(m2);
00437       return;
00438     }
00439   }
00440   else if (value_zero_p(e1->d) && value_notzero_p(res->d)) {
00441     fprintf(stderr,"eadd: cannot add evalue to const\n");
00442     value_clear(g); value_clear(m1); value_clear(m2);
00443     return;
00444   }
00445   else {    /* ((e1->d==0) && (res->d==0)) */  
00446     if ((e1->x.p->type != res->x.p->type) ||
00447         (e1->x.p->pos  != res->x.p->pos )) {
00448       fprintf(stderr, "eadd: ?cannot add, incompatible types\n");
00449       value_clear(g); value_clear(m1); value_clear(m2);
00450       return;
00451     }
00452     if (e1->x.p->size == res->x.p->size) {
00453       for (i=0; i<res->x.p->size; i++) {
00454         eadd(&e1->x.p->arr[i], &res->x.p->arr[i]);
00455       }
00456       value_clear(g); value_clear(m1); value_clear(m2);
00457       return;
00458     }
00459     
00460     /* Sizes are different */
00461     if (res->x.p->type==polynomial) { 
00462       
00463       /* VIN100: if e1-size > res-size you have to copy e1 in a   */
00464       /* new enode and add res to that new node. If you do not do */
00465       /* that, you lose the the upper weight part of e1 !         */
00466       
00467       if(e1->x.p->size > res->x.p->size) {
00468         enode *tmp;
00469         tmp = ecopy(e1->x.p);
00470         for(i=0;i<res->x.p->size;++i) {
00471           eadd(&res->x.p->arr[i], &tmp->arr[i]);
00472           free_evalue_refs(&res->x.p->arr[i]);
00473         }
00474         res->x.p = tmp;
00475       }
00476       else {
00477         for (i=0; i<e1->x.p->size ; i++) {
00478           eadd(&e1->x.p->arr[i], &res->x.p->arr[i]);
00479         }
00480         value_clear(g); value_clear(m1); value_clear(m2);
00481         return;
00482       }
00483     }
00484     else if (res->x.p->type==periodic) {
00485       fprintf(stderr, "eadd: ?addition of different sized periodic nos\n");
00486       value_clear(g); value_clear(m1); value_clear(m2);
00487       return;
00488     }
00489     else { /* evector */
00490       fprintf(stderr, "eadd: ?cannot add vectors of different length\n");
00491       value_clear(g); value_clear(m1); value_clear(m2);
00492       return;
00493     }
00494   }
00495   value_clear(g); value_clear(m1); value_clear(m2);
00496   return;
00497 } /* eadd */
00498 
00499 /** 
00500 
00501 computes the inner product of two vectors. Result = result (evalue) =
00502 v1.v2 (dot product)
00503 
00504 @param  v1 an enode (vector)
00505 @param  v2 an enode (vector of constants)
00506 @param res result (evalue)
00507 
00508 */
00509 void edot(enode *v1,enode *v2,evalue *res) {
00510   
00511     int i;
00512     evalue tmp;
00513   
00514     if ((v1->type != evector) || (v2->type != evector)) {
00515         fprintf(stderr, "edot: ?expecting vectors\n");
00516         return;
00517     }
00518     if (v1->size != v2->size) {
00519         fprintf(stderr, "edot: ? vector lengths do not agree\n");
00520         return;
00521     }
00522     if (v1->size<=0) {
00523         value_set_si(res->d,1); /* set result to 0/1 */
00524         value_init(res->x.n);
00525         value_set_si(res->x.n,0);
00526         return;
00527     }
00528   
00529     /* vector v2 is expected to have only rational numbers in */
00530     /* the array.  No pointers. */  
00531     emul(&v1->arr[0],&v2->arr[0],res);
00532     for (i=1; i<v1->size; i++) {
00533         value_init(tmp.d);
00534      
00535         /* res = res + v1[i]*v2[i] */
00536         emul(&v1->arr[i],&v2->arr[i],&tmp);
00537         eadd(&tmp,res);
00538         free_evalue_refs(&tmp);
00539     }
00540     return;
00541 } /* edot */
00542 
00543 /**
00544 
00545 local recursive function used in the following ref contains the new
00546 position for each old index position
00547 
00548 @param e pointer to an evalue
00549 @param ref transformation Matrix
00550 
00551 */
00552 static void aep_evalue(evalue *e, int *ref) {
00553   
00554     enode *p;
00555     int i;
00556   
00557     if (value_notzero_p(e->d))
00558         return;         /* a rational number, its already reduced */
00559     if(!(p = e->x.p))
00560         return;         /* hum... an overflow probably occured */
00561   
00562     /* First check the components of p */
00563     for (i=0;i<p->size;i++)
00564         aep_evalue(&p->arr[i],ref);
00565   
00566     /* Then p itself */
00567     p->pos = ref[p->pos-1]+1;
00568     return;
00569 } /* aep_evalue */
00570 
00571 /** Comments */
00572 static void addeliminatedparams_evalue(evalue *e,Matrix *CT) {
00573         
00574     enode *p;
00575     int i, j;
00576     int *ref;
00577 
00578     if (value_notzero_p(e->d))
00579         return;          /* a rational number, its already reduced */
00580     if(!(p = e->x.p))
00581         return;          /* hum... an overflow probably occured */
00582   
00583     /* Compute ref */
00584     ref = (int *)malloc(sizeof(int)*(CT->NbRows-1));
00585     for(i=0;i<CT->NbRows-1;i++)
00586         for(j=0;j<CT->NbColumns;j++)
00587             if(value_notzero_p(CT->p[i][j])) {
00588                 ref[i] = j;
00589                 break;
00590             }
00591   
00592     /* Transform the references in e, using ref */
00593     aep_evalue(e,ref);
00594     free( ref );
00595     return;
00596 } /* addeliminatedparams_evalue */
00597 
00598 /** 
00599 
00600 This procedure finds an integer point contained in polyhedron D /
00601 first checks for positive values, then for negative values returns
00602 TRUE on success. Result is in min.  returns FALSE if no integer point
00603 is found
00604 
00605 <p>
00606 
00607 This is the maximum number of iterations for a given parameter to find
00608 a integer point inside the context. Kind of weird. cherche_min should
00609 
00610 <p>
00611 
00612 @param min
00613 @param D
00614 @param pos
00615 
00616 */
00617 /* FIXME: needs to be rewritten ! */
00618 #define MAXITER 100
00619 int cherche_min(Value *min,Polyhedron *D,int pos) {
00620         
00621     Value binf, bsup;   /* upper & lower bound */
00622     Value i;
00623     int flag, maxiter;
00624   
00625     if(!D)
00626         return(1);
00627     if(pos > D->Dimension)
00628         return(1);
00629   
00630     value_init(binf); value_init(bsup);
00631     value_init(i);
00632   
00633 #ifdef EDEBUG61
00634     fprintf(stderr,"Entering Cherche min --> \n");
00635     fprintf(stderr,"LowerUpperBounds :\n");
00636     fprintf(stderr,"pos = %d\n",pos);
00637     fprintf(stderr,"current min = (");
00638     value_print(stderr,P_VALUE_FMT,min[1]);
00639     {int j;
00640     for(j=2;j<=D->Dimension ; j++) {
00641         fprintf(stderr,", ");
00642         value_print(stderr,P_VALUE_FMT,min[j]);
00643     }  
00644     }
00645     fprintf(stderr,")\n");
00646 #endif
00647         
00648     flag = lower_upper_bounds(pos,D,min,&binf,&bsup);
00649   
00650 #ifdef EDEBUG61
00651     fprintf(stderr, "flag = %d\n", flag);
00652     fprintf(stderr,"binf = ");
00653     value_print(stderr,P_VALUE_FMT,binf);
00654     fprintf(stderr,"\n");
00655     fprintf(stderr,"bsup = ");
00656     value_print(stderr,P_VALUE_FMT,bsup);
00657     fprintf(stderr,"\n");
00658 #endif
00659 
00660     if(flag&LB_INFINITY)
00661         value_set_si(binf,0);
00662   
00663     /* Loop from 0 (or binf if positive) to bsup */
00664     for(maxiter=0,(((flag&LB_INFINITY) || value_neg_p(binf)) ? 
00665             value_set_si(i,0) : value_assign(i,binf));
00666         ((flag&UB_INFINITY) || value_le(i,bsup)) && maxiter<MAXITER ;
00667         value_increment(i,i),maxiter++) {
00668     
00669         value_assign(min[pos],i);
00670         if(cherche_min(min,D->next,pos+1)) {
00671             value_clear(binf); value_clear(bsup);
00672             value_clear(i);
00673             return(1);
00674         }  
00675     }
00676   
00677     /* Descending loop from -1 (or bsup if negative) to binf */
00678     if((flag&LB_INFINITY) || value_neg_p(binf))
00679         for(maxiter=0,(((flag&UB_INFINITY) || value_pos_p(bsup))?
00680                 value_set_si(i,-1)
00681                 :value_assign(i,bsup));
00682             ((flag&LB_INFINITY) || value_ge(i,binf)) && maxiter<MAXITER  ;
00683             value_decrement(i,i),maxiter++) {
00684 
00685             value_assign(min[pos],i);
00686             if(cherche_min(min,D->next,pos+1)) {
00687                 value_clear(binf); value_clear(bsup);
00688                 value_clear(i);
00689                 return(1);
00690             }   
00691         }
00692     value_clear(binf); value_clear(bsup);
00693     value_clear(i);
00694 
00695     value_set_si(min[pos],0);
00696     return(0);       /* not found :-( */
00697 } /* cherche_min */
00698 
00699 /** 
00700 
00701 This procedure finds the smallest parallelepiped of size
00702 '<i>size[i]</i>' for every dimension i, contained in polyhedron D.
00703 If this is not possible, NULL is returned
00704 
00705 <p>
00706 
00707 <pre>
00708 written by vin100, 2000, for version 4.19
00709 modified 2002, version 5.10
00710 </pre>
00711 
00712 <p>
00713 
00714 It first finds the coordinates of the lexicographically smallest edge
00715 of the hypercube, obtained by transforming the constraints of D (by
00716 adding 'size' as many times as there are negative coeficients in each
00717 constraint), and finding the lexicographical min of this
00718 polyhedron. Then it builds the hypercube and returns it.
00719 
00720 <p>
00721 @param D
00722 @param size
00723 @param MAXRAYS
00724 
00725 */
00726 
00727 Polyhedron *Polyhedron_Preprocess(Polyhedron *D,Value *size,unsigned MAXRAYS)
00728 {
00729     Matrix *M;
00730     int i, j, d;
00731     Polyhedron *T, *S, *H, *C;
00732     Value *min;
00733 
00734     d = D->Dimension;
00735     if (MAXRAYS < 2*D->NbConstraints)
00736         MAXRAYS = 2*D->NbConstraints;
00737     M = Matrix_Alloc(MAXRAYS, D->Dimension+2);
00738     M->NbRows = D->NbConstraints;
00739   
00740     /* Original constraints */
00741     for(i=0;i<D->NbConstraints;i++)
00742         Vector_Copy(D->Constraint[i],M->p[i],(d+2));
00743 
00744 #ifdef EDEBUG6
00745     fprintf(stderr,"M for PreProcess : ");
00746     Matrix_Print(stderr,P_VALUE_FMT,M);
00747     fprintf(stderr,"\nsize == ");
00748     for( i=0 ; i<d ; i++ )
00749         value_print(stderr,P_VALUE_FMT,size[i]);
00750     fprintf(stderr,"\n");
00751 #endif
00752 
00753     /* Additionnal constraints */
00754     for(i=0;i<D->NbConstraints;i++) {
00755         if(value_zero_p(D->Constraint[i][0])) {
00756             fprintf(stderr,"Polyhedron_Preprocess: ");
00757             fprintf(stderr,
00758                     "an equality was found where I did expect an inequality.\n");
00759             fprintf(stderr,"Trying to continue...\n");
00760             continue;
00761         }
00762         Vector_Copy(D->Constraint[i],M->p[M->NbRows],(d+2));
00763         for(j=1;j<=d;j++)
00764             if(value_neg_p(D->Constraint[i][j])) {
00765               value_addmul(M->p[M->NbRows][d+1], D->Constraint[i][j], size[j-1]);
00766             }
00767     
00768         /* If anything changed, add this new constraint */
00769         if(value_ne(M->p[M->NbRows][d+1],D->Constraint[i][d+1]))
00770             M->NbRows ++ ;
00771     }
00772   
00773 #ifdef EDEBUG6
00774     fprintf(stderr,"M used to find min : ");
00775     Matrix_Print(stderr,P_VALUE_FMT,M);
00776 #endif
00777   
00778     T = Constraints2Polyhedron(M,MAXRAYS);
00779     Matrix_Free(M);
00780     if (!T || emptyQ(T)) {
00781         if(T)
00782             Polyhedron_Free(T);
00783         return(NULL);
00784     }
00785   
00786     /* Ok, now find the lexicographical min of T */
00787     min = (Value *) malloc(sizeof(Value) * (d+2));
00788     for(i=0;i<=d;i++) {
00789         value_init(min[i]);
00790         value_set_si(min[i],0);
00791     }  
00792     value_init(min[i]);
00793     value_set_si(min[i],1);
00794     C = Universe_Polyhedron(0);
00795     S = Polyhedron_Scan(T,C,MAXRAYS);
00796     Polyhedron_Free(C);
00797     Polyhedron_Free(T);
00798 
00799 #ifdef EDEBUG6
00800     for(i=0;i<=(d+1);i++) {
00801         value_print(stderr,P_VALUE_FMT,min[i]);
00802         fprintf(stderr," ,");
00803     }
00804     fprintf(stderr,"\n");
00805     Polyhedron_Print(stderr,P_VALUE_FMT,S);
00806     fprintf(stderr,"\n");
00807 #endif
00808     
00809     if (!cherche_min(min,S,1))
00810         {
00811             for(i=0;i<=(d+1);i++)
00812                 value_clear(min[i]);
00813             return(NULL);
00814         }
00815     Domain_Free(S);
00816   
00817 #ifdef EDEBUG6
00818     fprintf(stderr,"min = ( ");
00819     value_print(stderr,P_VALUE_FMT,min[1]);
00820     for(i=2;i<=d;i++) {
00821         fprintf(stderr,", ");
00822         value_print(stderr,P_VALUE_FMT,min[i]);
00823     }  
00824     fprintf(stderr,")\n");
00825 #endif
00826   
00827     /* Min is the point from which we can construct the hypercube */
00828     M = Matrix_Alloc(d*2,d+2);
00829     for(i=0;i<d;i++) {
00830     
00831         /* Creates inequality  1 0..0 1 0..0 -min[i+1] */
00832         value_set_si(M->p[2*i][0],1);
00833         for(j=1;j<=d;j++)
00834             value_set_si(M->p[2*i][j],0);
00835         value_set_si(M->p[2*i][i+1],1);
00836         value_oppose(M->p[2*i][d+1],min[i+1]);
00837     
00838         /* Creates inequality  1 0..0 -1 0..0 min[i+1]+size -1 */
00839         value_set_si(M->p[2*i+1][0],1);
00840         for(j=1;j<=d;j++)
00841             value_set_si(M->p[2*i+1][j],0);
00842         value_set_si(M->p[2*i+1][i+1],-1);
00843         value_addto(M->p[2*i+1][d+1],min[i+1],size[i]);
00844         value_sub_int(M->p[2*i+1][d+1],M->p[2*i+1][d+1],1);
00845     }
00846   
00847 #ifdef EDEBUG6
00848     fprintf(stderr,"PolyhedronPreprocess: constraints H = ");
00849     Matrix_Print(stderr,P_VALUE_FMT,M);
00850 #endif
00851   
00852     H = Constraints2Polyhedron(M,MAXRAYS);
00853   
00854 #ifdef EDEBUG6
00855     Polyhedron_Print(stderr,P_VALUE_FMT,H);
00856     fprintf(stderr,"\n");
00857 #endif
00858   
00859     Matrix_Free(M);
00860     for(i=0;i<=(d+1);i++)
00861         value_clear(min[i]);
00862     free(min);
00863     assert(!emptyQ(H));
00864     return(H);
00865 } /* Polyhedron_Preprocess */
00866 
00867 
00868 /** This procedure finds an hypercube of size 'size', containing
00869 polyhedron D increases size and lcm if necessary (and not "too big")
00870 If this is not possible, an empty polyhedron is returned
00871 
00872 <p>
00873 
00874 <pre> written by vin100, 2001, for version 4.19</pre>
00875 
00876 @param D
00877 @param size
00878 @param lcm
00879 @param MAXRAYS
00880 
00881 */
00882 Polyhedron *Polyhedron_Preprocess2(Polyhedron *D,Value *size,
00883                                    Value *lcm,unsigned MAXRAYS) {
00884   
00885     Matrix *c;
00886     Polyhedron *H;
00887     int i,j,r;
00888     Value n;      /* smallest/biggest value */
00889     Value s;    /* size in this dimension */
00890     Value tmp1,tmp2;
00891 
00892 #ifdef EDEBUG62
00893     int np;
00894 #endif
00895 
00896     value_init(n); value_init(s);
00897     value_init(tmp1); value_init(tmp2);
00898     c = Matrix_Alloc(D->Dimension*2,D->Dimension+2);
00899   
00900 #ifdef EDEBUG62
00901     fprintf(stderr,"\nPreProcess2 : starting\n");
00902     fprintf(stderr,"lcm = ");
00903     for( np=0 ; np<D->Dimension; np++ )
00904         value_print(stderr,VALUE_FMT,lcm[np]);
00905     fprintf(stderr,", size = ");
00906     for( np=0 ; np<D->Dimension; np++ )
00907         value_print(stderr,VALUE_FMT,size[np]);
00908     fprintf(stderr,"\n");
00909 #endif
00910   
00911     for(i=0;i<D->Dimension;i++) {
00912     
00913         /* Create constraint 1 0..0 1 0..0 -min */
00914         value_set_si(c->p[2*i][0],1);
00915         for(j=0;j<D->Dimension;j++)
00916             value_set_si(c->p[2*i][1+j],0);
00917         value_division(n,D->Ray[0][i+1],D->Ray[0][D->Dimension+1]);
00918         for(r=1;r<D->NbRays;r++) {
00919             value_division(tmp1,D->Ray[r][i+1],D->Ray[r][D->Dimension+1]);
00920             if(value_gt(n,tmp1)) {
00921         
00922                 /* New min */
00923                 value_division(n,D->Ray[r][i+1],D->Ray[r][D->Dimension+1]);
00924             }
00925         }
00926         value_set_si(c->p[2*i][i+1],1);
00927         value_oppose(c->p[2*i][D->Dimension+1],n);
00928     
00929         /* Create constraint 1 0..0 -1 0..0 max */
00930         value_set_si(c->p[2*i+1][0],1);
00931         for(j=0;j<D->Dimension;j++)
00932             value_set_si(c->p[2*i+1][1+j],0);
00933     
00934         /* n = (num+den-1)/den */
00935         value_addto(tmp1,D->Ray[0][i+1],D->Ray[0][D->Dimension+1]);
00936         value_sub_int(tmp1,tmp1,1);
00937         value_division(n,tmp1,D->Ray[0][D->Dimension+1]);
00938         for(r=1;r<D->NbRays;r++) {
00939             value_addto(tmp1,D->Ray[r][i+1],D->Ray[r][D->Dimension+1]);
00940             value_sub_int(tmp1,tmp1,1);
00941             value_division(tmp1,tmp1,D->Ray[r][D->Dimension+1]);
00942             if (value_lt(n,tmp1)) {
00943         
00944                 /* New max */
00945                 value_addto(tmp1,D->Ray[r][i+1],D->Ray[r][D->Dimension+1]);
00946                 value_sub_int(tmp1,tmp1,1);
00947                 value_division(n,tmp1,D->Ray[r][D->Dimension+1]);
00948             }
00949         }
00950         value_set_si(c->p[2*i+1][i+1],-1);
00951         value_assign(c->p[2*i+1][D->Dimension+1],n);
00952         value_addto(s,c->p[2*i+1][D->Dimension+1],c->p[2*i][D->Dimension+1]);
00953     
00954         /* Now test if the dimension of the cube is greater than the size */
00955         if(value_gt(s,size[i])) {
00956       
00957 #ifdef EDEBUG62
00958             fprintf(stderr,"size on dimension %d\n",i);
00959             fprintf(stderr,"lcm = ");
00960             for( np=0 ; np<D->Dimension; np++ )
00961                 value_print(stderr,VALUE_FMT,lcm[np]);
00962             fprintf(stderr,", size = ");
00963             for( np=0 ; np<D->Dimension; np++ )
00964                 value_print(stderr,VALUE_FMT,size[np]);
00965             fprintf(stderr,"\n");
00966             fprintf(stderr,"required size (s) = ");
00967             value_print(stderr,VALUE_FMT,s);
00968             fprintf(stderr,"\n");
00969 #endif
00970       
00971             /* If the needed size is "small enough"(<=20 or less than 
00972                twice *size),
00973                then increase *size, and artificially increase lcm too !*/
00974             value_set_si(tmp1,20);
00975             value_addto(tmp2,size[i],size[i]);
00976             if(value_le(s,tmp1)
00977                     || value_le(s,tmp2)) {
00978 
00979                 if( value_zero_p(lcm[i]) )
00980                     value_set_si(lcm[i],1);
00981                 /* lcm divides size... */
00982                 value_division(tmp1,size[i],lcm[i]);
00983         
00984                 /* lcm = ceil(s/h) */
00985                 value_addto(tmp2,s,tmp1);
00986                 value_add_int(tmp2,tmp2,1);
00987                 value_division(lcm[i],tmp2,tmp1);
00988         
00989                 /* new size = lcm*h */
00990                 value_multiply(size[i],lcm[i],tmp1);
00991         
00992 #ifdef EDEBUG62
00993                 fprintf(stderr,"new size = ");
00994                 for( np=0 ; np<D->Dimension; np++ )
00995                     value_print(stderr,VALUE_FMT,size[np]);
00996                 fprintf(stderr,", new lcm = ");
00997                 for( np=0 ; np<D->Dimension; np++ )
00998                     value_print(stderr,VALUE_FMT,lcm[np]);
00999                 fprintf(stderr,"\n");
01000 #endif
01001 
01002             }
01003             else {
01004         
01005 #ifdef EDEBUG62
01006                 fprintf(stderr,"Failed on dimension %d.\n",i);
01007 #endif
01008                 break;
01009             }
01010         }
01011     }
01012     if(i!=D->Dimension) {
01013         Matrix_Free(c);
01014         value_clear(n); value_clear(s);
01015         value_clear(tmp1); value_clear(tmp2);
01016         return(NULL);
01017     }
01018     for(i=0;i<D->Dimension;i++) {
01019         value_subtract(c->p[2*i+1][D->Dimension+1],size[i], 
01020                 c->p[2*i][D->Dimension+1]);
01021     }
01022   
01023 #ifdef EDEBUG62
01024     fprintf(stderr,"PreProcess2 : c =");
01025     Matrix_Print(stderr,P_VALUE_FMT,c);
01026 #endif
01027 
01028     H = Constraints2Polyhedron(c,MAXRAYS);
01029     Matrix_Free(c);
01030     value_clear(n); value_clear(s);
01031     value_clear(tmp1); value_clear(tmp2);
01032     return(H);
01033 } /* Polyhedron_Preprocess2 */
01034 
01035 /**  
01036 
01037 This procedure adds additional constraints to D so that as each
01038 parameter is scanned, it will have a minimum of 'size' points If this
01039 is not possible, an empty polyhedron is returned
01040 
01041 @param D
01042 @param size
01043 @param MAXRAYS
01044 
01045 */
01046 Polyhedron *old_Polyhedron_Preprocess(Polyhedron *D,Value size,
01047                                       unsigned MAXRAYS) {
01048   
01049     int p, p1, ub, lb;
01050     Value a, a1, b, b1, g, aa;
01051     Value abs_a, abs_b, size_copy;
01052     int dim, con, newi, needed;
01053     Value **C;
01054     Matrix *M;
01055     Polyhedron *D1;
01056   
01057     value_init(a); value_init(a1); value_init(b);
01058     value_init(b1); value_init(g); value_init(aa);
01059     value_init(abs_a); value_init(abs_b); value_init(size_copy);
01060   
01061     dim = D->Dimension;
01062     con = D->NbConstraints;
01063     M = Matrix_Alloc(MAXRAYS,dim+2);
01064     newi = 0;
01065     value_assign(size_copy,size);
01066     C = D->Constraint;
01067     for (p=1; p<=dim; p++) {
01068         for (ub=0; ub<con; ub++) {
01069             value_assign(a,C[ub][p]);
01070             if (value_posz_p(a))        /* a >= 0 */
01071                 continue;               /* not an upper bound */
01072             for (lb=0;lb<con;lb++) {
01073                 value_assign(b,C[lb][p]);
01074                 if (value_negz_p(b))
01075                     continue;   /* not a lower bound */
01076         
01077                 /* Check if a new constraint is needed for this (ub,lb) pair */
01078                 /* a constraint is only needed if a previously scanned */
01079                 /* parameter (1..p-1) constrains this parameter (p) */
01080                 needed=0;
01081                 for (p1=1; p1<p; p1++) {
01082                     if (value_notzero_p(C[ub][p1]) ||
01083                         value_notzero_p(C[lb][p1])) {
01084                         needed=1; 
01085                         break;
01086                     }
01087                 }
01088                 if (!needed) continue;  
01089                 value_absolute(abs_a,a);
01090                 value_absolute(abs_b,b);
01091 
01092                 /* Create new constraint: b*UB-a*LB >= a*b*size */
01093                 value_gcd(g, abs_a, abs_b);
01094                 value_divexact(a1, a, g);
01095                 value_divexact(b1, b, g);
01096                 value_set_si(M->p[newi][0],1);
01097                 value_oppose(abs_a,a1);           /* abs_a = -a1 */
01098                 Vector_Combine(&(C[ub][1]),&(C[lb][1]),&(M->p[newi][1]),
01099                         b1,abs_a,dim+1);
01100                 value_multiply(aa,a1,b1);
01101                 value_addmul(M->p[newi][dim+1], aa, size_copy);
01102                 Vector_Normalize(&(M->p[newi][1]),(dim+1));
01103                 newi++;
01104             }
01105         }
01106     }
01107     D1 = AddConstraints(M->p_Init,newi,D,MAXRAYS);
01108     Matrix_Free(M);
01109   
01110     value_clear(a); value_clear(a1); value_clear(b);
01111     value_clear(b1); value_clear(g); value_clear(aa);
01112     value_clear(abs_a); value_clear(abs_b); value_clear(size_copy);
01113     return D1;
01114 } /* old_Polyhedron_Preprocess */
01115 
01116 /** 
01117 
01118 PROCEDURES TO COMPUTE ENUMERATION. recursive procedure, recurse for
01119 each imbriquation
01120 
01121 @param pos index position of current loop index (1..hdim-1)
01122 @param P loop domain
01123 @param context context values for fixed indices 
01124 @param res the number of integer points in this
01125 polyhedron 
01126 
01127 */
01128 void count_points (int pos,Polyhedron *P,Value *context, Value *res) {
01129    
01130     Value LB, UB, k, c;
01131 
01132     POL_ENSURE_FACETS(P);
01133     POL_ENSURE_VERTICES(P);
01134 
01135     if (emptyQ(P)) {
01136         value_set_si(*res, 0);
01137         return;
01138     }
01139 
01140     value_init(LB); value_init(UB); value_init(k);
01141     value_set_si(LB,0);
01142     value_set_si(UB,0);
01143 
01144     if (lower_upper_bounds(pos,P,context,&LB,&UB) !=0) {
01145     
01146         /* Problem if UB or LB is INFINITY */
01147         fprintf(stderr, "count_points: ? infinite domain\n");
01148         value_clear(LB); value_clear(UB); value_clear(k);
01149         value_set_si(*res, -1);
01150         return;
01151     }
01152   
01153 #ifdef EDEBUG1
01154     if (!P->next) {
01155         int i;
01156         for (value_assign(k,LB); value_le(k,UB); value_increment(k,k)) {
01157             fprintf(stderr, "(");
01158             for (i=1; i<pos; i++) {
01159                 value_print(stderr,P_VALUE_FMT,context[i]);
01160                 fprintf(stderr,",");
01161             }
01162             value_print(stderr,P_VALUE_FMT,k);
01163             fprintf(stderr,")\n");
01164         }
01165     }
01166 #endif
01167   
01168     value_set_si(context[pos],0);
01169     if (value_lt(UB,LB)) {
01170         value_clear(LB); value_clear(UB); value_clear(k);
01171         value_set_si(*res, 0);
01172         return;  
01173     }  
01174     if (!P->next) {
01175         value_subtract(k,UB,LB);
01176         value_add_int(k,k,1);
01177         value_assign(*res, k);
01178         value_clear(LB); value_clear(UB); value_clear(k);
01179         return;
01180     } 
01181 
01182     /*-----------------------------------------------------------------*/
01183     /* Optimization idea                                               */
01184     /*   If inner loops are not a function of k (the current index)    */
01185     /*   i.e. if P->Constraint[i][pos]==0 for all P following this and */
01186     /*        for all i,                                               */
01187     /*   Then CNT = (UB-LB+1)*count_points(pos+1, P->next, context)    */
01188     /*   (skip the for loop)                                           */
01189     /*-----------------------------------------------------------------*/
01190   
01191     value_init(c);
01192     value_set_si(*res, 0);
01193     for (value_assign(k,LB);value_le(k,UB);value_increment(k,k)) {
01194         /* Insert k in context */
01195         value_assign(context[pos],k);
01196         count_points(pos+1,P->next,context,&c);
01197         if(value_notmone_p(c))
01198             value_addto(*res, *res, c);
01199         else {
01200             value_set_si(*res, -1);
01201             break;
01202         }
01203     }
01204     value_clear(c);
01205   
01206 #ifdef EDEBUG11
01207     fprintf(stderr,"%d\n",CNT);
01208 #endif
01209   
01210     /* Reset context */
01211     value_set_si(context[pos],0);
01212     value_clear(LB); value_clear(UB); value_clear(k);
01213     return;
01214 } /* count_points */
01215 
01216 /*-------------------------------------------------------------------*/
01217 /* enode *P_Enum(L, LQ, context, pos, nb_param, dim, lcm,param_name) */
01218 /*     L : list of polyhedra for the loop nest                       */
01219 /*     LQ : list of polyhedra for the parameter loop nest            */
01220 /*     pos : 1..nb_param, position of the parameter                  */
01221 /*     nb_param : number of parameters total                         */
01222 /*     dim : total dimension of the polyhedron, param incl.          */
01223 /*     lcm : denominator array [0..dim-1] of the polyhedron          */
01224 /*     param_name : name of the parameters                           */
01225 /* Returns an enode tree representing the pseudo polynomial          */
01226 /*   expression for the enumeration of the polyhedron.               */
01227 /* A recursive procedure.                                            */
01228 /*-------------------------------------------------------------------*/
01229 static enode *P_Enum(Polyhedron *L,Polyhedron *LQ,Value *context,int pos,
01230                      int nb_param,int dim,Value *lcm, const char **param_name)
01231 {
01232   enode *res,*B,*C;
01233   int hdim,i,j,rank,flag;
01234   Value n,g,nLB,nUB,nlcm,noff,nexp,k1,nm,hdv,k,lcm_copy;
01235   Value tmp;
01236   Matrix *A;
01237 
01238 #ifdef EDEBUG
01239   fprintf(stderr,"-------------------- begin P_Enum -------------------\n");
01240   fprintf(stderr,"Calling P_Enum with pos = %d\n",pos);
01241 #endif
01242   
01243   /* Initialize all the 'Value' variables */
01244   value_init(n); value_init(g); value_init(nLB);
01245   value_init(nUB); value_init(nlcm); value_init(noff);
01246   value_init(nexp); value_init(k1); value_init(nm);
01247   value_init(hdv); value_init(k); value_init(tmp);
01248   value_init(lcm_copy);
01249 
01250   if( value_zero_p(lcm[pos-1]) )
01251   {
01252                 hdim = 1;
01253                 value_set_si( lcm_copy, 1 );
01254   }
01255   else
01256   {
01257           /* hdim is the degree of the polynomial + 1 */
01258                 hdim = dim-nb_param+1; /* homogenous dim w/o parameters */
01259                 value_assign( lcm_copy, lcm[pos-1] );
01260   }  
01261 
01262   /* code to limit generation of equations to valid parameters only */
01263   /*----------------------------------------------------------------*/
01264   flag = lower_upper_bounds(pos,LQ,&context[dim-nb_param],&nLB,&nUB);
01265   if (flag & LB_INFINITY) {
01266     if (!(flag & UB_INFINITY)) {
01267       
01268       /* Only an upper limit: set lower limit */
01269       /* Compute nLB such that (nUB-nLB+1) >= (hdim*lcm) */
01270       value_sub_int(nLB,nUB,1);
01271       value_set_si(hdv,hdim);
01272       value_multiply(tmp,hdv,lcm_copy);
01273       value_subtract(nLB,nLB,tmp);
01274       if(value_pos_p(nLB))
01275         value_set_si(nLB,0);
01276     }
01277     else {
01278       value_set_si(nLB,0);
01279       
01280       /* No upper nor lower limit: set lower limit to 0 */
01281       value_set_si(hdv,hdim);
01282       value_multiply(nUB,hdv,lcm_copy);
01283       value_add_int(nUB,nUB,1);
01284     }
01285   }
01286 
01287   /* if (nUB-nLB+1) < (hdim*lcm) then we have more unknowns than equations */
01288   /* We can: 1. Find more equations by changing the context parameters, or */
01289   /* 2. Assign extra unknowns values in such a way as to simplify result.  */
01290   /* Think about ways to scan parameter space to get as much info out of it*/
01291   /* as possible.                                                          */
01292   
01293 #ifdef REDUCE_DEGREE
01294   if (pos==1 && (flag & UB_INFINITY)==0) {
01295     /* only for finite upper bound on first parameter */
01296     /* NOTE: only first parameter because subsequent parameters may
01297        be artificially limited by the choice of the first parameter */
01298    
01299 #ifdef EDEBUG
01300     fprintf(stderr,"*************** n **********\n");
01301     value_print(stderr,VALUE_FMT,n);
01302     fprintf(stderr,"\n");
01303 #endif
01304 
01305     value_subtract(n,nUB,nLB);
01306     value_increment(n,n);
01307     
01308 #ifdef EDEBUG 
01309     value_print(stderr,VALUE_FMT,n);
01310     fprintf(stderr,"\n*************** n ************\n");
01311 #endif 
01312 
01313     /* Total number of samples>0 */
01314     if(value_neg_p(n))
01315       i=0;
01316     else {
01317       value_modulus(tmp,n,lcm_copy);
01318       if(value_notzero_p(tmp)) {
01319                   value_division(tmp,n,lcm_copy);
01320                   value_increment(tmp,tmp);
01321                   i = VALUE_TO_INT(tmp);
01322       }
01323       else {
01324                   value_division(tmp,n,lcm_copy);
01325                   i =   VALUE_TO_INT(tmp);      /* ceiling of n/lcm */
01326       }
01327     }
01328 
01329 #ifdef EDEBUG 
01330     value_print(stderr,VALUE_FMT,n);
01331     fprintf(stderr,"\n*************** n ************\n");
01332 #endif 
01333     
01334     /* Reduce degree of polynomial based on number of sample points */
01335     if (i < hdim){
01336       hdim=i;
01337       
01338 #ifdef EDEBUG4
01339       fprintf(stdout,"Parameter #%d: LB=",pos);
01340       value_print(stdout,VALUE_FMT,nLB);
01341       fprintf(stdout," UB=");
01342       value_print(stdout,VALUE_FMT,nUB);
01343       fprintf(stdout," lcm=");
01344       value_print(stdout,VALUE_FMT,lcm_copy);
01345       fprintf(stdout," degree reduced to %d\n",hdim-1);
01346 #endif
01347       
01348     }
01349   }
01350 #endif /* REDUCE_DEGREE */
01351   
01352   /* hdim is now set */  
01353   /* allocate result structure */
01354   res = new_enode(polynomial,hdim,pos);
01355   for (i=0;i<hdim;i++) {
01356     int l;
01357     l = VALUE_TO_INT(lcm_copy);
01358     res->arr[i].x.p = new_enode(periodic,l,pos);
01359   }
01360   
01361   /* Utility arrays */
01362   A = Matrix_Alloc(hdim, 2*hdim+1);               /* used for Gauss */
01363   B = new_enode(evector, hdim, 0);
01364   C = new_enode(evector, hdim, 0);
01365 
01366   /* We'll create these again when we need them */
01367   for (j = 0; j < hdim; ++j)
01368     free_evalue_refs(&C->arr[j]);
01369   
01370   /*----------------------------------------------------------------*/
01371   /*                                                                */
01372   /*                                0<-----+---k--------->          */
01373   /* |---------noff----------------->-nlcm->-------lcm---->         */
01374   /* |--- . . . -----|--------------|------+-------|------+-------|-*/
01375   /* 0          (q-1)*lcm         q*lcm    |  (q+1)*lcm   |         */
01376   /*                                      nLB          nLB+lcm      */
01377   /*                                                                */
01378   /*----------------------------------------------------------------*/
01379   if(value_neg_p(nLB)) {
01380     value_modulus(nlcm,nLB,lcm_copy);
01381     value_addto(nlcm,nlcm,lcm_copy);
01382   }
01383   else {
01384     value_modulus(nlcm,nLB,lcm_copy);
01385   }
01386   
01387   /* noff is a multiple of lcm */
01388   value_subtract(noff,nLB,nlcm);
01389   value_addto(tmp,lcm_copy,nlcm);
01390   for (value_assign(k,nlcm);value_lt(k,tmp);) {
01391  
01392 #ifdef EDEBUG
01393     fprintf(stderr,"Finding ");
01394     value_print(stderr,VALUE_FMT,k);
01395     fprintf(stderr,"-th elements of periodic coefficients\n");
01396 #endif
01397 
01398     value_set_si(hdv,hdim);
01399     value_multiply(nm,hdv,lcm_copy);
01400     value_addto(nm,nm,nLB);
01401     i=0;
01402     for (value_addto(n,k,noff); value_lt(n,nm); 
01403          value_addto(n,n,lcm_copy),i++) {
01404       
01405       /* n == i*lcm + k + noff;   */
01406       /* nlcm <= k < nlcm+lcm     */
01407       /* n mod lcm == k1 */
01408       
01409 #ifdef ALL_OVERFLOW_WARNINGS
01410       if (((flag & UB_INFINITY)==0) && value_gt(n,nUB)) {
01411         fprintf(stdout,"Domain Overflow: Parameter #%d:",pos);
01412         fprintf(stdout,"nLB=");
01413         value_print(stdout,VALUE_FMT,nLB);
01414         fprintf(stdout," n=");
01415         value_print(stdout,VALUE_FMT,n);
01416         fprintf(stdout," nUB=");
01417         value_print(stdout,VALUE_FMT,nUB);
01418         fprintf(stdout,"\n");
01419       }
01420 #else
01421       if (overflow_warning_flag && ((flag & UB_INFINITY)==0) &&
01422           value_gt(n,nUB)) {
01423         fprintf(stdout,"\nWARNING: Parameter Domain Overflow.");
01424         fprintf(stdout," Result may be incorrect on this domain.\n");
01425         overflow_warning_flag = 0;
01426       }
01427 #endif
01428       
01429       /* Set parameter to n */
01430       value_assign(context[dim-nb_param+pos],n);
01431       
01432 #ifdef EDEBUG1
01433         if( param_name )
01434         {
01435       fprintf(stderr,"%s = ",param_name[pos-1]);
01436       value_print(stderr,VALUE_FMT,n);
01437       fprintf(stderr," (hdim=%d, lcm[%d]=",hdim,pos-1);
01438       value_print(stderr,VALUE_FMT,lcm_copy);
01439       fprintf(stderr,")\n");
01440         }
01441         else
01442         {
01443       fprintf(stderr,"P%d = ",pos);
01444       value_print(stderr,VALUE_FMT,n);
01445       fprintf(stderr," (hdim=%d, lcm[%d]=",hdim,pos-1);
01446       value_print(stderr,VALUE_FMT,lcm_copy);
01447       fprintf(stderr,")\n");      
01448         }
01449 #endif
01450       
01451       /* Setup B vector */
01452       if (pos==nb_param) {
01453         
01454 #ifdef EDEBUG   
01455         fprintf(stderr,"Yes\n");
01456 #endif 
01457         
01458         /* call count */
01459         /* count can only be called when the context is fully specified */
01460         value_set_si(B->arr[i].d,1);
01461         value_init(B->arr[i].x.n);
01462         count_points(1,L,context,&B->arr[i].x.n);
01463         
01464 #ifdef EDEBUG3
01465         for (j=1; j<pos; j++) fputs("   ",stdout);
01466         fprintf(stdout, "E(");
01467         for (j=1; j<nb_param; j++) {
01468           value_print(stdout,VALUE_FMT,context[dim-nb_param+j]);
01469           fprintf(stdout,",");
01470         }  
01471         value_print(stdout,VALUE_FMT,n);
01472         fprintf(stdout,") = ");
01473         value_print(stdout,VALUE_FMT,B->arr[i].x.n);
01474         fprintf(stdout," =");
01475 #endif
01476         
01477       }
01478       else {    /* count is a function of other parameters */
01479         /* call P_Enum recursively */
01480         value_set_si(B->arr[i].d,0);
01481         B->arr[i].x.p = P_Enum(L,LQ->next,context,pos+1,
01482                                nb_param,dim,lcm,param_name);
01483         
01484 #ifdef EDEBUG3
01485         if( param_name )
01486         {
01487                 for (j=1; j<pos; j++)
01488                   fputs("   ", stdout);
01489                 fprintf(stdout, "E(");
01490                 for (j=1; j<=pos; j++) {
01491                   value_print(stdout,VALUE_FMT,context[dim-nb_param+j]);
01492                   fprintf(stdout,",");
01493                 }         
01494                 for (j=pos+1; j<nb_param; j++)
01495                   fprintf(stdout,"%s,",param_name[j]);
01496                 fprintf(stdout,"%s) = ",param_name[j]);
01497                 print_enode(stdout,B->arr[i].x.p,param_name);
01498                 fprintf(stdout," =");
01499         }
01500 #endif
01501         
01502       }
01503       
01504       /* Create i-th equation*/
01505       /* K_0 + K_1 * n**1 + ... + K_dim * n**dim | Identity Matrix */
01506       
01507       value_set_si(A->p[i][0],0);  /* status bit = equality */
01508       value_set_si(nexp,1);
01509       for (j=1;j<=hdim;j++) {
01510         value_assign(A->p[i][j],nexp);
01511         value_set_si(A->p[i][j+hdim],0);
01512         
01513 #ifdef EDEBUG3
01514         fprintf(stdout," + ");
01515         value_print(stdout,VALUE_FMT,nexp);
01516         fprintf(stdout," c%d",j);
01517 #endif  
01518         value_multiply(nexp,nexp,n);
01519       }
01520       
01521 #ifdef EDEBUG3
01522       fprintf(stdout, "\n");
01523 #endif
01524       
01525       value_set_si(A->p[i][i+1+hdim],1);      
01526     }
01527     
01528     /* Assertion check */
01529     if (i!=hdim)
01530       fprintf(stderr, "P_Enum: ?expecting i==hdim\n");
01531     
01532 #ifdef EDEBUG
01533         if( param_name )
01534         {
01535     fprintf(stderr,"B (enode) =\n");
01536     print_enode(stderr,B,param_name);
01537         }
01538     fprintf(stderr,"A (Before Gauss) =\n");
01539     Matrix_Print(stderr,P_VALUE_FMT,A);
01540 #endif
01541     
01542     /* Solve hdim (=dim+1) equations with hdim unknowns, result in CNT */
01543     rank = Gauss(A,hdim,2*hdim);
01544     
01545 #ifdef EDEBUG
01546     fprintf(stderr,"A (After Gauss) =\n");
01547     Matrix_Print(stderr,P_VALUE_FMT,A);
01548 #endif
01549     
01550     /* Assertion check */
01551     if (rank!=hdim) {
01552       fprintf(stderr, "P_Enum: ?expecting rank==hdim\n");
01553     }
01554     
01555     /* if (rank < hdim) then set the last hdim-rank coefficients to ? */
01556     /* if (rank == 0) then set all coefficients to 0 */    
01557     /* copy result as k1-th element of periodic numbers */
01558     if(value_lt(k,lcm_copy))
01559       value_assign(k1,k);
01560     else
01561       value_subtract(k1,k,lcm_copy);
01562     
01563     for (i=0; i<rank; i++) {
01564       
01565       /* Set up coefficient vector C from i-th row of inverted matrix */
01566       for (j=0; j<rank; j++) {
01567         value_gcd(g, A->p[i][i+1], A->p[i][j+1+hdim]);
01568         value_init(C->arr[j].d);
01569         value_divexact(C->arr[j].d, A->p[i][i+1], g);
01570         value_init(C->arr[j].x.n);
01571         value_divexact(C->arr[j].x.n, A->p[i][j+1+hdim], g);
01572       }
01573       
01574 #ifdef EDEBUG
01575         if( param_name )
01576         {
01577       fprintf(stderr, "C (enode) =\n");
01578       print_enode(stderr, C, param_name);
01579         }
01580 #endif
01581       
01582       /* The i-th enode is the lcm-periodic coefficient of term n**i */
01583       edot(B,C,&(res->arr[i].x.p->arr[VALUE_TO_INT(k1)]));
01584       
01585 #ifdef EDEBUG
01586         if( param_name )
01587         {
01588       fprintf(stderr, "B.C (evalue)=\n");
01589       print_evalue(stderr,&(res->arr[i].x.p->arr[VALUE_TO_INT(k1)]),
01590                    param_name);
01591       fprintf(stderr,"\n");
01592         }
01593 #endif
01594       
01595       for (j = 0; j < rank; ++j)
01596         free_evalue_refs(&C->arr[j]);
01597     }
01598     value_addto(tmp,lcm_copy,nlcm);
01599 
01600     value_increment(k,k);
01601     for (i = 0; i < hdim; ++i) {
01602       free_evalue_refs(&B->arr[i]);
01603       if (value_lt(k,tmp))
01604         value_init(B->arr[i].d);
01605     }
01606   }
01607   
01608 #ifdef EDEBUG
01609         if( param_name )
01610         {
01611           fprintf(stderr,"res (enode) =\n");
01612           print_enode(stderr,res,param_name);
01613         }
01614   fprintf(stderr, "-------------------- end P_Enum -----------------------\n");
01615 #endif
01616   
01617   /* Reset context */
01618   value_set_si(context[dim-nb_param+pos],0);
01619   
01620   /* Release memory */
01621   Matrix_Free(A);
01622   free(B);
01623   free(C);
01624   
01625   /* Clear all the 'Value' variables */
01626   value_clear(n); value_clear(g); value_clear(nLB);
01627   value_clear(nUB); value_clear(nlcm); value_clear(noff);
01628   value_clear(nexp); value_clear(k1); value_clear(nm);
01629   value_clear(hdv); value_clear(k); value_clear(tmp);
01630   value_clear(lcm_copy);
01631   return res;
01632 } /* P_Enum */
01633 
01634 /*----------------------------------------------------------------*/
01635 /* Scan_Vertices(PP, Q, CT)                                       */
01636 /*    PP : ParamPolyhedron                                        */
01637 /*    Q : Domain                                                  */
01638 /*    CT : Context transformation matrix                          */
01639 /*    lcm : lcm array (output)                                    */
01640 /*    nbp : number of parameters                                  */
01641 /*    param_name : name of the parameters                         */
01642 /*----------------------------------------------------------------*/
01643 static void Scan_Vertices(Param_Polyhedron *PP,Param_Domain *Q,Matrix *CT,
01644    Value *lcm, int nbp, const char **param_name)
01645 {
01646   Param_Vertices *V;
01647   int i, j, ix, l, np;
01648   unsigned bx;
01649   Value k,m1;
01650 
01651   /* Compute the denominator of P */
01652   /* lcm = Least Common Multiple of the denominators of the vertices of P */
01653   /* and print the vertices */  
01654 
01655   value_init(k); value_init(m1);
01656   for( np=0 ; np<nbp ; np++ )
01657     value_set_si( lcm[np], 0 );
01658 
01659         if( param_name )
01660           fprintf(stdout,"Vertices:\n");
01661 
01662   for(i=0,ix=0,bx=MSB,V=PP->V; V && i<PP->nbV; i++,V=V->next) {
01663     if (Q->F[ix] & bx) {
01664       if( param_name )
01665         {
01666           if(CT) {
01667             Matrix *v;
01668             v = VertexCT(V->Vertex,CT);
01669             Print_Vertex(stdout,v,param_name);
01670             Matrix_Free(v);
01671           }
01672           else
01673             Print_Vertex(stdout,V->Vertex,param_name);
01674           fprintf(stdout,"\n");
01675         }
01676       
01677       for(j=0;j<V->Vertex->NbRows;j++) {
01678         /* A matrix */
01679         for( l=0 ; l<V->Vertex->NbColumns-1 ; l++ )
01680           {
01681             if( value_notzero_p(V->Vertex->p[j][l]) )
01682               {
01683                 value_gcd(m1, V->Vertex->p[j][V->Vertex->NbColumns-1],
01684                           V->Vertex->p[j][l]);
01685                 value_divexact(k, V->Vertex->p[j][V->Vertex->NbColumns-1], m1);
01686                 if( value_notzero_p(lcm[l]) )
01687                   {
01688                     /* lcm[l] = lcm[l] * k / gcd(k,lcm[l]) */
01689                     if (value_notzero_p(k) && value_notone_p(k))
01690                       {
01691                         value_gcd(m1, lcm[l], k);
01692                         value_divexact(k, k, m1);
01693                         value_multiply(lcm[l],lcm[l],k);
01694                       }
01695                   }
01696                 else
01697                   {
01698                     value_assign(lcm[l],k);
01699                   }
01700               }
01701           }
01702       }
01703     }
01704     NEXT(ix,bx);
01705   }
01706   value_clear(k); value_clear(m1);
01707 } /* Scan_Vertices */
01708 
01709 /**
01710 
01711 Procedure to count points in a non-parameterized polytope.
01712 
01713 @param P       Polyhedron to count
01714 @param C       Parameter Context domain
01715 @param CT      Matrix to transform context to original
01716 @param CEq     additionnal equalities in context
01717 @param MAXRAYS workspace size
01718 @param param_name parameter names
01719 
01720 */
01721 Enumeration *Enumerate_NoParameters(Polyhedron *P,Polyhedron *C,
01722                                     Matrix *CT,Polyhedron *CEq,
01723                                     unsigned MAXRAYS, const char **param_name)
01724 {
01725     Polyhedron *L;
01726     Enumeration *res;
01727     Value *context;
01728     int j;
01729     int hdim = P->Dimension + 1;
01730     int r,i;
01731   
01732     /* Create a context vector size dim+2 */
01733     context = (Value *) malloc((hdim+1)*sizeof(Value));
01734     for (j=0;j<= hdim;j++) 
01735         value_init(context[j]);
01736   
01737     res = (Enumeration *)malloc(sizeof(Enumeration));
01738     res->next = NULL;
01739     res->ValidityDomain = Universe_Polyhedron(0);  /* no parameters */
01740     value_init(res->EP.d);
01741     value_set_si(res->EP.d,0);  
01742     L = Polyhedron_Scan(P,res->ValidityDomain,MAXRAYS);
01743   
01744 #ifdef EDEBUG2
01745     fprintf(stderr, "L = \n");
01746     Polyhedron_Print(stderr, P_VALUE_FMT, L);
01747 #endif
01748   
01749     if(CT) {
01750         Polyhedron *Dt;
01751     
01752         /* Add parameters to validity domain */
01753         Dt = Polyhedron_Preimage(res->ValidityDomain,CT,MAXRAYS);
01754         Polyhedron_Free(res->ValidityDomain);
01755         res->ValidityDomain = DomainIntersection(Dt,CEq,MAXRAYS);
01756         Polyhedron_Free(Dt);
01757     }
01758   
01759         if( param_name )
01760         {
01761     fprintf(stdout,"---------------------------------------\n");
01762     fprintf(stdout,"Domain:\n");
01763     Print_Domain(stdout,res->ValidityDomain, param_name);
01764   
01765     /* Print the vertices */
01766     printf("Vertices:\n");
01767     for(r=0;r<P->NbRays;++r) {
01768         if(value_zero_p(P->Ray[r][0]))
01769             printf("(line) ");
01770         printf("[");
01771         if (P->Dimension > 0)
01772             value_print(stdout,P_VALUE_FMT,P->Ray[r][1]);
01773         for(i=1;i<P->Dimension;i++) {
01774             printf(", ");
01775             value_print(stdout,P_VALUE_FMT,P->Ray[r][i+1]);
01776         }  
01777         printf("]");
01778         if(value_notone_p(P->Ray[r][P->Dimension+1])) {
01779             printf("/");
01780             value_print(stdout,P_VALUE_FMT, P->Ray[r][P->Dimension+1]);
01781         }
01782         printf("\n");
01783     }
01784         }
01785 
01786   res->EP.x.p = new_enode(polynomial,1,0);;
01787   value_set_si(res->EP.x.p->arr[0].d, 1);
01788   value_init(res->EP.x.p->arr[0].x.n);
01789 
01790   if (emptyQ(P)) {
01791     value_set_si(res->EP.x.p->arr[0].x.n, 0);
01792   } else if (!L) {
01793     /* Non-empty zero-dimensional domain */
01794     value_set_si(res->EP.x.p->arr[0].x.n, 1);
01795   } else {
01796     CATCH(overflow_error) {
01797         fprintf(stderr,"Enumerate: arithmetic overflow error.\n");
01798         fprintf(stderr,"You should rebuild PolyLib using GNU-MP"
01799                 " or increasing the size of integers.\n");
01800         overflow_warning_flag = 0;
01801         assert(overflow_warning_flag);
01802     }
01803     TRY {
01804     
01805         Vector_Set(context,0,(hdim+1));
01806     
01807         /* Set context[hdim] = 1  (the constant) */
01808         value_set_si(context[hdim],1);
01809         count_points(1, L, context, &res->EP.x.p->arr[0].x.n);
01810         UNCATCH(overflow_error);
01811     }
01812   }
01813   
01814     Domain_Free(L);
01815   
01816     /*  **USELESS, there are no references to parameters in res**
01817         if( CT )
01818         addeliminatedparams_evalue(&res->EP, CT);
01819     */
01820   
01821         if( param_name )
01822         {
01823     fprintf(stdout,"\nEhrhart Polynomial:\n");
01824     print_evalue(stdout,&res->EP,param_name);
01825     fprintf(stdout, "\n");
01826         }
01827 
01828     for (j=0;j<= hdim;j++) 
01829         value_clear(context[j]);  
01830     free(context);
01831     return(res);
01832 } /* Enumerate_NoParameters */
01833 
01834 /**  Procedure to count points in a parameterized polytope.
01835 
01836 @param Pi Polyhedron to enumerate
01837 @param C Context Domain
01838 @param MAXRAYS size of workspace
01839 @param param_name parameter names (array of strings), may be NULL
01840 @return a list of validity domains + evalues EP
01841 
01842 */
01843 Enumeration *Polyhedron_Enumerate(Polyhedron *Pi,Polyhedron *C,
01844                                   unsigned MAXRAYS, const char **param_name)
01845 {
01846   Polyhedron *L, *CQ, *CQ2, *LQ, *U, *CEq, *rVD, *P, *Ph = NULL;
01847   Matrix *CT;
01848   Param_Polyhedron *PP;
01849   Param_Domain   *Q;
01850   int i,hdim, dim, nb_param, np;
01851   Value *lcm, *m1, hdv;
01852   Value *context;
01853   Enumeration *en, *res;
01854 
01855   if (POL_ISSET(MAXRAYS, POL_NO_DUAL))
01856     MAXRAYS = 0;
01857 
01858   POL_ENSURE_FACETS(Pi);
01859   POL_ENSURE_VERTICES(Pi);
01860   POL_ENSURE_FACETS(C);
01861   POL_ENSURE_VERTICES(C);
01862 
01863   res = NULL;
01864   P = Pi;
01865 
01866 #ifdef EDEBUG2
01867   fprintf(stderr,"C = \n");
01868   Polyhedron_Print(stderr,P_VALUE_FMT,C);
01869   fprintf(stderr,"P = \n");
01870   Polyhedron_Print(stderr,P_VALUE_FMT,P);
01871 #endif
01872 
01873   hdim          = P->Dimension + 1;
01874   dim           = P->Dimension;
01875   nb_param      = C->Dimension;
01876 
01877   /* Don't call Polyhedron2Param_Domain if there are no parameters */
01878   if(nb_param == 0) {
01879     
01880     return(Enumerate_NoParameters(P,C,NULL,NULL,MAXRAYS,param_name));  
01881   }
01882   if(nb_param == dim) {
01883     res = (Enumeration *)malloc(sizeof(Enumeration));
01884     res->next = 0;
01885     res->ValidityDomain = DomainIntersection(P,C,MAXRAYS);
01886     value_init(res->EP.d);
01887     value_init(res->EP.x.n);
01888     value_set_si(res->EP.d,1);
01889     value_set_si(res->EP.x.n,1);
01890     if( param_name ) {
01891       fprintf(stdout,"---------------------------------------\n");
01892       fprintf(stdout,"Domain:\n");
01893       Print_Domain(stdout,res->ValidityDomain, param_name);
01894       fprintf(stdout,"\nEhrhart Polynomial:\n");
01895       print_evalue(stdout,&res->EP,param_name);
01896       fprintf(stdout, "\n");
01897     }
01898     return res;
01899   }
01900   PP = Polyhedron2Param_SimplifiedDomain(&P,C,MAXRAYS,&CEq,&CT);
01901   if(!PP) {
01902         if( param_name )
01903     fprintf(stdout, "\nEhrhart Polynomial:\nNULL\n");
01904 
01905     return(NULL);
01906   }
01907   
01908   /* CT : transformation matrix to eliminate useless ("false") parameters */
01909   if(CT) {
01910     nb_param -= CT->NbColumns-CT->NbRows;
01911     dim  -= CT->NbColumns-CT->NbRows;
01912     hdim -= CT->NbColumns-CT->NbRows;
01913     
01914     /* Don't call Polyhedron2Param_Domain if there are no parameters */
01915     if(nb_param == 0) {
01916         res = Enumerate_NoParameters(P,C,CT,CEq,MAXRAYS,param_name);
01917         Param_Polyhedron_Free(PP);
01918         goto out;
01919     }  
01920   }
01921 
01922   /* get memory for Values */
01923   lcm = (Value *)malloc((nb_param+1) * sizeof(Value));
01924   m1  = (Value *)malloc((nb_param+1) * sizeof(Value));
01925   /* Initialize all the 'Value' variables */
01926   for( np=0 ; np < nb_param+1; np++ )
01927   {
01928     value_init(lcm[np]); value_init(m1[np]);
01929   }
01930   value_init(hdv);
01931 
01932   for(Q=PP->D;Q;Q=Q->next) {
01933     int hom = 0;
01934     if(CT) {
01935       Polyhedron *Dt;
01936       CQ = Q->Domain;      
01937       Dt = Polyhedron_Preimage(Q->Domain,CT,MAXRAYS);
01938       rVD = DomainIntersection(Dt,CEq,MAXRAYS);
01939       
01940       /* if rVD is empty or too small in geometric dimension */
01941       if(!rVD || emptyQ(rVD) ||
01942          (rVD->Dimension-rVD->NbEq < Dt->Dimension-Dt->NbEq-CEq->NbEq)) {
01943         if(rVD)
01944           Polyhedron_Free(rVD);
01945         Polyhedron_Free(Dt);
01946         Polyhedron_Free(CQ);
01947         continue;               /* empty validity domain */
01948       }
01949       Polyhedron_Free(Dt);
01950     }
01951     else
01952       rVD = CQ = Q->Domain;    
01953     en = (Enumeration *)malloc(sizeof(Enumeration));
01954     en->next = res;
01955     res = en;
01956     res->ValidityDomain = rVD;
01957     
01958     if( param_name ) {
01959       fprintf(stdout,"---------------------------------------\n");
01960       fprintf(stdout,"Domain:\n");
01961     
01962 #ifdef EPRINT_ALL_VALIDITY_CONSTRAINTS
01963       Print_Domain(stdout,res->ValidityDomain,param_name);
01964 #else    
01965       {
01966         Polyhedron *VD;
01967         VD = DomainSimplify(res->ValidityDomain,C,MAXRAYS);
01968         Print_Domain(stdout,VD,param_name);
01969         Domain_Free(VD);
01970       }
01971 #endif /* EPRINT_ALL_VALIDITY_CONSTRAINTS */
01972     }
01973     
01974     overflow_warning_flag = 1;
01975     
01976     /* Scan the vertices and compute lcm */
01977     Scan_Vertices(PP,Q,CT,lcm,nb_param,param_name);
01978     
01979 #ifdef EDEBUG2
01980     fprintf(stderr,"Denominator = ");
01981     for( np=0;np<nb_param;np++)
01982       value_print(stderr,P_VALUE_FMT,lcm[np]);
01983     fprintf(stderr," and hdim == %d \n",hdim);
01984 #endif
01985     
01986 #ifdef EDEBUG2
01987     fprintf(stderr,"CQ = \n");
01988     Polyhedron_Print(stderr,P_VALUE_FMT,CQ);
01989 #endif
01990 
01991     /* Before scanning, add constraints to ensure at least hdim*lcm */
01992     /* points in every dimension */
01993     value_set_si(hdv,hdim-nb_param);
01994 
01995     for( np=0;np<nb_param+1;np++) {
01996         if( value_notzero_p(lcm[np]) )
01997             value_multiply(m1[np],hdv,lcm[np]);
01998         else
01999             value_set_si(m1[np],1);
02000     }
02001 
02002 #ifdef EDEBUG2 
02003     fprintf(stderr,"m1 == ");
02004     for( np=0;np<nb_param;np++)
02005       value_print(stderr,P_VALUE_FMT,m1[np]);
02006     fprintf(stderr,"\n");
02007 #endif 
02008 
02009     CATCH(overflow_error) {
02010       fprintf(stderr,"Enumerate: arithmetic overflow error.\n");
02011       CQ2 = NULL;
02012     }
02013     TRY {      
02014       CQ2 = Polyhedron_Preprocess(CQ,m1,MAXRAYS);
02015 
02016 #ifdef EDEBUG2
02017       fprintf(stderr,"After preprocess, CQ2 = ");
02018       Polyhedron_Print(stderr,P_VALUE_FMT,CQ2);
02019 #endif
02020       
02021       UNCATCH(overflow_error);
02022     }
02023 
02024     /* Vin100, Feb 2001 */
02025     /* in case of degenerate, try to find a domain _containing_ CQ */
02026     if ((!CQ2 || emptyQ(CQ2)) && CQ->NbBid==0) {
02027       int r;
02028       
02029 #ifdef EDEBUG2
02030       fprintf(stderr,"Trying to call Polyhedron_Preprocess2 : CQ = \n");
02031       Polyhedron_Print(stderr,P_VALUE_FMT,CQ);
02032 #endif
02033       
02034       /* Check if CQ is bounded */
02035       for(r=0;r<CQ->NbRays;r++) {
02036         if(value_zero_p(CQ->Ray[r][0]) ||
02037            value_zero_p(CQ->Ray[r][CQ->Dimension+1]))
02038           break;
02039       }
02040       if(r==CQ->NbRays) {
02041         
02042         /* ok, CQ is bounded */
02043         /* now find if CQ is contained in a hypercube of size m1 */
02044         CQ2 = Polyhedron_Preprocess2(CQ,m1,lcm,MAXRAYS);
02045       }
02046     }
02047 
02048     if (!CQ2) {
02049       Polyhedron *tmp;
02050 #ifdef EDEBUG2
02051       fprintf(stderr,"Homogenize.\n");
02052 #endif
02053       hom = 1;
02054       tmp = homogenize(CQ, MAXRAYS);
02055       CQ2 = Polyhedron_Preprocess(tmp,m1,MAXRAYS);
02056       Polyhedron_Free(tmp);
02057       if (!Ph)
02058         Ph = homogenize(P, MAXRAYS);
02059       for (np=0; np < nb_param+1; np++)
02060           if (value_notzero_p(lcm[np]))
02061               value_addto(m1[np],m1[np],lcm[np]);
02062     }
02063     
02064     if (!CQ2 || emptyQ(CQ2)) {
02065 #ifdef EDEBUG2
02066       fprintf(stderr,"Degenerate.\n");
02067 #endif
02068       fprintf(stdout,"Degenerate Domain. Can not continue.\n");
02069       value_init(res->EP.d);
02070       value_init(res->EP.x.n);
02071       value_set_si(res->EP.d,1);
02072       value_set_si(res->EP.x.n,-1);
02073     }
02074     else {
02075       
02076 #ifdef EDEBUG2
02077       fprintf(stderr,"CQ2 = \n");
02078       Polyhedron_Print(stderr,P_VALUE_FMT,CQ2);
02079       if( ! PolyhedronIncludes(CQ, CQ2) )
02080         fprintf( stderr,"CQ does not include CQ2 !\n");
02081       else
02082         fprintf( stderr,"CQ includes CQ2.\n");
02083       if( ! PolyhedronIncludes(res->ValidityDomain, CQ2) )
02084         fprintf( stderr,"CQ2 is *not* included in validity domain !\n");
02085       else
02086         fprintf( stderr,"CQ2 is included in validity domain.\n");
02087 #endif
02088       
02089       /* L is used in counting the number of points in the base cases */
02090       L = Polyhedron_Scan(hom ? Ph : P,CQ2,MAXRAYS);
02091       U = Universe_Polyhedron(0);
02092       
02093       /* LQ is used to scan the parameter space */
02094       LQ = Polyhedron_Scan(CQ2,U,MAXRAYS); /* bounds on parameters */
02095       Domain_Free(U);
02096       if(CT)    /* we did compute another Q->Domain */
02097         Domain_Free(CQ);
02098       
02099       /* Else, CQ was Q->Domain (used in res) */
02100       Domain_Free(CQ2);
02101       
02102 #ifdef EDEBUG2
02103       fprintf(stderr,"L = \n");
02104       Polyhedron_Print(stderr,P_VALUE_FMT,L);
02105       fprintf(stderr,"LQ = \n");
02106       Polyhedron_Print(stderr,P_VALUE_FMT,LQ);
02107 #endif
02108 #ifdef EDEBUG3
02109       fprintf(stdout,"\nSystem of Equations:\n");
02110 #endif
02111       
02112       value_init(res->EP.d);
02113       value_set_si(res->EP.d,0);
02114       
02115       /* Create a context vector size dim+2 */
02116       context = (Value *) malloc ((hdim+1+hom)*sizeof(Value));  
02117       for(i=0;i<=(hdim+hom);i++)
02118         value_init(context[i]);
02119       Vector_Set(context,0,(hdim+1+hom));
02120       
02121       /* Set context[hdim] = 1  (the constant) */
02122       value_set_si(context[hdim+hom],1);
02123       
02124       CATCH(overflow_error) {
02125           fprintf(stderr,"Enumerate: arithmetic overflow error.\n");
02126           fprintf(stderr,"You should rebuild PolyLib using GNU-MP "
02127                   "or increasing the size of integers.\n");
02128           overflow_warning_flag = 0;
02129           assert(overflow_warning_flag);
02130         
02131       }
02132       TRY {
02133           res->EP.x.p = P_Enum(L,LQ,context,1,nb_param+hom,
02134                                dim+hom,lcm,param_name);
02135           UNCATCH(overflow_error);      
02136       }
02137       if (hom)
02138           dehomogenize_evalue(&res->EP, nb_param+1);
02139       
02140       for(i=0;i<=(hdim+hom);i++)
02141         value_clear(context[i]);
02142       free(context);
02143       Domain_Free(L);
02144       Domain_Free(LQ);
02145       
02146 #ifdef EDEBUG5
02147         if( param_name )
02148    {
02149       fprintf(stdout,"\nEhrhart Polynomial (before simplification):\n");
02150       print_evalue(stdout,&res->EP,param_name);
02151         }
02152 #endif
02153 
02154       /* Try to simplify the result */
02155       reduce_evalue(&res->EP);
02156       
02157       /* Put back the original parameters into result */
02158       /* (equalities have been eliminated)            */
02159       if(CT) 
02160           addeliminatedparams_evalue(&res->EP,CT);
02161       
02162       if (param_name) {
02163         fprintf(stdout,"\nEhrhart Polynomial:\n");
02164         print_evalue(stdout,&res->EP, param_name);
02165         fprintf(stdout,"\n");
02166         /* sometimes the final \n lacks (when a single constant is printed) */
02167       }
02168       
02169     }
02170   }
02171 
02172   if (Ph)
02173     Polyhedron_Free(Ph);
02174   /* Clear all the 'Value' variables */
02175   for (np=0; np < nb_param+1; np++)
02176   {
02177     value_clear(lcm[np]); value_clear(m1[np]);
02178   }
02179   value_clear(hdv);
02180   free(lcm);
02181   free(m1);
02182   /* We can't simply call Param_Polyhedron_Free because we've reused the domains */
02183   Param_Vertices_Free(PP->V);
02184   while (PP->D) {
02185     Q = PP->D;
02186     PP->D = PP->D->next;
02187     free(Q->F);
02188     free(Q);
02189   }
02190   free(PP);
02191 
02192 out:
02193   if (CEq)
02194     Polyhedron_Free(CEq);
02195   if (CT)
02196     Matrix_Free(CT);
02197   if( P != Pi )
02198     Polyhedron_Free( P );
02199 
02200   return res;
02201 } /* Polyhedron_Enumerate */ 
02202 
02203 void Enumeration_Free(Enumeration *en)
02204 {
02205   Enumeration *ee;
02206 
02207   while( en )
02208   {
02209           free_evalue_refs( &(en->EP) );
02210           Domain_Free( en->ValidityDomain );
02211           ee = en ->next;
02212           free( en );
02213           en = ee;
02214   }
02215 }
02216 
02217 /* adds by B. Meister for Ehrhart Polynomial approximation */
02218 
02219 /**
02220  * Divides the evalue e by the integer n<br/>
02221  * recursive function<br/>
02222  * Warning :  modifies e
02223  * @param e an evalue (to be divided by n)
02224  * @param n
02225  */
02226 
02227 void evalue_div(evalue * e, Value n) {
02228   int i;
02229   Value gc;
02230   value_init(gc);
02231   if (value_zero_p(e->d)) {
02232     for (i=0; i< e->x.p->size; i++) {
02233       evalue_div(&(e->x.p->arr[i]), n);
02234     }
02235   }
02236   else {
02237     value_multiply(e->d, e->d, n);
02238     /* simplify the new rational if needed */
02239     value_gcd(gc, e->x.n, e->d);
02240     if (value_notone_p(gc)) {
02241       value_divexact(e->d, e->d, gc);
02242       value_divexact(e->x.n, e->x.n, gc);
02243     }
02244   }
02245   value_clear(gc);
02246 } /* evalue_div */
02247 
02248 
02249 /** 
02250 
02251 Ehrhart_Quick_Apx_Full_Dim(P, C, MAXRAYS, param_names)
02252 
02253 Procedure to estimate the number of points in a parameterized polytope.
02254 Returns a list of validity domains + evalues EP
02255 B.M.
02256 The most rough and quick approximation by variables expansion  
02257 Deals with the full-dimensional case.                          
02258 @param Pi : Polyhedron to enumerate (approximatively)
02259 @param C : Context Domain
02260 @param MAXRAYS : size of workspace
02261 @param param_name : names for the parameters (char strings)
02262 
02263 */
02264 Enumeration *Ehrhart_Quick_Apx_Full_Dim(Polyhedron *Pi,Polyhedron *C,
02265                                         unsigned MAXRAYS, const char **param_name)
02266 {
02267   Polyhedron *L, *CQ, *CQ2, *LQ, *U, *CEq, *rVD, *P;
02268   Matrix *CT;
02269   Param_Polyhedron *PP;
02270   Param_Domain   *Q;
02271   int i,j,hdim, dim, nb_param, np;
02272   Value *lcm, *m1, hdv;
02273   Value *context;
02274   Enumeration *en, *res;
02275   Value expansion_det;
02276   Polyhedron * Expanded;
02277 
02278   /* used to scan the vertices */
02279   Param_Vertices * V_tmp;
02280 
02281   res = NULL;
02282   P = Pi;
02283 
02284   value_init(expansion_det);
02285 
02286 #ifdef EDEBUG2
02287   fprintf(stderr,"C = \n");
02288   Polyhedron_Print(stderr,P_VALUE_FMT,C);
02289   fprintf(stderr,"P = \n");
02290   Polyhedron_Print(stderr,P_VALUE_FMT,P);
02291 #endif
02292 
02293   hdim          = P->Dimension + 1;
02294   dim           = P->Dimension;
02295   nb_param      = C->Dimension;
02296 
02297   /* Don't call Polyhedron2Param_Domain if there are no parameters */
02298   if(nb_param == 0) {
02299     
02300     return(Enumerate_NoParameters(P,C,NULL,NULL,MAXRAYS, param_name));  
02301   }
02302 
02303 #if EDEBUG2
02304   printf("Enumerating polyhedron : \n");
02305   Polyhedron_Print(stdout, P_VALUE_FMT, P);
02306 #endif
02307 
02308   PP = Polyhedron2Param_SimplifiedDomain(&P,C,MAXRAYS,&CEq,&CT);
02309   if(!PP) {
02310     if( param_name )
02311       fprintf(stdout, "\nEhrhart Polynomial:\nNULL\n");
02312 
02313     return(NULL);
02314   }
02315   
02316   /* CT : transformation matrix to eliminate useless ("false") parameters */
02317   if(CT) {
02318     nb_param -= CT->NbColumns-CT->NbRows;
02319     dim  -= CT->NbColumns-CT->NbRows;
02320     hdim -= CT->NbColumns-CT->NbRows;
02321     
02322     /* Don't call Polyhedron2Param_Domain if there are no parameters */
02323     if(nb_param == 0)
02324     {
02325             res = Enumerate_NoParameters(P,C,CT,CEq,MAXRAYS,param_name);
02326             if( P != Pi )
02327                     Polyhedron_Free( P );
02328             return( res );
02329     }  
02330   }
02331 
02332   if (!PP->nbV)
02333     /* Leaks memory */
02334     return NULL;
02335 
02336   /* get memory for Values */
02337   lcm = (Value *)malloc( nb_param * sizeof(Value));
02338   m1  = (Value *)malloc( nb_param * sizeof(Value));
02339   /* Initialize all the 'Value' variables */
02340   for( np=0 ; np<nb_param ; np++ )
02341   {
02342     value_init(lcm[np]); value_init(m1[np]);
02343   }
02344   value_init(hdv);
02345 
02346 #if EDEBUG2 
02347   Polyhedron_Print(stderr, P_VALUE_FMT, P);
02348 #endif
02349 
02350   Expanded = P;
02351   Param_Polyhedron_Scale_Integer(PP, &Expanded, &expansion_det, MAXRAYS);
02352 
02353 #if EDEBUG2
02354   Polyhedron_Print(stderr, P_VALUE_FMT, Expanded);
02355 #endif
02356 
02357   if (P != Expanded)
02358     Polyhedron_Free(P);
02359   P = Expanded;
02360 
02361   /* formerly : Scan the vertices and compute lcm 
02362      Scan_Vertices_Quick_Apx(PP,Q,CT,lcm,nb_param); */
02363   /* now : lcm = 1 (by construction) */
02364   /* OPT : A lot among what happens after this point can be simplified by
02365      knowing that lcm[i] = 1 for now, we just conservatively fool the rest of
02366      the function with lcm = 1 */
02367   for (i=0; i< nb_param; i++) value_set_si(lcm[i], 1);
02368   
02369   for(Q=PP->D;Q;Q=Q->next) {
02370     if(CT) {
02371       Polyhedron *Dt;
02372       CQ = Q->Domain;      
02373       Dt = Polyhedron_Preimage(Q->Domain,CT,MAXRAYS);
02374       rVD = DomainIntersection(Dt,CEq,MAXRAYS);
02375       
02376       /* if rVD is empty or too small in geometric dimension */
02377       if(!rVD || emptyQ(rVD) ||
02378          (rVD->Dimension-rVD->NbEq < Dt->Dimension-Dt->NbEq-CEq->NbEq)) {
02379         if(rVD)
02380           Polyhedron_Free(rVD);
02381         Polyhedron_Free(Dt);
02382         continue;               /* empty validity domain */
02383       }
02384       Polyhedron_Free(Dt);
02385     }
02386     else
02387       rVD = CQ = Q->Domain;
02388     en = (Enumeration *)malloc(sizeof(Enumeration));
02389     en->next = res;
02390     res = en;
02391     res->ValidityDomain = rVD;
02392         
02393     if( param_name )
02394       {    
02395         fprintf(stdout,"---------------------------------------\n");
02396         fprintf(stdout,"Domain:\n");
02397     
02398 #ifdef EPRINT_ALL_VALIDITY_CONSTRAINTS
02399         Print_Domain(stdout,res->ValidityDomain,param_name);
02400 #else    
02401         {
02402           Polyhedron *VD;
02403           VD = DomainSimplify(res->ValidityDomain,C,MAXRAYS);
02404           Print_Domain(stdout,VD,param_name);
02405           Domain_Free(VD);
02406         }
02407 #endif /* EPRINT_ALL_VALIDITY_CONSTRAINTS */
02408       }
02409     
02410     overflow_warning_flag = 1;
02411 
02412 #ifdef EDEBUG2
02413     fprintf(stderr,"Denominator = ");
02414     for( np=0;np<nb_param;np++)
02415       value_print(stderr,P_VALUE_FMT,lcm[np]);
02416     fprintf(stderr," and hdim == %d \n",hdim);
02417 #endif
02418     
02419 #ifdef EDEBUG2
02420     fprintf(stderr,"CQ = \n");
02421     Polyhedron_Print(stderr,P_VALUE_FMT,CQ);
02422 #endif
02423 
02424     /* Before scanning, add constraints to ensure at least hdim*lcm */
02425     /* points in every dimension */
02426     value_set_si(hdv,hdim-nb_param);
02427 
02428     for( np=0;np<nb_param;np++)
02429     {
02430                 if( value_notzero_p(lcm[np]) )
02431                         value_multiply(m1[np],hdv,lcm[np]);
02432                 else
02433                         value_set_si(m1[np],1);
02434     }
02435 
02436 #ifdef EDEBUG2 
02437     fprintf(stderr,"m1 == ");
02438     for( np=0;np<nb_param;np++)
02439       value_print(stderr,P_VALUE_FMT,m1[np]);
02440     fprintf(stderr,"\n");
02441 #endif 
02442 
02443     CATCH(overflow_error) {
02444       fprintf(stderr,"Enumerate: arithmetic overflow error.\n");
02445       CQ2 = NULL;
02446     }
02447     TRY {      
02448       CQ2 = Polyhedron_Preprocess(CQ,m1,MAXRAYS);
02449 
02450 #ifdef EDEBUG2
02451       fprintf(stderr,"After preprocess, CQ2 = ");
02452       Polyhedron_Print(stderr,P_VALUE_FMT,CQ2);
02453 #endif
02454       
02455       UNCATCH(overflow_error);
02456     }
02457     
02458     /* Vin100, Feb 2001 */
02459     /* in case of degenerate, try to find a domain _containing_ CQ */
02460     if ((!CQ2 || emptyQ(CQ2)) && CQ->NbBid==0) {
02461       int r;
02462       
02463 #ifdef EDEBUG2
02464       fprintf(stderr,"Trying to call Polyhedron_Preprocess2 : CQ = \n");
02465       Polyhedron_Print(stderr,P_VALUE_FMT,CQ);
02466 #endif
02467       
02468       /* Check if CQ is bounded */
02469       for(r=0;r<CQ->NbRays;r++) {
02470         if(value_zero_p(CQ->Ray[r][0]) ||
02471            value_zero_p(CQ->Ray[r][CQ->Dimension+1]))
02472           break;
02473       }
02474       if(r==CQ->NbRays) {
02475         
02476         /* ok, CQ is bounded */
02477         /* now find if CQ is contained in a hypercube of size m1 */
02478         CQ2 = Polyhedron_Preprocess2(CQ,m1,lcm,MAXRAYS);
02479       }
02480     }
02481     if (!CQ2 || emptyQ(CQ2)) {
02482 #ifdef EDEBUG2
02483       fprintf(stderr,"Degenerate.\n");
02484 #endif
02485       fprintf(stdout,"Degenerate Domain. Can not continue.\n");
02486       value_init(res->EP.d);
02487       value_init(res->EP.x.n);
02488       value_set_si(res->EP.d,1);
02489       value_set_si(res->EP.x.n,-1);
02490     }
02491     else {
02492       
02493 #ifdef EDEBUG2
02494       fprintf(stderr,"CQ2 = \n");
02495       Polyhedron_Print(stderr,P_VALUE_FMT,CQ2);
02496       if( ! PolyhedronIncludes(CQ, CQ2) )
02497         fprintf( stderr,"CQ does not include CQ2 !\n");
02498       else
02499         fprintf( stderr,"CQ includes CQ2.\n");
02500       if( ! PolyhedronIncludes(res->ValidityDomain, CQ2) )
02501         fprintf( stderr,"CQ2 is *not* included in validity domain !\n");
02502       else
02503         fprintf( stderr,"CQ2 is included in validity domain.\n");
02504 #endif
02505       
02506       /* L is used in counting the number of points in the base cases */
02507       L = Polyhedron_Scan(P,CQ,MAXRAYS);
02508       U = Universe_Polyhedron(0);
02509       
02510       /* LQ is used to scan the parameter space */
02511       LQ = Polyhedron_Scan(CQ2,U,MAXRAYS); /* bounds on parameters */
02512       Domain_Free(U);
02513       if(CT)    /* we did compute another Q->Domain */
02514         Domain_Free(CQ);
02515       
02516       /* Else, CQ was Q->Domain (used in res) */
02517       Domain_Free(CQ2);
02518       
02519 #ifdef EDEBUG2
02520       fprintf(stderr,"L = \n");
02521       Polyhedron_Print(stderr,P_VALUE_FMT,L);
02522       fprintf(stderr,"LQ = \n");
02523       Polyhedron_Print(stderr,P_VALUE_FMT,LQ);
02524 #endif
02525 #ifdef EDEBUG3
02526       fprintf(stdout,"\nSystem of Equations:\n");
02527 #endif
02528       
02529       value_init(res->EP.d);
02530       value_set_si(res->EP.d,0);
02531       
02532       /* Create a context vector size dim+2 */
02533       context = (Value *) malloc ((hdim+1)*sizeof(Value));  
02534       for(i=0;i<=(hdim);i++)
02535         value_init(context[i]);
02536       Vector_Set(context,0,(hdim+1));
02537       
02538       /* Set context[hdim] = 1  (the constant) */
02539       value_set_si(context[hdim],1);
02540       
02541       CATCH(overflow_error) {
02542         fprintf(stderr,"Enumerate: arithmetic overflow error.\n");
02543         fprintf(stderr,"You should rebuild PolyLib using GNU-MP "
02544                 "or increasing the size of integers.\n");
02545         overflow_warning_flag = 0;
02546         assert(overflow_warning_flag);
02547         
02548       }
02549       TRY {
02550         res->EP.x.p = P_Enum(L,LQ,context,1,nb_param,dim,lcm, param_name);
02551         UNCATCH(overflow_error);        
02552       }
02553       
02554       for(i=0;i<=(hdim);i++)
02555         value_clear(context[i]);
02556       free(context);
02557       Domain_Free(L);
02558       Domain_Free(LQ);
02559       
02560 #ifdef EDEBUG5
02561       if( param_name )
02562         {
02563           fprintf(stdout,"\nEhrhart Polynomial (before simplification):\n");
02564           print_evalue(stdout,&res->EP,param_name);
02565         }
02566 
02567       /* BM: divide EP by denom_det, the expansion factor */
02568       fprintf(stdout,"\nEhrhart Polynomial (before division):\n");
02569       print_evalue(stdout,&(res->EP),param_name);
02570 #endif
02571 
02572       evalue_div(&(res->EP), expansion_det);
02573 
02574 
02575       /* Try to simplify the result */
02576       reduce_evalue(&res->EP);
02577       
02578       /* Put back the original parameters into result */
02579       /* (equalities have been eliminated)            */
02580       if(CT) 
02581           addeliminatedparams_evalue(&res->EP,CT);
02582       
02583       if( param_name )
02584         {
02585           fprintf(stdout,"\nEhrhart Polynomial:\n");
02586           print_evalue(stdout,&res->EP, param_name);
02587           fprintf(stdout,"\n");
02588           /* sometimes the final \n lacks (when a single constant is printed)
02589           */
02590         }
02591       
02592     }
02593   }
02594   value_clear(expansion_det);
02595 
02596   if( P != Pi )
02597         Polyhedron_Free( P );
02598   /* Clear all the 'Value' variables */
02599   for( np=0; np<nb_param ; np++ )
02600   {
02601     value_clear(lcm[np]); value_clear(m1[np]);
02602   }
02603   value_clear(hdv);
02604 
02605   return res;
02606 } /* Ehrhart_Quick_Apx_Full_Dim */ 
02607 
02608 
02609 /** 
02610  * Computes the approximation of the Ehrhart polynomial of a polyhedron 
02611  * (implicit form -> matrix), treating the non-full-dimensional case.
02612  * @param M a polyhedron under implicit form
02613  * @param C  M's context under implicit form
02614  * @param Validity_Lattice a pointer to the parameter's validity lattice
02615  * @param MAXRAYS the needed "working space" for other polylib functions used here
02616  * @param param_name the names of the parameters, 
02617  */
02618 Enumeration *Ehrhart_Quick_Apx(Matrix * M, Matrix * C, 
02619                                Matrix **Validity_Lattice, unsigned maxRays) { 
02620                                /* char ** param_name) {*/
02621 
02622   /* 0- compute a full-dimensional polyhedron with the same number of points,
02623      and its parameter's validity lattice */
02624   Matrix * M_full;
02625   Polyhedron * P, * PC;
02626   Enumeration *en;
02627   
02628   M_full = full_dimensionize(M, C->NbColumns-2, Validity_Lattice);
02629   /* 1- apply the same tranformation to the context that what has been applied
02630      to the parameters space of the polyhedron. */
02631   mpolyhedron_compress_last_vars(C, *Validity_Lattice);
02632   show_matrix(M_full);
02633   P = Constraints2Polyhedron(M_full, maxRays);
02634   PC = Constraints2Polyhedron(C, maxRays);
02635   Matrix_Free(M_full);
02636   /* compute the Ehrhart polynomial of the "equivalent" polyhedron */
02637   en = Ehrhart_Quick_Apx_Full_Dim(P, PC, maxRays, NULL);
02638 
02639   /* clean up */
02640   Polyhedron_Free(P);
02641   Polyhedron_Free(PC);
02642   return en;
02643 } /* Ehrhart_Quick_Apx */
02644 
02645 
02646 
02647 /** 
02648  * Computes the approximation of the Ehrhart polynomial of a polyhedron (implicit
02649  * form -> matrix), treating the non-full-dimensional case.  If there are some
02650  * equalities involving only parameters, these are used to eliminate useless 
02651  * parameters.
02652  * @param M a polyhedron under implicit form
02653  * @param C  M's context under implicit form
02654  * @param validityLattice a pointer to the parameter's validity lattice
02655  * (returned)
02656  * @param parmsEqualities Equalities involving only the parameters
02657  * @param maxRays the needed "working space" for other polylib functions used here
02658  * @param elimParams  array of the indices of the eliminated parameters (returned)
02659  */
02660 Enumeration *Constraints_EhrhartQuickApx(Matrix const * M, Matrix const * C, 
02661                                          Matrix ** validityLattice, 
02662                                          Matrix ** parmEqualities,
02663                                          unsigned int ** elimParms, 
02664                                          unsigned maxRays) {
02665   Enumeration *EP;
02666   Matrix * Mp = Matrix_Copy(M);
02667   Matrix * Cp = Matrix_Copy(C);
02668   /* remove useless equalities involving only parameters, using these 
02669      equalities to remove parameters. */
02670   (*parmEqualities) = Constraints_Remove_parm_eqs(&Mp, &Cp, 0, elimParms);
02671   if (Mp->NbRows>=0) {/* if there is no contradiction */
02672     EP = Ehrhart_Quick_Apx(Mp, Cp, validityLattice, maxRays);
02673     return EP;
02674   }
02675   else {
02676     /* if there are contradictions, return a zero Ehrhart polynomial */
02677     return NULL;
02678   }
02679   
02680 }
02681 
02682 
02683 /** 
02684  * Returns the array of parameter names after some of them have been eliminated.
02685  * @param parmNames the initial names of the parameters
02686  * @param elimParms a list of parameters that have been eliminated from the
02687  * original parameters. The first element of this array is the number of
02688  * elements.
02689  * <p> Note: does not copy the parameters names themselves. </p>
02690  * @param nbParms the initial number of parameters
02691 */
02692 const char **parmsWithoutElim(char const **parmNames, 
02693                               unsigned int const *elimParms, 
02694                               unsigned int nbParms)
02695 {
02696   int i=0, j=0,k;
02697   int newParmNb = nbParms - elimParms[0];
02698   const char **newParmNames = (const char **)malloc(newParmNb * sizeof(char *));
02699   for (k=1; k<= elimParms[0]; k++) {
02700     while (i!=elimParms[k]) {
02701       newParmNames[i-k+1] = parmNames[i];
02702       i++;
02703     }
02704   }
02705   return newParmNames;
02706 }
02707 
02708 
02709 /** 
02710  * returns a constant Ehrhart polynomial whose value is zero for any value of
02711  * the parameters.
02712  * @param nbParms the number of parameters, i.e., the number of arguments to
02713  * the Ehrhart polynomial
02714  */
02715 Enumeration * Enumeration_zero(unsigned int nbParms, unsigned int maxRays) {
02716   Matrix * Mz = Matrix_Alloc(1, nbParms+3);
02717   Polyhedron * emptyP;
02718   Polyhedron * universe;
02719   Enumeration * zero;
02720   /* 1- build an empty polyhedron with the right dimension */
02721   /* here we choose to take 2i = -1 */
02722   value_set_si(Mz->p[0][1], 2);
02723   value_set_si(Mz->p[0][nbParms+2], 1);
02724   emptyP = Constraints2Polyhedron(Mz, maxRays);
02725   Matrix_Free(Mz);
02726   universe = Universe_Polyhedron(nbParms);
02727   zero = Polyhedron_Enumerate(emptyP, universe, maxRays, NULL);
02728   Polyhedron_Free(emptyP);
02729   Polyhedron_Free(universe);
02730   return zero;
02731 } /* Enumeration_zero() */
02732 

Generated on Thu Sep 4 15:28:57 2008 for polylib by doxygen 1.3.5