polylib: SolveDio.c Source File

- Main Page
- Classes
- Files

# 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_addmul(sum, T[j], hermi->p[i][j]);
    00126     }
    00127     value_subtract(tmp,C[i],sum);
    00128     value_modulus(tmp,tmp,hermi->p[i][i]);
    00129     if (value_notzero_p(tmp)) { /* no solution to the equation */
    00130       *U = Matrix_Alloc(0,0);
    00131       *X = Vector_Alloc (0);
    00132       value_clear(sum); value_clear(tmp);
    00133       for (i = 0; i < k1; i++)
    00134         value_clear(C[i]);
    00135       for (i = 0; i < k2; i++)
    00136         value_clear(T[i]);
    00137       free(C);
    00138       free(T);
    00139       return (-1);
    00140     };
    00141     value_subtract(tmp,C[i],sum);
    00142     value_division(T[i],tmp,hermi->p[i][i]);
    00143   }
    00144
    00145   /** Case when rank < Number of Columns; **/
    00146
    00147   for (i = rank; i < hermi->NbColumns; i++)
    00148     value_set_si(T[i],0);
    00149
    00150   /** Solved the equtions **/
    00151   /** When rank < hermi->NbRows; Verifying whether the solution agrees
    00152       with the remaining n-rank rows as well. **/
    00153
    00154   for (i = rank; i < hermi->NbRows; i++) {
    00155     value_set_si(sum,0);
    00156     for (j = 0; j < hermi->NbColumns; j++) {
    00157       value_addmul(sum, T[j], hermi->p[i][j]);
    00158     }
    00159     if (value_ne(sum,C[i])) {
    00160       *U = Matrix_Alloc(0,0);
    00161       *X = Vector_Alloc (0);
    00162       value_clear(sum); value_clear(tmp);
    00163       for (i = 0; i < k1; i++)
    00164         value_clear(C[i]);
    00165       for (i = 0; i < k2; i++)
    00166         value_clear(T[i]);
    00167       free(C);
    00168       free(T);
    00169       return (-1);
    00170     }
    00171   }
    00172   unimodinv = Matrix_Alloc(unimod->NbRows, unimod->NbColumns);
    00173   Matrix_Inverse(unimod, unimodinv);
    00174   Matrix_Free(unimod);
    00175   *X = Vector_Alloc(M->NbColumns-1);
    00176
    00177   if (rank == hermi->NbColumns)
    00178     *U = Matrix_Alloc(0,0);
    00179   else { /* Extracting the General solution form U(inverse) */
    00180
    00181     *U = Matrix_Alloc(hermi->NbColumns, hermi->NbColumns-rank);
    00182     for (i = 0; i < U[0]->NbRows; i++)
    00183       for (j = 0; j < U[0]->NbColumns; j++)
    00184         value_assign(U[0]->p[i][j],unimodinv->p[i][j+rank]);
    00185   }
    00186
    00187   for (i = 0; i < unimodinv->NbRows; i++) {
    00188
    00189     /* Calculating the vector X = Uinv * T */
    00190     value_set_si(sum,0);
    00191     for (j = 0; j < unimodinv->NbColumns; j++) {
    00192       value_addmul(sum, unimodinv->p[i][j], T[j]);
    00193     }
    00194     value_assign(X[0]->p[i],sum);
    00195   }
    00196
    00197   /*
    00198     for (i = rank; i < A->NbColumns; i ++)
    00199     X[0]->p[i] = 0;
    00200   */
    00201   Matrix_Free (unimodinv);
    00202   Matrix_Free (hermi);
    00203   Matrix_Free (temp);
    00204   value_clear(sum); value_clear(tmp);
    00205   for (i = 0; i < k1; i++)
    00206     value_clear(C[i]);
    00207   for (i = 0; i < k2; i++)
    00208     value_clear(T[i]);
    00209   free(C);
    00210   free(T);
    00211   return (rank);
    00212 } /* SolveDiophantine */
    00213
    00214 /*
    00215  * Rearrange :
    00216  *            This function takes as input a matrix M (pointer to it)
    00217  *            and it returns the tranformed matrix M, such that the first
    00218  *            'rank' rows of the new matrix M are the ones which contribute
    00219  *            to the rank of the matrix M.
    00220  *
    00221  *            1) For a start we try to put all the zero rows at the end.
    00222  *            2) Then cur = 1st row of the remaining matrix.
    00223  *            3) nextrow = 2ndrow of M.
    00224  *            4) temp = cur + nextrow
    00225  *            5) If (rank(temp) == temp->NbRows.) {cur = temp;nextrow ++}
    00226  *            6) Else (Exchange the nextrow of M with the currentlastrow.
    00227  *                     and currentlastrow --).
    00228  *            7) Repeat steps 4,5,6 till it is no longer possible.
    00229  *
    00230  */
    00231 static void RearrangeMatforSolveDio(Matrix *M) {
    00232
    00233   int i, j, curend, curRow, min, rank=1;
    00234   Bool add = True;
    00235   Matrix *A, *L, *H, *U;
    00236
    00237   /* Though I could have used the Lattice function
    00238         Extract Linear Part, I chose not to use it so that
    00239         this function can be independent of Lattice Operations */
    00240
    00241   L = Matrix_Alloc(M->NbRows-1,M->NbColumns-1);
    00242   for (i = 0; i < L->NbRows; i++)
    00243     for (j = 0; j < L->NbColumns; j++)
    00244       value_assign(L->p[i][j],M->p[i][j]);
    00245
    00246   /* Putting the zero rows at the end */
    00247   curend = L->NbRows-1;
    00248   for (i = 0; i < curend; i++) {
    00249     for (j = 0; j < L->NbColumns; j++)
    00250       if (value_notzero_p(L->p[i][j]))
    00251         break;
    00252     if (j == L->NbColumns) {
    00253       ExchangeRows(M,i,curend);
    00254       curend --;
    00255     }
    00256   }
    00257
    00258   /* Trying to put the redundant rows at the end */
    00259
    00260   if (curend > 0) { /* there are some useful rows */
    00261
    00262     Matrix *temp;
    00263     A = Matrix_Alloc(1, L->NbColumns);
    00264
    00265     for (i = 0; i <L->NbColumns; i++)
    00266       value_assign(A->p[0][i],L->p[0][i]);
    00267     curRow = 1;
    00268     while (add == True ) {
    00269       temp= AddANullRow(A);
    00270       for (i = 0;i <A->NbColumns; i++)
    00271         value_assign(temp->p[curRow][i],L->p[curRow][i]);
    00272       Hermite(temp, &H, &U);
    00273       for (i = 0; i < H->NbRows; i++)
    00274         if (value_zero_p(H->p[i][i]))
    00275           break;
    00276       if (i != H->NbRows) {
    00277         ExchangeRows(M, curRow, curend);
    00278         curend --;
    00279       }
    00280       else {
    00281         curRow ++;
    00282         rank ++;
    00283         Matrix_Free (A);
    00284         A = Matrix_Copy (temp);
    00285         Matrix_Free (temp);
    00286       }
    00287       Matrix_Free (H);
    00288       Matrix_Free (U);
    00289       min = (curend >= L->NbColumns) ? L->NbColumns : curend ;
    00290       if (rank==min || curRow >= curend)
    00291         break;
    00292     }
    00293     Matrix_Free (A);
    00294   }
    00295   Matrix_Free (L);
    00296   return;
    00297 } /* RearrangeMatforSolveDio */