polylib: matrix_addon.c Source File

- Main Page
- Classes
- Files

- File List
- File Members

# matrix_addon.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: matrix_addon.c,v 1.17 2007/03/18 18:49:08 skimo Exp $
    00020  *
    00021  * Polylib matrix addons
    00022  * Mainly, deals with polyhedra represented as a matrix (implicit form)
    00023  * @author Benoit Meister <meister@icps.u-strasbg.fr>
    00024  *
    00025  */
    00026
    00027 #include <stdlib.h>
    00028 #include<polylib/polylib.h>
    00029 #include <polylib/matrix_addon.h>
    00030
    00031 /** Creates a view of the constraints of a polyhedron as a Matrix * */
    00032 Matrix * constraintsView(Polyhedron * P) {
    00033   Matrix * view = (Matrix *)malloc(sizeof(Matrix));
    00034   view->NbRows = P->NbConstraints;
    00035   view->NbColumns = P->Dimension+2;
    00036   view->p = P->Constraint;
    00037   return view;
    00038 }
    00039
    00040 /** "Frees" a view of the constraints of a polyhedron */
    00041 void constraintsView_Free(Matrix * M) {
    00042   free(M);
    00043 }
    00044
    00045 /**
    00046  * splits a matrix of constraints M into a matrix of equalities Eqs and a
    00047  *  matrix of inequalities Ineqs allocs the new matrices.
    00048  * Allocates Eqs and Ineqs.
    00049 */
    00050 void split_constraints(Matrix const * M, Matrix ** Eqs, Matrix **Ineqs) {
    00051   unsigned int i, j, k_eq, k_ineq, nb_eqs=0;
    00052
    00053   /* 1- count the number of equations */
    00054   for (i=0; i< M->NbRows; i++)
    00055     if (value_zero_p(M->p[i][0])) nb_eqs++;
    00056
    00057   /* 2- extract the two matrices of equations */
    00058   (*Eqs) = Matrix_Alloc(nb_eqs, M->NbColumns);
    00059   (*Ineqs) = Matrix_Alloc(M->NbRows-nb_eqs, M->NbColumns);
    00060
    00061   k_eq = k_ineq = 0;
    00062   for(i=0; i< M->NbRows; i++) {
    00063     if (value_zero_p(M->p[i][0]))
    00064       {
    00065         for(j=0; j< M->NbColumns; j++)
    00066           value_assign((*Eqs)->p[k_eq][j], M->p[i][j]);
    00067         k_eq++;
    00068       }
    00069     else
    00070        {
    00071         for(j=0; j< M->NbColumns; j++)
    00072           value_assign((*Ineqs)->p[k_ineq][j], M->p[i][j]);
    00073         k_ineq++;
    00074       }
    00075   }
    00076 }
    00077
    00078
    00079 /* returns the dim-dimensional identity matrix */
    00080 Matrix * Identity_Matrix(unsigned int dim) {
    00081   Matrix * ret = Matrix_Alloc(dim, dim);
    00082   unsigned int i,j;
    00083   for (i=0; i< dim; i++) {
    00084     for (j=0; j< dim; j++) {
    00085       if (i==j)
    00086         { value_set_si(ret->p[i][j], 1); }
    00087       else value_set_si(ret->p[i][j], 0);
    00088     }
    00089   }
    00090   return ret;
    00091 } /* Identity_Matrix */
    00092
    00093
    00094 /**
    00095  * returns the dim-dimensional identity matrix.
    00096  * If I is set to NULL, allocates it first.
    00097  * Else, assumes an existing, allocated Matrix.
    00098 */
    00099 void Matrix_identity(unsigned int dim, Matrix ** I) {
    00100   int i,j;
    00101   if (*I==NULL) {
    00102     (*I) = Identity_Matrix(dim);
    00103   }
    00104   else {
    00105     assert((*I)->NbRows>=dim && (*I)->NbColumns>=dim);
    00106     for (i=0; i< dim; i++) {
    00107       for (j=0; j< dim; j++) {
    00108         if (i==j) {
    00109             value_set_si((*I)->p[i][j], 1);
    00110           }
    00111         else {
    00112           value_set_si((*I)->p[i][j], 0);
    00113         }
    00114       }
    00115     }
    00116   }
    00117 } /* Matrix_identity */
    00118
    00119
    00120 /** given a n x n integer transformation matrix transf, compute its inverse
    00121     M/g, where M is a nxn integer matrix.  g is a common denominator for
    00122     elements of (transf^{-1}) */
    00123 void mtransformation_inverse(Matrix * transf, Matrix ** inverse, Value * g) {
    00124   Value factor;
    00125   unsigned int i,j;
    00126   Matrix *tmp, *inv;
    00127
    00128   value_init(*g);
    00129   value_set_si(*g,1);
    00130
    00131   /* a - compute the inverse as usual (n x (n+1) matrix) */
    00132   tmp = Matrix_Copy(transf);
    00133   inv = Matrix_Alloc(transf->NbRows, transf->NbColumns+1);
    00134   MatInverse(tmp, inv);
    00135   Matrix_Free(tmp);
    00136
    00137   /* b - as it is rational, put it to the same denominator*/
    00138   (*inverse) = Matrix_Alloc(transf->NbRows, transf->NbRows);
    00139   for (i=0; i< inv->NbRows; i++)
    00140     value_lcm(*g, *g, inv->p[i][inv->NbColumns-1]);
    00141   for (i=0; i< inv->NbRows; i++) {
    00142     value_division(factor, *g, inv->p[i][inv->NbColumns-1]);
    00143     for (j=0; j< (*inverse)->NbColumns; j++)
    00144       value_multiply((*inverse)->p[i][j], inv->p[i][j],  factor);
    00145   }
    00146
    00147   /* c- clean up */
    00148   value_clear(factor);
    00149   Matrix_Free(inv);
    00150 } /* mtransformation_inverse */
    00151
    00152
    00153 /** takes a transformation matrix, and expands it to a higher dimension with
    00154     the identity matrix regardless of it homogeneousness */
    00155 Matrix * mtransformation_expand_left_to_dim(Matrix * M, int new_dim) {
    00156   Matrix * ret = Identity_Matrix(new_dim);
    00157   int offset = new_dim-M->NbRows;
    00158   unsigned int i,j;
    00159
    00160   assert(new_dim>=M->NbColumns);
    00161   assert(M->NbRows==M->NbColumns);
    00162
    00163   for (i=0; i< M->NbRows; i++)
    00164     for (j=0; j< M->NbRows; j++)
    00165       value_assign(ret->p[offset+i][offset+j], M->p[i][j]);
    00166   return ret;
    00167 } /* mtransformation_expand_left_to_dim */
    00168
    00169
    00170 /** simplify a matrix seen as a polyhedron, by dividing its rows by the gcd of
    00171    their elements. */
    00172 void mpolyhedron_simplify(Matrix * polyh) {
    00173   int i, j;
    00174   Value cur_gcd;
    00175   value_init(cur_gcd);
    00176   for (i=0; i< polyh->NbRows; i++) {
    00177     Vector_Gcd(polyh->p[i]+1, polyh->NbColumns-1, &cur_gcd);
    00178     printf(" gcd[%d] = ", i);
    00179     value_print(stdout, VALUE_FMT, cur_gcd);printf("\n");
    00180     Vector_AntiScale(polyh->p[i]+1, polyh->p[i]+1, cur_gcd, polyh->NbColumns-1);
    00181   }
    00182   value_clear(cur_gcd);
    00183 } /* mpolyhedron_simplify */
    00184
    00185
    00186 /** inflates a polyhedron (represented as a matrix) P, so that the apx of its
    00187     Ehrhart Polynomial is an upper bound of the Ehrhart polynomial of P
    00188     WARNING: this inflation is supposed to be applied on full-dimensional
    00189     polyhedra. */
    00190 void mpolyhedron_inflate(Matrix * polyh, unsigned int nb_parms) {
    00191   unsigned int i,j;
    00192   unsigned nb_vars = polyh->NbColumns-nb_parms-2;
    00193   Value infl;
    00194   value_init(infl);
    00195   /* subtract the sum of the negative coefficients of each inequality */
    00196   for (i=0; i< polyh->NbRows; i++) {
    00197     value_set_si(infl, 0);
    00198     for (j=0; j< nb_vars; j++) {
    00199       if (value_neg_p(polyh->p[i][1+j]))
    00200         value_addto(infl, infl, polyh->p[i][1+j]);
    00201     }
    00202     /* here, we subtract a negative value */
    00203     value_subtract(polyh->p[i][polyh->NbColumns-1],
    00204                    polyh->p[i][polyh->NbColumns-1], infl);
    00205   }
    00206   value_clear(infl);
    00207 } /* mpolyhedron_inflate */
    00208
    00209
    00210 /** deflates a polyhedron (represented as a matrix) P, so that the apx of its
    00211     Ehrhart Polynomial is a lower bound of the Ehrhart polynomial of P WARNING:
    00212     this deflation is supposed to be applied on full-dimensional polyhedra. */
    00213 void mpolyhedron_deflate(Matrix * polyh, unsigned int nb_parms) {
    00214   unsigned int i,j;
    00215   unsigned nb_vars = polyh->NbColumns-nb_parms-2;
    00216   Value defl;
    00217   value_init(defl);
    00218   /* substract the sum of the negative coefficients of each inequality */
    00219   for (i=0; i< polyh->NbRows; i++) {
    00220     value_set_si(defl, 0);
    00221     for (j=0; j< nb_vars; j++) {
    00222       if (value_pos_p(polyh->p[i][1+j]))
    00223         value_addto(defl, defl, polyh->p[i][1+j]);
    00224     }
    00225     /* here, we substract a negative value */
    00226     value_subtract(polyh->p[i][polyh->NbColumns-1],
    00227                    polyh->p[i][polyh->NbColumns-1], defl);
    00228   }
    00229   value_clear(defl);
    00230 } /* mpolyhedron_deflate */
    00231
    00232
    00233 /** use an eliminator row to eliminate a variable in a victim row (without
    00234  * changing the sign of the victim row -> important if it is an inequality).
    00235  * @param Eliminator the matrix containing the eliminator row
    00236  * @param eliminator_row the index of the eliminator row in <tt>Eliminator</tt>
    00237  * @param Victim the matrix containing the row to be eliminated
    00238  * @param victim_row the row to be eliminated in <tt>Victim</tt>
    00239  * @param var_to_elim the variable to be eliminated.
    00240  */
    00241 void eliminate_var_with_constr(Matrix * Eliminator,
    00242                                unsigned int eliminator_row, Matrix * Victim,
    00243                                unsigned int victim_row,
    00244                                unsigned int var_to_elim) {
    00245   Value cur_lcm, mul_a, mul_b;
    00246   Value tmp, tmp2;
    00247   int k;
    00248
    00249   value_init(cur_lcm);
    00250   value_init(mul_a);
    00251   value_init(mul_b);
    00252   value_init(tmp);
    00253   value_init(tmp2);
    00254   /* if the victim coefficient is not zero */
    00255   if (value_notzero_p(Victim->p[victim_row][var_to_elim+1])) {
    00256     value_lcm(cur_lcm, Eliminator->p[eliminator_row][var_to_elim+1],
    00257               Victim->p[victim_row][var_to_elim+1]);
    00258     /* multiplication factors */
    00259     value_division(mul_a, cur_lcm,
    00260                    Eliminator->p[eliminator_row][var_to_elim+1]);
    00261     value_division(mul_b, cur_lcm,
    00262                    Victim->p[victim_row][var_to_elim+1]);
    00263     /* the multiplicator for the vitim row has to be positive */
    00264     if (value_pos_p(mul_b)) {
    00265       value_oppose(mul_a, mul_a);
    00266     }
    00267     else {
    00268       value_oppose(mul_b, mul_b);
    00269     }
    00270     value_clear(cur_lcm);
    00271     /* now we have a.mul_a = -(b.mul_b) and mul_a > 0 */
    00272     for (k=1; k<Victim->NbColumns; k++) {
    00273       value_multiply(tmp, Eliminator->p[eliminator_row][k], mul_a);
    00274       value_multiply(tmp2, Victim->p[victim_row][k], mul_b);
    00275       value_addto(Victim->p[victim_row][k], tmp, tmp2);
    00276     }
    00277   }
    00278   value_clear(mul_a);
    00279   value_clear(mul_b);
    00280   value_clear(tmp);
    00281   value_clear(tmp2);
    00282 }
    00283 /* eliminate_var_with_constr */
    00284
    00285
    00286 /* STUFF WITH PARTIAL MAPPINGS (Mappings to a subset of the
    00287    variables/parameters) : on the first or last variables/parameters */
    00288
    00289 /** compress the last vars/pars of the polyhedron M expressed as a polylib
    00290     matrix
    00291  - adresses the full-rank compressions only
    00292  - modfies M */
    00293 void mpolyhedron_compress_last_vars(Matrix * M, Matrix * compression) {
    00294   unsigned int i, j, k;
    00295   unsigned int offset = M->NbColumns - compression->NbRows;
    00296   /* the computations on M will begin on column "offset" */
    00297
    00298   Matrix * M_tmp = Matrix_Alloc(1, M->NbColumns);
    00299   assert(compression->NbRows==compression->NbColumns);
    00300   /* basic matrix multiplication (using a temporary row instead of a whole
    00301      temporary matrix), but with a column offset */
    00302   for(i=0; i< M->NbRows; i++) {
    00303     for (j=0; j< compression->NbRows; j++) {
    00304       value_set_si(M_tmp->p[0][j], 0);
    00305       for (k=0; k< compression->NbRows; k++) {
    00306         value_addmul(M_tmp->p[0][j], M->p[i][k+offset],compression->p[k][j]);
    00307       }
    00308     }
    00309     for (j=0; j< compression->NbRows; j++)
    00310       value_assign(M->p[i][j+offset], M_tmp->p[0][j]);
    00311   }
    00312   Matrix_Free(M_tmp);
    00313 } /* mpolyhedron_compress_last_vars */
    00314
    00315
    00316 /** use a set of m equalities Eqs to eliminate m variables in the polyhedron
    00317     Ineqs represented as a matrix
    00318  eliminates the m first variables
    00319  - assumes that Eqs allow to eliminate the m equalities
    00320  - modifies Eqs and Ineqs */
    00321 unsigned int mpolyhedron_eliminate_first_variables(Matrix * Eqs,
    00322                                                    Matrix *Ineqs) {
    00323   unsigned int i, j, k;
    00324   /* eliminate one variable (index i) after each other */
    00325   for (i=0; i< Eqs->NbRows; i++) {
    00326     /* find j, the first (non-marked) row of Eqs with a non-zero coefficient */
    00327     for (j=0; j<Eqs->NbRows && (Eqs->p[j][i+1]==0 ||
    00328                                 ( !value_cmp_si(Eqs->p[j][0],2) ));
    00329          j++);
    00330     /* if no row is found in Eqs that allows to eliminate variable i, return an
    00331        error code (0) */
    00332     if (j==Eqs->NbRows) return 0;
    00333     /* else, eliminate variable i in Eqs and Ineqs with the j^th row of Eqs
    00334        (and mark this row so we don't use it again for an elimination) */
    00335     for (k=j+1; k<Eqs->NbRows; k++)
    00336       eliminate_var_with_constr(Eqs, j, Eqs, k, i);
    00337     for (k=0; k< Ineqs->NbRows; k++)
    00338       eliminate_var_with_constr(Eqs, j, Ineqs, k, i);
    00339     /* mark the row */
    00340     value_set_si(Eqs->p[j][0],2);
    00341   }
    00342   /* un-mark all the rows */
    00343   for (i=0; i< Eqs->NbRows; i++) value_set_si(Eqs->p[i][0],0);
    00344   return 1;
    00345 } /* mpolyhedron_eliminate_first_variables */
    00346
    00347
    00348 /** returns a contiguous submatrix of a matrix.
    00349  * @param M the input matrix
    00350  * @param sr the index of the starting row
    00351  * @param sc the index of the starting column
    00352  * @param er the index ofthe ending row (excluded)
    00353  * @param ec the ined of the ending colummn (excluded)
    00354  * @param sub (returned), the submatrix. Allocated if set to NULL, assumed to
    00355  * be already allocated else.
    00356  */
    00357 void Matrix_subMatrix(Matrix * M, unsigned int sr, unsigned int sc,
    00358                           unsigned int er, unsigned int ec, Matrix ** sub) {
    00359   int i;
    00360   int nbR = er-sr;
    00361   int nbC = ec-sc;
    00362   assert (er<=M->NbRows && ec<=M->NbColumns);
    00363   if ((*sub)==NULL) {
    00364     (*sub) = Matrix_Alloc(nbR, nbC);
    00365   }
    00366   if (nbR==0 || nbC==0) return;
    00367   for (i=0; i< nbR; i++) {
    00368     Vector_Copy(&(M->p[i+sr][sc]), (*sub)->p[i], nbC);
    00369   }
    00370 }/* Matrix_subMatrix */
    00371
    00372
    00373 /**
    00374  * Cloning function. Similar to Matrix_Copy() but allocates the target matrix
    00375  * if it is set to NULL.
    00376  */
    00377 void Matrix_clone(Matrix * M, Matrix ** Cl) {
    00378   Matrix_subMatrix(M, 0,0, M->NbRows, M->NbColumns, Cl);
    00379 }
    00380
    00381
    00382 /**
    00383  * Copies a contiguous submatrix of M1 into M2, at the indicated position.
    00384  * M1 and M2 are assumed t be allocated already.
    00385  * @param M1 the source matrix
    00386  * @param sr1 the starting source row
    00387  * @param sc1 the starting source column
    00388  * @param nbR the number of rows
    00389  * @param nbC the number of columns
    00390  * @param M2 the target matrix
    00391  * @param sr2 the starting target row
    00392  * @param sc2 the starting target column
    00393 */
    00394 void Matrix_copySubMatrix(Matrix *M1,
    00395                           unsigned int sr1, unsigned int sc1,
    00396                           unsigned int nbR, unsigned int nbC,
    00397                           Matrix * M2,
    00398                           unsigned int sr2, unsigned int sc2) {
    00399   int i;
    00400   for (i=0; i< nbR; i++) {
    00401     Vector_Copy(&(M1->p[i+sr1][sc1]), &(M2->p[i+sr2][sc2]), nbC);
    00402   }
    00403 } /* Matrix_copySubMatrix */
    00404
    00405
    00406 /**
    00407  * transforms a matrix M into -M
    00408  */
    00409 void Matrix_oppose(Matrix * M) {
    00410   int i,j;
    00411   for (i=0; i<M->NbRows; i++) {
    00412     for (j=0; j< M->NbColumns; j++) {
    00413       value_oppose(M->p[i][j], M->p[i][j]);
    00414     }
    00415   }
    00416 }