polylib: compress_parms.c Source File

- Main Page
- Classes
- Files

- File List
- File Members

# compress_parms.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  * $Id: compress_parms.c,v 1.32 2006/11/03 17:34:26 skimo Exp $
    00020  *
    00021  * The integer points in a parametric linear subspace of Q^n are generally
    00022  * lying on a sub-lattice of Z^n.
    00023  * Functions here use and compute validity lattices, i.e. lattices induced on a
    00024  * set of variables by such equalities involving another set of integer
    00025  * variables.
    00026  * @author B. Meister 12/2003-2006 meister@icps.u-strasbg.fr
    00027  * LSIIT -ICPS
    00028  * UMR 7005 CNRS
    00029  * Louis Pasteur University (ULP), Strasbourg, France
    00030 */
    00031
    00032 #include <stdlib.h>
    00033 #include <polylib/polylib.h>
    00034
    00035 /**
    00036  * debug flags (2 levels)
    00037  */
    00038 #define dbgCompParm 0
    00039 #define dbgCompParmMore 0
    00040
    00041 #define dbgStart(a) if (dbgCompParmMore) { printf(" -- begin "); \
    00042                                            printf(#a);        \
    00043                                            printf(" --\n"); }   \
    00044                                            while(0)
    00045 #define dbgEnd(a) if (dbgCompParmMore) { printf(" -- end "); \
    00046                                          printf(#a);      \
    00047                                          printf(" --\n"); } \
    00048                                          while(0)
    00049
    00050
    00051 /**
    00052  * Given a full-row-rank nxm matrix M made of m row-vectors), computes the
    00053  * basis K (made of n-m column-vectors) of the integer kernel of the rows of M
    00054  * so we have: M.K = 0
    00055 */
    00056 Matrix * int_ker(Matrix * M) {
    00057   Matrix *U, *Q, *H, *H2, *K=NULL;
    00058   int i, j, rk;
    00059
    00060   if (dbgCompParm)
    00061     show_matrix(M);
    00062   /* eliminate redundant rows : UM = H*/
    00063   right_hermite(M, &H, &Q, &U);
    00064   for (rk=H->NbRows-1; (rk>=0) && Vector_IsZero(H->p[rk], H->NbColumns); rk--);
    00065   rk++;
    00066   if (dbgCompParmMore) {
    00067     printf("rank = %d\n", rk);
    00068   }
    00069
    00070   /* there is a non-null kernel if and only if the dimension m of
    00071      the space spanned by the rows
    00072      is inferior to the number n of variables */
    00073   if (M->NbColumns <= rk) {
    00074     Matrix_Free(H);
    00075     Matrix_Free(Q);
    00076     Matrix_Free(U);
    00077     K = Matrix_Alloc(M->NbColumns, 0);
    00078     return K;
    00079   }
    00080   Matrix_Free(U);
    00081   Matrix_Free(Q);
    00082   /* fool left_hermite  by giving NbRows =rank of M*/
    00083   H->NbRows=rk;
    00084   /* computes MU = [H 0] */
    00085   left_hermite(H, &H2, &Q, &U);
    00086    if (dbgCompParmMore) {
    00087     printf("-- Int. Kernel -- \n");
    00088     show_matrix(M);
    00089     printf(" = \n");
    00090     show_matrix(H2);
    00091     show_matrix(U);
    00092   }
    00093   H->NbRows==M->NbRows;
    00094   Matrix_Free(H);
    00095   /* the Integer Kernel is made of the last n-rk columns of U */
    00096   Matrix_subMatrix(U, 0, rk, U->NbRows, U->NbColumns, &K);
    00097
    00098   /* clean up */
    00099   Matrix_Free(H2);
    00100   Matrix_Free(U);
    00101   Matrix_Free(Q);
    00102   return K;
    00103 } /* int_ker */
    00104
    00105
    00106 /**
    00107  * Computes the intersection of two linear lattices, whose base vectors are
    00108  * respectively represented in A and B.
    00109  * If I and/or Lb is set to NULL, then the matrix is allocated.
    00110  * Else, the matrix is assumed to be allocated already.
    00111  * I and Lb are rk x rk, where rk is the rank of A (or B).
    00112  * @param A the full-row rank matrix whose column-vectors are the basis for the
    00113  * first linear lattice.
    00114  * @param B the matrix whose column-vectors are the basis for the second linear
    00115  * lattice.
    00116  * @param Lb the matrix such that B.Lb = I, where I is the intersection.
    00117  * @return their intersection.
    00118  */
    00119 static void linearInter(Matrix * A, Matrix * B, Matrix ** I, Matrix **Lb) {
    00120   Matrix * AB=NULL;
    00121   int rk = A->NbRows;
    00122   int a = A->NbColumns;
    00123   int b = B->NbColumns;
    00124   int i,j, z=0;
    00125
    00126   Matrix * H, *U, *Q;
    00127   /* ensure that the spanning vectors are in the same space */
    00128   assert(B->NbRows==rk);
    00129   /* 1- build the matrix
    00130    * (A 0 1)
    00131    * (0 B 1)
    00132    */
    00133   AB = Matrix_Alloc(2*rk, a+b+rk);
    00134   Matrix_copySubMatrix(A, 0, 0, rk, a, AB, 0, 0);
    00135   Matrix_copySubMatrix(B, 0, 0, rk, b, AB, rk, a);
    00136   for (i=0; i< rk; i++) {
    00137       value_set_si(AB->p[i][a+b+i], 1);
    00138       value_set_si(AB->p[i+rk][a+b+i], 1);
    00139   }
    00140   if (dbgCompParm) {
    00141     show_matrix(AB);
    00142   }
    00143
    00144   /* 2- Compute its left Hermite normal form. AB.U = [H 0] */
    00145   left_hermite(AB, &H, &Q, &U);
    00146   Matrix_Free(AB);
    00147   Matrix_Free(Q);
    00148   /* count the number of non-zero colums in H */
    00149   for (z=H->NbColumns-1; value_zero_p(H->p[H->NbRows-1][z]); z--);
    00150   z++;
    00151   if (dbgCompParm) {
    00152     show_matrix(H);
    00153     printf("z=%d\n", z);
    00154   }
    00155   Matrix_Free(H);
    00156   /* if you split U in 9 submatrices, you have:
    00157    * A.U_13 = -U_33
    00158    * B.U_23 = -U_33,
    00159    * where the nb of cols of U_{*3} equals the nb of zero-cols of H
    00160    * U_33 is a (the smallest) combination of col-vectors of A and B at the same
    00161    * time: their intersection.
    00162   */
    00163   Matrix_subMatrix(U, a+b, z, U->NbColumns, U->NbColumns, I);
    00164   Matrix_subMatrix(U, a, z, a+b, U->NbColumns, Lb);
    00165   if (dbgCompParm) {
    00166     show_matrix(U);
    00167   }
    00168   Matrix_Free(U);
    00169 } /* linearInter */
    00170
    00171
    00172 /**
    00173  * Given a system of equalities, looks if it has an integer solution in the
    00174  * combined space, and if yes, returns one solution.
    00175  * <p>pre-condition: the equalities are full-row rank (without the constant
    00176  * part)</p>
    00177  * @param Eqs the system of equations (as constraints)
    00178  * @param I a feasible integer solution if it exists, else NULL. Allocated if
    00179  * initially set to NULL, else reused.
    00180  */
    00181 void Equalities_integerSolution(Matrix * Eqs, Matrix **I) {
    00182   Matrix * Hm, *H=NULL, *U, *Q, *M=NULL, *C=NULL, *Hi;
    00183   Matrix *Ip;
    00184   int i;
    00185   Value mod;
    00186   unsigned int rk;
    00187   if (Eqs==NULL){
    00188     if ((*I)!=NULL) Matrix_Free(*I);
    00189     I = NULL;
    00190     return;
    00191   }
    00192   /* we use: AI = C = (Ha 0).Q.I = (Ha 0)(I' 0)^T */
    00193   /* with I = Qinv.I' = U.I'*/
    00194   /* 1- compute I' = Hainv.(-C) */
    00195   /* HYP: the equalities are full-row rank */
    00196   rk = Eqs->NbRows;
    00197   Matrix_subMatrix(Eqs, 0, 1, rk, Eqs->NbColumns-1, &M);
    00198   left_hermite(M, &Hm, &Q, &U);
    00199   Matrix_Free(M);
    00200   Matrix_subMatrix(Hm, 0, 0, rk, rk, &H);
    00201   if (dbgCompParmMore) {
    00202     show_matrix(Hm);
    00203     show_matrix(H);
    00204     show_matrix(U);
    00205   }
    00206   Matrix_Free(Q);
    00207   Matrix_Free(Hm);
    00208   Matrix_subMatrix(Eqs, 0, Eqs->NbColumns-1, rk, Eqs->NbColumns, &C);
    00209   Matrix_oppose(C);
    00210   Hi = Matrix_Alloc(rk, rk+1);
    00211   MatInverse(H, Hi);
    00212   if (dbgCompParmMore) {
    00213     show_matrix(C);
    00214     show_matrix(Hi);
    00215   }
    00216   /* put the numerator of Hinv back into H */
    00217   Matrix_subMatrix(Hi, 0, 0, rk, rk, &H);
    00218   Ip = Matrix_Alloc(Eqs->NbColumns-2, 1);
    00219   /* fool Matrix_Product on the size of Ip */
    00220   Ip->NbRows = rk;
    00221   Matrix_Product(H, C, Ip);
    00222   Ip->NbRows = Eqs->NbColumns-2;
    00223   Matrix_Free(H);
    00224   Matrix_Free(C);
    00225   value_init(mod);
    00226   for (i=0; i< rk; i++) {
    00227     /* if Hinv.C is not integer, return NULL (no solution) */
    00228     value_pmodulus(mod, Ip->p[i][0], Hi->p[i][rk]);
    00229     if (value_notzero_p(mod)) {
    00230       if ((*I)!=NULL) Matrix_Free(*I);
    00231       value_clear(mod);
    00232       Matrix_Free(U);
    00233       Matrix_Free(Ip);
    00234       Matrix_Free(Hi);
    00235       I = NULL;
    00236       return;
    00237     }
    00238     else {
    00239       value_pdivision(Ip->p[i][0], Ip->p[i][0], Hi->p[i][rk]);
    00240     }
    00241   }
    00242   /* fill the rest of I' with zeros */
    00243   for (i=rk; i< Eqs->NbColumns-2; i++) {
    00244     value_set_si(Ip->p[i][0], 0);
    00245   }
    00246   value_clear(mod);
    00247   Matrix_Free(Hi);
    00248   /* 2 - Compute the particular solution I = U.(I' 0) */
    00249   ensureMatrix((*I), Eqs->NbColumns-2, 1);
    00250   Matrix_Product(U, Ip, (*I));
    00251   Matrix_Free(U);
    00252   Matrix_Free(Ip);
    00253   if (dbgCompParm) {
    00254     show_matrix(*I);
    00255   }
    00256 }
    00257
    00258
    00259 /**
    00260  * Computes the validity lattice of a set of equalities. I.e., the lattice
    00261  * induced on the last <tt>b</tt> variables by the equalities involving the
    00262  * first <tt>a</tt> integer existential variables.  The submatrix of Eqs that
    00263  * concerns only the existential variables (so the first a columns) is assumed
    00264  * to be full-row rank.
    00265  * @param Eqs the equalities
    00266  * @param a the number of existential integer variables, placed as first
    00267  * variables
    00268  * @param vl the (returned) validity lattice, in homogeneous form. It is
    00269  * allocated if initially set to null, or reused if already allocated.
    00270  */
    00271 void Equalities_validityLattice(Matrix * Eqs, int a, Matrix** vl) {
    00272   unsigned int b = Eqs->NbColumns-2-a;
    00273   unsigned int r = Eqs->NbRows;
    00274   Matrix * A=NULL, * B=NULL, *I = NULL, *Lb=NULL, *sol=NULL;
    00275   Matrix *H, *U, *Q;
    00276   unsigned int i;
    00277
    00278   if (dbgCompParm) {
    00279     printf("Computing validity lattice induced by the %d first variables of:"
    00280            ,a);
    00281     show_matrix(Eqs);
    00282   }
    00283   if (b==0) {
    00284     ensureMatrix((*vl), 1, 1);
    00285     value_set_si((*vl)->p[0][0], 1);
    00286     return;
    00287   }
    00288
    00289   /* 1- check that there is an integer solution to the equalities */
    00290   /* OPT: could change integerSolution's profile to allocate or not*/
    00291   Equalities_integerSolution(Eqs, &sol);
    00292   /* if there is no integer solution, there is no validity lattice */
    00293   if (sol==NULL) {
    00294     if ((*vl)!=NULL) Matrix_Free(*vl);
    00295     return;
    00296   }
    00297   Matrix_subMatrix(Eqs, 0, 1, r, 1+a, &A);
    00298   Matrix_subMatrix(Eqs, 0, 1+a, r, 1+a+b, &B);
    00299   linearInter(A, B, &I, &Lb);
    00300   Matrix_Free(A);
    00301   Matrix_Free(B);
    00302   Matrix_Free(I);
    00303   if (dbgCompParm) {
    00304     show_matrix(Lb);
    00305   }
    00306
    00307   /* 2- The linear part of the validity lattice is the left HNF of Lb */
    00308   left_hermite(Lb, &H, &Q, &U);
    00309   Matrix_Free(Lb);
    00310   Matrix_Free(Q);
    00311   Matrix_Free(U);
    00312
    00313   /* 3- build the validity lattice */
    00314   ensureMatrix((*vl), b+1, b+1);
    00315   Matrix_copySubMatrix(H, 0, 0, b, b, (*vl), 0,0);
    00316   Matrix_Free(H);
    00317   for (i=0; i< b; i++) {
    00318     value_assign((*vl)->p[i][b], sol->p[0][a+i]);
    00319   }
    00320   Matrix_Free(sol);
    00321   Vector_Set((*vl)->p[b],0, b);
    00322   value_set_si((*vl)->p[b][b], 1);
    00323
    00324 } /* validityLattice */
    00325
    00326
    00327 /**
    00328  * Eliminate the columns corresponding to a list of eliminated parameters.
    00329  * @param M the constraints matrix whose columns are to be removed
    00330  * @param nbVars an offset to be added to the ranks of the variables to be
    00331  * removed
    00332  * @param elimParms the list of ranks of the variables to be removed
    00333  * @param newM (output) the matrix without the removed columns
    00334  */
    00335 void Constraints_removeElimCols(Matrix * M, unsigned int nbVars,
    00336                            unsigned int *elimParms, Matrix ** newM) {
    00337   unsigned int i, j, k;
    00338   if (elimParms[0]==0) {
    00339     Matrix_clone(M, newM);
    00340     return;
    00341   }
    00342   if ((*newM)==NULL) {
    00343     (*newM) = Matrix_Alloc(M->NbRows, M->NbColumns - elimParms[0]);
    00344   }
    00345   else {
    00346     assert ((*newM)->NbColumns==M->NbColumns - elimParms[0]);
    00347   }
    00348   for (i=0; i< M->NbRows; i++) {
    00349     value_assign((*newM)->p[i][0], M->p[i][0]); /* kind of cstr */
    00350     k=0;
    00351     Vector_Copy(&(M->p[i][1]), &((*newM)->p[i][1]), nbVars);
    00352     for (j=0; j< M->NbColumns-2-nbVars; j++) {
    00353       if (j!=elimParms[k+1]) {
    00354         value_assign((*newM)->p[i][j-k+nbVars+1], M->p[i][j+nbVars+1]);
    00355       }
    00356       else {
    00357         k++;
    00358       }
    00359     }
    00360     value_assign((*newM)->p[i][(*newM)->NbColumns-1],
    00361                  M->p[i][M->NbColumns-1]); /* cst part */
    00362   }
    00363 } /* Constraints_removeElimCols */
    00364
    00365
    00366 /**
    00367  * Eliminates all the equalities in a set of constraints and returns the set of
    00368  * constraints defining a full-dimensional polyhedron, such that there is a
    00369  * bijection between integer points of the original polyhedron and these of the
    00370  * resulting (projected) polyhedron).
    00371  * If VL is set to NULL, this funciton allocates it. Else, it assumes that
    00372  * (*VL) points to a matrix of the right size.
    00373  * <p> The following things are done:
    00374  * <ol>
    00375  * <li> remove equalities involving only parameters, and remove as many
    00376  *      parameters as there are such equalities. From that, the list of
    00377  *      eliminated parameters <i>elimParms</i> is built.
    00378  * <li> remove equalities that involve variables. This requires a compression
    00379  *      of the parameters and of the other variables that are not eliminated.
    00380  *      The affine compresson is represented by matrix VL (for <i>validity
    00381  *      lattice</i>) and is such that (N I 1)^T = VL.(N' I' 1), where N', I'
    00382  *      are integer (they are the parameters and variables after compression).
    00383  *</ol>
    00384  *</p>
    00385  */
    00386 void Constraints_fullDimensionize(Matrix ** M, Matrix ** C, Matrix ** VL,
    00387                                   Matrix ** Eqs, Matrix ** ParmEqs,
    00388                                   unsigned int ** elimVars,
    00389                                   unsigned int ** elimParms,
    00390                                   int maxRays) {
    00391   unsigned int i, j;
    00392   Matrix * A=NULL, *B=NULL;
    00393   Matrix * Ineqs=NULL;
    00394   unsigned int nbVars = (*M)->NbColumns - (*C)->NbColumns;
    00395   unsigned int nbParms;
    00396   int nbElimVars;
    00397   Matrix * fullDim = NULL;
    00398
    00399   /* variables for permutations */
    00400   unsigned int * permutation;
    00401   Matrix * permutedEqs=NULL, * permutedIneqs=NULL;
    00402
    00403   /* 1- Eliminate the equalities involving only parameters. */
    00404   (*ParmEqs) = Constraints_removeParmEqs(M, C, 0, elimParms);
    00405   /* if the polyehdron is empty, return now. */
    00406   if ((*M)->NbColumns==0) return;
    00407   /* eliminate the columns corresponding to the eliminated parameters */
    00408   if (elimParms[0]!=0) {
    00409     Constraints_removeElimCols(*M, nbVars, (*elimParms), &A);
    00410     Matrix_Free(*M);
    00411     (*M) = A;
    00412     Constraints_removeElimCols(*C, 0, (*elimParms), &B);
    00413     Matrix_Free(*C);
    00414     (*C) = B;
    00415     if (dbgCompParm) {
    00416       printf("After false parameter elimination: \n");
    00417       show_matrix(*M);
    00418       show_matrix(*C);
    00419     }
    00420   }
    00421   nbParms = (*C)->NbColumns-2;
    00422
    00423   /* 2- Eliminate the equalities involving variables */
    00424   /*   a- extract the (remaining) equalities from the poyhedron */
    00425   split_constraints((*M), Eqs, &Ineqs);
    00426   nbElimVars = (*Eqs)->NbRows;
    00427   /*    if the polyhedron is already full-dimensional, return */
    00428   if ((*Eqs)->NbRows==0) {
    00429     Matrix_identity(nbParms+1, VL);
    00430     return;
    00431   }
    00432   /*   b- choose variables to be eliminated */
    00433   permutation = find_a_permutation((*Eqs), nbParms);
    00434
    00435   if (dbgCompParm) {
    00436     printf("Permuting the vars/parms this way: [ ");
    00437     for (i=0; i< (*Eqs)->NbColumns-2; i++) {
    00438       printf("%d ", permutation[i]);
    00439     }
    00440     printf("]\n");
    00441   }
    00442
    00443   Constraints_permute((*Eqs), permutation, &permutedEqs);
    00444   Equalities_validityLattice(permutedEqs, (*Eqs)->NbRows, VL);
    00445
    00446   if (dbgCompParm) {
    00447     printf("Validity lattice: ");
    00448     show_matrix(*VL);
    00449   }
    00450   Constraints_compressLastVars(permutedEqs, (*VL));
    00451   Constraints_permute(Ineqs, permutation, &permutedIneqs);
    00452   if (dbgCompParmMore) {
    00453     show_matrix(permutedIneqs);
    00454     show_matrix(permutedEqs);
    00455   }
    00456   Matrix_Free(*Eqs);
    00457   Matrix_Free(Ineqs);
    00458   Constraints_compressLastVars(permutedIneqs, (*VL));
    00459   if (dbgCompParm) {
    00460     printf("After compression: ");
    00461     show_matrix(permutedIneqs);
    00462   }
    00463   /*   c- eliminate the first variables */
    00464   assert(Constraints_eliminateFirstVars(permutedEqs, permutedIneqs));
    00465   if (dbgCompParmMore) {
    00466     printf("After elimination of the variables: ");
    00467     show_matrix(permutedIneqs);
    00468   }
    00469
    00470   /*   d- get rid of the first (zero) columns,
    00471        which are now useless, and put the parameters back at the end */
    00472   fullDim = Matrix_Alloc(permutedIneqs->NbRows,
    00473                          permutedIneqs->NbColumns-nbElimVars);
    00474   for (i=0; i< permutedIneqs->NbRows; i++) {
    00475     value_set_si(fullDim->p[i][0], 1);
    00476     for (j=0; j< nbParms; j++) {
    00477       value_assign(fullDim->p[i][j+fullDim->NbColumns-nbParms-1],
    00478                    permutedIneqs->p[i][j+nbElimVars+1]);
    00479     }
    00480     for (j=0; j< permutedIneqs->NbColumns-nbParms-2-nbElimVars; j++) {
    00481       value_assign(fullDim->p[i][j+1],
    00482                    permutedIneqs->p[i][nbElimVars+nbParms+j+1]);
    00483     }
    00484     value_assign(fullDim->p[i][fullDim->NbColumns-1],
    00485                  permutedIneqs->p[i][permutedIneqs->NbColumns-1]);
    00486   }
    00487   Matrix_Free(permutedIneqs);
    00488
    00489 } /* Constraints_fullDimensionize */
    00490
    00491
    00492 /**
    00493  * Given a matrix that defines a full-dimensional affine lattice, returns the
    00494  * affine sub-lattice spanned in the k first dimensions.
    00495  * Useful for instance when you only look for the parameters' validity lattice.
    00496  * @param lat the original full-dimensional lattice
    00497  * @param subLat the sublattice
    00498  */
    00499 void Lattice_extractSubLattice(Matrix * lat, unsigned int k, Matrix ** subLat) {
    00500   Matrix * H, *Q, *U, *linLat = NULL;
    00501   unsigned int i;
    00502   dbgStart(Lattice_extractSubLattice);
    00503   /* if the dimension is already good, just copy the initial lattice */
    00504   if (k==lat->NbRows-1) {
    00505     if (*subLat==NULL) {
    00506       (*subLat) = Matrix_Copy(lat);
    00507     }
    00508     else {
    00509       Matrix_copySubMatrix(lat, 0, 0, lat->NbRows, lat->NbColumns, (*subLat), 0, 0);
    00510     }
    00511     return;
    00512   }
    00513   assert(k<lat->NbRows-1);
    00514   /* 1- Make the linear part of the lattice triangular to eliminate terms from
    00515      other dimensions */
    00516   Matrix_subMatrix(lat, 0, 0, lat->NbRows, lat->NbColumns-1, &linLat);
    00517   /* OPT: any integer column-vector elimination is ok indeed. */
    00518   /* OPT: could test if the lattice is already in triangular form. */
    00519   left_hermite(linLat, &H, &Q, &U);
    00520   if (dbgCompParmMore) {
    00521     show_matrix(H);
    00522   }
    00523   Matrix_Free(Q);
    00524   Matrix_Free(U);
    00525   Matrix_Free(linLat);
    00526   /* if not allocated yet, allocate it */
    00527   if (*subLat==NULL) {
    00528     (*subLat) = Matrix_Alloc(k+1, k+1);
    00529   }
    00530   Matrix_copySubMatrix(H, 0, 0, k, k, (*subLat), 0, 0);
    00531   Matrix_Free(H);
    00532   Matrix_copySubMatrix(lat, 0, lat->NbColumns-1, k, 1, (*subLat), 0, k);
    00533   for (i=0; i<k; i++) {
    00534     value_set_si((*subLat)->p[k][i], 0);
    00535   }
    00536   value_set_si((*subLat)->p[k][k], 1);
    00537   dbgEnd(Lattice_extractSubLattice);
    00538 } /* Lattice_extractSubLattice */
    00539
    00540
    00541 /**
    00542  * Computes the overall period of the variables I for (MI) mod |d|, where M is
    00543  * a matrix and |d| a vector. Produce a diagonal matrix S = (s_k) where s_k is
    00544  * the overall period of i_k
    00545  * @param M the set of affine functions of I (row-vectors)
    00546  * @param d the column-vector representing the modulos
    00547 */
    00548 Matrix * affine_periods(Matrix * M, Matrix * d) {
    00549   Matrix * S;
    00550   unsigned int i,j;
    00551   Value tmp;
    00552   Value * periods = (Value *)malloc(sizeof(Value) * M->NbColumns);
    00553   value_init(tmp);
    00554   for(i=0; i< M->NbColumns; i++) {
    00555     value_init(periods[i]);
    00556     value_set_si(periods[i], 1);
    00557   }
    00558   for (i=0; i<M->NbRows; i++) {
    00559     for (j=0; j< M->NbColumns; j++) {
    00560       value_gcd(tmp, d->p[i][0], M->p[i][j]);
    00561       value_divexact(tmp, d->p[i][0], tmp);
    00562       value_lcm(periods[j], periods[j], tmp);
    00563      }
    00564   }
    00565   value_clear(tmp);
    00566
    00567   /* 2- build S */
    00568   S = Matrix_Alloc(M->NbColumns, M->NbColumns);
    00569   for (i=0; i< M->NbColumns; i++)
    00570     for (j=0; j< M->NbColumns; j++)
    00571       if (i==j) value_assign(S->p[i][j],periods[j]);
    00572       else value_set_si(S->p[i][j], 0);
    00573
    00574   /* 3- clean up */
    00575   for(i=0; i< M->NbColumns; i++) value_clear(periods[i]);
    00576   free(periods);
    00577   return S;
    00578 } /* affine_periods */
    00579
    00580
    00581 /**
    00582  * Given an integer matrix B with m rows and integer m-vectors C and d,
    00583  * computes the basis of the integer solutions to (BN+C) mod d = 0 (1).
    00584  * This is an affine lattice (G): (N 1)^T= G(N' 1)^T, forall N' in Z^b.
    00585  * If there is no solution, returns NULL.
    00586  * @param B B, a (m x b) matrix
    00587  * @param C C, a (m x 1) integer matrix
    00588  * @param d d, a (1 x m) integer matrix
    00589  * @param imb the affine (b+1)x(b+1) basis of solutions, in the homogeneous
    00590  * form. Allocated if initially set to NULL, reused if not.
    00591 */
    00592 void Equalities_intModBasis(Matrix * B, Matrix * C, Matrix * d, Matrix ** imb) {
    00593   int b = B->NbColumns;
    00594   /* FIXME: treat the case d=0 as a regular equality B_kN+C_k = 0: */
    00595   /* OPT: could keep only equalities for which d>1 */
    00596   int nbEqs = B->NbRows;
    00597   unsigned int i;
    00598
    00599   /* 1- buid the problem DI+BN+C = 0 */
    00600   Matrix * eqs = Matrix_Alloc(nbEqs, nbEqs+b+1);
    00601   for (i=0; i< nbEqs; i++) {
    00602     value_assign(eqs->p[i][i], d->p[0][i]);
    00603   }
    00604   Matrix_copySubMatrix(B, 0, 0, nbEqs, b, eqs, 0, nbEqs);
    00605   Matrix_copySubMatrix(C, 0, 0, nbEqs, 1, eqs, 0, nbEqs+b);
    00606
    00607   /* 2- the solution is the validity lattice of the equalities */
    00608   Equalities_validityLattice(eqs, nbEqs, imb);
    00609   Matrix_Free(eqs);
    00610 } /* Equalities_intModBasis */
    00611
    00612
    00613 /** kept here for backwards compatiblity. Wrapper to Equalities_intModBasis() */
    00614 Matrix * int_mod_basis(Matrix * B, Matrix * C, Matrix * d) {
    00615   Matrix * imb = NULL;
    00616   Equalities_intModBasis(B, C, d, &imb);
    00617   return imb;
    00618 } /* int_mod_basis */
    00619
    00620
    00621 /**
    00622  * Given a parameterized constraints matrix with m equalities, computes the
    00623  * compression matrix G such that there is an integer solution in the variables
    00624  * space for each value of N', with N = G N' (N are the "nb_parms" parameters)
    00625  * @param E a matrix of parametric equalities @param nb_parms the number of
    00626  * parameters
    00627  * <b>Note: </b>this function is mostly here for backwards
    00628  * compatibility. Prefer the use of <tt>Equalities_validityLattice</tt>.
    00629 */
    00630 Matrix * compress_parms(Matrix * E, int nbParms) {
    00631   Matrix * vl=NULL;
    00632   Equalities_validityLattice(E, E->NbColumns-2-nbParms, &vl);
    00633   return vl;
    00634 }/* compress_parms */
    00635
    00636
    00637 /** Removes the equalities that involve only parameters, by eliminating some
    00638  * parameters in the polyhedron's constraints and in the context.<p>
    00639  * <b>Updates M and Ctxt.</b>
    00640  * @param M1 the polyhedron's constraints
    00641  * @param Ctxt1 the constraints of the polyhedron's context
    00642  * @param renderSpace tells if the returned equalities must be expressed in the
    00643  * parameters space (renderSpace=0) or in the combined var/parms space
    00644  * (renderSpace = 1)
    00645  * @param elimParms the list of parameters that have been removed: an array
    00646  * whose 1st element is the number of elements in the list.  (returned)
    00647  * @return the system of equalities that involve only parameters.
    00648  */
    00649 Matrix * Constraints_Remove_parm_eqs(Matrix ** M1, Matrix ** Ctxt1,
    00650                                      int renderSpace,
    00651                                      unsigned int ** elimParms) {
    00652   int i, j, k, nbEqsParms =0;
    00653   int nbEqsM, nbEqsCtxt, allZeros, nbTautoM = 0, nbTautoCtxt = 0;
    00654   Matrix * M = (*M1);
    00655   Matrix * Ctxt = (*Ctxt1);
    00656   int nbVars = M->NbColumns-Ctxt->NbColumns;
    00657   Matrix * Eqs;
    00658   Matrix * EqsMTmp;
    00659
    00660   /* 1- build the equality matrix(ces) */
    00661   nbEqsM = 0;
    00662   for (i=0; i< M->NbRows; i++) {
    00663     k = First_Non_Zero(M->p[i], M->NbColumns);
    00664     /* if it is a tautology, count it as such */
    00665     if (k==-1) {
    00666       nbTautoM++;
    00667     }
    00668     else {
    00669       /* if it only involves parameters, count it */
    00670       if (k>= nbVars+1) nbEqsM++;
    00671     }
    00672   }
    00673
    00674   nbEqsCtxt = 0;
    00675   for (i=0; i< Ctxt->NbRows; i++) {
    00676     if (value_zero_p(Ctxt->p[i][0])) {
    00677       if (First_Non_Zero(Ctxt->p[i], Ctxt->NbColumns)==-1) {
    00678         nbTautoCtxt++;
    00679       }
    00680       else {
    00681         nbEqsCtxt ++;
    00682       }
    00683     }
    00684   }
    00685   nbEqsParms = nbEqsM + nbEqsCtxt;
    00686
    00687   /* nothing to do in this case */
    00688   if (nbEqsParms+nbTautoM+nbTautoCtxt==0) {
    00689     (*elimParms) = (unsigned int*) malloc(sizeof(int));
    00690     (*elimParms)[0] = 0;
    00691     if (renderSpace==0) {
    00692       return Matrix_Alloc(0,Ctxt->NbColumns);
    00693     }
    00694     else {
    00695       return Matrix_Alloc(0,M->NbColumns);
    00696     }
    00697   }
    00698
    00699   Eqs= Matrix_Alloc(nbEqsParms, Ctxt->NbColumns);
    00700   EqsMTmp= Matrix_Alloc(nbEqsParms, M->NbColumns);
    00701
    00702   /* copy equalities from the context */
    00703   k = 0;
    00704   for (i=0; i< Ctxt->NbRows; i++) {
    00705     if (value_zero_p(Ctxt->p[i][0])
    00706                      && First_Non_Zero(Ctxt->p[i], Ctxt->NbColumns)!=-1) {
    00707       Vector_Copy(Ctxt->p[i], Eqs->p[k], Ctxt->NbColumns);
    00708       Vector_Copy(Ctxt->p[i]+1, EqsMTmp->p[k]+nbVars+1,
    00709                   Ctxt->NbColumns-1);
    00710       k++;
    00711     }
    00712   }
    00713   for (i=0; i< M->NbRows; i++) {
    00714     j=First_Non_Zero(M->p[i], M->NbColumns);
    00715     /* copy equalities that involve only parameters from M */
    00716     if (j>=nbVars+1) {
    00717       Vector_Copy(M->p[i]+nbVars+1, Eqs->p[k]+1, Ctxt->NbColumns-1);
    00718       Vector_Copy(M->p[i]+nbVars+1, EqsMTmp->p[k]+nbVars+1,
    00719                   Ctxt->NbColumns-1);
    00720       /* mark these equalities for removal */
    00721       value_set_si(M->p[i][0], 2);
    00722       k++;
    00723     }
    00724     /* mark the all-zero equalities for removal */
    00725     if (j==-1) {
    00726       value_set_si(M->p[i][0], 2);
    00727     }
    00728   }
    00729
    00730   /* 2- eliminate parameters until all equalities are used or until we find a
    00731   contradiction (overconstrained system) */
    00732   (*elimParms) = (unsigned int *) malloc((Eqs->NbRows+1) * sizeof(int));
    00733   (*elimParms)[0] = 0;
    00734   allZeros = 0;
    00735   for (i=0; i< Eqs->NbRows; i++) {
    00736     /* find a variable that can be eliminated */
    00737     k = First_Non_Zero(Eqs->p[i], Eqs->NbColumns);
    00738     if (k!=-1) { /* nothing special to do for tautologies */
    00739
    00740       /* if there is a contradiction, return empty matrices */
    00741       if (k==Eqs->NbColumns-1) {
    00742         printf("Contradiction in %dth row of Eqs: ",k);
    00743         show_matrix(Eqs);
    00744         Matrix_Free(Eqs);
    00745         Matrix_Free(EqsMTmp);
    00746         (*M1) = Matrix_Alloc(0, M->NbColumns);
    00747         Matrix_Free(M);
    00748         (*Ctxt1) = Matrix_Alloc(0,Ctxt->NbColumns);
    00749         Matrix_Free(Ctxt);
    00750         free(*elimParms);
    00751         (*elimParms) = (unsigned int *) malloc(sizeof(int));
    00752         (*elimParms)[0] = 0;
    00753         if (renderSpace==1) {
    00754           return Matrix_Alloc(0,(*M1)->NbColumns);
    00755         }
    00756         else {
    00757           return Matrix_Alloc(0,(*Ctxt1)->NbColumns);
    00758         }
    00759       }
    00760       /* if we have something we can eliminate, do it in 3 places:
    00761          Eqs, Ctxt, and M */
    00762       else {
    00763         k--; /* k is the rank of the variable, now */
    00764         (*elimParms)[0]++;
    00765         (*elimParms)[(*elimParms[0])]=k;
    00766         for (j=0; j< Eqs->NbRows; j++) {
    00767           if (i!=j) {
    00768             eliminate_var_with_constr(Eqs, i, Eqs, j, k);
    00769             eliminate_var_with_constr(EqsMTmp, i, EqsMTmp, j, k+nbVars);
    00770           }
    00771         }
    00772         for (j=0; j< Ctxt->NbRows; j++) {
    00773           if (value_notzero_p(Ctxt->p[i][0])) {
    00774             eliminate_var_with_constr(Eqs, i, Ctxt, j, k);
    00775           }
    00776         }
    00777         for (j=0; j< M->NbRows; j++) {
    00778           if (value_cmp_si(M->p[i][0], 2)) {
    00779             eliminate_var_with_constr(EqsMTmp, i, M, j, k+nbVars);
    00780           }
    00781         }
    00782       }
    00783     }
    00784     /* if (k==-1): count the tautologies in Eqs to remove them later */
    00785     else {
    00786       allZeros++;
    00787     }
    00788   }
    00789
    00790   /* elimParms may have been overallocated. Now we know how many parms have
    00791      been eliminated so we can reallocate the right amount of memory. */
    00792   if (!realloc((*elimParms), ((*elimParms)[0]+1)*sizeof(int))) {
    00793     fprintf(stderr, "Constraints_Remove_parm_eqs > cannot realloc()");
    00794   }
    00795
    00796   Matrix_Free(EqsMTmp);
    00797
    00798   /* 3- remove the "bad" equalities from the input matrices
    00799      and copy the equalities involving only parameters */
    00800   EqsMTmp = Matrix_Alloc(M->NbRows-nbEqsM-nbTautoM, M->NbColumns);
    00801   k=0;
    00802   for (i=0; i< M->NbRows; i++) {
    00803     if (value_cmp_si(M->p[i][0], 2)) {
    00804       Vector_Copy(M->p[i], EqsMTmp->p[k], M->NbColumns);
    00805       k++;
    00806     }
    00807   }
    00808   Matrix_Free(M);
    00809   (*M1) = EqsMTmp;
    00810
    00811   EqsMTmp = Matrix_Alloc(Ctxt->NbRows-nbEqsCtxt-nbTautoCtxt, Ctxt->NbColumns);
    00812   k=0;
    00813   for (i=0; i< Ctxt->NbRows; i++) {
    00814     if (value_notzero_p(Ctxt->p[i][0])) {
    00815       Vector_Copy(Ctxt->p[i], EqsMTmp->p[k], Ctxt->NbColumns);
    00816       k++;
    00817     }
    00818   }
    00819   Matrix_Free(Ctxt);
    00820   (*Ctxt1) = EqsMTmp;
    00821
    00822   if (renderSpace==0) {/* renderSpace=0: equalities in the parameter space */
    00823     EqsMTmp = Matrix_Alloc(Eqs->NbRows-allZeros, Eqs->NbColumns);
    00824     k=0;
    00825     for (i=0; i<Eqs->NbRows; i++) {
    00826       if (First_Non_Zero(Eqs->p[i], Eqs->NbColumns)!=-1) {
    00827         Vector_Copy(Eqs->p[i], EqsMTmp->p[k], Eqs->NbColumns);
    00828         k++;
    00829       }
    00830     }
    00831   }
    00832   else {/* renderSpace=1: equalities rendered in the combined space */
    00833     EqsMTmp = Matrix_Alloc(Eqs->NbRows-allZeros, (*M1)->NbColumns);
    00834     k=0;
    00835     for (i=0; i<Eqs->NbRows; i++) {
    00836       if (First_Non_Zero(Eqs->p[i], Eqs->NbColumns)!=-1) {
    00837         Vector_Copy(Eqs->p[i], &(EqsMTmp->p[k][nbVars]), Eqs->NbColumns);
    00838         k++;
    00839       }
    00840     }
    00841   }
    00842   Matrix_Free(Eqs);
    00843   Eqs = EqsMTmp;
    00844
    00845   return Eqs;
    00846 } /* Constraints_Remove_parm_eqs */
    00847
    00848
    00849 /** Removes equalities involving only parameters, but starting from a
    00850  * Polyhedron and its context.
    00851  * @param P the polyhedron
    00852  * @param C P's context
    00853  * @param renderSpace: 0 for the parameter space, =1 for the combined space.
    00854  * @maxRays Polylib's usual <i>workspace</i>.
    00855  */
    00856 Polyhedron * Polyhedron_Remove_parm_eqs(Polyhedron ** P, Polyhedron ** C,
    00857                                         int renderSpace,
    00858                                         unsigned int ** elimParms,
    00859                                         int maxRays) {
    00860   Matrix * Eqs;
    00861   Polyhedron * Peqs;
    00862   Matrix * M = Polyhedron2Constraints((*P));
    00863   Matrix * Ct = Polyhedron2Constraints((*C));
    00864
    00865   /* if the Minkowski representation is not computed yet, do not compute it in
    00866      Constraints2Polyhedron */
    00867   if (F_ISSET((*P), POL_VALID | POL_INEQUALITIES) &&
    00868       (F_ISSET((*C), POL_VALID | POL_INEQUALITIES))) {
    00869     FL_INIT(maxRays, POL_NO_DUAL);
    00870   }
    00871
    00872   Eqs = Constraints_Remove_parm_eqs(&M, &Ct, renderSpace, elimParms);
    00873   Peqs = Constraints2Polyhedron(Eqs, maxRays);
    00874   Matrix_Free(Eqs);
    00875
    00876   /* particular case: no equality involving only parms is found */
    00877   if (Eqs->NbRows==0) {
    00878     Matrix_Free(M);
    00879     Matrix_Free(Ct);
    00880     return Peqs;
    00881   }
    00882   Polyhedron_Free(*P);
    00883   Polyhedron_Free(*C);
    00884   (*P) = Constraints2Polyhedron(M, maxRays);
    00885   (*C) = Constraints2Polyhedron(Ct, maxRays);
    00886   Matrix_Free(M);
    00887   Matrix_Free(Ct);
    00888   return Peqs;
    00889 } /* Polyhedron_Remove_parm_eqs */
    00890
    00891
    00892 /**
    00893  * Given a matrix with m parameterized equations, compress the nb_parms
    00894  * parameters and n-m variables so that m variables are integer, and transform
    00895  * the variable space into a n-m space by eliminating the m variables (using
    00896  * the equalities) the variables to be eliminated are chosen automatically by
    00897  * the function.
    00898  * <b>Deprecated.</b> Try to use Constraints_fullDimensionize instead.
    00899  * @param M the constraints
    00900  * @param the number of parameters
    00901  * @param validityLattice the the integer lattice underlying the integer
    00902  * solutions.
    00903 */
    00904 Matrix * full_dimensionize(Matrix const * M, int nbParms,
    00905                            Matrix ** validityLattice) {
    00906   Matrix * Eqs, * Ineqs;
    00907   Matrix * permutedEqs, * permutedIneqs;
    00908   Matrix * Full_Dim;
    00909   Matrix * WVL; /* The Whole Validity Lattice (vars+parms) */
    00910   unsigned int i,j;
    00911   int nbElimVars;
    00912   unsigned int * permutation, * permutationInv;
    00913   /* 0- Split the equalities and inequalities from each other */
    00914   split_constraints(M, &Eqs, &Ineqs);
    00915
    00916   /* 1- if the polyhedron is already full-dimensional, return it */
    00917   if (Eqs->NbRows==0) {
    00918     Matrix_Free(Eqs);
    00919     (*validityLattice) = Identity_Matrix(nbParms+1);
    00920     return Ineqs;
    00921   }
    00922   nbElimVars = Eqs->NbRows;
    00923
    00924   /* 2- put the vars to be eliminated at the first positions,
    00925      and compress the other vars/parms
    00926      -> [ variables to eliminate / parameters / variables to keep ] */
    00927   permutation = find_a_permutation(Eqs, nbParms);
    00928   if (dbgCompParm) {
    00929     printf("Permuting the vars/parms this way: [ ");
    00930     for (i=0; i< Eqs->NbColumns; i++) {
    00931       printf("%d ", permutation[i]);
    00932     }
    00933     printf("]\n");
    00934   }
    00935   permutedEqs = mpolyhedron_permute(Eqs, permutation);
    00936   WVL = compress_parms(permutedEqs, Eqs->NbColumns-2-Eqs->NbRows);
    00937   if (dbgCompParm) {
    00938     printf("Whole validity lattice: ");
    00939     show_matrix(WVL);
    00940   }
    00941   mpolyhedron_compress_last_vars(permutedEqs, WVL);
    00942   permutedIneqs = mpolyhedron_permute(Ineqs, permutation);
    00943   if (dbgCompParm) {
    00944     show_matrix(permutedEqs);
    00945   }
    00946   Matrix_Free(Eqs);
    00947   Matrix_Free(Ineqs);
    00948   mpolyhedron_compress_last_vars(permutedIneqs, WVL);
    00949   if (dbgCompParm) {
    00950     printf("After compression: ");
    00951     show_matrix(permutedIneqs);
    00952   }
    00953   /* 3- eliminate the first variables */
    00954   if (!mpolyhedron_eliminate_first_variables(permutedEqs, permutedIneqs)) {
    00955     fprintf(stderr,"full-dimensionize > variable elimination failed. \n");
    00956     return NULL;
    00957   }
    00958   if (dbgCompParm) {
    00959     printf("After elimination of the variables: ");
    00960     show_matrix(permutedIneqs);
    00961   }
    00962
    00963   /* 4- get rid of the first (zero) columns,
    00964      which are now useless, and put the parameters back at the end */
    00965   Full_Dim = Matrix_Alloc(permutedIneqs->NbRows,
    00966                           permutedIneqs->NbColumns-nbElimVars);
    00967   for (i=0; i< permutedIneqs->NbRows; i++) {
    00968     value_set_si(Full_Dim->p[i][0], 1);
    00969     for (j=0; j< nbParms; j++)
    00970       value_assign(Full_Dim->p[i][j+Full_Dim->NbColumns-nbParms-1],
    00971                    permutedIneqs->p[i][j+nbElimVars+1]);
    00972     for (j=0; j< permutedIneqs->NbColumns-nbParms-2-nbElimVars; j++)
    00973       value_assign(Full_Dim->p[i][j+1],
    00974                    permutedIneqs->p[i][nbElimVars+nbParms+j+1]);
    00975     value_assign(Full_Dim->p[i][Full_Dim->NbColumns-1],
    00976                  permutedIneqs->p[i][permutedIneqs->NbColumns-1]);
    00977   }
    00978   Matrix_Free(permutedIneqs);
    00979
    00980   /* 5- Keep only the the validity lattice restricted to the parameters */
    00981   *validityLattice = Matrix_Alloc(nbParms+1, nbParms+1);
    00982   for (i=0; i< nbParms; i++) {
    00983     for (j=0; j< nbParms; j++)
    00984       value_assign((*validityLattice)->p[i][j],
    00985                    WVL->p[i][j]);
    00986     value_assign((*validityLattice)->p[i][nbParms],
    00987                  WVL->p[i][WVL->NbColumns-1]);
    00988   }
    00989   for (j=0; j< nbParms; j++)
    00990     value_set_si((*validityLattice)->p[nbParms][j], 0);
    00991   value_assign((*validityLattice)->p[nbParms][nbParms],
    00992                WVL->p[WVL->NbColumns-1][WVL->NbColumns-1]);
    00993
    00994   /* 6- Clean up */
    00995   Matrix_Free(WVL);
    00996   return Full_Dim;
    00997 } /* full_dimensionize */
    00998
    00999 #undef dbgCompParm
    01000 #undef dbgCompParmMore