polylib: matrix_permutations.c Source File

- Main Page
- Classes
- Files

- File List
- File Members

# matrix_permutations.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_permutations.c,v 1.8 2006/10/01 02:10:46 meister Exp $
    00020  *
    00021  * Permutations on matrices Matrices are seen either as transformations
    00022  * (mtransformation) or as polyhedra (mpolyhedron)
    00023  * @author B. Meister
    00024  * LSIIT -ICPS
    00025  * UMR 7005 CNRS
    00026  * Louis Pasteur University (ULP), Strasbourg, France
    00027  *
    00028  * Permutations are just indirection vectors: the k^th element of a permutation
    00029  * vector is the position of the k^th variable in the permuted object.
    00030  */
    00031
    00032 #include <stdlib.h>
    00033 #include <polylib/matrix_permutations.h>
    00034
    00035 /** utility function : bit count (i know, there are faster methods) */
    00036 unsigned int nb_bits(unsigned long long int x) {
    00037   unsigned int i,n=0;
    00038   unsigned long long int y=x;
    00039   for (i=0; i< 64; i++) {
    00040     n+=y%2;
    00041     y>>=1;
    00042   }
    00043   return n;
    00044 }
    00045
    00046
    00047 /** Gives the inverse permutation vector of a permutation vector
    00048  * @param perm the permutation vector
    00049  * @param
    00050 */
    00051 unsigned int * permutation_inverse(unsigned int * perm, unsigned int nb_elems) {
    00052   int i;
    00053   unsigned int * inv_perm = (unsigned int *)malloc(sizeof(unsigned int) * nb_elems);
    00054   for (i=0; i< nb_elems; i++) inv_perm[perm[i]] = i;
    00055   return inv_perm;
    00056 }
    00057
    00058
    00059 /**
    00060  * Given a linear tranformation on initial variables, and a variable
    00061  * permutation, computes the tranformation for the permuted variables.  perm is
    00062  * a vector giving the new "position of the k^th variable, k \in [1..n] we can
    00063  * call it a "permutation vector" if you wish transf[x][y] ->
    00064  * permuted[permutation(x)][permutation(y)]
    00065  */
    00066 Matrix * mtransformation_permute(Matrix * transf, unsigned int * permutation) {
    00067   Matrix * permuted;
    00068   unsigned int i,j;
    00069   /* the transformation is supposed to be from Q^n to Q^n, so a square matrix. */
    00070   assert(transf->NbRows==transf->NbColumns);
    00071   permuted = Matrix_Alloc(transf->NbRows, transf->NbRows);
    00072   for (i= 0; i< transf->NbRows; i++) {
    00073     for (j= 0; j< transf->NbRows; j++) {
    00074       value_assign(permuted->p[permutation[i]][permutation[j]], transf->p[i][j]);
    00075     }
    00076   }
    00077   return permuted;
    00078 }
    00079
    00080
    00081 /** permutes the variables of the constraints of a polyhedron
    00082  * @param polyh the constraints of the polyhedron
    00083  * @param permutation a permutation vector
    00084 */
    00085 Matrix * mpolyhedron_permute(Matrix * polyh, unsigned int * permutation) {
    00086   unsigned int i,j;
    00087   Matrix * permuted = Matrix_Alloc(polyh->NbRows, polyh->NbColumns);
    00088   for (i= 0; i< polyh->NbRows; i++) {
    00089     value_assign(permuted->p[i][0], polyh->p[i][0]);
    00090     for (j= 1; j< polyh->NbColumns; j++) {
    00091       value_assign(permuted->p[i][permutation[j-1]+1], polyh->p[i][j]);
    00092     }
    00093   }
    00094   return permuted;
    00095 }
    00096
    00097
    00098 /** permutes the variables of the constraints of a polyhedron
    00099  * @param C the original set of constraints
    00100  * @param perm a permutation vector
    00101  * @param Cp (returned) the set of constraints whose variables are
    00102  * permuted. Allocated if set to NULL, assumed to be already allocated if not.
    00103  */
    00104 void Constraints_permute(Matrix * C, unsigned int * perm, Matrix ** Cp) {
    00105   unsigned int i,j;
    00106   if ((*Cp)==NULL) {
    00107     (*Cp) = Matrix_Alloc(C->NbRows, C->NbColumns);
    00108   }
    00109   else {
    00110     assert((*Cp)->NbRows == C->NbRows && (*Cp)->NbColumns==C->NbColumns);
    00111   }
    00112   for (i= 0; i< C->NbRows; i++) {
    00113     value_assign((*Cp)->p[i][0], C->p[i][0]);
    00114     for (j= 1; j< C->NbColumns; j++) {
    00115       value_assign((*Cp)->p[i][perm[j-1]+1], C->p[i][j]);
    00116     }
    00117   }
    00118 } /* Constraints_permute */
    00119
    00120
    00121 /** Given a set of <i>equalities</i>, find a set of variables that can be
    00122  * eliminated using these equalities.  The variables that we agree to eliminate
    00123  * are in a zone of contiguous variables (or parameters).  <p>
    00124  * Notes:
    00125  <ul>
    00126  <li>brute force, surely enhanceable algorithm</li>
    00127  <li>limited number of variables in the zone: limit = bitwidth of long long
    00128  </ul>
    00129  * @param Eqs the matrix of equalities.
    00130  * @param start the rank of the first variable (inclusive) of the zone in Eqs
    00131  * @param end the rank of the last variable (inclusive) of the zone
    00132  * return a bitfield where bits set to one define the variables to eliminate
    00133 */
    00134 unsigned long long int eliminable_vars(Matrix * Eqs, unsigned start,
    00135                                       unsigned end) {
    00136   unsigned long long int combination;
    00137   unsigned int i,j,k;
    00138   Matrix * M, * H, * Q, *U;
    00139   Matrix * Square_Mat, *Eqs2;
    00140   unsigned nb_vars = end - start + 1 ;
    00141   Polyhedron * OverConstrained;
    00142
    00143   assert (start>0 && end < Eqs->NbColumns-1);
    00144
    00145   /* if the affine hull is overconstrained, return 0 */
    00146   if (Eqs->NbRows >nb_vars) {
    00147     /* FIXME: there is a magic maximum number of rays here */
    00148     Eqs2 = Matrix_Copy(Eqs);
    00149     OverConstrained = Constraints2Polyhedron(Eqs2,
    00150                                              Eqs->NbColumns*Eqs->NbColumns);
    00151     Matrix_Free(Eqs2);
    00152     if (emptyQ(OverConstrained)) {
    00153       Polyhedron_Free(OverConstrained);
    00154       return 0;
    00155     }
    00156     Polyhedron_Free(OverConstrained);
    00157   }
    00158
    00159   /* do not accept 0 = 0 equalities */
    00160   for (i=0; i< Eqs->NbRows; i++) {
    00161     assert (!Vector_IsZero(Eqs->p[i], Eqs->NbColumns));
    00162   }
    00163
    00164   Square_Mat= Matrix_Alloc(Eqs->NbRows, Eqs->NbRows);
    00165
    00166   /* There are Eqs->NbRows variables to eliminate.
    00167      Generate all the combinations of Eqs->NbRows variables (-> bits to 1 in
    00168      the word "combination") among nb_vars WARNING : we assume here that we
    00169      have not more than 64 variables.  You may convert it to use GNU MP to
    00170      set it to an infinite number of bits
    00171   */
    00172   for (combination = ((unsigned long long int) 1<<(Eqs->NbRows))-1;
    00173        (combination < ((unsigned long long int) 1 << nb_vars)) ;
    00174        combination++) {
    00175     if (nb_bits(combination) == Eqs->NbRows) {
    00176       k=0;
    00177       /* 1- put the m colums in a square matrix */
    00178       for (j=0; j< nb_vars; j++) {
    00179         if ((combination>>j)%2) {
    00180           for (i=0; i< Eqs->NbRows; i++) {
    00181             value_assign(Square_Mat->p[i][k], Eqs->p[i][j+start]);
    00182           }
    00183           k++;
    00184         }
    00185       }
    00186       /* 2- see if the matrix is full-row-rank */
    00187       right_hermite(Square_Mat, &H, &Q, &U);
    00188       Matrix_Free(Q);
    00189       Matrix_Free(U);
    00190
    00191       /* if it is full-row-rank, we have found a set of variables that can be
    00192          eliminated. */
    00193       if ( value_notzero_p((H->p[Eqs->NbRows-1][Eqs->NbRows-1])) ) {
    00194         Matrix_Free(Square_Mat);
    00195         Matrix_Free(H);
    00196         return combination;
    00197       }
    00198       Matrix_Free(H);
    00199     }
    00200   }
    00201   Matrix_Free(Square_Mat);
    00202   return (unsigned long long int) 0;
    00203 } /* eliminable_vars */
    00204
    00205
    00206
    00207 /**
    00208  * finds a valid permutation : for a set of m equations, find m variables that
    00209  * will be put at the beginning (to be eliminated).
    00210  * Note: inherits the limited the number of variables from
    00211  * <i>eliminable_vars</i>
    00212  */
    00213 unsigned int * find_a_permutation(Matrix * Eqs, unsigned int nb_parms) {
    00214   unsigned int i, j, k;
    00215   int nb_vars = Eqs->NbColumns-nb_parms-2;
    00216   unsigned long long int combination;
    00217   unsigned int * permutation = (unsigned int *)malloc(sizeof(unsigned int) *
    00218                                                       Eqs->NbColumns-1);
    00219
    00220   /* 1- find a set of variables to eliminate */
    00221   if ((combination = eliminable_vars(Eqs, 1, nb_vars)) == 0) {
    00222     /* if it is impossible to eliminate enough variables, return error code */
    00223     return NULL;
    00224   }
    00225
    00226   /* 2- make the permutation matrix
    00227    *   a- deal with the variables */
    00228   k=0;
    00229   for (i=0; i< nb_vars; i++) {
    00230     /* if the variable has to be eliminated, put them at the beginning */
    00231     if (combination%2) {
    00232       permutation[i] = k;
    00233       k++;
    00234     }
    00235     /* if not, put the variables at the end */
    00236     else permutation[i] = Eqs->NbRows+nb_parms+ i-k;
    00237     combination>>=1;
    00238   }
    00239   /*  b- deal with the parameters */
    00240   for (i=0; i< nb_parms; i++) {
    00241     permutation[nb_vars+i] = Eqs->NbRows+i;
    00242   }
    00243   /*  c- deal with the constant */
    00244   permutation[Eqs->NbColumns-2] = Eqs->NbColumns-2;
    00245
    00246   return permutation;
    00247 } /* find_a_permutation */
    00248
    00249
    00250
    00251 /** computes the permutation of variables and parameters, according to some
    00252  * variables to keep.  put the variables not to be kept at the beginning, then
    00253  * the parameters and finally the variables to be kept.  strongly related to
    00254  * the function compress_to_full_dim2
    00255  */
    00256 unsigned int * permutation_for_full_dim2(unsigned int * vars_to_keep,
    00257                                          unsigned int nb_keep,
    00258                                          unsigned int nb_vars_parms,
    00259                                          unsigned int nb_parms) {
    00260   unsigned int * permutation =
    00261     (unsigned int*)malloc(sizeof(unsigned int) * nb_vars_parms+1);
    00262   unsigned int i;
    00263   int cur_keep =0, cur_go = 0;/*current number of variables to eliminate/keep*/
    00264   for (i=0; i< nb_vars_parms - nb_parms; i++) {
    00265     if (i==vars_to_keep[cur_keep]) {
    00266       permutation[i] = nb_vars_parms-nb_keep+cur_keep;
    00267       cur_keep++;
    00268     }
    00269     else {
    00270       permutation[i] = cur_go;
    00271       cur_go++;
    00272     }
    00273   }
    00274   /* parameters are just left-shifted */
    00275   for (i=0; i< nb_parms; i++)
    00276     permutation[i+nb_vars_parms-nb_parms] = i+nb_vars_parms-nb_parms-nb_keep;
    00277
    00278   /* contants stay where they are */
    00279   permutation[nb_vars_parms] = nb_vars_parms;
    00280   return permutation;
    00281 } /* permutation_for_full_dim2 */