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

matrix.c

Go to the documentation of this file.
00001 /* matrix.c 
00002      COPYRIGHT
00003           Both this software and its documentation are
00004 
00005               Copyright 1993 by IRISA /Universite de Rennes I -
00006               France, Copyright 1995,1996 by BYU, Provo, Utah
00007                          all rights reserved.
00008 
00009           Permission is granted to copy, use, and distribute
00010           for any commercial or noncommercial purpose under the terms
00011           of the GNU General Public license, version 2, June 1991
00012           (see file : LICENSING).
00013 */
00014 
00015 #include <stdio.h>
00016 #include <stdlib.h>
00017 #include <string.h>
00018 #include <ctype.h>
00019 #include <polylib/polylib.h>
00020 
00021 #ifdef mac_os
00022   #define abs __abs
00023 #endif
00024 
00025 /* 
00026  * Allocate space for matrix dimensioned by 'NbRows X NbColumns'.
00027  */
00028 Matrix *Matrix_Alloc(unsigned NbRows,unsigned NbColumns) {
00029   
00030   Matrix *Mat;
00031   Value *p, **q;
00032   int i,j;
00033 
00034   Mat=(Matrix *)malloc(sizeof(Matrix));
00035   if(!Mat) {    
00036     errormsg1("Matrix_Alloc", "outofmem", "out of memory space");
00037     return 0;
00038   }
00039   Mat->NbRows=NbRows;
00040   Mat->NbColumns=NbColumns;
00041   if(NbRows==0) {
00042     Mat->p = (Value **)0;
00043     Mat->p_Init= (Value *)0;
00044   }  
00045   else {
00046     if(NbColumns==0) {
00047       Mat->p = (Value **)0;
00048       Mat->p_Init= (Value *)0;
00049     }
00050     else {
00051       q = (Value **)malloc(NbRows * sizeof(*q));
00052       if(!q) {
00053         free(Mat);
00054         errormsg1("Matrix_Alloc", "outofmem", "out of memory space");
00055         return 0;
00056       }
00057       p = (Value *)malloc(NbRows * NbColumns * sizeof(Value));
00058       if(!p) {
00059         free(q);
00060         free(Mat);
00061         errormsg1("Matrix_Alloc", "outofmem", "out of memory space");
00062         return 0;
00063       }
00064       Mat->p = q;
00065       Mat->p_Init = p;
00066       for (i=0;i<NbRows;i++) {
00067         *q++ = p;
00068         for (j=0;j<NbColumns;j++)   
00069           value_init(*(p+j));
00070         p += NbColumns;
00071       }
00072     }
00073   }
00074   p = NULL;
00075   q = NULL;
00076   Mat->p_Init_size = NbColumns*NbRows;
00077 
00078   return Mat;
00079 } /* Matrix_Alloc */
00080 
00081 /* 
00082  * Free the memory space occupied by Matrix 'Mat' 
00083  */
00084 void Matrix_Free(Matrix *Mat) {
00085   
00086   int i,j;
00087   Value *p;
00088 
00089   if( Mat->p )
00090   {
00091     p = *(Mat->p);
00092     for(i=0;i<Mat->p_Init_size;i++) {
00093       value_clear(*p++);
00094     }
00095   }
00096 
00097   if (Mat->p_Init)
00098     free(Mat->p_Init);
00099   if (Mat->p)
00100     free(Mat->p);
00101   free(Mat);
00102 
00103 } /* Matrix_Free */
00104 
00105 /* 
00106  * Print the contents of the Matrix 'Mat'
00107  */
00108 void Matrix_Print(FILE *Dst,char *Format,Matrix *Mat) {
00109   
00110   Value *p;
00111   int i, j;
00112   unsigned NbRows, NbColumns;
00113   
00114   fprintf(Dst,"%d %d\n", NbRows=Mat->NbRows, NbColumns=Mat->NbColumns);
00115   for (i=0;i<NbRows;i++) {
00116     p=*(Mat->p+i);
00117     for (j=0;j<NbColumns;j++) {
00118       if (!Format) {
00119         value_print(Dst," "P_VALUE_FMT" ",*p++);
00120       }
00121       else { 
00122         value_print(Dst,Format,*p++);
00123       } 
00124     }
00125     fprintf(Dst, "\n");
00126   }
00127 } /* Matrix_Print */
00128 
00129 /* 
00130  * Read the contents of the Matrix 'Mat' 
00131  */
00132 void Matrix_Read_Input(Matrix *Mat) {
00133   
00134   Value *p;
00135   int i,j,n;
00136   char *c, s[1024],str[1024];
00137   
00138   p = Mat->p_Init;
00139   for (i=0;i<Mat->NbRows;i++) {
00140     do {
00141       c = fgets(s, 1024, stdin);
00142       while(isspace(*c) && *c!='\n')
00143         ++c;
00144     } while(c && (*c =='#' || *c== '\n'));
00145     
00146     if (!c) {
00147       errormsg1( "Matrix_Read", "baddim", "not enough rows" );
00148       break;
00149     }
00150     for (j=0;j<Mat->NbColumns;j++) {
00151       if(!c || *c=='\n' || *c=='#') {
00152         errormsg1("Matrix_Read", "baddim", "not enough columns");
00153         break;
00154       }
00155       if (sscanf(c,"%s%n",str,&n) == 0) {
00156         errormsg1( "Matrix_Read", "baddim", "not enough columns" );
00157         break;
00158       }
00159       value_read(*(p++),str);
00160       c += n;
00161     }
00162   }
00163 } /* Matrix_Read_Input */
00164 
00165 /* 
00166  * Read the contents of the matrix 'Mat' from standard input. 
00167  * A '#' in the first column is a comment line 
00168  */
00169 Matrix *Matrix_Read(void) {
00170   
00171   Matrix *Mat;
00172   unsigned NbRows, NbColumns;
00173   char s[1024];
00174   
00175   while(fgets(s, 1024, stdin)==0);
00176   while ((*s=='#' || *s=='\n') ||
00177          (sscanf(s, "%d %d", &NbRows, &NbColumns)<2))
00178     fgets(s, 1024, stdin);
00179   Mat = Matrix_Alloc(NbRows,NbColumns);
00180   if(!Mat) {
00181     errormsg1("Matrix_Read", "outofmem", "out of memory space");
00182     return(NULL);
00183   }
00184   Matrix_Read_Input(Mat);
00185   return Mat;
00186 } /* Matrix_Read */
00187 
00188 /* 
00189  * Basic hermite engine 
00190  */
00191 static int hermite(Matrix *H,Matrix *U,Matrix *Q) {
00192   
00193   int nc, nr, i, j, k, rank, reduced, pivotrow;
00194   Value pivot,x,aux;
00195   Value *temp1, *temp2;
00196   
00197   /*                     T                     -1   T */
00198   /* Computes form: A = Q H  and U A = H  and U  = Q  */
00199   
00200   if (!H) { 
00201     errormsg1("Domlib", "nullH", "hermite: ? Null H");
00202     return -1;
00203   }
00204   nc = H->NbColumns;
00205   nr = H->NbRows;
00206   temp1 = (Value *) malloc(nc * sizeof(Value));
00207   temp2 = (Value *) malloc(nr * sizeof(Value));
00208   if (!temp1 ||!temp2) {
00209     errormsg1("Domlib", "outofmem", "out of memory space");
00210     return -1;
00211   }
00212   
00213   /* Initialize all the 'Value' variables */
00214   value_init(pivot); value_init(x); 
00215   value_init(aux);   
00216   for(i=0;i<nc;i++)
00217     value_init(temp1[i]);
00218   for(i=0;i<nr;i++)
00219     value_init(temp2[i]);
00220   
00221 #ifdef DEBUG
00222   fprintf(stderr,"Start  -----------\n");
00223   Matrix_Print(stderr,0,H);
00224 #endif
00225   for (k=0, rank=0; k<nc && rank<nr; k=k+1) {
00226     reduced = 1;        /* go through loop the first time */
00227 #ifdef DEBUG
00228     fprintf(stderr, "Working on col %d.  Rank=%d ----------\n", k+1, rank+1);
00229 #endif
00230     while (reduced) {
00231       reduced=0;
00232       
00233       /* 1. find pivot row */
00234       value_absolute(pivot,H->p[rank][k]);
00235       
00236       /* the kth-diagonal element */
00237       pivotrow = rank;
00238       
00239       /* find the row i>rank with smallest nonzero element in col k */
00240       for (i=rank+1; i<nr; i++) {
00241         value_absolute(x,H->p[i][k]);
00242         if (value_notzero_p(x) &&
00243             (value_lt(x,pivot) || value_zero_p(pivot))) {
00244           value_assign(pivot,x);
00245           pivotrow = i;
00246         }
00247       }
00248       
00249       /* 2. Bring pivot to diagonal (exchange rows pivotrow and rank) */
00250       if (pivotrow != rank) {
00251         Vector_Exchange(H->p[pivotrow],H->p[rank],nc);
00252         if (U)
00253           Vector_Exchange(U->p[pivotrow],U->p[rank],nr);
00254         if (Q)
00255           Vector_Exchange(Q->p[pivotrow],Q->p[rank],nr);
00256 
00257 #ifdef DEBUG
00258         fprintf(stderr,"Exchange rows %d and %d  -----------\n", rank+1, pivotrow+1);
00259         Matrix_Print(stderr,0,H);
00260 #endif
00261       }
00262       value_assign(pivot,H->p[rank][k]);        /* actual ( no abs() ) pivot */
00263       
00264       /* 3. Invert the row 'rank' if pivot is negative */
00265       if (value_neg_p(pivot)) {
00266         value_oppose(pivot,pivot); /* pivot = -pivot */
00267         for (j=0; j<nc; j++)
00268           value_oppose(H->p[rank][j],H->p[rank][j]);
00269         
00270         /* H->p[rank][j] = -(H->p[rank][j]); */
00271         if (U)
00272           for (j=0; j<nr; j++)
00273             value_oppose(U->p[rank][j],U->p[rank][j]);
00274         
00275         /* U->p[rank][j] = -(U->p[rank][j]); */
00276         if (Q)
00277           for (j=0; j<nr; j++)
00278             value_oppose(Q->p[rank][j],Q->p[rank][j]);
00279         
00280         /* Q->p[rank][j] = -(Q->p[rank][j]); */
00281 #ifdef DEBUG
00282         fprintf(stderr,"Negate row %d  -----------\n", rank+1);
00283         Matrix_Print(stderr,0,H);
00284 #endif
00285 
00286       }      
00287       if (value_notzero_p(pivot)) {
00288         
00289         /* 4. Reduce the column modulo the pivot */
00290         /*    This eventually zeros out everything below the */
00291         /*    diagonal and produces an upper triangular matrix */
00292         
00293         for (i=rank+1;i<nr;i++) {
00294           value_assign(x,H->p[i][k]);
00295           if (value_notzero_p(x)) {         
00296             value_modulus(aux,x,pivot);
00297             
00298             /* floor[integer division] (corrected for neg x) */
00299             if (value_neg_p(x) && value_notzero_p(aux)) {
00300               
00301               /* x=(x/pivot)-1; */
00302               value_division(x,x,pivot);
00303               value_decrement(x,x);
00304             }   
00305             else 
00306               value_division(x,x,pivot);
00307             for (j=0; j<nc; j++) {
00308               value_multiply(aux,x,H->p[rank][j]);
00309               value_substract(H->p[i][j],H->p[i][j],aux);
00310             }
00311             
00312             /* U->p[i][j] -= (x * U->p[rank][j]); */
00313             if (U)
00314               for (j=0; j<nr; j++) {
00315                 value_multiply(aux,x,U->p[rank][j]);
00316                 value_substract(U->p[i][j],U->p[i][j],aux);
00317               }
00318             
00319             /* Q->p[rank][j] += (x * Q->p[i][j]); */
00320             if (Q)
00321               for(j=0;j<nr;j++) {
00322                 value_multiply(aux,x,Q->p[i][j]);
00323                 value_addto(Q->p[rank][j],Q->p[rank][j],aux);
00324               }
00325             reduced = 1;
00326 
00327 #ifdef DEBUG
00328             fprintf(stderr,
00329                     "row %d = row %d - %d row %d -----------\n", i+1, i+1, x, rank+1);
00330             Matrix_Print(stderr,0,H);
00331 #endif
00332         
00333           } /* if (x) */
00334         } /* for (i) */
00335       } /* if (pivot != 0) */
00336     } /* while (reduced) */
00337     
00338     /* Last finish up this column */
00339     /* 5. Make pivot column positive (above pivot row) */
00340     /*    x should be zero for i>k */
00341     
00342     if (value_notzero_p(pivot)) {
00343       for (i=0; i<rank; i++) {
00344         value_assign(x,H->p[i][k]);
00345         if (value_notzero_p(x)) {         
00346           value_modulus(aux,x,pivot);
00347           
00348           /* floor[integer division] (corrected for neg x) */
00349           if (value_neg_p(x) && value_notzero_p(aux)) {
00350             value_division(x,x,pivot);
00351             value_decrement(x,x);
00352             
00353             /* x=(x/pivot)-1; */
00354           }
00355           else
00356             value_division(x,x,pivot);
00357           
00358           /* H->p[i][j] -= x * H->p[rank][j]; */
00359           for (j=0; j<nc; j++) {
00360             value_multiply(aux,x,H->p[rank][j]);
00361             value_substract(H->p[i][j],H->p[i][j],aux);
00362           }
00363           
00364           /* U->p[i][j] -= x * U->p[rank][j]; */
00365           if (U)
00366             for (j=0; j<nr; j++) {
00367               value_multiply(aux,x,U->p[rank][j]);
00368               value_substract(U->p[i][j],U->p[i][j],aux);
00369             }
00370           
00371           /* Q->p[rank][j] += x * Q->p[i][j]; */
00372           if (Q)
00373             for (j=0; j<nr; j++) {
00374               value_multiply(aux,x,Q->p[i][j]);
00375               value_addto(Q->p[rank][j],Q->p[rank][j],aux);
00376             }  
00377 #ifdef DEBUG
00378           fprintf(stderr,
00379                   "row %d = row %d - %d row %d -----------\n", i+1, i+1, x, rank+1);
00380           Matrix_Print(stderr,0,H);
00381 #endif
00382         } /* if (x) */
00383       } /* for (i) */
00384       rank++;
00385     } /* if (pivot!=0) */
00386   } /* for (k) */
00387   
00388   /* Clear all the 'Value' variables */
00389   value_clear(pivot); value_clear(x); 
00390   value_clear(aux); 
00391   for(i=0;i<nc;i++)
00392     value_clear(temp1[i]);
00393   for(i=0;i<nr;i++)
00394     value_clear(temp2[i]);
00395   free(temp2);
00396   free(temp1);
00397   return rank;
00398 } /* Hermite */ 
00399 
00400 void right_hermite(Matrix *A,Matrix **Hp,Matrix **Up,Matrix **Qp) {
00401   
00402   Matrix *H, *Q, *U;
00403   int i, j, nr, nc, rank;
00404   Value tmp;
00405   
00406   /* Computes form: A = QH , UA = H */  
00407   nc = A->NbColumns;
00408   nr = A->NbRows;
00409   
00410   /* H = A */
00411   *Hp = H = Matrix_Alloc(nr,nc);
00412   if (!H) { 
00413     errormsg1("DomRightHermite", "outofmem", "out of memory space");
00414     return;
00415   }
00416   
00417   /* Initialize all the 'Value' variables */
00418   value_init(tmp);
00419   
00420   Vector_Copy(A->p_Init,H->p_Init,nr*nc);
00421   
00422   /* U = I */
00423   if (Up) {
00424     *Up = U = Matrix_Alloc(nr, nr);
00425     if (!U) {
00426       errormsg1("DomRightHermite", "outofmem", "out of memory space");
00427       value_clear(tmp);
00428       return;
00429     }
00430     Vector_Set(U->p_Init,0,nr*nr);             /* zero's */
00431     for(i=0;i<nr;i++)                          /* with diagonal of 1's */
00432       value_set_si(U->p[i][i],1);
00433   }
00434   else
00435     U = (Matrix *)0;
00436   
00437   /* Q = I */
00438   /* Actually I compute Q transpose... its easier */
00439   if (Qp) {
00440     *Qp = Q = Matrix_Alloc(nr,nr);
00441     if (!Q) {
00442       errormsg1("DomRightHermite", "outofmem", "out of memory space");
00443       value_clear(tmp);
00444       return;
00445     }
00446     Vector_Set(Q->p_Init,0,nr*nr);            /* zero's */
00447     for (i=0;i<nr;i++)                      /* with diagonal of 1's */
00448       value_set_si(Q->p[i][i],1);
00449   }
00450   else
00451     Q = (Matrix *)0;
00452   
00453   rank = hermite(H,U,Q);
00454   
00455   /* Q is returned transposed */ 
00456   /* Transpose Q */
00457   if (Q) {
00458     for (i=0; i<nr; i++) {
00459       for (j=i+1; j<nr; j++) {
00460         value_assign(tmp,Q->p[i][j]);
00461         value_assign(Q->p[i][j],Q->p[j][i] );
00462         value_assign(Q->p[j][i],tmp);
00463       }
00464     }
00465   }
00466   value_clear(tmp);
00467   return;
00468 } /* right_hermite */
00469 
00470 void left_hermite(Matrix *A,Matrix **Hp,Matrix **Qp,Matrix **Up) {
00471   
00472   Matrix *H, *HT, *Q, *U;
00473   int i, j, nc, nr, rank;
00474   Value tmp;
00475   
00476   /* Computes left form: A = HQ , AU = H , 
00477      T    T T    T T   T
00478      using right form  A  = Q H  , U A = H */
00479   
00480   nr = A->NbRows;
00481   nc = A->NbColumns;
00482   
00483   /* HT = A transpose */
00484   HT = Matrix_Alloc(nc, nr);
00485   if (!HT) {
00486     errormsg1("DomLeftHermite", "outofmem", "out of memory space");
00487     return;
00488   }
00489   value_init(tmp);
00490   for (i=0; i<nr; i++)
00491     for (j=0; j<nc; j++)
00492       value_assign(HT->p[j][i],A->p[i][j]);
00493   
00494   /* U = I */
00495   if (Up) {
00496     *Up = U = Matrix_Alloc(nc,nc);
00497     if (!U) {
00498       errormsg1("DomLeftHermite", "outofmem", "out of memory space");
00499       value_clear(tmp);
00500       return;
00501     }
00502     Vector_Set(U->p_Init,0,nc*nc);            /* zero's */
00503     for (i=0;i<nc;i++)                        /* with diagonal of 1's */
00504       value_set_si(U->p[i][i],1);
00505   }
00506   else U=(Matrix *)0;
00507   
00508   /* Q = I */
00509   if (Qp) {
00510     *Qp = Q = Matrix_Alloc(nc, nc);
00511     if (!Q) {
00512       errormsg1("DomLeftHermite", "outofmem", "out of memory space");
00513       value_clear(tmp);
00514       return;
00515     }
00516     Vector_Set(Q->p_Init,0,nc*nc);            /* zero's */
00517     for (i=0;i<nc;i++)                        /* with diagonal of 1's */
00518       value_set_si(Q->p[i][i],1);
00519   }
00520   else Q=(Matrix *)0;
00521   rank = hermite(HT,U,Q);
00522   
00523   /* H = HT transpose */
00524   *Hp = H = Matrix_Alloc(nr,nc);
00525   if (!H) {
00526     errormsg1("DomLeftHermite", "outofmem", "out of memory space");
00527     value_clear(tmp);
00528     return;
00529   }
00530   for (i=0; i<nr; i++)
00531     for (j=0;j<nc;j++)
00532       value_assign(H->p[i][j],HT->p[j][i]);
00533   Matrix_Free(HT);
00534   
00535   /* Transpose U */
00536   if (U) {
00537     for (i=0; i<nc; i++) {
00538       for (j=i+1; j<nc; j++) {
00539         value_assign(tmp,U->p[i][j]);
00540         value_assign(U->p[i][j],U->p[j][i] );
00541         value_assign(U->p[j][i],tmp);
00542       }
00543     }
00544   }
00545 } /* left_hermite */
00546 
00547 /*
00548  * Given a integer matrix 'Mat'(k x k), compute its inverse rational matrix 
00549  * 'MatInv' k x (k+1). The last column of each row in matrix MatInv is used 
00550  * to store the common denominator of the entries in a row. The output is 1,
00551  * if 'Mat' is non-singular (invertible), otherwise the output is 0. Note:: 
00552  * (1) Matrix 'Mat' is modified during the inverse operation.
00553  * (2) Matrix 'MatInv' must be preallocated before passing into this function.
00554  */
00555 int MatInverse(Matrix *Mat,Matrix *MatInv ) {
00556   
00557   int i, k, j, c;
00558   Value x, gcd, piv;
00559   Value m1,m2;
00560   
00561   if(Mat->NbRows != Mat->NbColumns) {
00562    fprintf(stderr,"Trying to invert a non-square matrix !\n");
00563     return 0;
00564   }
00565   
00566   /* Initialize all the 'Value' variables */
00567   value_init(x);  value_init(gcd); value_init(piv);
00568   value_init(m1); value_init(m2);
00569 
00570   k = Mat->NbRows; 
00571 
00572   /* Initialise MatInv */
00573   Vector_Set(MatInv->p[0],0,k*(k+1));
00574 
00575   /* Initialize 'MatInv' to Identity matrix form. Each diagonal entry is set*/
00576   /* to 1. Last column of each row (denominator of each entry in a row) is  */
00577   /* also set to 1.                                                         */ 
00578   for(i=0;i<k;++i) {
00579     value_set_si(MatInv->p[i][i],1);    
00580     value_set_si(MatInv->p[i][k],1);    /* denum */
00581   }  
00582   /* Apply Gauss-Jordan elimination method on the two matrices 'Mat' and  */
00583   /* 'MatInv' in parallel.                                                */
00584   for(i=0;i<k;++i) {
00585     
00586     /* Check if the diagonal entry (new pivot) is non-zero or not */
00587     if(value_zero_p(Mat->p[i][i])) {    
00588       
00589       /* Search for a non-zero pivot down the column(i) */
00590       for(j=i;j<k;++j)      
00591         if(value_notzero_p(Mat->p[j][i]))
00592           break;
00593       
00594       /* If no non-zero pivot is found, the matrix 'Mat' is non-invertible */
00595       /* Return 0.                                                         */
00596       if(j==k) {
00597         
00598         /* Clear all the 'Value' variables */
00599         value_clear(x);  value_clear(gcd); value_clear(piv);
00600         value_clear(m1); value_clear(m2);
00601         return 0;
00602       } 
00603       
00604       /* Exchange the rows, row(i) and row(j) so that the diagonal element */
00605       /* Mat->p[i][i] (pivot) is non-zero. Repeat the same operations on    */
00606       /* matrix 'MatInv'.                                                   */
00607       for(c=0;c<k;++c) {
00608 
00609         /* Interchange rows, row(i) and row(j) of matrix 'Mat'    */
00610         value_assign(x,Mat->p[j][c]);
00611         value_assign(Mat->p[j][c],Mat->p[i][c]);
00612         value_assign(Mat->p[i][c],x);
00613         
00614         /* Interchange rows, row(i) and row(j) of matrix 'MatInv' */
00615         value_assign(x,MatInv->p[j][c]);
00616         value_assign(MatInv->p[j][c],MatInv->p[i][c]);
00617         value_assign(MatInv->p[i][c],x);
00618       }
00619     }
00620     
00621     /* Make all the entries in column(i) of matrix 'Mat' zero except the */
00622     /* diagonal entry. Repeat the same sequence of operations on matrix  */
00623     /* 'MatInv'.                                                         */
00624     for(j=0;j<k;++j) {
00625       if (j==i) continue;                /* Skip the pivot */
00626       value_assign(x,Mat->p[j][i]);
00627       if(value_notzero_p(x)) {
00628         value_assign(piv,Mat->p[i][i]);
00629         Gcd(x,piv,&gcd);
00630         if (value_notone_p(gcd) ) {
00631           value_division(x,x,gcd);
00632           value_division(piv,piv,gcd);
00633         }
00634         for(c=((j>i)?i:0);c<k;++c) {
00635           value_multiply(m1,piv,Mat->p[j][c]);
00636           value_multiply(m2,x,Mat->p[i][c]);
00637           value_substract(Mat->p[j][c],m1,m2); 
00638         }
00639         for(c=0;c<k;++c) {
00640           value_multiply(m1,piv,MatInv->p[j][c]);
00641           value_multiply(m2,x,MatInv->p[i][c]);
00642           value_substract(MatInv->p[j][c],m1,m2);
00643         }
00644               
00645         /* Simplify row(j) of the two matrices 'Mat' and 'MatInv' by */
00646         /* dividing the rows with the common GCD.                     */
00647         Vector_Gcd(&MatInv->p[j][0],k,&m1);
00648         Vector_Gcd(&Mat->p[j][0],k,&m2);
00649         Gcd(m1,m2,&gcd);
00650         if(value_notone_p(gcd)) {
00651           for(c=0;c<k;++c) {
00652             value_division(Mat->p[j][c],Mat->p[j][c],gcd);
00653             value_division(MatInv->p[j][c],MatInv->p[j][c],gcd);
00654           }
00655         }
00656       }
00657     }
00658   }
00659   
00660   /* Simplify every row so that 'Mat' reduces to Identity matrix. Perform  */
00661   /* the same sequence of operations on the matrix 'MatInv'.               */
00662   for(j=0;j<k;++j) {
00663     value_assign(MatInv->p[j][k],Mat->p[j][j]);
00664     
00665     /* Make the last column (denominator of each entry) of every row greater */
00666     /* than zero.                                                            */
00667     Vector_Normalize_Positive(&MatInv->p[j][0],k+1,k); 
00668   }
00669   
00670   /* Clear all the 'Value' variables */
00671   value_clear(x);  value_clear(gcd); value_clear(piv);
00672   value_clear(m1); value_clear(m2);
00673 
00674   return 1;
00675 } /* Mat_Inverse */
00676 
00677 /*
00678  * Given (m x n) integer matrix 'X' and n x (k+1) rational matrix 'P', compute
00679  * the rational m x (k+1) rational matrix  'S'. The last column in each row of
00680  * the rational matrices is used to store the common denominator of elements
00681  * in a row.                              
00682  */
00683 void rat_prodmat(Matrix *S,Matrix *X,Matrix *P) {
00684   
00685   int i,j,k;
00686   int last_column_index = P->NbColumns - 1;
00687   Value lcm, old_lcm,gcd,last_column_entry,s1,s2;
00688   Value m1,m2;
00689   
00690   /* Initialize all the 'Value' variables */
00691   value_init(lcm); value_init(old_lcm); value_init(gcd);
00692   value_init(last_column_entry); value_init(s1); value_init(s2);
00693   value_init(m1); value_init(m2);
00694 
00695   /* Compute the LCM of last column entries (denominators) of rows */
00696   value_assign(lcm,P->p[0][last_column_index]); 
00697   for(k=1;k<P->NbRows;++k) {
00698     value_assign(old_lcm,lcm);
00699     value_assign(last_column_entry,P->p[k][last_column_index]);
00700     Gcd(lcm,last_column_entry,&gcd);
00701     value_division(m1,last_column_entry,gcd);
00702     value_multiply(lcm,lcm,m1);
00703   }
00704   
00705   /* S[i][j] = Sum(X[i][k] * P[k][j] where Sum is extended over k = 1..nbrows*/
00706   for(i=0;i<X->NbRows;++i)
00707     for(j=0;j<P->NbColumns-1;++j) {
00708       
00709       /* Initialize s1 to zero. */
00710       value_set_si(s1,0);
00711       for(k=0;k<P->NbRows;++k) {
00712         
00713         /* If the LCM of last column entries is one, simply add the products */
00714         if(value_one_p(lcm)) {
00715           value_set_si(s2,0);
00716           value_multiply(s2,X->p[i][k],P->p[k][j]);
00717           value_addto(s1,s1,s2);
00718         }  
00719         
00720         /* Numerator (num) and denominator (denom) of S[i][j] is given by :- */
00721         /* numerator  = Sum(X[i][k]*P[k][j]*lcm/P[k][last_column_index]) and */
00722         /* denominator= lcm where Sum is extended over k = 1..nbrows.        */
00723         else {
00724           value_multiply(m1,X->p[i][k],P->p[k][j]);
00725           value_division(m2,lcm,P->p[k][last_column_index]);
00726           value_multiply(s2,m1,m2);
00727           value_addto(s1,s1,s2);
00728         }
00729       } 
00730       value_assign(S->p[i][j],s1);
00731     }
00732   
00733   for(i=0;i<S->NbRows;++i) {
00734     value_assign(S->p[i][last_column_index],lcm);
00735 
00736     /* Normalize the rows so that last element >=0 */
00737     Vector_Normalize_Positive(&S->p[i][0],S->NbColumns,S->NbColumns-1);
00738   }
00739   
00740   /* Clear all the 'Value' variables */
00741   value_clear(lcm); value_clear(old_lcm); value_clear(gcd);
00742   value_clear(last_column_entry); value_clear(s1); value_clear(s2);
00743   value_clear(m1); value_clear(m2);
00744  
00745   return;
00746 } /* rat_prodmat */
00747 
00748 /*
00749  * Given a matrix 'Mat' and vector 'p1', compute the matrix-vector product 
00750  * and store the result in vector 'p2'. 
00751  */
00752 void Matrix_Vector_Product(Matrix *Mat,Value *p1,Value *p2) {
00753 
00754   int NbRows, NbColumns, i, j;
00755   Value **cm, *q, *cp1, *cp2;
00756   Value s;
00757   
00758   value_init(s);
00759   NbRows=Mat->NbRows;
00760   NbColumns=Mat->NbColumns;
00761   
00762   cm = Mat->p;
00763   cp2 = p2;
00764   for(i=0;i<NbRows;i++) {
00765     q = *cm++;
00766     cp1 = p1;
00767     value_multiply(*cp2,*q,*cp1);
00768     q++;
00769     cp1++;
00770     
00771     /* *cp2 = *q++ * *cp1++ */
00772     for(j=1;j<NbColumns;j++) {
00773       
00774       value_set_si(s,0);
00775       value_multiply(s,*q, *cp1);
00776       value_addto(*cp2,*cp2,s);
00777       q++;
00778       cp1++;
00779     }
00780     cp2++;
00781   }
00782   value_clear(s);
00783   return;
00784 } /* Matrix_Vector_Product */
00785 
00786 /*
00787  * Given a vector 'p1' and a matrix 'Mat', compute the vector-matrix product 
00788  * and store the result in vector 'p2'
00789  */
00790 void Vector_Matrix_Product(Value *p1,Matrix *Mat,Value *p2) {
00791   
00792   int NbRows, NbColumns, i, j;
00793   Value **cm, *cp1, *cp2;
00794   Value s;
00795   
00796   value_init(s);
00797   NbRows=Mat->NbRows;
00798   NbColumns=Mat->NbColumns;
00799   cp2 = p2;
00800   cm  = Mat->p;
00801   for (j=0;j<NbColumns;j++) {
00802     cp1 = p1;
00803     value_multiply(*cp2,*(*cm+j),*cp1);
00804     cp1++;
00805     
00806     /* *cp2= *(*cm+j) * *cp1++; */
00807     for (i=1;i<NbRows;i++) {
00808       
00809       value_set_si(s,0);
00810       value_multiply(s,*(*(cm+i)+j),*cp1);
00811       value_addto(*cp2,*cp2,s);
00812       cp1++;
00813     }
00814     cp2++;
00815   }
00816   value_clear(s);
00817   return;
00818 } /* Vector_Matrix_Product */
00819 
00820 /* 
00821  * Given matrices 'Mat1' and 'Mat2', compute the matrix product and store in 
00822  * matrix 'Mat3' 
00823  */
00824 void Matrix_Product(Matrix *Mat1,Matrix *Mat2,Matrix *Mat3) {
00825   
00826   int Size, i, j, k;
00827   unsigned NbRows, NbColumns;
00828   Value **q1, **q2, *p1, *p3,sum,s;
00829   
00830   NbRows    = Mat1->NbRows;
00831   NbColumns = Mat2->NbColumns;
00832   
00833   Size      = Mat1->NbColumns;
00834   if(Mat2->NbRows!=Size||Mat3->NbRows!=NbRows||Mat3->NbColumns!=NbColumns) {
00835     fprintf(stderr, "? Matrix_Product : incompatable matrix dimension\n");
00836     return;
00837   }     
00838   value_init(sum); value_init(s);
00839   p3 = Mat3->p_Init;
00840   q1 = Mat1->p;
00841   q2 = Mat2->p;
00842   
00843   /* Mat3[i][j] = Sum(Mat1[i][k]*Mat2[k][j] where sum is over k = 1..nbrows */
00844   for (i=0;i<NbRows;i++) {
00845     for (j=0;j<NbColumns;j++) {
00846       p1 = *(q1+i);
00847       value_set_si(sum,0);
00848       for (k=0;k<Size;k++) {
00849         
00850         /* sum+=*p1++ * *(*(q2+k)+j); */
00851         value_set_si(s,0);
00852         value_multiply(s,*p1, *(*(q2+k)+j));
00853         value_addto(sum,sum,s);
00854         p1++;
00855       }
00856       value_assign(*p3,sum);
00857       p3++;
00858     }
00859   }
00860   value_clear(sum); value_clear(s);
00861   return;
00862 } /* Matrix_Product */
00863   
00864 /*
00865  * Given a rational matrix 'Mat'(k x k), compute its inverse rational matrix 
00866  * 'MatInv' k x k.
00867  * The output is 1,
00868  * if 'Mat' is non-singular (invertible), otherwise the output is 0. Note:: 
00869  * (1) Matrix 'Mat' is modified during the inverse operation.
00870  * (2) Matrix 'MatInv' must be preallocated before passing into this function.
00871  */
00872 int Matrix_Inverse(Matrix *Mat,Matrix *MatInv ) {
00873   
00874   int i, k, j, c;
00875   Value x, gcd, piv;
00876   Value m1,m2;
00877   Value *den;
00878   
00879   if(Mat->NbRows != Mat->NbColumns) {
00880    fprintf(stderr,"Trying to invert a non-square matrix !\n");
00881     return 0;
00882   }
00883   
00884   /* Initialize all the 'Value' variables */
00885   value_init(x);  value_init(gcd); value_init(piv);
00886   value_init(m1); value_init(m2);
00887 
00888   k = Mat->NbRows; 
00889 
00890   /* Initialise MatInv */
00891   Vector_Set(MatInv->p[0],0,k*k);
00892 
00893   /* Initialize 'MatInv' to Identity matrix form. Each diagonal entry is set*/
00894   /* to 1. Last column of each row (denominator of each entry in a row) is  */
00895   /* also set to 1.                                                         */ 
00896   for(i=0;i<k;++i) {
00897     value_set_si(MatInv->p[i][i],1);    
00898     // value_set_si(MatInv->p[i][k],1); /* denum */
00899   }  
00900   /* Apply Gauss-Jordan elimination method on the two matrices 'Mat' and  */
00901   /* 'MatInv' in parallel.                                                */
00902   for(i=0;i<k;++i) {
00903     
00904     /* Check if the diagonal entry (new pivot) is non-zero or not */
00905     if(value_zero_p(Mat->p[i][i])) {    
00906       
00907       /* Search for a non-zero pivot down the column(i) */
00908       for(j=i;j<k;++j)      
00909         if(value_notzero_p(Mat->p[j][i]))
00910           break;
00911       
00912       /* If no non-zero pivot is found, the matrix 'Mat' is non-invertible */
00913       /* Return 0.                                                         */
00914       if(j==k) {
00915         
00916         /* Clear all the 'Value' variables */
00917         value_clear(x);  value_clear(gcd); value_clear(piv);
00918         value_clear(m1); value_clear(m2);
00919         return 0;
00920       } 
00921       
00922       /* Exchange the rows, row(i) and row(j) so that the diagonal element */
00923       /* Mat->p[i][i] (pivot) is non-zero. Repeat the same operations on    */
00924       /* matrix 'MatInv'.                                                   */
00925       for(c=0;c<k;++c) {
00926 
00927         /* Interchange rows, row(i) and row(j) of matrix 'Mat'    */
00928         value_assign(x,Mat->p[j][c]);
00929         value_assign(Mat->p[j][c],Mat->p[i][c]);
00930         value_assign(Mat->p[i][c],x);
00931         
00932         /* Interchange rows, row(i) and row(j) of matrix 'MatInv' */
00933         value_assign(x,MatInv->p[j][c]);
00934         value_assign(MatInv->p[j][c],MatInv->p[i][c]);
00935         value_assign(MatInv->p[i][c],x);
00936       }
00937     }
00938     
00939     /* Make all the entries in column(i) of matrix 'Mat' zero except the */
00940     /* diagonal entry. Repeat the same sequence of operations on matrix  */
00941     /* 'MatInv'.                                                         */
00942     for(j=0;j<k;++j) {
00943       if (j==i) continue;                /* Skip the pivot */
00944       value_assign(x,Mat->p[j][i]);
00945       if(value_notzero_p(x)) {
00946         value_assign(piv,Mat->p[i][i]);
00947         Gcd(x,piv,&gcd);
00948         if (value_notone_p(gcd) ) {
00949           value_division(x,x,gcd);
00950           value_division(piv,piv,gcd);
00951         }
00952         for(c=((j>i)?i:0);c<k;++c) {
00953           value_multiply(m1,piv,Mat->p[j][c]);
00954           value_multiply(m2,x,Mat->p[i][c]);
00955           value_substract(Mat->p[j][c],m1,m2); 
00956         }
00957         for(c=0;c<k;++c) {
00958           value_multiply(m1,piv,MatInv->p[j][c]);
00959           value_multiply(m2,x,MatInv->p[i][c]);
00960           value_substract(MatInv->p[j][c],m1,m2);
00961         }
00962               
00963         /* Simplify row(j) of the two matrices 'Mat' and 'MatInv' by */
00964         /* dividing the rows with the common GCD.                     */
00965         Vector_Gcd(&MatInv->p[j][0],k,&m1);
00966         Vector_Gcd(&Mat->p[j][0],k,&m2);
00967         Gcd(m1,m2,&gcd);
00968         if(value_notone_p(gcd)) {
00969           for(c=0;c<k;++c) {
00970             value_division(Mat->p[j][c],Mat->p[j][c],gcd);
00971             value_division(MatInv->p[j][c],MatInv->p[j][c],gcd);
00972           }
00973         }
00974       }
00975     }
00976   }
00977   
00978   /* Find common denom for each row */ 
00979    den = (Value *)malloc(k*sizeof(Value));
00980    value_set_si(x,1);
00981    for(j=0 ; j<k ; ++j) {
00982      value_init(den[j]);
00983      value_assign(den[j],Mat->p[j][j]);
00984      
00985      /* gcd is always positive */
00986      Vector_Gcd(&MatInv->p[j][0],k,&gcd);
00987      Gcd(gcd,den[j],&gcd);
00988      if (value_neg_p(den[j])) 
00989        value_oppose(gcd,gcd); /* make denominator positive */
00990      if (value_notone_p(gcd)) {
00991        for (c=0; c<k; c++) 
00992          value_division(MatInv->p[j][c],MatInv->p[j][c],gcd); /* normalize */
00993        value_division(den[j],den[j],gcd);
00994      }  
00995      Gcd(x,den[j],&gcd);
00996      value_division(m1,den[j],gcd);
00997      value_multiply(x,x,m1);
00998    }
00999    if (value_notone_p(x)) 
01000      for(j=0 ; j<k ; ++j) {       
01001        for (c=0; c<k; c++) {
01002          value_division(m1,x,den[j]);
01003          value_multiply(MatInv->p[j][c],MatInv->p[j][c],m1);  /* normalize */
01004        }
01005      }
01006 
01007    /* Clear all the 'Value' variables */
01008    for(j=0 ; j<k ; ++j) {
01009      value_clear(den[j]);
01010    }  
01011    value_clear(x);  value_clear(gcd); value_clear(piv);
01012    value_clear(m1); value_clear(m2);
01013    free(den);
01014    
01015    return 1;
01016 } /* Matrix_Inverse */
01017 
01018 
01019 
01020 
01021 
01022 
01023 
01024 

Generated on Mon Sep 12 14:48:29 2005 for polylib by doxygen 1.3.5