2 #include <polylib/polylib.h>
4 static void RearrangeMatforSolveDio(Matrix
*M
);
7 * Solve Diophantine Equations :
8 * This function takes as input a system of equations in the form
9 * Ax + C = 0 and finds the solution for it, if it exists
11 * Input : The matrix form the system of the equations Ax + C = 0
12 * ( a pointer to a Matrix. )
13 * A pointer to the pointer, where the matrix U
14 * corresponding to the free variables of the equation
16 * A pointer to the pointer of a vector is a solution to T.
19 * Output : The above matrix U and the vector T.
22 * Given an integral matrix A, we can split it such that
23 * A = HU, where H is in HNF (lowr triangular)
24 * and U is unimodular.
25 * So Ax = c -> HUx = c -> Ht = c ( where Ux = t).
26 * Solving for Ht = c is easy.
27 * Using 't' we find x = U(inverse) * t.
30 * 1) For the above algorithm to work correctly to
31 * need the condition that the first 'rank' rows are
32 * the rows which contribute to the rank of the matrix.
33 * So first we copy Input into a matrix 'A' and
34 * rearrange the rows of A (if required) such that
35 * the first rank rows contribute to the rank.
36 * 2) Extract A and C from the matrix 'A'. A = n * l matrix.
37 * 3) Find the Hermite normal form of the matrix A.
38 * ( the matrices the lower tri. H and the unimod U).
39 * 4) Using H, find the values of T one by one.
40 * Here we use a sort of Gaussian elimination to find
41 * the solution. You have a lower triangular matrix
43 * [ [a11, 0], [a21, a22, 0] ...,[arank1...a rankrank 0]]
44 * and the solution vector [t1.. tn] and the vector
45 * [ c1, c2 .. cl], now as we are traversing down the
46 * rows one by one, we will have all the information
47 * needed to calculate the next 't'.
49 * That is to say, when you want to calculate t2,
50 * you would have already calculated the value of t1
51 * and similarly if you are calculating t3, you will
52 * need t1 and t2 which will be available by that time.
53 * So, we apply a sort of Gaussian Elimination inorder
54 * to find the vector T.
56 * 5) After finding t_rank, the remaining (l-rank) t's are
57 * made equal to zero, and we verify, if these values
58 * agree with the remaining (n-rank) rows of A.
60 * 6) If a solution exists, find the values of X using
64 int SolveDiophantine(Matrix
*M
, Matrix
**U
, Vector
**X
) {
66 int i
, j
, k1
, k2
, min
, rank
;
67 Matrix
*A
, *temp
, *hermi
, *unimod
, *unimodinv
;
68 Value
*C
; /* temp storage for the vector C */
69 Value
*T
; /* storage for the vector t */
74 fp
= fopen("_debug", "a");
75 fprintf(fp
,"\nEntered SOLVEDIOPHANTINE\n");
79 value_init(sum
); value_init(tmp
);
81 /* Ensuring that the first rank row of A contribute to the rank*/
83 RearrangeMatforSolveDio(A
);
84 temp
= Matrix_Alloc(A
->NbRows
-1, A
->NbColumns
-1);
86 /* Copying A into temp, ignoring the Homogeneous part */
87 for (i
= 0; i
< A
->NbRows
-1; i
++)
88 for (j
= 0; j
< A
->NbColumns
-1; j
++)
89 value_assign(temp
->p
[i
][j
],A
->p
[i
][j
]);
91 /* Copying C into a temp, ignoring the Homogeneous part */
92 C
= (Value
*) malloc (sizeof(Value
) * (A
->NbRows
-1));
95 for (i
= 0; i
< k1
; i
++) {
97 value_oppose(C
[i
],A
->p
[i
][A
->NbColumns
-1]);
101 /* Finding the HNF of temp */
102 Hermite(temp
, &hermi
, &unimod
);
104 /* Testing for existence of a Solution */
106 min
=(hermi
->NbRows
<= hermi
->NbColumns
) ? hermi
->NbRows
: hermi
->NbColumns
;
108 for (i
= 0; i
< min
; i
++) {
109 if (value_notzero_p(hermi
->p
[i
][i
]))
115 /* Solving the Equation using Gaussian Elimination*/
117 T
= (Value
*) malloc(sizeof(Value
) * temp
->NbColumns
);
118 k2
= temp
->NbColumns
;
122 for (i
= 0; i
< rank
; i
++) {
124 for (j
= 0; j
< i
; j
++) {
125 value_addmul(sum
, T
[j
], hermi
->p
[i
][j
]);
127 value_subtract(tmp
,C
[i
],sum
);
128 value_modulus(tmp
,tmp
,hermi
->p
[i
][i
]);
129 if (value_notzero_p(tmp
)) { /* no solution to the equation */
130 *U
= Matrix_Alloc(0,0);
131 *X
= Vector_Alloc (0);
132 Matrix_Free (unimod
);
135 value_clear(sum
); value_clear(tmp
);
136 for (i
= 0; i
< k1
; i
++)
138 for (i
= 0; i
< k2
; i
++)
144 value_subtract(tmp
,C
[i
],sum
);
145 value_division(T
[i
],tmp
,hermi
->p
[i
][i
]);
148 /** Case when rank < Number of Columns; **/
150 for (i
= rank
; i
< hermi
->NbColumns
; i
++)
151 value_set_si(T
[i
],0);
153 /** Solved the equtions **/
154 /** When rank < hermi->NbRows; Verifying whether the solution agrees
155 with the remaining n-rank rows as well. **/
157 for (i
= rank
; i
< hermi
->NbRows
; i
++) {
159 for (j
= 0; j
< hermi
->NbColumns
; j
++) {
160 value_addmul(sum
, T
[j
], hermi
->p
[i
][j
]);
162 if (value_ne(sum
,C
[i
])) {
163 *U
= Matrix_Alloc(0,0);
164 *X
= Vector_Alloc (0);
165 Matrix_Free (unimod
);
168 value_clear(sum
); value_clear(tmp
);
169 for (i
= 0; i
< k1
; i
++)
171 for (i
= 0; i
< k2
; i
++)
178 unimodinv
= Matrix_Alloc(unimod
->NbRows
, unimod
->NbColumns
);
179 Matrix_Inverse(unimod
, unimodinv
);
181 *X
= Vector_Alloc(M
->NbColumns
-1);
183 if (rank
== hermi
->NbColumns
)
184 *U
= Matrix_Alloc(0,0);
185 else { /* Extracting the General solution form U(inverse) */
187 *U
= Matrix_Alloc(hermi
->NbColumns
, hermi
->NbColumns
-rank
);
188 for (i
= 0; i
< U
[0]->NbRows
; i
++)
189 for (j
= 0; j
< U
[0]->NbColumns
; j
++)
190 value_assign(U
[0]->p
[i
][j
],unimodinv
->p
[i
][j
+rank
]);
193 for (i
= 0; i
< unimodinv
->NbRows
; i
++) {
195 /* Calculating the vector X = Uinv * T */
197 for (j
= 0; j
< unimodinv
->NbColumns
; j
++) {
198 value_addmul(sum
, unimodinv
->p
[i
][j
], T
[j
]);
200 value_assign(X
[0]->p
[i
],sum
);
204 for (i = rank; i < A->NbColumns; i ++)
207 Matrix_Free (unimodinv
);
210 value_clear(sum
); value_clear(tmp
);
211 for (i
= 0; i
< k1
; i
++)
213 for (i
= 0; i
< k2
; i
++)
218 } /* SolveDiophantine */
222 * This function takes as input a matrix M (pointer to it)
223 * and it returns the tranformed matrix M, such that the first
224 * 'rank' rows of the new matrix M are the ones which contribute
225 * to the rank of the matrix M.
227 * 1) For a start we try to put all the zero rows at the end.
228 * 2) Then cur = 1st row of the remaining matrix.
229 * 3) nextrow = 2ndrow of M.
230 * 4) temp = cur + nextrow
231 * 5) If (rank(temp) == temp->NbRows.) {cur = temp;nextrow ++}
232 * 6) Else (Exchange the nextrow of M with the currentlastrow.
233 * and currentlastrow --).
234 * 7) Repeat steps 4,5,6 till it is no longer possible.
237 static void RearrangeMatforSolveDio(Matrix
*M
) {
239 int i
, j
, curend
, curRow
, min
, rank
=1;
241 Matrix
*A
, *L
, *H
, *U
;
243 /* Though I could have used the Lattice function
244 Extract Linear Part, I chose not to use it so that
245 this function can be independent of Lattice Operations */
247 L
= Matrix_Alloc(M
->NbRows
-1,M
->NbColumns
-1);
248 for (i
= 0; i
< L
->NbRows
; i
++)
249 for (j
= 0; j
< L
->NbColumns
; j
++)
250 value_assign(L
->p
[i
][j
],M
->p
[i
][j
]);
252 /* Putting the zero rows at the end */
253 curend
= L
->NbRows
-1;
254 for (i
= 0; i
< curend
; i
++) {
255 for (j
= 0; j
< L
->NbColumns
; j
++)
256 if (value_notzero_p(L
->p
[i
][j
]))
258 if (j
== L
->NbColumns
) {
259 ExchangeRows(M
,i
,curend
);
264 /* Trying to put the redundant rows at the end */
266 if (curend
> 0) { /* there are some useful rows */
269 A
= Matrix_Alloc(1, L
->NbColumns
);
271 for (i
= 0; i
<L
->NbColumns
; i
++)
272 value_assign(A
->p
[0][i
],L
->p
[0][i
]);
274 while (add
== True
) {
275 temp
= AddANullRow(A
);
276 for (i
= 0;i
<A
->NbColumns
; i
++)
277 value_assign(temp
->p
[curRow
][i
],L
->p
[curRow
][i
]);
278 Hermite(temp
, &H
, &U
);
279 for (i
= 0; i
< H
->NbRows
; i
++)
280 if (value_zero_p(H
->p
[i
][i
]))
282 if (i
!= H
->NbRows
) {
283 ExchangeRows(M
, curRow
, curend
);
290 A
= Matrix_Copy (temp
);
295 min
= (curend
>= L
->NbColumns
) ? L
->NbColumns
: curend
;
296 if (rank
==min
|| curRow
>= curend
)
303 } /* RearrangeMatforSolveDio */