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

SolveDio.c

Go to the documentation of this file.
00001 #include <stdlib.h>
00002 #include <polylib/polylib.h>
00003 
00004 static void RearrangeMatforSolveDio(Matrix *M);
00005 
00006 /*
00007  *  Solve Diophantine Equations :
00008  *        This function takes as input a system of equations in the form
00009  *          Ax + C = 0 and finds the solution for it, if it exists
00010  *       
00011  *        Input : The matrix form the system of the equations Ax + C = 0
00012  *                 ( a pointer to a Matrix. )
00013  *                 A pointer to the pointer, where the matrix U 
00014  *                  corresponding to the free variables of the equation
00015  *                  is stored.
00016  *                 A pointer to the pointer of a vector is a solution to T.
00017  *
00018  *
00019  *        Output : The above matrix U and the vector T.
00020  *
00021  *        Algorithm :
00022  *                    Given an integral matrix A, we can split it such that
00023  *                    A = HU, where H is in HNF (lowr triangular)
00024  *                      and U is unimodular.
00025  *                    So Ax = c -> HUx = c -> Ht = c ( where Ux = t).
00026  *                       Solving for Ht = c is easy.
00027  *                       Using 't' we find x = U(inverse) * t.
00028  * 
00029  *        Steps :
00030  *                   1) For the above algorithm to work correctly to
00031  *                      need the condition that the first 'rank' rows are
00032  *                      the rows which contribute to the rank of the matrix.
00033  *                      So first we copy Input into a matrix 'A' and 
00034  *                      rearrange the rows of A (if required) such that
00035  *                      the first rank rows contribute to the rank.
00036  *                   2) Extract A and C from the matrix 'A'. A = n * l matrix.
00037  *                   3) Find the Hermite normal form of the matrix A.
00038  *                       ( the matrices the lower tri. H and the unimod U).
00039  *                   4) Using H, find the values of T one by one.
00040  *                      Here we use a sort of Gaussian elimination to find
00041  *                      the solution. You have a lower triangular matrix
00042  *                      and a vector, 
00043  *                      [ [a11, 0], [a21, a22, 0] ...,[arank1...a rankrank 0]]
00044  *                       and the solution vector [t1.. tn] and the vector 
00045  *                      [ c1, c2 .. cl], now as we are traversing down the
00046  *                      rows one by one, we will have all the information 
00047  *                      needed to calculate the next 't'.
00048  *                      
00049  *                      That is to say, when you want to calculate t2, 
00050  *                      you would have already calculated the value of t1
00051  *                      and similarly if you are calculating t3, you will 
00052  *                      need t1 and t2 which will be available by that time.
00053  *                      So, we apply a sort of Gaussian Elimination inorder
00054  *                      to find the vector T.
00055  *
00056  *                   5) After finding t_rank, the remaining (l-rank) t's are
00057  *                      made equal to zero, and we verify, if these values
00058  *                      agree with the remaining (n-rank) rows of A.
00059  *
00060  *                   6) If a solution exists, find the values of X using 
00061  *                        U (inverse) * T.
00062  */
00063 
00064 int SolveDiophantine(Matrix *M, Matrix **U, Vector **X) {
00065   
00066   int i, j, k1, k2, min, rank;
00067   Matrix *A, *temp, *hermi, *unimod,  *unimodinv ;
00068   Value *C; /* temp storage for the vector C */
00069   Value *T; /* storage for the vector t */
00070   Value sum, tmp;
00071   
00072 #ifdef DOMDEBUG
00073   FILE *fp;
00074   fp = fopen("_debug", "a");
00075   fprintf(fp,"\nEntered SOLVEDIOPHANTINE\n"); 
00076   fclose(fp);
00077 #endif
00078 
00079   value_init(sum); value_init(tmp);
00080   
00081   /* Ensuring that the first rank row of A contribute to the rank*/ 
00082   A = Matrix_Copy(M);
00083   RearrangeMatforSolveDio(A);
00084   temp = Matrix_Alloc(A->NbRows-1, A->NbColumns-1);
00085   
00086   /* Copying A into temp, ignoring the Homogeneous part */ 
00087   for (i = 0; i < A->NbRows -1; i++)
00088     for (j = 0; j < A->NbColumns-1; j++)
00089       value_assign(temp->p[i][j],A->p[i][j]);
00090   
00091   /* Copying C into a temp, ignoring the Homogeneous part */ 
00092   C = (Value *) malloc (sizeof(Value) * (A->NbRows-1));
00093   k1 = A->NbRows-1;
00094   
00095   for (i = 0; i < k1; i++) {
00096     value_init(C[i]);
00097     value_oppose(C[i],A->p[i][A->NbColumns-1]);
00098   }
00099   Matrix_Free (A); 
00100   
00101   /* Finding the HNF of temp */  
00102   Hermite(temp, &hermi, &unimod);
00103   
00104   /* Testing for existence of a Solution */
00105   
00106   min=(hermi->NbRows <= hermi->NbColumns ) ? hermi->NbRows : hermi->NbColumns ;
00107   rank = 0;
00108   for (i = 0; i < min ; i++) {
00109     if (value_notzero_p(hermi->p[i][i]))
00110       rank ++;
00111     else
00112       break ;
00113   }
00114   
00115   /* Solving the Equation using Gaussian Elimination*/
00116   
00117   T = (Value *) malloc(sizeof(Value) * temp->NbColumns);
00118   k2 = temp->NbColumns;
00119   for(i=0;i< k2; i++) 
00120     value_init(T[i]);
00121 
00122   for (i = 0; i < rank ; i++) {
00123     value_set_si(sum,0);
00124     for (j = 0; j < i; j++) {
00125       value_multiply(tmp,T[j],hermi->p[i][j]);
00126       value_addto(sum,sum,tmp);
00127     } 
00128     value_substract(tmp,C[i],sum);
00129     value_modulus(tmp,tmp,hermi->p[i][i]);
00130     if (value_notzero_p(tmp)) { /* no solution to the equation */
00131       *U = Matrix_Alloc(0,0);
00132       *X = Vector_Alloc (0);
00133       value_clear(sum); value_clear(tmp);
00134       for (i = 0; i < k1; i++) 
00135         value_clear(C[i]);
00136       for (i = 0; i < k2; i++) 
00137         value_clear(T[i]);
00138       free(C);
00139       free(T);
00140       return (-1);
00141     };
00142     value_substract(tmp,C[i],sum);
00143     value_division(tmp,tmp,hermi->p[i][i]);
00144     value_assign(T[i],tmp);
00145   }
00146   
00147   /** Case when rank < Number of Columns; **/
00148   
00149   for (i = rank; i < hermi->NbColumns; i++)
00150     value_set_si(T[i],0);
00151   
00152   /** Solved the equtions **/
00153   /** When rank < hermi->NbRows; Verifying whether the solution agrees 
00154       with the remaining n-rank rows as well. **/
00155   
00156   for (i = rank; i < hermi->NbRows; i++) {
00157     value_set_si(sum,0);
00158     for (j = 0; j < hermi->NbColumns; j++) {
00159       value_multiply(tmp,T[j],hermi->p[i][j]);
00160       value_addto(sum,sum,tmp);
00161     }  
00162     if (value_ne(sum,C[i])) {
00163       *U = Matrix_Alloc(0,0);
00164       *X = Vector_Alloc (0);
00165       value_clear(sum); value_clear(tmp);
00166       for (i = 0; i < k1; i++) 
00167         value_clear(C[i]);
00168       for (i = 0; i < k2; i++) 
00169         value_clear(T[i]);
00170       free(C);
00171       free(T);
00172       return (-1);
00173     }
00174   }     
00175   unimodinv = Matrix_Alloc(unimod->NbRows, unimod->NbColumns);
00176   Matrix_Inverse(unimod, unimodinv);
00177   Matrix_Free(unimod);
00178   *X = Vector_Alloc(M->NbColumns-1);
00179   
00180   if (rank == hermi->NbColumns)
00181     *U = Matrix_Alloc(0,0);
00182   else { /* Extracting the General solution form U(inverse) */
00183     
00184     *U = Matrix_Alloc(hermi->NbColumns, hermi->NbColumns-rank);   
00185     for (i = 0; i < U[0]->NbRows; i++)
00186       for (j = 0; j < U[0]->NbColumns; j++)
00187         value_assign(U[0]->p[i][j],unimodinv->p[i][j+rank]);
00188   }
00189   
00190   for (i = 0; i < unimodinv->NbRows; i++) { 
00191     
00192     /* Calculating the vector X = Uinv * T */
00193     value_set_si(sum,0);
00194     for (j = 0; j < unimodinv->NbColumns; j++) {
00195       value_multiply(tmp,unimodinv->p[i][j],T[j]);
00196       value_addto(sum,sum,tmp);
00197     }  
00198     value_assign(X[0]->p[i],sum);
00199   }
00200   
00201   /*
00202     for (i = rank; i < A->NbColumns; i ++)
00203     X[0]->p[i] = 0;
00204   */
00205   Matrix_Free (unimodinv);
00206   Matrix_Free (hermi);
00207   Matrix_Free (temp);
00208   value_clear(sum); value_clear(tmp);
00209   for (i = 0; i < k1; i++) 
00210     value_clear(C[i]);
00211   for (i = 0; i < k2; i++) 
00212     value_clear(T[i]);
00213   free(C);
00214   free(T);
00215   return (rank);  
00216 } /* SolveDiophantine */
00217 
00218 /*
00219  * Rearrange :
00220  *            This function takes as input a matrix M (pointer to it)
00221  *            and it returns the tranformed matrix M, such that the first
00222  *            'rank' rows of the new matrix M are the ones which contribute
00223  *            to the rank of the matrix M. 
00224  *          
00225  *            1) For a start we try to put all the zero rows at the end.
00226  *            2) Then cur = 1st row of the remaining matrix.
00227  *            3) nextrow = 2ndrow of M.
00228  *            4) temp = cur + nextrow
00229  *            5) If (rank(temp) == temp->NbRows.) {cur = temp;nextrow ++}
00230  *            6) Else (Exchange the nextrow of M with the currentlastrow.
00231  *                     and currentlastrow --).
00232  *            7) Repeat steps 4,5,6 till it is no longer possible.
00233  *            
00234  */
00235 static void RearrangeMatforSolveDio(Matrix *M) {
00236   
00237   int i, j, curend, curRow, min, rank=1;
00238   Bool add = True;
00239   Matrix *A, *L, *H, *U;
00240   
00241   /* Though I could have used the Lattice function
00242         Extract Linear Part, I chose not to use it so that
00243         this function can be independent of Lattice Operations */
00244 
00245   L = Matrix_Alloc(M->NbRows-1,M->NbColumns-1);
00246   for (i = 0; i < L->NbRows; i++)
00247     for (j = 0; j < L->NbColumns; j++)
00248       value_assign(L->p[i][j],M->p[i][j]);
00249   
00250   /* Putting the zero rows at the end */
00251   curend = L->NbRows-1;
00252   for (i = 0; i < curend; i++) {
00253     for (j = 0; j < L->NbColumns; j++) 
00254       if (value_notzero_p(L->p[i][j]))
00255         break;
00256     if (j == L->NbColumns) {
00257       ExchangeRows(M,i,curend);
00258       curend --;
00259     }
00260   } 
00261   
00262   /* Trying to put the redundant rows at the end */
00263   
00264   if (curend > 0) { /* there are some useful rows */
00265     
00266     Matrix *temp;
00267     A = Matrix_Alloc(1, L->NbColumns); 
00268     
00269     for (i = 0; i <L->NbColumns; i++) 
00270       value_assign(A->p[0][i],L->p[0][i]);     
00271     curRow = 1;    
00272     while (add == True ) {
00273       temp= AddANullRow(A);
00274       for (i = 0;i <A->NbColumns; i++)
00275         value_assign(temp->p[curRow][i],L->p[curRow][i]);      
00276       Hermite(temp, &H, &U);
00277       for (i = 0; i < H->NbRows; i++)
00278         if (value_zero_p(H->p[i][i]))
00279           break;
00280       if (i != H->NbRows) {
00281         ExchangeRows(M, curRow, curend);
00282         curend --;
00283       }
00284       else {
00285         curRow ++;
00286         rank ++;
00287         Matrix_Free (A);
00288         A = Matrix_Copy (temp);
00289         Matrix_Free (temp);
00290       }      
00291       Matrix_Free (H);
00292       Matrix_Free (U);
00293       min = (curend >= L->NbColumns) ? L->NbColumns : curend ;
00294       if (rank==min || curRow >= curend)
00295         break;
00296     }
00297   }
00298   return;
00299 } /* RearrangeMatforSolveDio */

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