polylib: matrix_permutations.c Source File

- Main Page
- Classes
- Files

# matrix_permutations.c

Go to the documentation of this file.

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