polylib: SolveDio.c Source File

- Main Page
- Classes
- Files

- File List
- File Members

# SolveDio.c

Go to the documentation of this file.

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