polylib 5.22.8
SolveDio.c
Go to the documentation of this file.
1#include <polylib/polylib.h>
2#include <stdlib.h>
3
4static void RearrangeMatforSolveDio(Matrix *M);
5
6/*
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
10 *
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
15 * is stored.
16 * A pointer to the pointer of a vector is a solution to T.
17 *
18 *
19 * Output : The above matrix U and the vector T.
20 *
21 * Algorithm :
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.
28 *
29 * Steps :
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
42 * and a vector,
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'.
48 *
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.
55 *
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.
59 *
60 * 6) If a solution exists, find the values of X using
61 * U (inverse) * T.
62 */
63
65
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 */
70 Value sum, tmp;
71
72#ifdef DOMDEBUG
73 FILE *fp;
74 fp = fopen("_debug", "a");
75 fprintf(fp, "\nEntered SOLVEDIOPHANTINE\n");
76 fclose(fp);
77#endif
78
79 value_init(sum);
80 value_init(tmp);
81
82 /* Ensuring that the first rank row of A contribute to the rank*/
83 A = Matrix_Copy(M);
85 temp = Matrix_Alloc(A->NbRows - 1, A->NbColumns - 1);
86
87 /* Copying A into temp, ignoring the Homogeneous part */
88 for (i = 0; i < A->NbRows - 1; i++)
89 for (j = 0; j < A->NbColumns - 1; j++)
90 value_assign(temp->p[i][j], A->p[i][j]);
91
92 /* Copying C into a temp, ignoring the Homogeneous part */
93 C = (Value *)malloc(sizeof(Value) * (A->NbRows - 1));
94 k1 = A->NbRows - 1;
95
96 for (i = 0; i < k1; i++) {
97 value_init(C[i]);
98 value_oppose(C[i], A->p[i][A->NbColumns - 1]);
99 }
100 Matrix_Free(A);
101
102 /* Finding the HNF of temp */
103 Hermite(temp, &hermi, &unimod);
104
105 /* Testing for existence of a Solution */
106
107 min = (hermi->NbRows <= hermi->NbColumns) ? hermi->NbRows : hermi->NbColumns;
108 rank = 0;
109 for (i = 0; i < min; i++) {
110 if (value_notzero_p(hermi->p[i][i]))
111 rank++;
112 else
113 break;
114 }
115
116 /* Solving the Equation using Gaussian Elimination*/
117
118 T = (Value *)malloc(sizeof(Value) * temp->NbColumns);
119 k2 = temp->NbColumns;
120 for (i = 0; i < k2; i++)
121 value_init(T[i]);
122
123 for (i = 0; i < rank; i++) {
124 value_set_si(sum, 0);
125 for (j = 0; j < i; j++) {
126 value_addmul(sum, T[j], hermi->p[i][j]);
127 }
128 value_subtract(tmp, C[i], sum);
129 value_modulus(tmp, tmp, hermi->p[i][i]);
130 if (value_notzero_p(tmp)) { /* no solution to the equation */
131 *U = Matrix_Alloc(0, 0);
132 *X = Vector_Alloc(0);
133 Matrix_Free(unimod);
134 Matrix_Free(hermi);
135 Matrix_Free(temp);
136 value_clear(sum);
137 value_clear(tmp);
138 for (i = 0; i < k1; i++)
139 value_clear(C[i]);
140 for (i = 0; i < k2; i++)
141 value_clear(T[i]);
142 free(C);
143 free(T);
144 return (-1);
145 };
146 value_subtract(tmp, C[i], sum);
147 value_division(T[i], tmp, hermi->p[i][i]);
148 }
149
150 /** Case when rank < Number of Columns; **/
151
152 for (i = rank; i < hermi->NbColumns; i++)
153 value_set_si(T[i], 0);
154
155 /** Solved the equtions **/
156 /** When rank < hermi->NbRows; Verifying whether the solution agrees
157 with the remaining n-rank rows as well. **/
158
159 for (i = rank; i < hermi->NbRows; i++) {
160 value_set_si(sum, 0);
161 for (j = 0; j < hermi->NbColumns; j++) {
162 value_addmul(sum, T[j], hermi->p[i][j]);
163 }
164 if (value_ne(sum, C[i])) {
165 *U = Matrix_Alloc(0, 0);
166 *X = Vector_Alloc(0);
167 Matrix_Free(unimod);
168 Matrix_Free(hermi);
169 Matrix_Free(temp);
170 value_clear(sum);
171 value_clear(tmp);
172 for (i = 0; i < k1; i++)
173 value_clear(C[i]);
174 for (i = 0; i < k2; i++)
175 value_clear(T[i]);
176 free(C);
177 free(T);
178 return (-1);
179 }
180 }
181 unimodinv = Matrix_Alloc(unimod->NbRows, unimod->NbColumns);
182 Matrix_Inverse(unimod, unimodinv);
183 Matrix_Free(unimod);
184 *X = Vector_Alloc(M->NbColumns - 1);
185
186 if (rank == hermi->NbColumns)
187 *U = Matrix_Alloc(0, 0);
188 else { /* Extracting the General solution form U(inverse) */
189
190 *U = Matrix_Alloc(hermi->NbColumns, hermi->NbColumns - rank);
191 for (i = 0; i < U[0]->NbRows; i++)
192 for (j = 0; j < U[0]->NbColumns; j++)
193 value_assign(U[0]->p[i][j], unimodinv->p[i][j + rank]);
194 }
195
196 for (i = 0; i < unimodinv->NbRows; i++) {
197
198 /* Calculating the vector X = Uinv * T */
199 value_set_si(sum, 0);
200 for (j = 0; j < unimodinv->NbColumns; j++) {
201 value_addmul(sum, unimodinv->p[i][j], T[j]);
202 }
203 value_assign(X[0]->p[i], sum);
204 }
205
206 /*
207 for (i = rank; i < A->NbColumns; i ++)
208 X[0]->p[i] = 0;
209 */
210 Matrix_Free(unimodinv);
211 Matrix_Free(hermi);
212 Matrix_Free(temp);
213 value_clear(sum);
214 value_clear(tmp);
215 for (i = 0; i < k1; i++)
216 value_clear(C[i]);
217 for (i = 0; i < k2; i++)
218 value_clear(T[i]);
219 free(C);
220 free(T);
221 return (rank);
222} /* SolveDiophantine */
223
224/*
225 * Rearrange :
226 * This function takes as input a matrix M (pointer to it)
227 * and it returns the tranformed matrix M, such that the first
228 * 'rank' rows of the new matrix M are the ones which contribute
229 * to the rank of the matrix M.
230 *
231 * 1) For a start we try to put all the zero rows at the end.
232 * 2) Then cur = 1st row of the remaining matrix.
233 * 3) nextrow = 2ndrow of M.
234 * 4) temp = cur + nextrow
235 * 5) If (rank(temp) == temp->NbRows.) {cur = temp;nextrow ++}
236 * 6) Else (Exchange the nextrow of M with the currentlastrow.
237 * and currentlastrow --).
238 * 7) Repeat steps 4,5,6 till it is no longer possible.
239 *
240 */
242
243 int i, j, curend, curRow, min, rank = 1;
244 Bool add = True;
245 Matrix *A, *L, *H, *U;
246
247 /* Though I could have used the Lattice function
248 Extract Linear Part, I chose not to use it so that
249 this function can be independent of Lattice Operations */
250
251 L = Matrix_Alloc(M->NbRows - 1, M->NbColumns - 1);
252 for (i = 0; i < L->NbRows; i++)
253 for (j = 0; j < L->NbColumns; j++)
254 value_assign(L->p[i][j], M->p[i][j]);
255
256 /* Putting the zero rows at the end */
257 curend = L->NbRows - 1;
258 for (i = 0; i < curend; i++) {
259 for (j = 0; j < L->NbColumns; j++)
260 if (value_notzero_p(L->p[i][j]))
261 break;
262 if (j == L->NbColumns) {
263 ExchangeRows(M, i, curend);
264 curend--;
265 }
266 }
267
268 /* Trying to put the redundant rows at the end */
269
270 if (curend > 0) { /* there are some useful rows */
271
272 Matrix *temp;
273 A = Matrix_Alloc(1, L->NbColumns);
274
275 for (i = 0; i < L->NbColumns; i++)
276 value_assign(A->p[0][i], L->p[0][i]);
277 curRow = 1;
278 while (add == True) {
279 temp = AddANullRow(A);
280 for (i = 0; i < A->NbColumns; i++)
281 value_assign(temp->p[curRow][i], L->p[curRow][i]);
282 Hermite(temp, &H, &U);
283 for (i = 0; i < H->NbRows; i++)
284 if (value_zero_p(H->p[i][i]))
285 break;
286 if (i != H->NbRows) {
287 ExchangeRows(M, curRow, curend);
288 curend--;
289 } else {
290 curRow++;
291 rank++;
292 Matrix_Free(A);
293 A = Matrix_Copy(temp);
294 Matrix_Free(temp);
295 }
296 Matrix_Free(H);
297 Matrix_Free(U);
298 min = (curend >= L->NbColumns) ? L->NbColumns : curend;
299 if (rank == min || curRow >= curend)
300 break;
301 }
302 Matrix_Free(A);
303 }
304 Matrix_Free(L);
305 return;
306} /* RearrangeMatforSolveDio */
Matrix * AddANullRow(Matrix *M)
Definition: Matop.c:250
void ExchangeRows(Matrix *M, int Row1, int Row2)
Definition: Matop.c:52
Matrix * Matrix_Copy(Matrix const *Src)
Definition: Matop.c:98
void Hermite(Matrix *A, Matrix **H, Matrix **U)
Hermite : This function takes a Matrix as its input and finds its HNF ( Left form )
Definition: NormalForms.c:663
int SolveDiophantine(Matrix *M, Matrix **U, Vector **X)
Definition: SolveDio.c:64
static void RearrangeMatforSolveDio(Matrix *M)
Definition: SolveDio.c:241
#define value_oppose(ref, val)
Definition: arithmetique.h:552
#define value_notzero_p(val)
Definition: arithmetique.h:576
#define value_ne(v1, v2)
Definition: arithmetique.h:503
#define value_zero_p(val)
Definition: arithmetique.h:575
#define value_assign(v1, v2)
Definition: arithmetique.h:482
#define value_set_si(val, i)
Definition: arithmetique.h:483
#define value_addmul(ref, val1, val2)
Definition: arithmetique.h:539
#define value_clear(val)
Definition: arithmetique.h:485
#define value_division(ref, val1, val2)
Definition: arithmetique.h:547
#define value_modulus(ref, val1, val2)
Definition: arithmetique.h:549
#define value_subtract(ref, val1, val2)
Definition: arithmetique.h:544
#define value_init(val)
Definition: arithmetique.h:481
Matrix * Matrix_Alloc(unsigned NbRows, unsigned NbColumns)
Definition: matrix.c:24
int Matrix_Inverse(Matrix *Mat, Matrix *MatInv)
Definition: matrix.c:917
void Matrix_Free(Matrix *Mat)
Definition: matrix.c:71
Definition: types.h:70
Definition: types.h:75
unsigned NbRows
Definition: types.h:76
Value ** p
Definition: types.h:77
unsigned NbColumns
Definition: types.h:76
Bool
Definition: types.h:218
@ True
Definition: types.h:218
Vector * Vector_Alloc(unsigned length)
Definition: vector.c:137
Value min
Definition: verif_ehrhart.c:43