polylib 7.01
compress_parms.c
Go to the documentation of this file.
1/**
2 * $Id: compress_parms.c,v 1.32 2006/11/03 17:34:26 skimo Exp $
3 *
4 * The integer points in a parametric linear subspace of Q^n are generally
5 * lying on a sub-lattice of Z^n.
6 * Functions here use and compute validity lattices, i.e. lattices induced on a
7 * set of variables by such equalities involving another set of integer
8 * variables.
9 * @author B. Meister 12/2003-2006 meister@icps.u-strasbg.fr
10 * LSIIT -ICPS
11 * UMR 7005 CNRS
12 * Louis Pasteur University (ULP), Strasbourg, France
13 */
14
15#include <polylib/polylib.h>
16#include <stdlib.h>
17
18/**
19 * debug flags (2 levels)
20 */
21#define dbgCompParm 0
22#define dbgCompParmMore 0
23
24#define dbgStart(a) \
25 if (dbgCompParmMore) { \
26 printf(" -- begin "); \
27 printf(#a); \
28 printf(" --\n"); \
29 } \
30 while (0)
31#define dbgEnd(a) \
32 if (dbgCompParmMore) { \
33 printf(" -- end "); \
34 printf(#a); \
35 printf(" --\n"); \
36 } \
37 while (0)
38
39/**
40 * Given a full-row-rank nxm matrix M made of m row-vectors), computes the
41 * basis K (made of n-m column-vectors) of the integer kernel of the rows of M
42 * so we have: M.K = 0
43 */
45 Matrix *U, *H, *H2, *K = NULL;
46 int rk;
47
48 if (dbgCompParm)
49 show_matrix(M);
50 /* eliminate redundant rows : UM = H*/
51 right_hermite(M, &H, NULL, &U);
52 for (rk = H->NbRows - 1; (rk >= 0) && Vector_IsZero(H->p[rk], H->NbColumns);
53 rk--)
54 ;
55 rk++;
56 if (dbgCompParmMore) {
57 printf("rank = %d\n", rk);
58 }
59
60 /* there is a non-null kernel if and only if the dimension m of
61 the space spanned by the rows
62 is inferior to the number n of variables */
63 if (M->NbColumns <= rk) {
64 Matrix_Free(H);
65 Matrix_Free(U);
66 K = Matrix_Alloc(M->NbColumns, 0);
67 return K;
68 }
69 Matrix_Free(U);
70 /* fool left_hermite by giving NbRows = rank of M*/
71 H->NbRows = rk;
72 /* computes MU = [H 0] */
73 left_hermite(H, &H2, NULL, &U);
74 if (dbgCompParmMore) {
75 printf("-- Int. Kernel -- \n");
76 show_matrix(M);
77 printf(" = \n");
78 show_matrix(H2);
79 show_matrix(U);
80 }
81 H->NbRows = M->NbRows;
82 Matrix_Free(H);
83 /* the Integer Kernel is made of the last n-rk columns of U */
84 Matrix_subMatrix(U, 0, rk, U->NbRows, U->NbColumns, &K);
85
86 /* clean up */
87 Matrix_Free(H2);
88 Matrix_Free(U);
89 return K;
90} /* int_ker */
91
92/**
93 * Computes the intersection of two linear lattices, whose base vectors are
94 * respectively represented in A and B.
95 * If I and/or Lb is set to NULL, then the matrix is allocated.
96 * Else, the matrix is assumed to be allocated already.
97 * I and Lb are rk x rk, where rk is the rank of A (or B).
98 * @param A the full-row rank matrix whose column-vectors are the basis for the
99 * first linear lattice.
100 * @param B the matrix whose column-vectors are the basis for the second linear
101 * lattice.
102 * @param Lb the matrix such that B.Lb = I, where I is the intersection.
103 * @return their intersection.
104 */
105static void linearInter(Matrix *A, Matrix *B, Matrix **I, Matrix **Lb) {
106 Matrix *AB = NULL;
107 int rk = A->NbRows;
108 int a = A->NbColumns;
109 int b = B->NbColumns;
110 int i, z = 0;
111
112 Matrix *H, *U, *Q;
113 /* ensure that the spanning vectors are in the same space */
114 assert(B->NbRows == rk);
115 /* 1- build the matrix
116 * (A 0 1)
117 * (0 B 1)
118 */
119 AB = Matrix_Alloc(2 * rk, a + b + rk);
120 Matrix_copySubMatrix(A, 0, 0, rk, a, AB, 0, 0);
121 Matrix_copySubMatrix(B, 0, 0, rk, b, AB, rk, a);
122 for (i = 0; i < rk; i++) {
123 value_set_si(AB->p[i][a + b + i], 1);
124 value_set_si(AB->p[i + rk][a + b + i], 1);
125 }
126 if (dbgCompParm) {
127 show_matrix(AB);
128 }
129
130 /* 2- Compute its left Hermite normal form. AB.U = [H 0] */
131 left_hermite(AB, &H, &Q, &U);
132 Matrix_Free(AB);
133 Matrix_Free(Q);
134 /* count the number of non-zero colums in H */
135 for (z = H->NbColumns - 1; value_zero_p(H->p[H->NbRows - 1][z]); z--)
136 ;
137 z++;
138 if (dbgCompParm) {
139 show_matrix(H);
140 printf("z=%d\n", z);
141 }
142 Matrix_Free(H);
143 /* if you split U in 9 submatrices, you have:
144 * A.U_13 = -U_33
145 * B.U_23 = -U_33,
146 * where the nb of cols of U_{*3} equals the nb of zero-cols of H
147 * U_33 is a (the smallest) combination of col-vectors of A and B at the same
148 * time: their intersection.
149 */
150 Matrix_subMatrix(U, a + b, z, U->NbColumns, U->NbColumns, I);
151 Matrix_subMatrix(U, a, z, a + b, U->NbColumns, Lb);
152 if (dbgCompParm) {
153 show_matrix(U);
154 }
155 Matrix_Free(U);
156} /* linearInter */
157
158/**
159 * Given a system of equalities, looks if it has an integer solution in the
160 * combined space, and if yes, returns one solution.
161 * <p>pre-condition: the equalities are full-row rank (without the constant
162 * part)</p>
163 * @param Eqs the system of equations (as constraints)
164 * @param I a feasible integer solution if it exists, else NULL. Allocated if
165 * initially set to NULL, else reused.
166 */
168 Matrix *Hm, *H = NULL, *U, *Q, *M = NULL, *C = NULL, *Hi;
169 Matrix *Ip;
170 int i;
171 Value mod;
172 unsigned int rk;
173 if (Eqs == NULL) {
174 if ((*I) != NULL)
175 Matrix_Free(*I);
176 I = NULL;
177 return;
178 }
179 /* we use: AI = C = (Ha 0).Q.I = (Ha 0)(I' 0)^T */
180 /* with I = Qinv.I' = U.I'*/
181 /* 1- compute I' = Hainv.(-C) */
182 /* HYP: the equalities are full-row rank */
183 rk = Eqs->NbRows;
184 Matrix_subMatrix(Eqs, 0, 1, rk, Eqs->NbColumns - 1, &M);
185 left_hermite(M, &Hm, &Q, &U);
186 Matrix_Free(M);
187 Matrix_subMatrix(Hm, 0, 0, rk, rk, &H);
188 if (dbgCompParmMore) {
189 show_matrix(Hm);
190 show_matrix(H);
191 show_matrix(U);
192 }
193 Matrix_Free(Q);
194 Matrix_Free(Hm);
195 Matrix_subMatrix(Eqs, 0, Eqs->NbColumns - 1, rk, Eqs->NbColumns, &C);
196 Matrix_oppose(C);
197 Hi = Matrix_Alloc(rk, rk + 1);
198 MatInverse(H, Hi);
199 if (dbgCompParmMore) {
200 show_matrix(C);
201 show_matrix(Hi);
202 }
203 /* put the numerator of Hinv back into H */
204 Matrix_subMatrix(Hi, 0, 0, rk, rk, &H);
205 Ip = Matrix_Alloc(Eqs->NbColumns - 2, 1);
206 /* fool Matrix_Product on the size of Ip */
207 Ip->NbRows = rk;
208 Matrix_Product(H, C, Ip);
209 Ip->NbRows = Eqs->NbColumns - 2;
210 Matrix_Free(H);
211 Matrix_Free(C);
212 value_init(mod);
213 for (i = 0; i < rk; i++) {
214 /* if Hinv.C is not integer, return NULL (no solution) */
215 value_pmodulus(mod, Ip->p[i][0], Hi->p[i][rk]);
216 if (value_notzero_p(mod)) {
217 if ((*I) != NULL)
218 Matrix_Free(*I);
219 value_clear(mod);
220 Matrix_Free(U);
221 Matrix_Free(Ip);
222 Matrix_Free(Hi);
223 I = NULL;
224 return;
225 } else {
226 value_pdivision(Ip->p[i][0], Ip->p[i][0], Hi->p[i][rk]);
227 }
228 }
229 /* fill the rest of I' with zeros */
230 for (i = rk; i < Eqs->NbColumns - 2; i++) {
231 value_set_si(Ip->p[i][0], 0);
232 }
233 value_clear(mod);
234 Matrix_Free(Hi);
235 /* 2 - Compute the particular solution I = U.(I' 0) */
236 ensureMatrix((*I), Eqs->NbColumns - 2, 1);
237 Matrix_Product(U, Ip, (*I));
238 Matrix_Free(U);
239 Matrix_Free(Ip);
240 if (dbgCompParm) {
241 show_matrix(*I);
242 }
243}
244
245/**
246 * Computes the validity lattice of a set of equalities. I.e., the lattice
247 * induced on the last <tt>b</tt> variables by the equalities involving the
248 * first <tt>a</tt> integer existential variables. The submatrix of Eqs that
249 * concerns only the existential variables (so the first a columns) is assumed
250 * to be full-row rank.
251 * @param Eqs the equalities
252 * @param a the number of existential integer variables, placed as first
253 * variables
254 * @param vl the (returned) validity lattice, in homogeneous form. It is
255 * allocated if initially set to null, or reused if already allocated.
256 */
257void Equalities_validityLattice(Matrix *Eqs, int a, Matrix **vl) {
258 unsigned int b = Eqs->NbColumns - 2 - a;
259 unsigned int r = Eqs->NbRows;
260 Matrix *A = NULL, *B = NULL, *I = NULL, *Lb = NULL, *sol = NULL;
261 Matrix *H, *U, *Q;
262 unsigned int i;
263
264 if (dbgCompParm) {
265 printf("Computing validity lattice induced by the %d first variables of:",
266 a);
267 show_matrix(Eqs);
268 }
269 if (b == 0) {
270 ensureMatrix((*vl), 1, 1);
271 value_set_si((*vl)->p[0][0], 1);
272 return;
273 }
274
275 /* 1- check that there is an integer solution to the equalities */
276 /* OPT: could change integerSolution's profile to allocate or not*/
278 /* if there is no integer solution, there is no validity lattice */
279 if (sol == NULL) {
280 if ((*vl) != NULL)
281 Matrix_Free(*vl);
282 return;
283 }
284 Matrix_subMatrix(Eqs, 0, 1, r, 1 + a, &A);
285 Matrix_subMatrix(Eqs, 0, 1 + a, r, 1 + a + b, &B);
286 linearInter(A, B, &I, &Lb);
287 Matrix_Free(A);
288 Matrix_Free(B);
289 Matrix_Free(I);
290 if (dbgCompParm) {
291 show_matrix(Lb);
292 }
293
294 /* 2- The linear part of the validity lattice is the left HNF of Lb */
295 left_hermite(Lb, &H, &Q, &U);
296 Matrix_Free(Lb);
297 Matrix_Free(Q);
298 Matrix_Free(U);
299
300 /* 3- build the validity lattice */
301 ensureMatrix((*vl), b + 1, b + 1);
302 Matrix_copySubMatrix(H, 0, 0, b, b, (*vl), 0, 0);
303 Matrix_Free(H);
304 for (i = 0; i < b; i++) {
305 value_assign((*vl)->p[i][b], sol->p[0][a + i]);
306 }
307 Matrix_Free(sol);
308 Vector_Set((*vl)->p[b], 0, b);
309 value_set_si((*vl)->p[b][b], 1);
310
311} /* validityLattice */
312
313/**
314 * Eliminate the columns corresponding to a list of eliminated parameters.
315 * @param M the constraints matrix whose columns are to be removed
316 * @param nbVars an offset to be added to the ranks of the variables to be
317 * removed
318 * @param elimParms the list of ranks of the variables to be removed
319 * @param newM (output) the matrix without the removed columns
320 */
321void Constraints_removeElimCols(Matrix *M, unsigned int nbVars,
322 unsigned int *elimParms, Matrix **newM) {
323 unsigned int i, j, k;
324 if (elimParms[0] == 0) {
325 Matrix_clone(M, newM);
326 return;
327 }
328 if ((*newM) == NULL) {
329 (*newM) = Matrix_Alloc(M->NbRows, M->NbColumns - elimParms[0]);
330 } else {
331 assert((*newM)->NbColumns == M->NbColumns - elimParms[0]);
332 }
333 for (i = 0; i < M->NbRows; i++) {
334 value_assign((*newM)->p[i][0], M->p[i][0]); /* kind of cstr */
335 k = 0;
336 Vector_Copy(&(M->p[i][1]), &((*newM)->p[i][1]), nbVars);
337 for (j = 0; j < M->NbColumns - 2 - nbVars; j++) {
338 if (j != elimParms[k + 1]) {
339 value_assign((*newM)->p[i][j - k + nbVars + 1],
340 M->p[i][j + nbVars + 1]);
341 } else {
342 k++;
343 }
344 }
345 value_assign((*newM)->p[i][(*newM)->NbColumns - 1],
346 M->p[i][M->NbColumns - 1]); /* cst part */
347 }
348} /* Constraints_removeElimCols */
349
350/**
351 * Eliminates all the equalities in a set of constraints and returns the set of
352 * constraints defining a full-dimensional polyhedron, such that there is a
353 * bijection between integer points of the original polyhedron and these of the
354 * resulting (projected) polyhedron).
355 * If VL is set to NULL, this funciton allocates it. Else, it assumes that
356 * (*VL) points to a matrix of the right size.
357 * <p> The following things are done:
358 * <ol>
359 * <li> remove equalities involving only parameters, and remove as many
360 * parameters as there are such equalities. From that, the list of
361 * eliminated parameters <i>elimParms</i> is built.
362 * <li> remove equalities that involve variables. This requires a compression
363 * of the parameters and of the other variables that are not eliminated.
364 * The affine compresson is represented by matrix VL (for <i>validity
365 * lattice</i>) and is such that (N I 1)^T = VL.(N' I' 1), where N', I'
366 * are integer (they are the parameters and variables after compression).
367 *</ol>
368 *</p>
369 */
371 Matrix **Eqs, Matrix **ParmEqs,
372 unsigned int **elimVars,
373 unsigned int **elimParms, int maxRays) {
374 unsigned int i, j;
375 Matrix *A = NULL, *B = NULL;
376 Matrix *Ineqs = NULL;
377 unsigned int nbVars = (*M)->NbColumns - (*C)->NbColumns;
378 unsigned int nbParms;
379 int nbElimVars;
380 Matrix *fullDim = NULL;
381
382 /* variables for permutations */
383 unsigned int *permutation;
384 Matrix *permutedEqs = NULL, *permutedIneqs = NULL;
385
386 /* 1- Eliminate the equalities involving only parameters. */
387 (*ParmEqs) = Constraints_removeParmEqs(M, C, 0, elimParms);
388 /* if the polyehdron is empty, return now. */
389 if ((*M)->NbColumns == 0)
390 return;
391 /* eliminate the columns corresponding to the eliminated parameters */
392 if (elimParms[0] != 0) {
393 Constraints_removeElimCols(*M, nbVars, (*elimParms), &A);
394 Matrix_Free(*M);
395 (*M) = A;
396 Constraints_removeElimCols(*C, 0, (*elimParms), &B);
397 Matrix_Free(*C);
398 (*C) = B;
399 if (dbgCompParm) {
400 printf("After false parameter elimination: \n");
401 show_matrix(*M);
402 show_matrix(*C);
403 }
404 }
405 nbParms = (*C)->NbColumns - 2;
406
407 /* 2- Eliminate the equalities involving variables */
408 /* a- extract the (remaining) equalities from the poyhedron */
409 split_constraints((*M), Eqs, &Ineqs);
410 nbElimVars = (*Eqs)->NbRows;
411 /* if the polyhedron is already full-dimensional, return */
412 if ((*Eqs)->NbRows == 0) {
413 Matrix_identity(nbParms + 1, VL);
414 return;
415 }
416 /* b- choose variables to be eliminated */
417 permutation = find_a_permutation((*Eqs), nbParms);
418
419 if (dbgCompParm) {
420 printf("Permuting the vars/parms this way: [ ");
421 for (i = 0; i < (*Eqs)->NbColumns - 2; i++) {
422 printf("%d ", permutation[i]);
423 }
424 printf("]\n");
425 }
426
427 Constraints_permute((*Eqs), permutation, &permutedEqs);
428 Equalities_validityLattice(permutedEqs, (*Eqs)->NbRows, VL);
429
430 if (dbgCompParm) {
431 printf("Validity lattice: ");
432 show_matrix(*VL);
433 }
434 Constraints_compressLastVars(permutedEqs, (*VL));
435 Constraints_permute(Ineqs, permutation, &permutedIneqs);
436 if (dbgCompParmMore) {
437 show_matrix(permutedIneqs);
438 show_matrix(permutedEqs);
439 }
440 Matrix_Free(*Eqs);
441 Matrix_Free(Ineqs);
442 Constraints_compressLastVars(permutedIneqs, (*VL));
443 if (dbgCompParm) {
444 printf("After compression: ");
445 show_matrix(permutedIneqs);
446 }
447 /* c- eliminate the first variables */
448 assert(Constraints_eliminateFirstVars(permutedEqs, permutedIneqs));
449 if (dbgCompParmMore) {
450 printf("After elimination of the variables: ");
451 show_matrix(permutedIneqs);
452 }
453
454 /* d- get rid of the first (zero) columns,
455 which are now useless, and put the parameters back at the end */
456 fullDim = Matrix_Alloc(permutedIneqs->NbRows,
457 permutedIneqs->NbColumns - nbElimVars);
458 for (i = 0; i < permutedIneqs->NbRows; i++) {
459 value_set_si(fullDim->p[i][0], 1);
460 for (j = 0; j < nbParms; j++) {
461 value_assign(fullDim->p[i][j + fullDim->NbColumns - nbParms - 1],
462 permutedIneqs->p[i][j + nbElimVars + 1]);
463 }
464 for (j = 0; j < permutedIneqs->NbColumns - nbParms - 2 - nbElimVars; j++) {
465 value_assign(fullDim->p[i][j + 1],
466 permutedIneqs->p[i][nbElimVars + nbParms + j + 1]);
467 }
468 value_assign(fullDim->p[i][fullDim->NbColumns - 1],
469 permutedIneqs->p[i][permutedIneqs->NbColumns - 1]);
470 }
471 Matrix_Free(permutedIneqs);
472
473} /* Constraints_fullDimensionize */
474
475/**
476 * Given a matrix that defines a full-dimensional affine lattice, returns the
477 * affine sub-lattice spanned in the k first dimensions.
478 * Useful for instance when you only look for the parameters' validity lattice.
479 * @param lat the original full-dimensional lattice
480 * @param subLat the sublattice
481 */
482void Lattice_extractSubLattice(Matrix *lat, unsigned int k, Matrix **subLat) {
483 Matrix *H, *Q, *U, *linLat = NULL;
484 unsigned int i;
486 /* if the dimension is already good, just copy the initial lattice */
487 if (k == lat->NbRows - 1) {
488 if (*subLat == NULL) {
489 (*subLat) = Matrix_Copy(lat);
490 } else {
491 Matrix_copySubMatrix(lat, 0, 0, lat->NbRows, lat->NbColumns, (*subLat), 0,
492 0);
493 }
494 return;
495 }
496 assert(k < lat->NbRows - 1);
497 /* 1- Make the linear part of the lattice triangular to eliminate terms from
498 other dimensions */
499 Matrix_subMatrix(lat, 0, 0, lat->NbRows, lat->NbColumns - 1, &linLat);
500 /* OPT: any integer column-vector elimination is ok indeed. */
501 /* OPT: could test if the lattice is already in triangular form. */
502 left_hermite(linLat, &H, &Q, &U);
503 if (dbgCompParmMore) {
504 show_matrix(H);
505 }
506 Matrix_Free(Q);
507 Matrix_Free(U);
508 Matrix_Free(linLat);
509 /* if not allocated yet, allocate it */
510 if (*subLat == NULL) {
511 (*subLat) = Matrix_Alloc(k + 1, k + 1);
512 }
513 Matrix_copySubMatrix(H, 0, 0, k, k, (*subLat), 0, 0);
514 Matrix_Free(H);
515 Matrix_copySubMatrix(lat, 0, lat->NbColumns - 1, k, 1, (*subLat), 0, k);
516 for (i = 0; i < k; i++) {
517 value_set_si((*subLat)->p[k][i], 0);
518 }
519 value_set_si((*subLat)->p[k][k], 1);
521} /* Lattice_extractSubLattice */
522
523/**
524 * Computes the overall period of the variables I for (MI) mod |d|, where M is
525 * a matrix and |d| a vector. Produce a diagonal matrix S = (s_k) where s_k is
526 * the overall period of i_k
527 * @param M the set of affine functions of I (row-vectors)
528 * @param d the column-vector representing the modulos
529 */
531 Matrix *S;
532 unsigned int i, j;
533 Value tmp;
534 Value *periods = (Value *)malloc(sizeof(Value) * M->NbColumns);
535 value_init(tmp);
536 for (i = 0; i < M->NbColumns; i++) {
537 value_init(periods[i]);
538 value_set_si(periods[i], 1);
539 }
540 for (i = 0; i < M->NbRows; i++) {
541 for (j = 0; j < M->NbColumns; j++) {
542 value_gcd(tmp, d->p[i][0], M->p[i][j]);
543 value_divexact(tmp, d->p[i][0], tmp);
544 value_lcm(periods[j], periods[j], tmp);
545 }
546 }
547 value_clear(tmp);
548
549 /* 2- build S */
550 S = Matrix_Alloc(M->NbColumns, M->NbColumns);
551 for (i = 0; i < M->NbColumns; i++)
552 for (j = 0; j < M->NbColumns; j++)
553 if (i == j)
554 value_assign(S->p[i][j], periods[j]);
555 else
556 value_set_si(S->p[i][j], 0);
557
558 /* 3- clean up */
559 for (i = 0; i < M->NbColumns; i++)
560 value_clear(periods[i]);
561 free(periods);
562 return S;
563} /* affine_periods */
564
565/**
566 * Given an integer matrix B with m rows and integer m-vectors C and d,
567 * computes the basis of the integer solutions to (BN+C) mod d = 0 (1).
568 * This is an affine lattice (G): (N 1)^T= G(N' 1)^T, forall N' in Z^b.
569 * If there is no solution, returns NULL.
570 * @param B B, a (m x b) matrix
571 * @param C C, a (m x 1) integer matrix
572 * @param d d, a (1 x m) integer matrix
573 * @param imb the affine (b+1)x(b+1) basis of solutions, in the homogeneous
574 * form. Allocated if initially set to NULL, reused if not.
575 */
577 int b = B->NbColumns;
578 /* FIXME: treat the case d=0 as a regular equality B_kN+C_k = 0: */
579 /* OPT: could keep only equalities for which d>1 */
580 int nbEqs = B->NbRows;
581 unsigned int i;
582
583 /* 1- buid the problem DI+BN+C = 0 */
584 Matrix *eqs = Matrix_Alloc(nbEqs, nbEqs + b + 1);
585 for (i = 0; i < nbEqs; i++) {
586 value_assign(eqs->p[i][i], d->p[0][i]);
587 }
588 Matrix_copySubMatrix(B, 0, 0, nbEqs, b, eqs, 0, nbEqs);
589 Matrix_copySubMatrix(C, 0, 0, nbEqs, 1, eqs, 0, nbEqs + b);
590
591 /* 2- the solution is the validity lattice of the equalities */
592 Equalities_validityLattice(eqs, nbEqs, imb);
593 Matrix_Free(eqs);
594} /* Equalities_intModBasis */
595
596/** kept here for backwards compatiblity. Wrapper to Equalities_intModBasis() */
598 Matrix *imb = NULL;
599 Equalities_intModBasis(B, C, d, &imb);
600 return imb;
601} /* int_mod_basis */
602
603/**
604 * Given a parameterized constraints matrix with m equalities, computes the
605 * compression matrix G such that there is an integer solution in the variables
606 * space for each value of N', with N = G N' (N are the "nb_parms" parameters)
607 * @param E a matrix of parametric equalities @param nb_parms the number of
608 * parameters
609 * <b>Note: </b>this function is mostly here for backwards
610 * compatibility. Prefer the use of <tt>Equalities_validityLattice</tt>.
611 */
612Matrix *compress_parms(Matrix *E, int nbParms) {
613 Matrix *vl = NULL;
614 Equalities_validityLattice(E, E->NbColumns - 2 - nbParms, &vl);
615 return vl;
616} /* compress_parms */
617
618/** Removes the equalities that involve only parameters, by eliminating some
619 * parameters in the polyhedron's constraints and in the context.<p>
620 * <b>Updates M and Ctxt.</b>
621 * @param M1 the polyhedron's constraints
622 * @param Ctxt1 the constraints of the polyhedron's context
623 * @param renderSpace tells if the returned equalities must be expressed in the
624 * parameters space (renderSpace=0) or in the combined var/parms space
625 * (renderSpace = 1)
626 * @param elimParms the list of parameters that have been removed: an array
627 * whose 1st element is the number of elements in the list. (returned)
628 * @return the system of equalities that involve only parameters.
629 */
631 int renderSpace, unsigned int **elimParms) {
632 int i, j, k, nbEqsParms = 0;
633 int nbEqsM, nbEqsCtxt, allZeros, nbTautoM = 0, nbTautoCtxt = 0;
634 Matrix *M = (*M1);
635 Matrix *Ctxt = (*Ctxt1);
636 int nbVars = M->NbColumns - Ctxt->NbColumns;
637 Matrix *Eqs;
638 Matrix *EqsMTmp;
639
640 /* 1- build the equality matrix(ces) */
641 nbEqsM = 0;
642 for (i = 0; i < M->NbRows; i++) {
643 k = First_Non_Zero(M->p[i], M->NbColumns);
644 /* if it is a tautology, count it as such */
645 if (k == -1) {
646 nbTautoM++;
647 } else {
648 /* if it only involves parameters, count it */
649 if (k >= nbVars + 1)
650 nbEqsM++;
651 }
652 }
653
654 nbEqsCtxt = 0;
655 for (i = 0; i < Ctxt->NbRows; i++) {
656 if (value_zero_p(Ctxt->p[i][0])) {
657 if (First_Non_Zero(Ctxt->p[i], Ctxt->NbColumns) == -1) {
658 nbTautoCtxt++;
659 } else {
660 nbEqsCtxt++;
661 }
662 }
663 }
664 nbEqsParms = nbEqsM + nbEqsCtxt;
665
666 /* nothing to do in this case */
667 if (nbEqsParms + nbTautoM + nbTautoCtxt == 0) {
668 (*elimParms) = (unsigned int *)malloc(sizeof(int));
669 (*elimParms)[0] = 0;
670 if (renderSpace == 0) {
671 return Matrix_Alloc(0, Ctxt->NbColumns);
672 } else {
673 return Matrix_Alloc(0, M->NbColumns);
674 }
675 }
676
677 Eqs = Matrix_Alloc(nbEqsParms, Ctxt->NbColumns);
678 EqsMTmp = Matrix_Alloc(nbEqsParms, M->NbColumns);
679
680 /* copy equalities from the context */
681 k = 0;
682 for (i = 0; i < Ctxt->NbRows; i++) {
683 if (value_zero_p(Ctxt->p[i][0]) &&
684 First_Non_Zero(Ctxt->p[i], Ctxt->NbColumns) != -1) {
685 Vector_Copy(Ctxt->p[i], Eqs->p[k], Ctxt->NbColumns);
686 Vector_Copy(Ctxt->p[i] + 1, EqsMTmp->p[k] + nbVars + 1,
687 Ctxt->NbColumns - 1);
688 k++;
689 }
690 }
691 for (i = 0; i < M->NbRows; i++) {
692 j = First_Non_Zero(M->p[i], M->NbColumns);
693 /* copy equalities that involve only parameters from M */
694 if (j >= nbVars + 1) {
695 Vector_Copy(M->p[i] + nbVars + 1, Eqs->p[k] + 1, Ctxt->NbColumns - 1);
696 Vector_Copy(M->p[i] + nbVars + 1, EqsMTmp->p[k] + nbVars + 1,
697 Ctxt->NbColumns - 1);
698 /* mark these equalities for removal */
699 value_set_si(M->p[i][0], 2);
700 k++;
701 }
702 /* mark the all-zero equalities for removal */
703 if (j == -1) {
704 value_set_si(M->p[i][0], 2);
705 }
706 }
707
708 /* 2- eliminate parameters until all equalities are used or until we find a
709 contradiction (overconstrained system) */
710 (*elimParms) = (unsigned int *)malloc((Eqs->NbRows + 1) * sizeof(int));
711 (*elimParms)[0] = 0;
712 allZeros = 0;
713 for (i = 0; i < Eqs->NbRows; i++) {
714 /* find a variable that can be eliminated */
715 k = First_Non_Zero(Eqs->p[i], Eqs->NbColumns);
716 if (k != -1) { /* nothing special to do for tautologies */
717
718 /* if there is a contradiction, return empty matrices */
719 if (k == Eqs->NbColumns - 1) {
720 printf("Contradiction in %dth row of Eqs: ", k);
721 show_matrix(Eqs);
722 Matrix_Free(Eqs);
723 Matrix_Free(EqsMTmp);
724 (*M1) = Matrix_Alloc(0, M->NbColumns);
725 Matrix_Free(M);
726 (*Ctxt1) = Matrix_Alloc(0, Ctxt->NbColumns);
727 Matrix_Free(Ctxt);
728 free(*elimParms);
729 (*elimParms) = (unsigned int *)malloc(sizeof(int));
730 (*elimParms)[0] = 0;
731 if (renderSpace == 1) {
732 return Matrix_Alloc(0, (*M1)->NbColumns);
733 } else {
734 return Matrix_Alloc(0, (*Ctxt1)->NbColumns);
735 }
736 }
737 /* if we have something we can eliminate, do it in 3 places:
738 Eqs, Ctxt, and M */
739 else {
740 k--; /* k is the rank of the variable, now */
741 (*elimParms)[0]++;
742 (*elimParms)[(*elimParms[0])] = k;
743 for (j = 0; j < Eqs->NbRows; j++) {
744 if (i != j) {
745 eliminate_var_with_constr(Eqs, i, Eqs, j, k);
746 eliminate_var_with_constr(EqsMTmp, i, EqsMTmp, j, k + nbVars);
747 }
748 }
749 for (j = 0; j < Ctxt->NbRows; j++) {
750 if (value_notzero_p(Ctxt->p[i][0])) {
751 eliminate_var_with_constr(Eqs, i, Ctxt, j, k);
752 }
753 }
754 for (j = 0; j < M->NbRows; j++) {
755 if (value_cmp_si(M->p[i][0], 2)) {
756 eliminate_var_with_constr(EqsMTmp, i, M, j, k + nbVars);
757 }
758 }
759 }
760 }
761 /* if (k==-1): count the tautologies in Eqs to remove them later */
762 else {
763 allZeros++;
764 }
765 }
766
767 /* elimParms may have been overallocated. Now we know how many parms have
768 been eliminated so we can reallocate the right amount of memory. */
769 if (!realloc((*elimParms), ((*elimParms)[0] + 1) * sizeof(int))) {
770 fprintf(stderr, "Constraints_Remove_parm_eqs > cannot realloc()");
771 }
772
773 Matrix_Free(EqsMTmp);
774
775 /* 3- remove the "bad" equalities from the input matrices
776 and copy the equalities involving only parameters */
777 EqsMTmp = Matrix_Alloc(M->NbRows - nbEqsM - nbTautoM, M->NbColumns);
778 k = 0;
779 for (i = 0; i < M->NbRows; i++) {
780 if (value_cmp_si(M->p[i][0], 2)) {
781 Vector_Copy(M->p[i], EqsMTmp->p[k], M->NbColumns);
782 k++;
783 }
784 }
785 Matrix_Free(M);
786 (*M1) = EqsMTmp;
787
788 EqsMTmp =
789 Matrix_Alloc(Ctxt->NbRows - nbEqsCtxt - nbTautoCtxt, Ctxt->NbColumns);
790 k = 0;
791 for (i = 0; i < Ctxt->NbRows; i++) {
792 if (value_notzero_p(Ctxt->p[i][0])) {
793 Vector_Copy(Ctxt->p[i], EqsMTmp->p[k], Ctxt->NbColumns);
794 k++;
795 }
796 }
797 Matrix_Free(Ctxt);
798 (*Ctxt1) = EqsMTmp;
799
800 if (renderSpace == 0) { /* renderSpace=0: equalities in the parameter space */
801 EqsMTmp = Matrix_Alloc(Eqs->NbRows - allZeros, Eqs->NbColumns);
802 k = 0;
803 for (i = 0; i < Eqs->NbRows; i++) {
804 if (First_Non_Zero(Eqs->p[i], Eqs->NbColumns) != -1) {
805 Vector_Copy(Eqs->p[i], EqsMTmp->p[k], Eqs->NbColumns);
806 k++;
807 }
808 }
809 } else { /* renderSpace=1: equalities rendered in the combined space */
810 EqsMTmp = Matrix_Alloc(Eqs->NbRows - allZeros, (*M1)->NbColumns);
811 k = 0;
812 for (i = 0; i < Eqs->NbRows; i++) {
813 if (First_Non_Zero(Eqs->p[i], Eqs->NbColumns) != -1) {
814 Vector_Copy(Eqs->p[i], &(EqsMTmp->p[k][nbVars]), Eqs->NbColumns);
815 k++;
816 }
817 }
818 }
819 Matrix_Free(Eqs);
820 Eqs = EqsMTmp;
821
822 return Eqs;
823} /* Constraints_Remove_parm_eqs */
824
825/** Removes equalities involving only parameters, but starting from a
826 * Polyhedron and its context.
827 * @param P the polyhedron
828 * @param C P's context
829 * @param renderSpace: 0 for the parameter space, =1 for the combined space.
830 * @maxRays Polylib's usual <i>workspace</i>.
831 */
833 int renderSpace,
834 unsigned int **elimParms, int maxRays) {
835 Matrix *Eqs;
836 Polyhedron *Peqs;
838 Matrix *Ct = Polyhedron2Constraints((*C));
839
840 /* if the Minkowski representation is not computed yet, do not compute it in
841 Constraints2Polyhedron */
842 if (F_ISSET((*P), POL_VALID | POL_INEQUALITIES) &&
845 }
846
847 Eqs = Constraints_Remove_parm_eqs(&M, &Ct, renderSpace, elimParms);
848 Peqs = Constraints2Polyhedron(Eqs, maxRays);
849 Matrix_Free(Eqs);
850
851 /* particular case: no equality involving only parms is found */
852 if (Eqs->NbRows == 0) {
853 Matrix_Free(M);
854 Matrix_Free(Ct);
855 return Peqs;
856 }
857 Polyhedron_Free(*P);
858 Polyhedron_Free(*C);
861 Matrix_Free(M);
862 Matrix_Free(Ct);
863 return Peqs;
864} /* Polyhedron_Remove_parm_eqs */
865
866/**
867 * Given a matrix with m parameterized equations, compress the nb_parms
868 * parameters and n-m variables so that m variables are integer, and transform
869 * the variable space into a n-m space by eliminating the m variables (using
870 * the equalities) the variables to be eliminated are chosen automatically by
871 * the function.
872 * <b>Deprecated.</b> Try to use Constraints_fullDimensionize instead.
873 * @param M the constraints
874 * @param the number of parameters
875 * @param validityLattice the the integer lattice underlying the integer
876 * solutions.
877 */
878Matrix *full_dimensionize(Matrix const *M, int nbParms,
879 Matrix **validityLattice) {
880 Matrix *Eqs, *Ineqs;
881 Matrix *permutedEqs, *permutedIneqs;
882 Matrix *Full_Dim;
883 Matrix *WVL; /* The Whole Validity Lattice (vars+parms) */
884 unsigned int i, j;
885 int nbElimVars;
886 unsigned int *permutation;
887 /* 0- Split the equalities and inequalities from each other */
888 split_constraints(M, &Eqs, &Ineqs);
889
890 /* 1- if the polyhedron is already full-dimensional, return it */
891 if (Eqs->NbRows == 0) {
892 Matrix_Free(Eqs);
893 (*validityLattice) = Identity_Matrix(nbParms + 1);
894 return Ineqs;
895 }
896 nbElimVars = Eqs->NbRows;
897
898 /* 2- put the vars to be eliminated at the first positions,
899 and compress the other vars/parms
900 -> [ variables to eliminate / parameters / variables to keep ] */
901 permutation = find_a_permutation(Eqs, nbParms);
902 if (dbgCompParm) {
903 printf("Permuting the vars/parms this way: [ ");
904 for (i = 0; i < Eqs->NbColumns; i++) {
905 printf("%d ", permutation[i]);
906 }
907 printf("]\n");
908 }
909 permutedEqs = mpolyhedron_permute(Eqs, permutation);
910 WVL = compress_parms(permutedEqs, Eqs->NbColumns - 2 - Eqs->NbRows);
911 /* Check for empty WVL (no solution) */
912 if (!WVL) {
913 fprintf(stderr, "full_dimensionize > parameters compression failed.\n");
914 Matrix_Free(Eqs);
915 Matrix_Free(Ineqs);
916 (*validityLattice) = Identity_Matrix(nbParms + 1);
917 return NULL;
918 }
919 if (dbgCompParm) {
920 printf("Whole validity lattice: ");
921 show_matrix(WVL);
922 }
923 mpolyhedron_compress_last_vars(permutedEqs, WVL);
924 permutedIneqs = mpolyhedron_permute(Ineqs, permutation);
925 if (dbgCompParm) {
926 show_matrix(permutedEqs);
927 }
928 Matrix_Free(Eqs);
929 Matrix_Free(Ineqs);
930 mpolyhedron_compress_last_vars(permutedIneqs, WVL);
931 if (dbgCompParm) {
932 printf("After compression: ");
933 show_matrix(permutedIneqs);
934 }
935 /* 3- eliminate the first variables */
936 if (!mpolyhedron_eliminate_first_variables(permutedEqs, permutedIneqs)) {
937 fprintf(stderr, "full_dimensionize > variable elimination failed.\n");
938 Matrix_Free(permutedIneqs);
939 (*validityLattice) = Identity_Matrix(nbParms + 1);
940 return NULL;
941 }
942 if (dbgCompParm) {
943 printf("After elimination of the variables: ");
944 show_matrix(permutedIneqs);
945 }
946
947 /* 4- get rid of the first (zero) columns,
948 which are now useless, and put the parameters back at the end */
949 Full_Dim = Matrix_Alloc(permutedIneqs->NbRows,
950 permutedIneqs->NbColumns - nbElimVars);
951 for (i = 0; i < permutedIneqs->NbRows; i++) {
952 value_set_si(Full_Dim->p[i][0], 1);
953 for (j = 0; j < nbParms; j++)
954 value_assign(Full_Dim->p[i][j + Full_Dim->NbColumns - nbParms - 1],
955 permutedIneqs->p[i][j + nbElimVars + 1]);
956 for (j = 0; j < permutedIneqs->NbColumns - nbParms - 2 - nbElimVars; j++)
957 value_assign(Full_Dim->p[i][j + 1],
958 permutedIneqs->p[i][nbElimVars + nbParms + j + 1]);
959 value_assign(Full_Dim->p[i][Full_Dim->NbColumns - 1],
960 permutedIneqs->p[i][permutedIneqs->NbColumns - 1]);
961 }
962 Matrix_Free(permutedIneqs);
963
964 /* 5- Keep only the the validity lattice restricted to the parameters */
965 *validityLattice = Matrix_Alloc(nbParms + 1, nbParms + 1);
966 for (i = 0; i < nbParms; i++) {
967 for (j = 0; j < nbParms; j++)
968 value_assign((*validityLattice)->p[i][j], WVL->p[i][j]);
969 value_assign((*validityLattice)->p[i][nbParms],
970 WVL->p[i][WVL->NbColumns - 1]);
971 }
972 for (j = 0; j < nbParms; j++)
973 value_set_si((*validityLattice)->p[nbParms][j], 0);
974 value_assign((*validityLattice)->p[nbParms][nbParms],
975 WVL->p[WVL->NbColumns - 1][WVL->NbColumns - 1]);
976
977 /* 6- Clean up */
978 Matrix_Free(WVL);
979 return Full_Dim;
980} /* full_dimensionize */
981
982#undef dbgCompParm
983#undef dbgCompParmMore
Matrix * Matrix_Copy(Matrix const *Src)
Definition: Matop.c:98
#define value_pdivision(ref, val1, val2)
Definition: arithmetique.h:553
#define value_notzero_p(val)
Definition: arithmetique.h:579
#define value_divexact(ref, val1, val2)
Definition: arithmetique.h:551
#define value_gcd(ref, val1, val2)
Definition: arithmetique.h:559
#define value_pmodulus(ref, val1, val2)
Definition: arithmetique.h:554
#define value_lcm(ref, val1, val2)
Definition: arithmetique.h:560
#define value_zero_p(val)
Definition: arithmetique.h:578
#define value_assign(v1, v2)
Definition: arithmetique.h:485
int Value
Definition: arithmetique.h:294
#define value_set_si(val, i)
Definition: arithmetique.h:486
#define value_clear(val)
Definition: arithmetique.h:488
#define value_init(val)
Definition: arithmetique.h:484
#define value_cmp_si(val, n)
Definition: arithmetique.h:584
#define assert(ex)
Definition: assert.h:16
void Equalities_integerSolution(Matrix *Eqs, Matrix **I)
Given a system of equalities, looks if it has an integer solution in the combined space,...
Matrix * compress_parms(Matrix *E, int nbParms)
Given a parameterized constraints matrix with m equalities, computes the compression matrix G such th...
void Equalities_intModBasis(Matrix *B, Matrix *C, Matrix *d, Matrix **imb)
Given an integer matrix B with m rows and integer m-vectors C and d, computes the basis of the intege...
void Constraints_fullDimensionize(Matrix **M, Matrix **C, Matrix **VL, Matrix **Eqs, Matrix **ParmEqs, unsigned int **elimVars, unsigned int **elimParms, int maxRays)
Eliminates all the equalities in a set of constraints and returns the set of constraints defining a f...
#define dbgCompParm
debug flags (2 levels)
void Constraints_removeElimCols(Matrix *M, unsigned int nbVars, unsigned int *elimParms, Matrix **newM)
Eliminate the columns corresponding to a list of eliminated parameters.
Matrix * Constraints_Remove_parm_eqs(Matrix **M1, Matrix **Ctxt1, int renderSpace, unsigned int **elimParms)
Removes the equalities that involve only parameters, by eliminating some parameters in the polyhedron...
#define dbgEnd(a)
#define dbgStart(a)
Matrix * affine_periods(Matrix *M, Matrix *d)
Computes the overall period of the variables I for (MI) mod |d|, where M is a matrix and |d| a vector...
static void linearInter(Matrix *A, Matrix *B, Matrix **I, Matrix **Lb)
Computes the intersection of two linear lattices, whose base vectors are respectively represented in ...
Matrix * int_mod_basis(Matrix *B, Matrix *C, Matrix *d)
kept here for backwards compatiblity.
#define dbgCompParmMore
void Lattice_extractSubLattice(Matrix *lat, unsigned int k, Matrix **subLat)
Given a matrix that defines a full-dimensional affine lattice, returns the affine sub-lattice spanned...
Matrix * int_ker(Matrix *M)
Given a full-row-rank nxm matrix M made of m row-vectors), computes the basis K (made of n-m column-v...
void Equalities_validityLattice(Matrix *Eqs, int a, Matrix **vl)
Computes the validity lattice of a set of equalities.
Polyhedron * Polyhedron_Remove_parm_eqs(Polyhedron **P, Polyhedron **C, int renderSpace, unsigned int **elimParms, int maxRays)
Removes equalities involving only parameters, but starting from a Polyhedron and its context.
Matrix * full_dimensionize(Matrix const *M, int nbParms, Matrix **validityLattice)
Given a matrix with m parameterized equations, compress the nb_parms parameters and n-m variables so ...
#define Constraints_removeParmEqs(a, b, c, d)
void Matrix_Product(Matrix *Mat1, Matrix *Mat2, Matrix *Mat3)
Definition: matrix.c:880
Matrix * Matrix_Alloc(unsigned NbRows, unsigned NbColumns)
Definition: matrix.c:24
void right_hermite(Matrix *A, Matrix **Hp, Matrix **Up, Matrix **Qp)
Definition: matrix.c:448
void left_hermite(Matrix *A, Matrix **Hp, Matrix **Qp, Matrix **Up)
Definition: matrix.c:523
int MatInverse(Matrix *Mat, Matrix *MatInv)
Definition: matrix.c:611
void Matrix_Free(Matrix *Mat)
Definition: matrix.c:69
void split_constraints(Matrix const *M, Matrix **Eqs, Matrix **Ineqs)
splits a matrix of constraints M into a matrix of equalities Eqs and a matrix of inequalities Ineqs a...
Definition: matrix_addon.c:31
void Matrix_subMatrix(Matrix *M, unsigned int sr, unsigned int sc, unsigned int er, unsigned int ec, Matrix **sub)
returns a contiguous submatrix of a matrix.
Definition: matrix_addon.c:325
void mpolyhedron_compress_last_vars(Matrix *M, Matrix *compression)
compress the last vars/pars of the polyhedron M expressed as a polylib matrix
Definition: matrix_addon.c:261
Matrix * Identity_Matrix(unsigned int dim)
Definition: matrix_addon.c:58
unsigned int mpolyhedron_eliminate_first_variables(Matrix *Eqs, Matrix *Ineqs)
use a set of m equalities Eqs to eliminate m variables in the polyhedron Ineqs represented as a matri...
Definition: matrix_addon.c:288
void eliminate_var_with_constr(Matrix *Eliminator, unsigned int eliminator_row, Matrix *Victim, unsigned int victim_row, unsigned int var_to_elim)
use an eliminator row to eliminate a variable in a victim row (without changing the sign of the victi...
Definition: matrix_addon.c:213
void Matrix_clone(Matrix *M, Matrix **Cl)
Cloning function.
Definition: matrix_addon.c:345
void Matrix_copySubMatrix(Matrix *M1, unsigned int sr1, unsigned int sc1, unsigned int nbR, unsigned int nbC, Matrix *M2, unsigned int sr2, unsigned int sc2)
Copies a contiguous submatrix of M1 into M2, at the indicated position.
Definition: matrix_addon.c:361
void Matrix_oppose(Matrix *M)
transforms a matrix M into -M
Definition: matrix_addon.c:373
void Matrix_identity(unsigned int dim, Matrix **I)
returns the dim-dimensional identity matrix.
Definition: matrix_addon.c:77
#define show_matrix(M)
Polylib matrix addons Mainly, deals with polyhedra represented in implicit form (set of constraints).
Definition: matrix_addon.h:15
#define ensureMatrix(M, r, c)
Allocates a matrix if it is null, or else asserts that it has at least a certain size.
Definition: matrix_addon.h:28
#define Constraints_compressLastVars(a, b)
Definition: matrix_addon.h:83
#define Constraints_eliminateFirstVars(a, b)
Definition: matrix_addon.h:90
void Constraints_permute(Matrix *C, unsigned int *perm, Matrix **Cp)
permutes the variables of the constraints of a polyhedron
Matrix * mpolyhedron_permute(Matrix *polyh, unsigned int *permutation)
permutes the variables of the constraints of a polyhedron
unsigned int * find_a_permutation(Matrix *Eqs, unsigned int nb_parms)
finds a valid permutation : for a set of m equations, find m variables that will be put at the beginn...
void Polyhedron_Free(Polyhedron *Pol)
Definition: polyhedron.c:1621
Matrix * Polyhedron2Constraints(Polyhedron *Pol)
Definition: polyhedron.c:2067
Polyhedron * Constraints2Polyhedron(Matrix *Constraints, unsigned NbMaxRays)
Given a matrix of constraints ('Constraints'), construct and return a polyhedron.
Definition: polyhedron.c:1912
Definition: types.h:88
unsigned NbRows
Definition: types.h:89
Value ** p
Definition: types.h:90
unsigned NbColumns
Definition: types.h:89
#define maxRays
#define POL_INEQUALITIES
Definition: types.h:116
#define F_ISSET(p, f)
Definition: types.h:107
#define POL_VALID
Definition: types.h:123
#define POL_NO_DUAL
Definition: types.h:75
#define FL_INIT(l, f)
Definition: types.h:99
void Vector_Set(Value *p, int n, unsigned length)
Definition: vector.c:248
int Vector_IsZero(Value *v, unsigned length)
Definition: vector.c:763
void Vector_Copy(Value *p1, Value *p2, unsigned length)
Definition: vector.c:276
int First_Non_Zero(Value *p, unsigned length)
Definition: vector.c:117