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

Generated on Mon Sep 12 15:15:11 2005 for polylib by doxygen 1.3.5