testlib: return success when tests run successfully
[barvinok.git] / util.c
blob85dc6ce72090b78be8866a5ef41387dc3678b156
1 #include <stdlib.h>
2 #include <assert.h>
3 #include <isl/val_gmp.h>
4 #include <isl_set_polylib.h>
5 #include <barvinok/util.h>
6 #include <barvinok/options.h>
7 #include <polylib/ranking.h>
8 #include "config.h"
9 #include "lattice_point.h"
11 #define ALLOC(type) (type*)malloc(sizeof(type))
12 #define ALLOCN(type,n) (type*)malloc((n) * sizeof(type))
14 #ifdef __GNUC__
15 #define NALLOC(p,n) p = (typeof(p))malloc((n) * sizeof(*p))
16 #else
17 #define NALLOC(p,n) p = (void *)malloc((n) * sizeof(*p))
18 #endif
20 void manual_count(Polyhedron *P, Value* result)
22 isl_ctx *ctx = isl_ctx_alloc();
23 isl_space *dim;
24 isl_set *set;
25 isl_val *v;
26 int nvar = P->Dimension;
28 dim = isl_space_set_alloc(ctx, 0, nvar);
29 set = isl_set_new_from_polylib(P, dim);
31 v = isl_set_count_val(set);
32 isl_val_get_num_gmp(v, *result);
33 isl_val_free(v);
35 isl_set_free(set);
36 isl_ctx_free(ctx);
38 assert(v);
41 #include <barvinok/evalue.h>
42 #include <barvinok/util.h>
43 #include <barvinok/barvinok.h>
45 /* Return random value between 0 and max-1 inclusive
47 int random_int(int max) {
48 return (int) (((double)(max))*rand()/(RAND_MAX+1.0));
51 Polyhedron *Polyhedron_Read(unsigned MaxRays)
53 int vertices = 0;
54 unsigned NbRows, NbColumns;
55 Matrix *M;
56 Polyhedron *P;
57 char s[128];
59 while (fgets(s, sizeof(s), stdin)) {
60 if (*s == '#')
61 continue;
62 if (strncasecmp(s, "vertices", sizeof("vertices")-1) == 0)
63 vertices = 1;
64 if (sscanf(s, "%u %u", &NbRows, &NbColumns) == 2)
65 break;
67 if (feof(stdin))
68 return NULL;
69 M = Matrix_Alloc(NbRows,NbColumns);
70 Matrix_Read_Input(M);
71 if (vertices)
72 P = Rays2Polyhedron(M, MaxRays);
73 else
74 P = Constraints2Polyhedron(M, MaxRays);
75 Matrix_Free(M);
76 return P;
79 /* Inplace polarization
81 void Polyhedron_Polarize(Polyhedron *P)
83 unsigned NbRows;
84 int i;
85 Value **q;
87 POL_ENSURE_FACETS(P);
88 POL_ENSURE_VERTICES(P);
89 NbRows = P->NbConstraints + P->NbRays;
90 q = (Value **)malloc(NbRows * sizeof(Value *));
91 assert(q);
92 for (i = 0; i < P->NbRays; ++i)
93 q[i] = P->Ray[i];
94 for (; i < NbRows; ++i)
95 q[i] = P->Constraint[i-P->NbRays];
96 P->NbConstraints = NbRows - P->NbConstraints;
97 P->NbRays = NbRows - P->NbRays;
98 free(P->Constraint);
99 P->Constraint = q;
100 P->Ray = q + P->NbConstraints;
104 * Rather general polar
105 * We can optimize it significantly if we assume that
106 * P includes zero
108 * Also, we calculate the polar as defined in Schrijver
109 * The opposite should probably work as well and would
110 * eliminate the need for multiplying by -1
112 Polyhedron* Polyhedron_Polar(Polyhedron *P, unsigned NbMaxRays)
114 int i;
115 Value mone;
116 unsigned dim = P->Dimension + 2;
117 Matrix *M = Matrix_Alloc(P->NbRays, dim);
119 assert(M);
120 value_init(mone);
121 value_set_si(mone, -1);
122 for (i = 0; i < P->NbRays; ++i) {
123 Vector_Scale(P->Ray[i], M->p[i], mone, dim);
124 value_multiply(M->p[i][0], M->p[i][0], mone);
125 value_multiply(M->p[i][dim-1], M->p[i][dim-1], mone);
127 P = Constraints2Polyhedron(M, NbMaxRays);
128 assert(P);
129 Matrix_Free(M);
130 value_clear(mone);
131 return P;
135 * Returns the supporting cone of P at the vertex with index v
137 Polyhedron* supporting_cone(Polyhedron *P, int v)
139 Matrix *M;
140 Value tmp;
141 int i, n, j;
142 unsigned char *supporting = (unsigned char *)malloc(P->NbConstraints);
143 unsigned dim = P->Dimension + 2;
145 assert(v >=0 && v < P->NbRays);
146 assert(value_pos_p(P->Ray[v][dim-1]));
147 assert(supporting);
149 value_init(tmp);
150 for (i = 0, n = 0; i < P->NbConstraints; ++i) {
151 Inner_Product(P->Constraint[i] + 1, P->Ray[v] + 1, dim - 1, &tmp);
152 if ((supporting[i] = value_zero_p(tmp)))
153 ++n;
155 assert(n >= dim - 2);
156 value_clear(tmp);
157 M = Matrix_Alloc(n, dim);
158 assert(M);
159 for (i = 0, j = 0; i < P->NbConstraints; ++i)
160 if (supporting[i]) {
161 value_set_si(M->p[j][dim-1], 0);
162 Vector_Copy(P->Constraint[i], M->p[j++], dim-1);
164 free(supporting);
165 P = Constraints2Polyhedron(M, P->NbRays+1);
166 assert(P);
167 Matrix_Free(M);
168 return P;
171 #define INT_BITS (sizeof(unsigned) * 8)
173 unsigned *supporting_constraints(Matrix *Constraints, Param_Vertices *v, int *n)
175 Value lcm, tmp, tmp2;
176 unsigned dim = Constraints->NbColumns;
177 unsigned nparam = v->Vertex->NbColumns - 2;
178 unsigned nvar = dim - nparam - 2;
179 int len = (Constraints->NbRows+INT_BITS-1)/INT_BITS;
180 unsigned *supporting = (unsigned *)calloc(len, sizeof(unsigned));
181 int i, j;
182 Vector *row;
183 int ix;
184 unsigned bx;
186 assert(supporting);
187 row = Vector_Alloc(nparam+1);
188 assert(row);
189 value_init(lcm);
190 value_init(tmp);
191 value_init(tmp2);
192 value_set_si(lcm, 1);
193 for (i = 0, *n = 0, ix = 0, bx = MSB; i < Constraints->NbRows; ++i) {
194 Vector_Set(row->p, 0, nparam+1);
195 for (j = 0 ; j < nvar; ++j) {
196 value_set_si(tmp, 1);
197 value_assign(tmp2, Constraints->p[i][j+1]);
198 if (value_ne(lcm, v->Vertex->p[j][nparam+1])) {
199 value_assign(tmp, lcm);
200 value_lcm(lcm, lcm, v->Vertex->p[j][nparam+1]);
201 value_division(tmp, lcm, tmp);
202 value_multiply(tmp2, tmp2, lcm);
203 value_division(tmp2, tmp2, v->Vertex->p[j][nparam+1]);
205 Vector_Combine(row->p, v->Vertex->p[j], row->p,
206 tmp, tmp2, nparam+1);
208 value_set_si(tmp, 1);
209 Vector_Combine(row->p, Constraints->p[i]+1+nvar, row->p, tmp, lcm, nparam+1);
210 for (j = 0; j < nparam+1; ++j)
211 if (value_notzero_p(row->p[j]))
212 break;
213 if (j == nparam + 1) {
214 supporting[ix] |= bx;
215 ++*n;
217 NEXT(ix, bx);
219 assert(*n >= nvar);
220 value_clear(tmp);
221 value_clear(tmp2);
222 value_clear(lcm);
223 Vector_Free(row);
225 return supporting;
228 Polyhedron* supporting_cone_p(Polyhedron *P, Param_Vertices *v)
230 Matrix *M;
231 unsigned dim = P->Dimension + 2;
232 unsigned nparam = v->Vertex->NbColumns - 2;
233 unsigned nvar = dim - nparam - 2;
234 int i, n, j;
235 int ix;
236 unsigned bx;
237 unsigned *supporting;
238 Matrix View;
240 Polyhedron_Matrix_View(P, &View, P->NbConstraints);
241 supporting = supporting_constraints(&View, v, &n);
242 M = Matrix_Alloc(n, nvar+2);
243 assert(M);
244 for (i = 0, j = 0, ix = 0, bx = MSB; i < P->NbConstraints; ++i) {
245 if (supporting[ix] & bx) {
246 value_set_si(M->p[j][nvar+1], 0);
247 Vector_Copy(P->Constraint[i], M->p[j++], nvar+1);
249 NEXT(ix, bx);
251 free(supporting);
252 P = Constraints2Polyhedron(M, P->NbRays+1);
253 assert(P);
254 Matrix_Free(M);
255 return P;
258 Polyhedron* triangulate_cone(Polyhedron *P, unsigned NbMaxCons)
260 struct barvinok_options *options = barvinok_options_new_with_defaults();
261 options->MaxRays = NbMaxCons;
262 P = triangulate_cone_with_options(P, options);
263 barvinok_options_free(options);
264 return P;
267 Polyhedron* triangulate_cone_with_options(Polyhedron *P,
268 struct barvinok_options *options)
270 const static int MAX_TRY=10;
271 int i, j, r, n, t;
272 Value tmp;
273 unsigned dim = P->Dimension;
274 Matrix *M = Matrix_Alloc(P->NbRays+1, dim+3);
275 Matrix *M2, *M3;
276 Polyhedron *L, *R, *T;
277 assert(P->NbEq == 0);
279 L = NULL;
280 R = NULL;
281 value_init(tmp);
283 Vector_Set(M->p[0]+1, 0, dim+1);
284 value_set_si(M->p[0][0], 1);
285 value_set_si(M->p[0][dim+2], 1);
286 Vector_Set(M->p[P->NbRays]+1, 0, dim+2);
287 value_set_si(M->p[P->NbRays][0], 1);
288 value_set_si(M->p[P->NbRays][dim+1], 1);
290 for (i = 0, r = 1; i < P->NbRays; ++i) {
291 if (value_notzero_p(P->Ray[i][dim+1]))
292 continue;
293 Vector_Copy(P->Ray[i], M->p[r], dim+1);
294 value_set_si(M->p[r][dim+2], 0);
295 ++r;
298 M2 = Matrix_Alloc(dim+1, dim+2);
300 t = 0;
301 if (options->try_Delaunay_triangulation) {
302 /* Delaunay triangulation */
303 for (r = 1; r < P->NbRays; ++r) {
304 Inner_Product(M->p[r]+1, M->p[r]+1, dim, &tmp);
305 value_assign(M->p[r][dim+1], tmp);
307 M3 = Matrix_Copy(M);
308 L = Rays2Polyhedron(M3, options->MaxRays);
309 Matrix_Free(M3);
310 ++t;
311 } else {
312 try_again:
313 /* Usually R should still be 0 */
314 Domain_Free(R);
315 Polyhedron_Free(L);
316 for (r = 1; r < P->NbRays; ++r) {
317 value_set_si(M->p[r][dim+1], random_int((t+1)*dim*P->NbRays)+1);
319 M3 = Matrix_Copy(M);
320 L = Rays2Polyhedron(M3, options->MaxRays);
321 Matrix_Free(M3);
322 ++t;
324 assert(t <= MAX_TRY);
326 R = NULL;
327 n = 0;
329 POL_ENSURE_FACETS(L);
330 for (i = 0; i < L->NbConstraints; ++i) {
331 /* Ignore perpendicular facets, i.e., facets with 0 z-coordinate */
332 if (value_negz_p(L->Constraint[i][dim+1]))
333 continue;
334 if (value_notzero_p(L->Constraint[i][dim+2]))
335 continue;
336 for (j = 1, r = 1; j < M->NbRows; ++j) {
337 Inner_Product(M->p[j]+1, L->Constraint[i]+1, dim+1, &tmp);
338 if (value_notzero_p(tmp))
339 continue;
340 if (r > dim)
341 goto try_again;
342 Vector_Copy(M->p[j]+1, M2->p[r]+1, dim);
343 value_set_si(M2->p[r][0], 1);
344 value_set_si(M2->p[r][dim+1], 0);
345 ++r;
347 assert(r == dim+1);
348 Vector_Set(M2->p[0]+1, 0, dim);
349 value_set_si(M2->p[0][0], 1);
350 value_set_si(M2->p[0][dim+1], 1);
351 T = Rays2Polyhedron(M2, P->NbConstraints+1);
352 T->next = R;
353 R = T;
354 ++n;
356 Matrix_Free(M2);
358 Polyhedron_Free(L);
359 value_clear(tmp);
360 Matrix_Free(M);
362 return R;
365 void check_triangulization(Polyhedron *P, Polyhedron *T)
367 Polyhedron *C, *D, *E, *F, *G, *U;
368 for (C = T; C; C = C->next) {
369 if (C == T)
370 U = C;
371 else
372 U = DomainConvex(DomainUnion(U, C, 100), 100);
373 for (D = C->next; D; D = D->next) {
374 F = C->next;
375 G = D->next;
376 C->next = NULL;
377 D->next = NULL;
378 E = DomainIntersection(C, D, 600);
379 assert(E->NbRays == 0 || E->NbEq >= 1);
380 Polyhedron_Free(E);
381 C->next = F;
382 D->next = G;
385 assert(PolyhedronIncludes(U, P));
386 assert(PolyhedronIncludes(P, U));
389 /* Computes x, y and g such that g = gcd(a,b) and a*x+b*y = g */
390 void Extended_Euclid(Value a, Value b, Value *x, Value *y, Value *g)
392 Value c, d, e, f, tmp;
394 value_init(c);
395 value_init(d);
396 value_init(e);
397 value_init(f);
398 value_init(tmp);
399 value_absolute(c, a);
400 value_absolute(d, b);
401 value_set_si(e, 1);
402 value_set_si(f, 0);
403 while(value_pos_p(d)) {
404 value_division(tmp, c, d);
405 value_multiply(tmp, tmp, f);
406 value_subtract(e, e, tmp);
407 value_division(tmp, c, d);
408 value_multiply(tmp, tmp, d);
409 value_subtract(c, c, tmp);
410 value_swap(c, d);
411 value_swap(e, f);
413 value_assign(*g, c);
414 if (value_zero_p(a))
415 value_set_si(*x, 0);
416 else if (value_pos_p(a))
417 value_assign(*x, e);
418 else value_oppose(*x, e);
419 if (value_zero_p(b))
420 value_set_si(*y, 0);
421 else {
422 value_multiply(tmp, a, *x);
423 value_subtract(tmp, c, tmp);
424 value_division(*y, tmp, b);
426 value_clear(c);
427 value_clear(d);
428 value_clear(e);
429 value_clear(f);
430 value_clear(tmp);
433 static int unimodular_complete_1(Matrix *m)
435 Value g, b, c, old, tmp;
436 unsigned i, j;
437 int ok;
439 value_init(b);
440 value_init(c);
441 value_init(g);
442 value_init(old);
443 value_init(tmp);
444 value_assign(g, m->p[0][0]);
445 for (i = 1; value_zero_p(g) && i < m->NbColumns; ++i) {
446 for (j = 0; j < m->NbColumns; ++j) {
447 if (j == i-1)
448 value_set_si(m->p[i][j], 1);
449 else
450 value_set_si(m->p[i][j], 0);
452 value_assign(g, m->p[0][i]);
454 for (; i < m->NbColumns; ++i) {
455 value_assign(old, g);
456 Extended_Euclid(old, m->p[0][i], &c, &b, &g);
457 value_oppose(b, b);
458 for (j = 0; j < m->NbColumns; ++j) {
459 if (j < i) {
460 value_multiply(tmp, m->p[0][j], b);
461 value_division(m->p[i][j], tmp, old);
462 } else if (j == i)
463 value_assign(m->p[i][j], c);
464 else
465 value_set_si(m->p[i][j], 0);
468 ok = value_one_p(g);
469 value_clear(b);
470 value_clear(c);
471 value_clear(g);
472 value_clear(old);
473 value_clear(tmp);
474 return ok;
477 int unimodular_complete(Matrix *M, int row)
479 int r;
480 int ok = 1;
481 Matrix *H, *Q, *U;
483 if (row == 1)
484 return unimodular_complete_1(M);
486 left_hermite(M, &H, &Q, &U);
487 Matrix_Free(U);
488 for (r = 0; ok && r < row; ++r)
489 if (value_notone_p(H->p[r][r]))
490 ok = 0;
491 Matrix_Free(H);
492 for (r = row; r < M->NbRows; ++r)
493 Vector_Copy(Q->p[r], M->p[r], M->NbColumns);
494 Matrix_Free(Q);
495 return ok;
499 * left_hermite may leave positive entries below the main diagonal in H.
500 * This function postprocesses the output of left_hermite to make
501 * the non-zero entries below the main diagonal negative.
503 void neg_left_hermite(Matrix *A, Matrix **H_p, Matrix **Q_p, Matrix **U_p)
505 int row, col, i, j;
506 Matrix *H, *U, *Q;
508 left_hermite(A, &H, &Q, &U);
509 *H_p = H;
510 *Q_p = Q;
511 *U_p = U;
513 for (row = 0, col = 0; col < H->NbColumns; ++col, ++row) {
514 while (value_zero_p(H->p[row][col]))
515 ++row;
516 for (i = 0; i < col; ++i) {
517 if (value_negz_p(H->p[row][i]))
518 continue;
520 /* subtract column col from column i in H and U */
521 for (j = 0; j < H->NbRows; ++j)
522 value_subtract(H->p[j][i], H->p[j][i], H->p[j][col]);
523 for (j = 0; j < U->NbRows; ++j)
524 value_subtract(U->p[j][i], U->p[j][i], U->p[j][col]);
526 /* add row i to row col in Q */
527 for (j = 0; j < Q->NbColumns; ++j)
528 value_addto(Q->p[col][j], Q->p[col][j], Q->p[i][j]);
534 * Returns a full-dimensional polyhedron with the same number
535 * of integer points as P
537 Polyhedron *remove_equalities(Polyhedron *P, unsigned MaxRays)
539 Matrix M;
540 Matrix *T;
541 Polyhedron *Q = Polyhedron_Copy(P);
542 unsigned dim = P->Dimension;
544 if (Q->NbEq == 0)
545 return Q;
547 Q = DomainConstraintSimplify(Q, MaxRays);
548 if (emptyQ2(Q))
549 return Q;
551 Polyhedron_Matrix_View(Q, &M, Q->NbEq);
552 T = compress_variables(&M, 0);
554 if (!T)
555 P = NULL;
556 else {
557 P = Polyhedron_Preimage(Q, T, MaxRays);
558 Matrix_Free(T);
561 Polyhedron_Free(Q);
563 return P;
567 * Returns a full-dimensional polyhedron with the same number
568 * of integer points as P
569 * nvar specifies the number of variables
570 * The remaining dimensions are assumed to be parameters
571 * Destroys P
572 * factor is NbEq x (nparam+2) matrix, containing stride constraints
573 * on the parameters; column nparam is the constant;
574 * column nparam+1 is the stride
576 * if factor is NULL, only remove equalities that don't affect
577 * the number of points
579 Polyhedron *remove_equalities_p(Polyhedron *P, unsigned nvar, Matrix **factor,
580 unsigned MaxRays)
582 Value g;
583 Polyhedron *Q;
584 unsigned dim = P->Dimension;
585 Matrix *m1, *m2, *f;
586 int i, j;
588 if (P->NbEq == 0)
589 return P;
591 m1 = Matrix_Alloc(nvar, nvar);
592 P = DomainConstraintSimplify(P, MaxRays);
593 if (factor) {
594 f = Matrix_Alloc(P->NbEq, dim-nvar+2);
595 *factor = f;
597 value_init(g);
598 for (i = 0, j = 0; i < P->NbEq; ++i) {
599 if (First_Non_Zero(P->Constraint[i]+1, nvar) == -1)
600 continue;
602 Vector_Gcd(P->Constraint[i]+1, nvar, &g);
603 if (!factor && value_notone_p(g))
604 continue;
606 if (factor) {
607 Vector_Copy(P->Constraint[i]+1+nvar, f->p[j], dim-nvar+1);
608 value_assign(f->p[j][dim-nvar+1], g);
611 Vector_Copy(P->Constraint[i]+1, m1->p[j], nvar);
613 ++j;
615 value_clear(g);
617 unimodular_complete(m1, j);
619 m2 = Matrix_Alloc(dim+1-j, dim+1);
620 for (i = 0; i < nvar-j ; ++i)
621 Vector_Copy(m1->p[i+j], m2->p[i], nvar);
622 Matrix_Free(m1);
623 for (i = nvar-j; i <= dim-j; ++i)
624 value_set_si(m2->p[i][i+j], 1);
626 Q = Polyhedron_Image(P, m2, MaxRays);
627 Matrix_Free(m2);
628 Polyhedron_Free(P);
630 return Q;
633 void Line_Length(Polyhedron *P, Value *len)
635 Value tmp, pos, neg;
636 int p = 0, n = 0;
637 int i;
639 assert(P->Dimension == 1);
641 if (P->NbEq > 0) {
642 if (mpz_divisible_p(P->Constraint[0][2], P->Constraint[0][1]))
643 value_set_si(*len, 1);
644 else
645 value_set_si(*len, 0);
646 return;
649 value_init(tmp);
650 value_init(pos);
651 value_init(neg);
653 for (i = 0; i < P->NbConstraints; ++i) {
654 value_oppose(tmp, P->Constraint[i][2]);
655 if (value_pos_p(P->Constraint[i][1])) {
656 mpz_cdiv_q(tmp, tmp, P->Constraint[i][1]);
657 if (!p || value_gt(tmp, pos))
658 value_assign(pos, tmp);
659 p = 1;
660 } else if (value_neg_p(P->Constraint[i][1])) {
661 mpz_fdiv_q(tmp, tmp, P->Constraint[i][1]);
662 if (!n || value_lt(tmp, neg))
663 value_assign(neg, tmp);
664 n = 1;
666 if (n && p) {
667 value_subtract(tmp, neg, pos);
668 value_increment(*len, tmp);
669 } else
670 value_set_si(*len, -1);
673 value_clear(tmp);
674 value_clear(pos);
675 value_clear(neg);
678 /* Update group[k] to the group column k belongs to.
679 * When merging two groups, only the group of the current
680 * group leader is changed. Here we change the group of
681 * the other members to also point to the group that the
682 * old group leader now points to.
684 static void update_group(int *group, int *cnt, int k)
686 int g = group[k];
687 while (cnt[g] == 0)
688 g = group[g];
689 group[k] = g;
693 * Factors the polyhedron P into polyhedra Q_i such that
694 * the number of integer points in P is equal to the product
695 * of the number of integer points in the individual Q_i
697 * If no factors can be found, NULL is returned.
698 * Otherwise, a linked list of the factors is returned.
700 * If there are factors and if T is not NULL, then a matrix will be
701 * returned through T expressing the old variables in terms of the
702 * new variables as they appear in the sequence of factors.
704 * The algorithm works by first computing the Hermite normal form
705 * and then grouping columns linked by one or more constraints together,
706 * where a constraints "links" two or more columns if the constraint
707 * has nonzero coefficients in the columns.
709 Polyhedron* Polyhedron_Factor(Polyhedron *P, unsigned nparam, Matrix **T,
710 unsigned NbMaxRays)
712 int i, j, k;
713 Matrix *M, *H, *Q, *U;
714 int *pos; /* for each column: row position of pivot */
715 int *group; /* group to which a column belongs */
716 int *cnt; /* number of columns in the group */
717 int *rowgroup; /* group to which a constraint belongs */
718 int nvar = P->Dimension - nparam;
719 Polyhedron *F = NULL;
721 if (nvar <= 1)
722 return NULL;
724 NALLOC(pos, nvar);
725 NALLOC(group, nvar);
726 NALLOC(cnt, nvar);
727 NALLOC(rowgroup, P->NbConstraints);
729 M = Matrix_Alloc(P->NbConstraints, nvar);
730 for (i = 0; i < P->NbConstraints; ++i)
731 Vector_Copy(P->Constraint[i]+1, M->p[i], nvar);
732 left_hermite(M, &H, &Q, &U);
733 Matrix_Free(M);
734 Matrix_Free(Q);
736 for (i = 0; i < P->NbConstraints; ++i)
737 rowgroup[i] = -1;
738 for (i = 0, j = 0; i < H->NbColumns; ++i) {
739 for ( ; j < H->NbRows; ++j)
740 if (value_notzero_p(H->p[j][i]))
741 break;
742 pos[i] = j;
744 for (i = 0; i < nvar; ++i) {
745 group[i] = i;
746 cnt[i] = 1;
748 for (i = 0; i < H->NbColumns && cnt[0] < nvar; ++i) {
749 if (pos[i] == H->NbRows)
750 continue; /* A line direction */
751 if (rowgroup[pos[i]] == -1)
752 rowgroup[pos[i]] = i;
753 for (j = pos[i]+1; j < H->NbRows; ++j) {
754 if (value_zero_p(H->p[j][i]))
755 continue;
756 if (rowgroup[j] != -1)
757 continue;
758 rowgroup[j] = group[i];
759 for (k = i+1; k < H->NbColumns && j >= pos[k]; ++k) {
760 update_group(group, cnt, k);
761 update_group(group, cnt, i);
762 if (group[k] != group[i] && value_notzero_p(H->p[j][k])) {
763 assert(cnt[group[k]] != 0);
764 assert(cnt[group[i]] != 0);
765 if (group[i] < group[k]) {
766 cnt[group[i]] += cnt[group[k]];
767 cnt[group[k]] = 0;
768 group[group[k]] = group[i];
769 } else {
770 cnt[group[k]] += cnt[group[i]];
771 cnt[group[i]] = 0;
772 group[group[i]] = group[k];
778 for (i = 1; i < nvar; ++i)
779 update_group(group, cnt, i);
781 if (cnt[0] != nvar) {
782 /* Extract out pure context constraints separately */
783 Polyhedron **next = &F;
784 int tot_d = 0;
785 if (T)
786 *T = Matrix_Alloc(nvar, nvar);
787 for (i = nparam ? -1 : 0; i < nvar; ++i) {
788 int d;
790 if (i == -1) {
791 for (j = 0, k = 0; j < P->NbConstraints; ++j)
792 if (rowgroup[j] == -1) {
793 if (First_Non_Zero(P->Constraint[j]+1+nvar,
794 nparam) == -1)
795 rowgroup[j] = -2;
796 else
797 ++k;
799 if (k == 0)
800 continue;
801 d = 0;
802 } else {
803 if (cnt[i] == 0)
804 continue;
805 d = cnt[i];
806 for (j = 0, k = 0; j < P->NbConstraints; ++j)
807 if (rowgroup[j] >= 0 && group[rowgroup[j]] == i) {
808 rowgroup[j] = i;
809 ++k;
813 if (T)
814 for (j = 0; j < nvar; ++j) {
815 int l, m;
816 for (l = 0, m = 0; m < d; ++l) {
817 if (group[l] != i)
818 continue;
819 value_assign((*T)->p[j][tot_d+m++], U->p[j][l]);
823 M = Matrix_Alloc(k, d+nparam+2);
824 for (j = 0, k = 0; j < P->NbConstraints; ++j) {
825 int l, m;
826 if (rowgroup[j] != i)
827 continue;
828 value_assign(M->p[k][0], P->Constraint[j][0]);
829 for (l = 0, m = 0; m < d; ++l) {
830 if (group[l] != i)
831 continue;
832 value_assign(M->p[k][1+m++], H->p[j][l]);
834 Vector_Copy(P->Constraint[j]+1+nvar, M->p[k]+1+m, nparam+1);
835 ++k;
837 *next = Constraints2Polyhedron(M, NbMaxRays);
838 next = &(*next)->next;
839 Matrix_Free(M);
840 tot_d += d;
843 Matrix_Free(U);
844 Matrix_Free(H);
845 free(pos);
846 free(group);
847 free(cnt);
848 free(rowgroup);
849 return F;
852 /* Computes the intersection of the contexts of a list of factors */
853 Polyhedron *Factor_Context(Polyhedron *F, unsigned nparam, unsigned MaxRays)
855 Polyhedron *Q;
856 Polyhedron *C = NULL;
858 for (Q = F; Q; Q = Q->next) {
859 Polyhedron *QC = Q;
860 Polyhedron *next = Q->next;
861 Q->next = NULL;
863 if (Q->Dimension != nparam)
864 QC = Polyhedron_Project(Q, nparam);
866 if (!C)
867 C = Q == QC ? Polyhedron_Copy(QC) : QC;
868 else {
869 Polyhedron *C2 = C;
870 C = DomainIntersection(C, QC, MaxRays);
871 Polyhedron_Free(C2);
872 if (QC != Q)
873 Polyhedron_Free(QC);
875 Q->next = next;
877 return C;
881 * Project on final dim dimensions
883 Polyhedron* Polyhedron_Project(Polyhedron *P, int dim)
885 int i;
886 int remove = P->Dimension - dim;
887 Matrix *T;
888 Polyhedron *I;
890 if (P->Dimension == dim)
891 return Polyhedron_Copy(P);
893 T = Matrix_Alloc(dim+1, P->Dimension+1);
894 for (i = 0; i < dim+1; ++i)
895 value_set_si(T->p[i][i+remove], 1);
896 I = Polyhedron_Image(P, T, P->NbConstraints);
897 Matrix_Free(T);
898 return I;
901 /* Constructs a new constraint that ensures that
902 * the first constraint is (strictly) smaller than
903 * the second.
905 static void smaller_constraint(Value *a, Value *b, Value *c, int pos, int shift,
906 int len, int strict, Value *tmp)
908 value_oppose(*tmp, b[pos+1]);
909 value_set_si(c[0], 1);
910 Vector_Combine(a+1+shift, b+1+shift, c+1, *tmp, a[pos+1], len-shift-1);
911 if (strict)
912 value_decrement(c[len-shift-1], c[len-shift-1]);
913 ConstraintSimplify(c, c, len-shift, tmp);
917 /* For each pair of lower and upper bounds on the first variable,
918 * calls fn with the set of constraints on the remaining variables
919 * where these bounds are active, i.e., (stricly) larger/smaller than
920 * the other lower/upper bounds, the lower and upper bound and the
921 * call back data.
923 * If the first variable is equal to an affine combination of the
924 * other variables then fn is called with both lower and upper
925 * pointing to the corresponding equality.
927 * If there is no lower (or upper) bound, then NULL is passed
928 * as the corresponding bound.
930 void for_each_lower_upper_bound(Polyhedron *P,
931 for_each_lower_upper_bound_init init,
932 for_each_lower_upper_bound_fn fn,
933 void *cb_data)
935 unsigned dim = P->Dimension;
936 Matrix *M;
937 int *pos;
938 int i, j, p, n, z;
939 int k, l, k2, l2, q;
940 Value g;
942 if (value_zero_p(P->Constraint[0][0]) &&
943 value_notzero_p(P->Constraint[0][1])) {
944 M = Matrix_Alloc(P->NbConstraints-1, dim-1+2);
945 for (i = 1; i < P->NbConstraints; ++i) {
946 value_assign(M->p[i-1][0], P->Constraint[i][0]);
947 Vector_Copy(P->Constraint[i]+2, M->p[i-1]+1, dim);
949 if (init)
950 init(1, cb_data);
951 fn(M, P->Constraint[0], P->Constraint[0], cb_data);
952 Matrix_Free(M);
953 return;
956 value_init(g);
957 pos = ALLOCN(int, P->NbConstraints);
959 for (i = 0, z = 0; i < P->NbConstraints; ++i)
960 if (value_zero_p(P->Constraint[i][1]))
961 pos[P->NbConstraints-1 - z++] = i;
962 /* put those with positive coefficients first; number: p */
963 for (i = 0, p = 0, n = P->NbConstraints-z-1; i < P->NbConstraints; ++i)
964 if (value_pos_p(P->Constraint[i][1]))
965 pos[p++] = i;
966 else if (value_neg_p(P->Constraint[i][1]))
967 pos[n--] = i;
968 n = P->NbConstraints-z-p;
970 if (init)
971 init(p*n, cb_data);
973 M = Matrix_Alloc((p ? p-1 : 0) + (n ? n-1 : 0) + z + 1, dim-1+2);
974 for (i = 0; i < z; ++i) {
975 value_assign(M->p[i][0], P->Constraint[pos[P->NbConstraints-1 - i]][0]);
976 Vector_Copy(P->Constraint[pos[P->NbConstraints-1 - i]]+2,
977 M->p[i]+1, dim);
979 for (k = p ? 0 : -1; k < p; ++k) {
980 for (k2 = 0; k2 < p; ++k2) {
981 if (k2 == k)
982 continue;
983 q = 1 + z + k2 - (k2 > k);
984 smaller_constraint(
985 P->Constraint[pos[k]],
986 P->Constraint[pos[k2]],
987 M->p[q], 0, 1, dim+2, k2 > k, &g);
989 for (l = n ? p : p-1; l < p+n; ++l) {
990 Value *lower;
991 Value *upper;
992 for (l2 = p; l2 < p+n; ++l2) {
993 if (l2 == l)
994 continue;
995 q = 1 + z + l2-1 - (l2 > l);
996 smaller_constraint(
997 P->Constraint[pos[l2]],
998 P->Constraint[pos[l]],
999 M->p[q], 0, 1, dim+2, l2 > l, &g);
1001 if (p && n)
1002 smaller_constraint(P->Constraint[pos[k]],
1003 P->Constraint[pos[l]],
1004 M->p[z], 0, 1, dim+2, 0, &g);
1005 lower = p ? P->Constraint[pos[k]] : NULL;
1006 upper = n ? P->Constraint[pos[l]] : NULL;
1007 fn(M, lower, upper, cb_data);
1010 Matrix_Free(M);
1012 free(pos);
1013 value_clear(g);
1016 struct section { Polyhedron * D; evalue E; };
1018 struct PLL_data {
1019 int nd;
1020 unsigned MaxRays;
1021 Polyhedron *C;
1022 evalue mone;
1023 struct section *s;
1026 static void PLL_init(unsigned n, void *cb_data)
1028 struct PLL_data *data = (struct PLL_data *)cb_data;
1030 data->s = ALLOCN(struct section, n);
1033 /* Computes ceil(-coef/abs(d)) */
1034 static evalue* bv_ceil3(Value *coef, int len, Value d, Polyhedron *P)
1036 Value t;
1037 evalue *EP, *f;
1038 Vector *val = Vector_Alloc(len);
1040 value_init(t);
1041 Vector_Oppose(coef, val->p, len);
1042 value_absolute(t, d);
1044 EP = ceiling(val->p, t, len-1, P);
1046 value_clear(t);
1047 Vector_Free(val);
1049 return EP;
1052 static void PLL_cb(Matrix *M, Value *lower, Value *upper, void *cb_data)
1054 struct PLL_data *data = (struct PLL_data *)cb_data;
1055 unsigned dim = M->NbColumns-1;
1056 Matrix *M2;
1057 Polyhedron *T;
1058 evalue *L, *U;
1060 assert(lower);
1061 assert(upper);
1063 M2 = Matrix_Copy(M);
1064 T = Constraints2Polyhedron(M2, data->MaxRays);
1065 Matrix_Free(M2);
1066 data->s[data->nd].D = DomainIntersection(T, data->C, data->MaxRays);
1067 Domain_Free(T);
1069 POL_ENSURE_VERTICES(data->s[data->nd].D);
1070 if (emptyQ(data->s[data->nd].D)) {
1071 Polyhedron_Free(data->s[data->nd].D);
1072 return;
1074 L = bv_ceil3(lower+1+1, dim-1+1, lower[0+1], data->s[data->nd].D);
1075 U = bv_ceil3(upper+1+1, dim-1+1, upper[0+1], data->s[data->nd].D);
1076 eadd(L, U);
1077 eadd(&data->mone, U);
1078 emul(&data->mone, U);
1079 data->s[data->nd].E = *U;
1080 evalue_free(L);
1081 free(U);
1082 ++data->nd;
1085 static evalue *ParamLine_Length_mod(Polyhedron *P, Polyhedron *C, unsigned MaxRays)
1087 unsigned dim = P->Dimension;
1088 unsigned nvar = dim - C->Dimension;
1089 struct PLL_data data;
1090 evalue *F;
1091 int k;
1093 assert(nvar == 1);
1095 value_init(data.mone.d);
1096 evalue_set_si(&data.mone, -1, 1);
1098 data.nd = 0;
1099 data.MaxRays = MaxRays;
1100 data.C = C;
1101 for_each_lower_upper_bound(P, PLL_init, PLL_cb, &data);
1103 free_evalue_refs(&data.mone);
1105 if (data.nd == 0) {
1106 free(data.s);
1107 return evalue_zero();
1110 F = ALLOC(evalue);
1111 value_init(F->d);
1112 value_set_si(F->d, 0);
1113 F->x.p = new_enode(partition, 2*data.nd, dim-nvar);
1114 for (k = 0; k < data.nd; ++k) {
1115 EVALUE_SET_DOMAIN(F->x.p->arr[2*k], data.s[k].D);
1116 value_clear(F->x.p->arr[2*k+1].d);
1117 F->x.p->arr[2*k+1] = data.s[k].E;
1119 free(data.s);
1121 return F;
1124 evalue* ParamLine_Length(Polyhedron *P, Polyhedron *C,
1125 struct barvinok_options *options)
1127 evalue* tmp;
1128 tmp = ParamLine_Length_mod(P, C, options->MaxRays);
1129 if (options->lookup_table) {
1130 evalue_mod2table(tmp, C->Dimension);
1131 reduce_evalue(tmp);
1133 return tmp;
1136 Bool isIdentity(Matrix *M)
1138 unsigned i, j;
1139 if (M->NbRows != M->NbColumns)
1140 return False;
1142 for (i = 0;i < M->NbRows; i ++)
1143 for (j = 0; j < M->NbColumns; j ++)
1144 if (i == j) {
1145 if(value_notone_p(M->p[i][j]))
1146 return False;
1147 } else {
1148 if(value_notzero_p(M->p[i][j]))
1149 return False;
1151 return True;
1154 void Param_Polyhedron_Print(FILE* DST, Param_Polyhedron *PP,
1155 const char **param_names)
1157 Param_Domain *P;
1158 Param_Vertices *V;
1160 for(P=PP->D;P;P=P->next) {
1162 /* prints current val. dom. */
1163 fprintf(DST, "---------------------------------------\n");
1164 fprintf(DST, "Domain :\n");
1165 Print_Domain(DST, P->Domain, param_names);
1167 /* scan the vertices */
1168 fprintf(DST, "Vertices :\n");
1169 FORALL_PVertex_in_ParamPolyhedron(V,P,PP) {
1171 /* prints each vertex */
1172 Print_Vertex(DST, V->Vertex, param_names);
1173 fprintf(DST, "\n");
1175 END_FORALL_PVertex_in_ParamPolyhedron;
1179 void Enumeration_Print(FILE *Dst, Enumeration *en, const char **params)
1181 for (; en; en = en->next) {
1182 Print_Domain(Dst, en->ValidityDomain, params);
1183 print_evalue(Dst, &en->EP, params);
1187 void Enumeration_Free(Enumeration *en)
1189 Enumeration *ee;
1191 while( en )
1193 free_evalue_refs( &(en->EP) );
1194 Domain_Free( en->ValidityDomain );
1195 ee = en ->next;
1196 free( en );
1197 en = ee;
1201 void Enumeration_mod2table(Enumeration *en, unsigned nparam)
1203 for (; en; en = en->next) {
1204 evalue_mod2table(&en->EP, nparam);
1205 reduce_evalue(&en->EP);
1209 size_t Enumeration_size(Enumeration *en)
1211 size_t s = 0;
1213 for (; en; en = en->next) {
1214 s += domain_size(en->ValidityDomain);
1215 s += evalue_size(&en->EP);
1217 return s;
1220 /* Check whether every set in D2 is included in some set of D1 */
1221 int DomainIncludes(Polyhedron *D1, Polyhedron *D2)
1223 for ( ; D2; D2 = D2->next) {
1224 Polyhedron *P1;
1225 for (P1 = D1; P1; P1 = P1->next)
1226 if (PolyhedronIncludes(P1, D2))
1227 break;
1228 if (!P1)
1229 return 0;
1231 return 1;
1234 int line_minmax(Polyhedron *I, Value *min, Value *max)
1236 int i;
1238 if (I->NbEq >= 1) {
1239 value_oppose(I->Constraint[0][2], I->Constraint[0][2]);
1240 /* There should never be a remainder here */
1241 if (value_pos_p(I->Constraint[0][1]))
1242 mpz_fdiv_q(*min, I->Constraint[0][2], I->Constraint[0][1]);
1243 else
1244 mpz_fdiv_q(*min, I->Constraint[0][2], I->Constraint[0][1]);
1245 value_assign(*max, *min);
1246 } else for (i = 0; i < I->NbConstraints; ++i) {
1247 if (value_zero_p(I->Constraint[i][1])) {
1248 Polyhedron_Free(I);
1249 return 0;
1252 value_oppose(I->Constraint[i][2], I->Constraint[i][2]);
1253 if (value_pos_p(I->Constraint[i][1]))
1254 mpz_cdiv_q(*min, I->Constraint[i][2], I->Constraint[i][1]);
1255 else
1256 mpz_fdiv_q(*max, I->Constraint[i][2], I->Constraint[i][1]);
1258 Polyhedron_Free(I);
1259 return 1;
1262 int DomainContains(Polyhedron *P, Value *list_args, int len,
1263 unsigned MaxRays, int set)
1265 int i;
1266 Value m;
1268 if (P->Dimension == len)
1269 return in_domain(P, list_args);
1271 assert(set); // assume list_args is large enough
1272 assert((P->Dimension - len) % 2 == 0);
1273 value_init(m);
1274 for (i = 0; i < P->Dimension - len; i += 2) {
1275 int j, k;
1276 for (j = 0 ; j < P->NbEq; ++j)
1277 if (value_notzero_p(P->Constraint[j][1+len+i]))
1278 break;
1279 assert(j < P->NbEq);
1280 value_absolute(m, P->Constraint[j][1+len+i]);
1281 k = First_Non_Zero(P->Constraint[j]+1, len);
1282 assert(k != -1);
1283 assert(First_Non_Zero(P->Constraint[j]+1+k+1, len - k - 1) == -1);
1284 mpz_fdiv_q(list_args[len+i], list_args[k], m);
1285 mpz_fdiv_r(list_args[len+i+1], list_args[k], m);
1287 value_clear(m);
1289 return in_domain(P, list_args);
1292 Polyhedron *DomainConcat(Polyhedron *head, Polyhedron *tail)
1294 Polyhedron *S;
1295 if (!head)
1296 return tail;
1297 for (S = head; S->next; S = S->next)
1299 S->next = tail;
1300 return head;
1303 evalue *barvinok_lexsmaller_ev(Polyhedron *P, Polyhedron *D, unsigned dim,
1304 Polyhedron *C, unsigned MaxRays)
1306 evalue *ranking;
1307 Polyhedron *RC, *RD, *Q;
1308 unsigned nparam = dim + C->Dimension;
1309 unsigned exist;
1310 Polyhedron *CA;
1312 RC = LexSmaller(P, D, dim, C, MaxRays);
1313 RD = RC->next;
1314 RC->next = NULL;
1316 exist = RD->Dimension - nparam - dim;
1317 CA = align_context(RC, RD->Dimension, MaxRays);
1318 Q = DomainIntersection(RD, CA, MaxRays);
1319 Polyhedron_Free(CA);
1320 Domain_Free(RD);
1321 Polyhedron_Free(RC);
1322 RD = Q;
1324 for (Q = RD; Q; Q = Q->next) {
1325 evalue *t;
1326 Polyhedron *next = Q->next;
1327 Q->next = 0;
1329 t = barvinok_enumerate_e(Q, exist, nparam, MaxRays);
1331 if (Q == RD)
1332 ranking = t;
1333 else {
1334 eadd(t, ranking);
1335 evalue_free(t);
1338 Q->next = next;
1341 Domain_Free(RD);
1343 return ranking;
1346 Enumeration *barvinok_lexsmaller(Polyhedron *P, Polyhedron *D, unsigned dim,
1347 Polyhedron *C, unsigned MaxRays)
1349 evalue *EP = barvinok_lexsmaller_ev(P, D, dim, C, MaxRays);
1351 return partition2enumeration(EP);
1354 /* "align" matrix to have nrows by inserting
1355 * the necessary number of rows and an equal number of columns in front
1357 Matrix *align_matrix(Matrix *M, int nrows)
1359 int i;
1360 int newrows = nrows - M->NbRows;
1361 Matrix *M2 = Matrix_Alloc(nrows, newrows + M->NbColumns);
1362 for (i = 0; i < newrows; ++i)
1363 value_set_si(M2->p[i][i], 1);
1364 for (i = 0; i < M->NbRows; ++i)
1365 Vector_Copy(M->p[i], M2->p[newrows+i]+newrows, M->NbColumns);
1366 return M2;
1369 static void print_varlist(FILE *out, int n, char **names)
1371 int i;
1372 fprintf(out, "[");
1373 for (i = 0; i < n; ++i) {
1374 if (i)
1375 fprintf(out, ",");
1376 fprintf(out, "%s", names[i]);
1378 fprintf(out, "]");
1381 static void print_term(FILE *out, Value v, int pos, int dim, int nparam,
1382 char **iter_names, char **param_names, int *first)
1384 if (value_zero_p(v)) {
1385 if (first && *first && pos >= dim + nparam)
1386 fprintf(out, "0");
1387 return;
1390 if (first) {
1391 if (!*first && value_pos_p(v))
1392 fprintf(out, "+");
1393 *first = 0;
1395 if (pos < dim + nparam) {
1396 if (value_mone_p(v))
1397 fprintf(out, "-");
1398 else if (!value_one_p(v))
1399 value_print(out, VALUE_FMT, v);
1400 if (pos < dim)
1401 fprintf(out, "%s", iter_names[pos]);
1402 else
1403 fprintf(out, "%s", param_names[pos-dim]);
1404 } else
1405 value_print(out, VALUE_FMT, v);
1408 char **util_generate_names(int n, const char *prefix)
1410 int i;
1411 int len = (prefix ? strlen(prefix) : 0) + 10;
1412 char **names = ALLOCN(char*, n);
1413 if (!names) {
1414 fprintf(stderr, "ERROR: memory overflow.\n");
1415 exit(1);
1417 for (i = 0; i < n; ++i) {
1418 names[i] = ALLOCN(char, len);
1419 if (!names[i]) {
1420 fprintf(stderr, "ERROR: memory overflow.\n");
1421 exit(1);
1423 if (!prefix)
1424 snprintf(names[i], len, "%d", i);
1425 else
1426 snprintf(names[i], len, "%s%d", prefix, i);
1429 return names;
1432 void util_free_names(int n, char **names)
1434 int i;
1435 for (i = 0; i < n; ++i)
1436 free(names[i]);
1437 free(names);
1440 void Polyhedron_pprint(FILE *out, Polyhedron *P, int dim, int nparam,
1441 char **iter_names, char **param_names)
1443 int i, j;
1444 Value tmp;
1446 assert(dim + nparam == P->Dimension);
1448 value_init(tmp);
1450 fprintf(out, "{ ");
1451 if (nparam) {
1452 print_varlist(out, nparam, param_names);
1453 fprintf(out, " -> ");
1455 print_varlist(out, dim, iter_names);
1456 fprintf(out, " : ");
1458 if (emptyQ2(P))
1459 fprintf(out, "FALSE");
1460 else for (i = 0; i < P->NbConstraints; ++i) {
1461 int first = 1;
1462 int v = First_Non_Zero(P->Constraint[i]+1, P->Dimension);
1463 if (v == -1 && value_pos_p(P->Constraint[i][0]))
1464 continue;
1465 if (i)
1466 fprintf(out, " && ");
1467 if (v == -1 && value_notzero_p(P->Constraint[i][1+P->Dimension]))
1468 fprintf(out, "FALSE");
1469 else if (value_pos_p(P->Constraint[i][v+1])) {
1470 print_term(out, P->Constraint[i][v+1], v, dim, nparam,
1471 iter_names, param_names, NULL);
1472 if (value_zero_p(P->Constraint[i][0]))
1473 fprintf(out, " = ");
1474 else
1475 fprintf(out, " >= ");
1476 for (j = v+1; j <= dim+nparam; ++j) {
1477 value_oppose(tmp, P->Constraint[i][1+j]);
1478 print_term(out, tmp, j, dim, nparam,
1479 iter_names, param_names, &first);
1481 } else {
1482 value_oppose(tmp, P->Constraint[i][1+v]);
1483 print_term(out, tmp, v, dim, nparam,
1484 iter_names, param_names, NULL);
1485 fprintf(out, " <= ");
1486 for (j = v+1; j <= dim+nparam; ++j)
1487 print_term(out, P->Constraint[i][1+j], j, dim, nparam,
1488 iter_names, param_names, &first);
1492 fprintf(out, " }\n");
1494 value_clear(tmp);
1497 /* Construct a cone over P with P placed at x_d = 1, with
1498 * x_d the coordinate of an extra dimension
1500 * It's probably a mistake to depend so much on the internal
1501 * representation. We should probably simply compute the
1502 * vertices/facets first.
1504 Polyhedron *Cone_over_Polyhedron(Polyhedron *P)
1506 unsigned NbConstraints = 0;
1507 unsigned NbRays = 0;
1508 Polyhedron *C;
1509 int i;
1511 if (POL_HAS(P, POL_INEQUALITIES))
1512 NbConstraints = P->NbConstraints + 1;
1513 if (POL_HAS(P, POL_POINTS))
1514 NbRays = P->NbRays + 1;
1516 C = Polyhedron_Alloc(P->Dimension+1, NbConstraints, NbRays);
1517 if (POL_HAS(P, POL_INEQUALITIES)) {
1518 C->NbEq = P->NbEq;
1519 for (i = 0; i < P->NbConstraints; ++i)
1520 Vector_Copy(P->Constraint[i], C->Constraint[i], P->Dimension+2);
1521 /* n >= 0 */
1522 value_set_si(C->Constraint[P->NbConstraints][0], 1);
1523 value_set_si(C->Constraint[P->NbConstraints][1+P->Dimension], 1);
1525 if (POL_HAS(P, POL_POINTS)) {
1526 C->NbBid = P->NbBid;
1527 for (i = 0; i < P->NbRays; ++i)
1528 Vector_Copy(P->Ray[i], C->Ray[i], P->Dimension+2);
1529 /* vertex 0 */
1530 value_set_si(C->Ray[P->NbRays][0], 1);
1531 value_set_si(C->Ray[P->NbRays][1+C->Dimension], 1);
1533 POL_SET(C, POL_VALID);
1534 if (POL_HAS(P, POL_INEQUALITIES))
1535 POL_SET(C, POL_INEQUALITIES);
1536 if (POL_HAS(P, POL_POINTS))
1537 POL_SET(C, POL_POINTS);
1538 if (POL_HAS(P, POL_VERTICES))
1539 POL_SET(C, POL_VERTICES);
1540 return C;
1543 /* Returns a (dim+nparam+1)x((dim-n)+nparam+1) matrix
1544 * mapping the transformed subspace back to the original space.
1545 * n is the number of equalities involving the variables
1546 * (i.e., not purely the parameters).
1547 * The remaining n coordinates in the transformed space would
1548 * have constant (parametric) values and are therefore not
1549 * included in the variables of the new space.
1551 Matrix *compress_variables(Matrix *Equalities, unsigned nparam)
1553 unsigned dim = (Equalities->NbColumns-2) - nparam;
1554 Matrix *M, *H, *Q, *U, *C, *ratH, *invH, *Ul, *T1, *T2, *T;
1555 Value mone;
1556 int n, i, j;
1557 int ok;
1559 for (n = 0; n < Equalities->NbRows; ++n)
1560 if (First_Non_Zero(Equalities->p[n]+1, dim) == -1)
1561 break;
1562 if (n == 0)
1563 return Identity(dim+nparam+1);
1564 value_init(mone);
1565 value_set_si(mone, -1);
1566 M = Matrix_Alloc(n, dim);
1567 C = Matrix_Alloc(n+1, nparam+1);
1568 for (i = 0; i < n; ++i) {
1569 Vector_Copy(Equalities->p[i]+1, M->p[i], dim);
1570 Vector_Scale(Equalities->p[i]+1+dim, C->p[i], mone, nparam+1);
1572 value_set_si(C->p[n][nparam], 1);
1573 left_hermite(M, &H, &Q, &U);
1574 Matrix_Free(M);
1575 Matrix_Free(Q);
1576 value_clear(mone);
1578 ratH = Matrix_Alloc(n+1, n+1);
1579 invH = Matrix_Alloc(n+1, n+1);
1580 for (i = 0; i < n; ++i)
1581 Vector_Copy(H->p[i], ratH->p[i], n);
1582 value_set_si(ratH->p[n][n], 1);
1583 ok = Matrix_Inverse(ratH, invH);
1584 assert(ok);
1585 Matrix_Free(H);
1586 Matrix_Free(ratH);
1587 T1 = Matrix_Alloc(n+1, nparam+1);
1588 Matrix_Product(invH, C, T1);
1589 Matrix_Free(C);
1590 Matrix_Free(invH);
1591 if (value_notone_p(T1->p[n][nparam])) {
1592 for (i = 0; i < n; ++i) {
1593 if (!mpz_divisible_p(T1->p[i][nparam], T1->p[n][nparam])) {
1594 Matrix_Free(T1);
1595 Matrix_Free(U);
1596 return NULL;
1598 /* compress_params should have taken care of this */
1599 for (j = 0; j < nparam; ++j)
1600 assert(mpz_divisible_p(T1->p[i][j], T1->p[n][nparam]));
1601 Vector_AntiScale(T1->p[i], T1->p[i], T1->p[n][nparam], nparam+1);
1603 value_set_si(T1->p[n][nparam], 1);
1605 Ul = Matrix_Alloc(dim+1, n+1);
1606 for (i = 0; i < dim; ++i)
1607 Vector_Copy(U->p[i], Ul->p[i], n);
1608 value_set_si(Ul->p[dim][n], 1);
1609 T2 = Matrix_Alloc(dim+1, nparam+1);
1610 Matrix_Product(Ul, T1, T2);
1611 Matrix_Free(Ul);
1612 Matrix_Free(T1);
1614 T = Matrix_Alloc(dim+nparam+1, (dim-n)+nparam+1);
1615 for (i = 0; i < dim; ++i) {
1616 Vector_Copy(U->p[i]+n, T->p[i], dim-n);
1617 Vector_Copy(T2->p[i], T->p[i]+dim-n, nparam+1);
1619 for (i = 0; i < nparam+1; ++i)
1620 value_set_si(T->p[dim+i][(dim-n)+i], 1);
1621 assert(value_one_p(T2->p[dim][nparam]));
1622 Matrix_Free(U);
1623 Matrix_Free(T2);
1625 return T;
1628 /* Computes the left inverse of an affine embedding M and, if Eq is not NULL,
1629 * the equalities that define the affine subspace onto which M maps
1630 * its argument.
1632 Matrix *left_inverse(Matrix *M, Matrix **Eq)
1634 int i, ok;
1635 Matrix *L, *H, *Q, *U, *ratH, *invH, *Ut, *inv;
1636 Vector *t;
1638 if (M->NbColumns == 1) {
1639 inv = Matrix_Alloc(1, M->NbRows);
1640 value_set_si(inv->p[0][M->NbRows-1], 1);
1641 if (Eq) {
1642 *Eq = Matrix_Alloc(M->NbRows-1, 1+(M->NbRows-1)+1);
1643 for (i = 0; i < M->NbRows-1; ++i) {
1644 value_oppose((*Eq)->p[i][1+i], M->p[M->NbRows-1][0]);
1645 value_assign((*Eq)->p[i][1+(M->NbRows-1)], M->p[i][0]);
1648 return inv;
1650 if (Eq)
1651 *Eq = NULL;
1652 L = Matrix_Alloc(M->NbRows-1, M->NbColumns-1);
1653 for (i = 0; i < L->NbRows; ++i)
1654 Vector_Copy(M->p[i], L->p[i], L->NbColumns);
1655 right_hermite(L, &H, &U, &Q);
1656 Matrix_Free(L);
1657 Matrix_Free(Q);
1658 t = Vector_Alloc(U->NbColumns);
1659 for (i = 0; i < U->NbColumns; ++i)
1660 value_oppose(t->p[i], M->p[i][M->NbColumns-1]);
1661 if (Eq) {
1662 *Eq = Matrix_Alloc(H->NbRows - H->NbColumns, 2 + U->NbColumns);
1663 for (i = 0; i < H->NbRows - H->NbColumns; ++i) {
1664 Vector_Copy(U->p[H->NbColumns+i], (*Eq)->p[i]+1, U->NbColumns);
1665 Inner_Product(U->p[H->NbColumns+i], t->p, U->NbColumns,
1666 (*Eq)->p[i]+1+U->NbColumns);
1669 ratH = Matrix_Alloc(H->NbColumns+1, H->NbColumns+1);
1670 invH = Matrix_Alloc(H->NbColumns+1, H->NbColumns+1);
1671 for (i = 0; i < H->NbColumns; ++i)
1672 Vector_Copy(H->p[i], ratH->p[i], H->NbColumns);
1673 value_set_si(ratH->p[ratH->NbRows-1][ratH->NbColumns-1], 1);
1674 Matrix_Free(H);
1675 ok = Matrix_Inverse(ratH, invH);
1676 assert(ok);
1677 Matrix_Free(ratH);
1678 Ut = Matrix_Alloc(invH->NbRows, U->NbColumns+1);
1679 for (i = 0; i < Ut->NbRows-1; ++i) {
1680 Vector_Copy(U->p[i], Ut->p[i], U->NbColumns);
1681 Inner_Product(U->p[i], t->p, U->NbColumns, &Ut->p[i][Ut->NbColumns-1]);
1683 Matrix_Free(U);
1684 Vector_Free(t);
1685 value_set_si(Ut->p[Ut->NbRows-1][Ut->NbColumns-1], 1);
1686 inv = Matrix_Alloc(invH->NbRows, Ut->NbColumns);
1687 Matrix_Product(invH, Ut, inv);
1688 Matrix_Free(Ut);
1689 Matrix_Free(invH);
1690 return inv;
1693 /* Check whether all rays are revlex positive in the parameters
1695 int Polyhedron_has_revlex_positive_rays(Polyhedron *P, unsigned nparam)
1697 int r;
1698 for (r = 0; r < P->NbRays; ++r) {
1699 int i;
1700 if (value_notzero_p(P->Ray[r][P->Dimension+1]))
1701 continue;
1702 for (i = P->Dimension-1; i >= P->Dimension-nparam; --i) {
1703 if (value_neg_p(P->Ray[r][i+1]))
1704 return 0;
1705 if (value_pos_p(P->Ray[r][i+1]))
1706 break;
1708 /* A ray independent of the parameters */
1709 if (i < P->Dimension-nparam)
1710 return 0;
1712 return 1;
1715 static Polyhedron *Recession_Cone(Polyhedron *P, unsigned nparam, unsigned MaxRays)
1717 int i;
1718 unsigned nvar = P->Dimension - nparam;
1719 Matrix *M = Matrix_Alloc(P->NbConstraints, 1 + nvar + 1);
1720 Polyhedron *R;
1721 for (i = 0; i < P->NbConstraints; ++i)
1722 Vector_Copy(P->Constraint[i], M->p[i], 1+nvar);
1723 R = Constraints2Polyhedron(M, MaxRays);
1724 Matrix_Free(M);
1725 return R;
1728 int Polyhedron_is_unbounded(Polyhedron *P, unsigned nparam, unsigned MaxRays)
1730 int i;
1731 int is_unbounded;
1732 Polyhedron *R = Recession_Cone(P, nparam, MaxRays);
1733 POL_ENSURE_VERTICES(R);
1734 if (R->NbBid == 0)
1735 for (i = 0; i < R->NbRays; ++i)
1736 if (value_zero_p(R->Ray[i][1+R->Dimension]))
1737 break;
1738 is_unbounded = R->NbBid > 0 || i < R->NbRays;
1739 Polyhedron_Free(R);
1740 return is_unbounded;
1743 static void SwapColumns(Value **V, int n, int i, int j)
1745 int r;
1747 for (r = 0; r < n; ++r)
1748 value_swap(V[r][i], V[r][j]);
1751 void Polyhedron_ExchangeColumns(Polyhedron *P, int Column1, int Column2)
1753 SwapColumns(P->Constraint, P->NbConstraints, Column1, Column2);
1754 SwapColumns(P->Ray, P->NbRays, Column1, Column2);
1755 if (P->NbEq) {
1756 Matrix M;
1757 Polyhedron_Matrix_View(P, &M, P->NbConstraints);
1758 Gauss(&M, P->NbEq, P->Dimension+1);
1762 /* perform transposition inline; assumes M is a square matrix */
1763 void Matrix_Transposition(Matrix *M)
1765 int i, j;
1767 assert(M->NbRows == M->NbColumns);
1768 for (i = 0; i < M->NbRows; ++i)
1769 for (j = i+1; j < M->NbColumns; ++j)
1770 value_swap(M->p[i][j], M->p[j][i]);
1773 /* Matrix "view" of first rows rows */
1774 void Polyhedron_Matrix_View(Polyhedron *P, Matrix *M, unsigned rows)
1776 M->NbRows = rows;
1777 M->NbColumns = P->Dimension+2;
1778 M->p_Init = P->p_Init;
1779 M->p = P->Constraint;
1782 int Last_Non_Zero(Value *p, unsigned len)
1784 int i;
1786 for (i = len - 1; i >= 0; --i)
1787 if (value_notzero_p(p[i]))
1788 return i;
1790 return -1;