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

matrix_addon.c

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

Generated on Mon Apr 23 19:23:52 2007 for polylib by doxygen 1.3.5