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

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