polylib: ehrhart.c Source File

- Main Page
- Classes
- Files

- File List
- File Members

# ehrhart.c

Go to the documentation of this file.

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