bound.c: drop redundant include
[barvinok.git] / util.c
blob2900ee5bc4a3e3840517653fc7b4a901b4ff0b27
1 #include <stdlib.h>
2 #include <string.h>
3 #include <assert.h>
4 #include <isl/ctx.h>
5 #include <isl/val.h>
6 #include <isl/val_gmp.h>
7 #include <isl/space.h>
8 #include <isl/set.h>
9 #include <isl_set_polylib.h>
10 #include <barvinok/polylib.h>
11 #include <barvinok/util.h>
12 #include <barvinok/options.h>
13 #include <polylib/ranking.h>
14 #include "config.h"
15 #include "lattice_point.h"
17 #define ALLOC(type) (type*)malloc(sizeof(type))
18 #define ALLOCN(type,n) (type*)malloc((n) * sizeof(type))
20 #ifdef __GNUC__
21 #define NALLOC(p,n) p = (typeof(p))malloc((n) * sizeof(*p))
22 #else
23 #define NALLOC(p,n) p = (void *)malloc((n) * sizeof(*p))
24 #endif
26 void manual_count(Polyhedron *P, Value* result)
28 isl_ctx *ctx = isl_ctx_alloc();
29 isl_space *dim;
30 isl_set *set;
31 isl_val *v;
32 int nvar = P->Dimension;
34 dim = isl_space_set_alloc(ctx, 0, nvar);
35 set = isl_set_new_from_polylib(P, dim);
37 v = isl_set_count_val(set);
38 isl_val_get_num_gmp(v, *result);
39 isl_val_free(v);
41 isl_set_free(set);
42 isl_ctx_free(ctx);
44 assert(v);
47 #include <barvinok/evalue.h>
48 #include <barvinok/util.h>
49 #include <barvinok/barvinok.h>
51 /* Return random value between 0 and max-1 inclusive
53 int random_int(int max) {
54 return (int) (((double)(max))*rand()/(RAND_MAX+1.0));
57 Polyhedron *Polyhedron_Read(unsigned MaxRays)
59 int vertices = 0;
60 unsigned NbRows, NbColumns;
61 Matrix *M;
62 Polyhedron *P;
63 char s[128];
65 while (fgets(s, sizeof(s), stdin)) {
66 if (*s == '#')
67 continue;
68 if (strncasecmp(s, "vertices", sizeof("vertices")-1) == 0)
69 vertices = 1;
70 if (sscanf(s, "%u %u", &NbRows, &NbColumns) == 2)
71 break;
73 if (feof(stdin))
74 return NULL;
75 M = Matrix_Alloc(NbRows,NbColumns);
76 Matrix_Read_Input(M);
77 if (vertices)
78 P = Rays2Polyhedron(M, MaxRays);
79 else
80 P = Constraints2Polyhedron(M, MaxRays);
81 Matrix_Free(M);
82 return P;
85 /* Inplace polarization
87 void Polyhedron_Polarize(Polyhedron *P)
89 unsigned NbRows;
90 int i;
91 Value **q;
93 POL_ENSURE_FACETS(P);
94 POL_ENSURE_VERTICES(P);
95 NbRows = P->NbConstraints + P->NbRays;
96 q = (Value **)malloc(NbRows * sizeof(Value *));
97 assert(q);
98 for (i = 0; i < P->NbRays; ++i)
99 q[i] = P->Ray[i];
100 for (; i < NbRows; ++i)
101 q[i] = P->Constraint[i-P->NbRays];
102 P->NbConstraints = NbRows - P->NbConstraints;
103 P->NbRays = NbRows - P->NbRays;
104 free(P->Constraint);
105 P->Constraint = q;
106 P->Ray = q + P->NbConstraints;
110 * Rather general polar
111 * We can optimize it significantly if we assume that
112 * P includes zero
114 * Also, we calculate the polar as defined in Schrijver
115 * The opposite should probably work as well and would
116 * eliminate the need for multiplying by -1
118 Polyhedron* Polyhedron_Polar(Polyhedron *P, unsigned NbMaxRays)
120 int i;
121 Value mone;
122 unsigned dim = P->Dimension + 2;
123 Matrix *M = Matrix_Alloc(P->NbRays, dim);
125 assert(M);
126 value_init(mone);
127 value_set_si(mone, -1);
128 for (i = 0; i < P->NbRays; ++i) {
129 Vector_Scale(P->Ray[i], M->p[i], mone, dim);
130 value_multiply(M->p[i][0], M->p[i][0], mone);
131 value_multiply(M->p[i][dim-1], M->p[i][dim-1], mone);
133 P = Constraints2Polyhedron(M, NbMaxRays);
134 assert(P);
135 Matrix_Free(M);
136 value_clear(mone);
137 return P;
141 * Returns the supporting cone of P at the vertex with index v
143 Polyhedron* supporting_cone(Polyhedron *P, int v)
145 Matrix *M;
146 Value tmp;
147 int i, n, j;
148 unsigned char *supporting = (unsigned char *)malloc(P->NbConstraints);
149 unsigned dim = P->Dimension + 2;
151 assert(v >=0 && v < P->NbRays);
152 assert(value_pos_p(P->Ray[v][dim-1]));
153 assert(supporting);
155 value_init(tmp);
156 for (i = 0, n = 0; i < P->NbConstraints; ++i) {
157 Inner_Product(P->Constraint[i] + 1, P->Ray[v] + 1, dim - 1, &tmp);
158 if ((supporting[i] = value_zero_p(tmp)))
159 ++n;
161 assert(n >= dim - 2);
162 value_clear(tmp);
163 M = Matrix_Alloc(n, dim);
164 assert(M);
165 for (i = 0, j = 0; i < P->NbConstraints; ++i)
166 if (supporting[i]) {
167 value_set_si(M->p[j][dim-1], 0);
168 Vector_Copy(P->Constraint[i], M->p[j++], dim-1);
170 free(supporting);
171 P = Constraints2Polyhedron(M, P->NbRays+1);
172 assert(P);
173 Matrix_Free(M);
174 return P;
177 #define INT_BITS (sizeof(unsigned) * 8)
179 unsigned *supporting_constraints(Matrix *Constraints, Param_Vertices *v, int *n)
181 Value lcm, tmp, tmp2;
182 unsigned dim = Constraints->NbColumns;
183 unsigned nparam = v->Vertex->NbColumns - 2;
184 unsigned nvar = dim - nparam - 2;
185 int len = (Constraints->NbRows+INT_BITS-1)/INT_BITS;
186 unsigned *supporting = (unsigned *)calloc(len, sizeof(unsigned));
187 int i, j;
188 Vector *row;
189 int ix;
190 unsigned bx;
192 assert(supporting);
193 row = Vector_Alloc(nparam+1);
194 assert(row);
195 value_init(lcm);
196 value_init(tmp);
197 value_init(tmp2);
198 value_set_si(lcm, 1);
199 for (i = 0, *n = 0, ix = 0, bx = MSB; i < Constraints->NbRows; ++i) {
200 Vector_Set(row->p, 0, nparam+1);
201 for (j = 0 ; j < nvar; ++j) {
202 value_set_si(tmp, 1);
203 value_assign(tmp2, Constraints->p[i][j+1]);
204 if (value_ne(lcm, v->Vertex->p[j][nparam+1])) {
205 value_assign(tmp, lcm);
206 value_lcm(lcm, lcm, v->Vertex->p[j][nparam+1]);
207 value_division(tmp, lcm, tmp);
208 value_multiply(tmp2, tmp2, lcm);
209 value_division(tmp2, tmp2, v->Vertex->p[j][nparam+1]);
211 Vector_Combine(row->p, v->Vertex->p[j], row->p,
212 tmp, tmp2, nparam+1);
214 value_set_si(tmp, 1);
215 Vector_Combine(row->p, Constraints->p[i]+1+nvar, row->p, tmp, lcm, nparam+1);
216 for (j = 0; j < nparam+1; ++j)
217 if (value_notzero_p(row->p[j]))
218 break;
219 if (j == nparam + 1) {
220 supporting[ix] |= bx;
221 ++*n;
223 NEXT(ix, bx);
225 assert(*n >= nvar);
226 value_clear(tmp);
227 value_clear(tmp2);
228 value_clear(lcm);
229 Vector_Free(row);
231 return supporting;
234 Polyhedron* supporting_cone_p(Polyhedron *P, Param_Vertices *v)
236 Matrix *M;
237 unsigned dim = P->Dimension + 2;
238 unsigned nparam = v->Vertex->NbColumns - 2;
239 unsigned nvar = dim - nparam - 2;
240 int i, n, j;
241 int ix;
242 unsigned bx;
243 unsigned *supporting;
244 Matrix View;
246 Polyhedron_Matrix_View(P, &View, P->NbConstraints);
247 supporting = supporting_constraints(&View, v, &n);
248 M = Matrix_Alloc(n, nvar+2);
249 assert(M);
250 for (i = 0, j = 0, ix = 0, bx = MSB; i < P->NbConstraints; ++i) {
251 if (supporting[ix] & bx) {
252 value_set_si(M->p[j][nvar+1], 0);
253 Vector_Copy(P->Constraint[i], M->p[j++], nvar+1);
255 NEXT(ix, bx);
257 free(supporting);
258 P = Constraints2Polyhedron(M, P->NbRays+1);
259 assert(P);
260 Matrix_Free(M);
261 return P;
264 Polyhedron* triangulate_cone(Polyhedron *P, unsigned NbMaxCons)
266 struct barvinok_options *options = barvinok_options_new_with_defaults();
267 options->MaxRays = NbMaxCons;
268 P = triangulate_cone_with_options(P, options);
269 barvinok_options_free(options);
270 return P;
273 Polyhedron* triangulate_cone_with_options(Polyhedron *P,
274 struct barvinok_options *options)
276 const static int MAX_TRY=10;
277 int i, j, r, n, t;
278 Value tmp;
279 unsigned dim = P->Dimension;
280 Matrix *M = Matrix_Alloc(P->NbRays+1, dim+3);
281 Matrix *M2, *M3;
282 Polyhedron *L, *R, *T;
283 assert(P->NbEq == 0);
285 L = NULL;
286 R = NULL;
287 value_init(tmp);
289 Vector_Set(M->p[0]+1, 0, dim+1);
290 value_set_si(M->p[0][0], 1);
291 value_set_si(M->p[0][dim+2], 1);
292 Vector_Set(M->p[P->NbRays]+1, 0, dim+2);
293 value_set_si(M->p[P->NbRays][0], 1);
294 value_set_si(M->p[P->NbRays][dim+1], 1);
296 for (i = 0, r = 1; i < P->NbRays; ++i) {
297 if (value_notzero_p(P->Ray[i][dim+1]))
298 continue;
299 Vector_Copy(P->Ray[i], M->p[r], dim+1);
300 value_set_si(M->p[r][dim+2], 0);
301 ++r;
304 M2 = Matrix_Alloc(dim+1, dim+2);
306 t = 0;
307 if (options->try_Delaunay_triangulation) {
308 /* Delaunay triangulation */
309 for (r = 1; r < P->NbRays; ++r) {
310 Inner_Product(M->p[r]+1, M->p[r]+1, dim, &tmp);
311 value_assign(M->p[r][dim+1], tmp);
313 M3 = Matrix_Copy(M);
314 L = Rays2Polyhedron(M3, options->MaxRays);
315 Matrix_Free(M3);
316 ++t;
317 } else {
318 try_again:
319 /* Usually R should still be 0 */
320 Domain_Free(R);
321 Polyhedron_Free(L);
322 for (r = 1; r < P->NbRays; ++r) {
323 value_set_si(M->p[r][dim+1], random_int((t+1)*dim*P->NbRays)+1);
325 M3 = Matrix_Copy(M);
326 L = Rays2Polyhedron(M3, options->MaxRays);
327 Matrix_Free(M3);
328 ++t;
330 assert(t <= MAX_TRY);
332 R = NULL;
333 n = 0;
335 POL_ENSURE_FACETS(L);
336 for (i = 0; i < L->NbConstraints; ++i) {
337 /* Ignore perpendicular facets, i.e., facets with 0 z-coordinate */
338 if (value_negz_p(L->Constraint[i][dim+1]))
339 continue;
340 if (value_notzero_p(L->Constraint[i][dim+2]))
341 continue;
342 for (j = 1, r = 1; j < M->NbRows; ++j) {
343 Inner_Product(M->p[j]+1, L->Constraint[i]+1, dim+1, &tmp);
344 if (value_notzero_p(tmp))
345 continue;
346 if (r > dim)
347 goto try_again;
348 Vector_Copy(M->p[j]+1, M2->p[r]+1, dim);
349 value_set_si(M2->p[r][0], 1);
350 value_set_si(M2->p[r][dim+1], 0);
351 ++r;
353 assert(r == dim+1);
354 Vector_Set(M2->p[0]+1, 0, dim);
355 value_set_si(M2->p[0][0], 1);
356 value_set_si(M2->p[0][dim+1], 1);
357 T = Rays2Polyhedron(M2, P->NbConstraints+1);
358 T->next = R;
359 R = T;
360 ++n;
362 Matrix_Free(M2);
364 Polyhedron_Free(L);
365 value_clear(tmp);
366 Matrix_Free(M);
368 return R;
371 void check_triangulization(Polyhedron *P, Polyhedron *T)
373 Polyhedron *C, *D, *E, *F, *G, *U;
374 for (C = T; C; C = C->next) {
375 if (C == T)
376 U = C;
377 else
378 U = DomainConvex(DomainUnion(U, C, 100), 100);
379 for (D = C->next; D; D = D->next) {
380 F = C->next;
381 G = D->next;
382 C->next = NULL;
383 D->next = NULL;
384 E = DomainIntersection(C, D, 600);
385 assert(E->NbRays == 0 || E->NbEq >= 1);
386 Polyhedron_Free(E);
387 C->next = F;
388 D->next = G;
391 assert(PolyhedronIncludes(U, P));
392 assert(PolyhedronIncludes(P, U));
395 /* Computes x, y and g such that g = gcd(a,b) and a*x+b*y = g */
396 void Extended_Euclid(Value a, Value b, Value *x, Value *y, Value *g)
398 Value c, d, e, f, tmp;
400 value_init(c);
401 value_init(d);
402 value_init(e);
403 value_init(f);
404 value_init(tmp);
405 value_absolute(c, a);
406 value_absolute(d, b);
407 value_set_si(e, 1);
408 value_set_si(f, 0);
409 while(value_pos_p(d)) {
410 value_division(tmp, c, d);
411 value_multiply(tmp, tmp, f);
412 value_subtract(e, e, tmp);
413 value_division(tmp, c, d);
414 value_multiply(tmp, tmp, d);
415 value_subtract(c, c, tmp);
416 value_swap(c, d);
417 value_swap(e, f);
419 value_assign(*g, c);
420 if (value_zero_p(a))
421 value_set_si(*x, 0);
422 else if (value_pos_p(a))
423 value_assign(*x, e);
424 else value_oppose(*x, e);
425 if (value_zero_p(b))
426 value_set_si(*y, 0);
427 else {
428 value_multiply(tmp, a, *x);
429 value_subtract(tmp, c, tmp);
430 value_division(*y, tmp, b);
432 value_clear(c);
433 value_clear(d);
434 value_clear(e);
435 value_clear(f);
436 value_clear(tmp);
439 static int unimodular_complete_1(Matrix *m)
441 Value g, b, c, old, tmp;
442 unsigned i, j;
443 int ok;
445 value_init(b);
446 value_init(c);
447 value_init(g);
448 value_init(old);
449 value_init(tmp);
450 value_assign(g, m->p[0][0]);
451 for (i = 1; value_zero_p(g) && i < m->NbColumns; ++i) {
452 for (j = 0; j < m->NbColumns; ++j) {
453 if (j == i-1)
454 value_set_si(m->p[i][j], 1);
455 else
456 value_set_si(m->p[i][j], 0);
458 value_assign(g, m->p[0][i]);
460 for (; i < m->NbColumns; ++i) {
461 value_assign(old, g);
462 Extended_Euclid(old, m->p[0][i], &c, &b, &g);
463 value_oppose(b, b);
464 for (j = 0; j < m->NbColumns; ++j) {
465 if (j < i) {
466 value_multiply(tmp, m->p[0][j], b);
467 value_division(m->p[i][j], tmp, old);
468 } else if (j == i)
469 value_assign(m->p[i][j], c);
470 else
471 value_set_si(m->p[i][j], 0);
474 ok = value_one_p(g);
475 value_clear(b);
476 value_clear(c);
477 value_clear(g);
478 value_clear(old);
479 value_clear(tmp);
480 return ok;
483 int unimodular_complete(Matrix *M, int row)
485 int r;
486 int ok = 1;
487 Matrix *H, *Q, *U;
489 if (row == 1)
490 return unimodular_complete_1(M);
492 left_hermite(M, &H, &Q, &U);
493 Matrix_Free(U);
494 for (r = 0; ok && r < row; ++r)
495 if (value_notone_p(H->p[r][r]))
496 ok = 0;
497 Matrix_Free(H);
498 for (r = row; r < M->NbRows; ++r)
499 Vector_Copy(Q->p[r], M->p[r], M->NbColumns);
500 Matrix_Free(Q);
501 return ok;
505 * left_hermite may leave positive entries below the main diagonal in H.
506 * This function postprocesses the output of left_hermite to make
507 * the non-zero entries below the main diagonal negative.
509 void neg_left_hermite(Matrix *A, Matrix **H_p, Matrix **Q_p, Matrix **U_p)
511 int row, col, i, j;
512 Matrix *H, *U, *Q;
514 left_hermite(A, &H, &Q, &U);
515 *H_p = H;
516 *Q_p = Q;
517 *U_p = U;
519 for (row = 0, col = 0; col < H->NbColumns; ++col, ++row) {
520 while (value_zero_p(H->p[row][col]))
521 ++row;
522 for (i = 0; i < col; ++i) {
523 if (value_negz_p(H->p[row][i]))
524 continue;
526 /* subtract column col from column i in H and U */
527 for (j = 0; j < H->NbRows; ++j)
528 value_subtract(H->p[j][i], H->p[j][i], H->p[j][col]);
529 for (j = 0; j < U->NbRows; ++j)
530 value_subtract(U->p[j][i], U->p[j][i], U->p[j][col]);
532 /* add row i to row col in Q */
533 for (j = 0; j < Q->NbColumns; ++j)
534 value_addto(Q->p[col][j], Q->p[col][j], Q->p[i][j]);
540 * Returns a full-dimensional polyhedron with the same number
541 * of integer points as P
543 Polyhedron *remove_equalities(Polyhedron *P, unsigned MaxRays)
545 Matrix M;
546 Matrix *T;
547 Polyhedron *Q = Polyhedron_Copy(P);
549 if (Q->NbEq == 0)
550 return Q;
552 Q = DomainConstraintSimplify(Q, MaxRays);
553 if (emptyQ2(Q))
554 return Q;
556 Polyhedron_Matrix_View(Q, &M, Q->NbEq);
557 T = compress_variables(&M, 0);
559 if (!T)
560 P = NULL;
561 else {
562 P = Polyhedron_Preimage(Q, T, MaxRays);
563 Matrix_Free(T);
566 Polyhedron_Free(Q);
568 return P;
572 * Returns a full-dimensional polyhedron with the same number
573 * of integer points as P
574 * nvar specifies the number of variables
575 * The remaining dimensions are assumed to be parameters
576 * Destroys P
577 * factor is NbEq x (nparam+2) matrix, containing stride constraints
578 * on the parameters; column nparam is the constant;
579 * column nparam+1 is the stride
581 * if factor is NULL, only remove equalities that don't affect
582 * the number of points
584 Polyhedron *remove_equalities_p(Polyhedron *P, unsigned nvar, Matrix **factor,
585 unsigned MaxRays)
587 Value g;
588 Polyhedron *Q;
589 unsigned dim = P->Dimension;
590 Matrix *m1, *m2, *f;
591 int i, j;
593 if (P->NbEq == 0)
594 return P;
596 m1 = Matrix_Alloc(nvar, nvar);
597 P = DomainConstraintSimplify(P, MaxRays);
598 if (factor) {
599 f = Matrix_Alloc(P->NbEq, dim-nvar+2);
600 *factor = f;
602 value_init(g);
603 for (i = 0, j = 0; i < P->NbEq; ++i) {
604 if (First_Non_Zero(P->Constraint[i]+1, nvar) == -1)
605 continue;
607 Vector_Gcd(P->Constraint[i]+1, nvar, &g);
608 if (!factor && value_notone_p(g))
609 continue;
611 if (factor) {
612 Vector_Copy(P->Constraint[i]+1+nvar, f->p[j], dim-nvar+1);
613 value_assign(f->p[j][dim-nvar+1], g);
616 Vector_Copy(P->Constraint[i]+1, m1->p[j], nvar);
618 ++j;
620 value_clear(g);
622 unimodular_complete(m1, j);
624 m2 = Matrix_Alloc(dim+1-j, dim+1);
625 for (i = 0; i < nvar-j ; ++i)
626 Vector_Copy(m1->p[i+j], m2->p[i], nvar);
627 Matrix_Free(m1);
628 for (i = nvar-j; i <= dim-j; ++i)
629 value_set_si(m2->p[i][i+j], 1);
631 Q = Polyhedron_Image(P, m2, MaxRays);
632 Matrix_Free(m2);
633 Polyhedron_Free(P);
635 return Q;
638 void Line_Length(Polyhedron *P, Value *len)
640 Value tmp, pos, neg;
641 int p = 0, n = 0;
642 int i;
644 assert(P->Dimension == 1);
646 if (P->NbEq > 0) {
647 if (mpz_divisible_p(P->Constraint[0][2], P->Constraint[0][1]))
648 value_set_si(*len, 1);
649 else
650 value_set_si(*len, 0);
651 return;
654 value_init(tmp);
655 value_init(pos);
656 value_init(neg);
658 for (i = 0; i < P->NbConstraints; ++i) {
659 value_oppose(tmp, P->Constraint[i][2]);
660 if (value_pos_p(P->Constraint[i][1])) {
661 mpz_cdiv_q(tmp, tmp, P->Constraint[i][1]);
662 if (!p || value_gt(tmp, pos))
663 value_assign(pos, tmp);
664 p = 1;
665 } else if (value_neg_p(P->Constraint[i][1])) {
666 mpz_fdiv_q(tmp, tmp, P->Constraint[i][1]);
667 if (!n || value_lt(tmp, neg))
668 value_assign(neg, tmp);
669 n = 1;
671 if (n && p) {
672 value_subtract(tmp, neg, pos);
673 value_increment(*len, tmp);
674 } else
675 value_set_si(*len, -1);
678 value_clear(tmp);
679 value_clear(pos);
680 value_clear(neg);
683 /* Update group[k] to the group column k belongs to.
684 * When merging two groups, only the group of the current
685 * group leader is changed. Here we change the group of
686 * the other members to also point to the group that the
687 * old group leader now points to.
689 static void update_group(int *group, int *cnt, int k)
691 int g = group[k];
692 while (cnt[g] == 0)
693 g = group[g];
694 group[k] = g;
698 * Factors the polyhedron P into polyhedra Q_i such that
699 * the number of integer points in P is equal to the product
700 * of the number of integer points in the individual Q_i
702 * If no factors can be found, NULL is returned.
703 * Otherwise, a linked list of the factors is returned.
705 * If there are factors and if T is not NULL, then a matrix will be
706 * returned through T expressing the old variables in terms of the
707 * new variables as they appear in the sequence of factors.
709 * The algorithm works by first computing the Hermite normal form
710 * and then grouping columns linked by one or more constraints together,
711 * where a constraints "links" two or more columns if the constraint
712 * has nonzero coefficients in the columns.
714 Polyhedron* Polyhedron_Factor(Polyhedron *P, unsigned nparam, Matrix **T,
715 unsigned NbMaxRays)
717 int i, j, k;
718 Matrix *M, *H, *Q, *U;
719 int *pos; /* for each column: row position of pivot */
720 int *group; /* group to which a column belongs */
721 int *cnt; /* number of columns in the group */
722 int *rowgroup; /* group to which a constraint belongs */
723 int nvar = P->Dimension - nparam;
724 Polyhedron *F = NULL;
726 if (nvar <= 1)
727 return NULL;
729 NALLOC(pos, nvar);
730 NALLOC(group, nvar);
731 NALLOC(cnt, nvar);
732 NALLOC(rowgroup, P->NbConstraints);
734 M = Matrix_Alloc(P->NbConstraints, nvar);
735 for (i = 0; i < P->NbConstraints; ++i)
736 Vector_Copy(P->Constraint[i]+1, M->p[i], nvar);
737 left_hermite(M, &H, &Q, &U);
738 Matrix_Free(M);
739 Matrix_Free(Q);
741 for (i = 0; i < P->NbConstraints; ++i)
742 rowgroup[i] = -1;
743 for (i = 0, j = 0; i < H->NbColumns; ++i) {
744 for ( ; j < H->NbRows; ++j)
745 if (value_notzero_p(H->p[j][i]))
746 break;
747 pos[i] = j;
749 for (i = 0; i < nvar; ++i) {
750 group[i] = i;
751 cnt[i] = 1;
753 for (i = 0; i < H->NbColumns && cnt[0] < nvar; ++i) {
754 if (pos[i] == H->NbRows)
755 continue; /* A line direction */
756 if (rowgroup[pos[i]] == -1)
757 rowgroup[pos[i]] = i;
758 for (j = pos[i]+1; j < H->NbRows; ++j) {
759 if (value_zero_p(H->p[j][i]))
760 continue;
761 if (rowgroup[j] != -1)
762 continue;
763 rowgroup[j] = group[i];
764 for (k = i+1; k < H->NbColumns && j >= pos[k]; ++k) {
765 update_group(group, cnt, k);
766 update_group(group, cnt, i);
767 if (group[k] != group[i] && value_notzero_p(H->p[j][k])) {
768 assert(cnt[group[k]] != 0);
769 assert(cnt[group[i]] != 0);
770 if (group[i] < group[k]) {
771 cnt[group[i]] += cnt[group[k]];
772 cnt[group[k]] = 0;
773 group[group[k]] = group[i];
774 } else {
775 cnt[group[k]] += cnt[group[i]];
776 cnt[group[i]] = 0;
777 group[group[i]] = group[k];
783 for (i = 1; i < nvar; ++i)
784 update_group(group, cnt, i);
786 if (cnt[0] != nvar) {
787 /* Extract out pure context constraints separately */
788 Polyhedron **next = &F;
789 int tot_d = 0;
790 if (T)
791 *T = Matrix_Alloc(nvar, nvar);
792 for (i = nparam ? -1 : 0; i < nvar; ++i) {
793 int d;
795 if (i == -1) {
796 for (j = 0, k = 0; j < P->NbConstraints; ++j)
797 if (rowgroup[j] == -1) {
798 if (First_Non_Zero(P->Constraint[j]+1+nvar,
799 nparam) == -1)
800 rowgroup[j] = -2;
801 else
802 ++k;
804 if (k == 0)
805 continue;
806 d = 0;
807 } else {
808 if (cnt[i] == 0)
809 continue;
810 d = cnt[i];
811 for (j = 0, k = 0; j < P->NbConstraints; ++j)
812 if (rowgroup[j] >= 0 && group[rowgroup[j]] == i) {
813 rowgroup[j] = i;
814 ++k;
818 if (T)
819 for (j = 0; j < nvar; ++j) {
820 int l, m;
821 for (l = 0, m = 0; m < d; ++l) {
822 if (group[l] != i)
823 continue;
824 value_assign((*T)->p[j][tot_d+m++], U->p[j][l]);
828 M = Matrix_Alloc(k, d+nparam+2);
829 for (j = 0, k = 0; j < P->NbConstraints; ++j) {
830 int l, m;
831 if (rowgroup[j] != i)
832 continue;
833 value_assign(M->p[k][0], P->Constraint[j][0]);
834 for (l = 0, m = 0; m < d; ++l) {
835 if (group[l] != i)
836 continue;
837 value_assign(M->p[k][1+m++], H->p[j][l]);
839 Vector_Copy(P->Constraint[j]+1+nvar, M->p[k]+1+m, nparam+1);
840 ++k;
842 *next = Constraints2Polyhedron(M, NbMaxRays);
843 next = &(*next)->next;
844 Matrix_Free(M);
845 tot_d += d;
848 Matrix_Free(U);
849 Matrix_Free(H);
850 free(pos);
851 free(group);
852 free(cnt);
853 free(rowgroup);
854 return F;
857 /* Computes the intersection of the contexts of a list of factors */
858 Polyhedron *Factor_Context(Polyhedron *F, unsigned nparam, unsigned MaxRays)
860 Polyhedron *Q;
861 Polyhedron *C = NULL;
863 for (Q = F; Q; Q = Q->next) {
864 Polyhedron *QC = Q;
865 Polyhedron *next = Q->next;
866 Q->next = NULL;
868 if (Q->Dimension != nparam)
869 QC = Polyhedron_Project(Q, nparam);
871 if (!C)
872 C = Q == QC ? Polyhedron_Copy(QC) : QC;
873 else {
874 Polyhedron *C2 = C;
875 C = DomainIntersection(C, QC, MaxRays);
876 Polyhedron_Free(C2);
877 if (QC != Q)
878 Polyhedron_Free(QC);
880 Q->next = next;
882 return C;
886 * Project on final dim dimensions
888 Polyhedron* Polyhedron_Project(Polyhedron *P, int dim)
890 int i;
891 int remove = P->Dimension - dim;
892 Matrix *T;
893 Polyhedron *I;
895 if (P->Dimension == dim)
896 return Polyhedron_Copy(P);
898 T = Matrix_Alloc(dim+1, P->Dimension+1);
899 for (i = 0; i < dim+1; ++i)
900 value_set_si(T->p[i][i+remove], 1);
901 I = Polyhedron_Image(P, T, P->NbConstraints);
902 Matrix_Free(T);
903 return I;
906 /* Constructs a new constraint that ensures that
907 * the first constraint is (strictly) smaller than
908 * the second.
910 static void smaller_constraint(Value *a, Value *b, Value *c, int pos, int shift,
911 int len, int strict, Value *tmp)
913 value_oppose(*tmp, b[pos+1]);
914 value_set_si(c[0], 1);
915 Vector_Combine(a+1+shift, b+1+shift, c+1, *tmp, a[pos+1], len-shift-1);
916 if (strict)
917 value_decrement(c[len-shift-1], c[len-shift-1]);
918 ConstraintSimplify(c, c, len-shift, tmp);
922 /* For each pair of lower and upper bounds on the first variable,
923 * calls fn with the set of constraints on the remaining variables
924 * where these bounds are active, i.e., (stricly) larger/smaller than
925 * the other lower/upper bounds, the lower and upper bound and the
926 * call back data.
928 * If the first variable is equal to an affine combination of the
929 * other variables then fn is called with both lower and upper
930 * pointing to the corresponding equality.
932 * If there is no lower (or upper) bound, then NULL is passed
933 * as the corresponding bound.
935 void for_each_lower_upper_bound(Polyhedron *P,
936 for_each_lower_upper_bound_init init,
937 for_each_lower_upper_bound_fn fn,
938 void *cb_data)
940 unsigned dim = P->Dimension;
941 Matrix *M;
942 int *pos;
943 int i, p, n, z;
944 int k, l, k2, l2, q;
945 Value g;
947 if (value_zero_p(P->Constraint[0][0]) &&
948 value_notzero_p(P->Constraint[0][1])) {
949 M = Matrix_Alloc(P->NbConstraints-1, dim-1+2);
950 for (i = 1; i < P->NbConstraints; ++i) {
951 value_assign(M->p[i-1][0], P->Constraint[i][0]);
952 Vector_Copy(P->Constraint[i]+2, M->p[i-1]+1, dim);
954 if (init)
955 init(1, cb_data);
956 fn(M, P->Constraint[0], P->Constraint[0], cb_data);
957 Matrix_Free(M);
958 return;
961 value_init(g);
962 pos = ALLOCN(int, P->NbConstraints);
964 for (i = 0, z = 0; i < P->NbConstraints; ++i)
965 if (value_zero_p(P->Constraint[i][1]))
966 pos[P->NbConstraints-1 - z++] = i;
967 /* put those with positive coefficients first; number: p */
968 for (i = 0, p = 0, n = P->NbConstraints-z-1; i < P->NbConstraints; ++i)
969 if (value_pos_p(P->Constraint[i][1]))
970 pos[p++] = i;
971 else if (value_neg_p(P->Constraint[i][1]))
972 pos[n--] = i;
973 n = P->NbConstraints-z-p;
975 if (init)
976 init(p*n, cb_data);
978 M = Matrix_Alloc((p ? p-1 : 0) + (n ? n-1 : 0) + z + 1, dim-1+2);
979 for (i = 0; i < z; ++i) {
980 value_assign(M->p[i][0], P->Constraint[pos[P->NbConstraints-1 - i]][0]);
981 Vector_Copy(P->Constraint[pos[P->NbConstraints-1 - i]]+2,
982 M->p[i]+1, dim);
984 for (k = p ? 0 : -1; k < p; ++k) {
985 for (k2 = 0; k2 < p; ++k2) {
986 if (k2 == k)
987 continue;
988 q = 1 + z + k2 - (k2 > k);
989 smaller_constraint(
990 P->Constraint[pos[k]],
991 P->Constraint[pos[k2]],
992 M->p[q], 0, 1, dim+2, k2 > k, &g);
994 for (l = n ? p : p-1; l < p+n; ++l) {
995 Value *lower;
996 Value *upper;
997 for (l2 = p; l2 < p+n; ++l2) {
998 if (l2 == l)
999 continue;
1000 q = 1 + z + l2-1 - (l2 > l);
1001 smaller_constraint(
1002 P->Constraint[pos[l2]],
1003 P->Constraint[pos[l]],
1004 M->p[q], 0, 1, dim+2, l2 > l, &g);
1006 if (p && n)
1007 smaller_constraint(P->Constraint[pos[k]],
1008 P->Constraint[pos[l]],
1009 M->p[z], 0, 1, dim+2, 0, &g);
1010 lower = p ? P->Constraint[pos[k]] : NULL;
1011 upper = n ? P->Constraint[pos[l]] : NULL;
1012 fn(M, lower, upper, cb_data);
1015 Matrix_Free(M);
1017 free(pos);
1018 value_clear(g);
1021 struct section { Polyhedron * D; evalue E; };
1023 struct PLL_data {
1024 int nd;
1025 unsigned MaxRays;
1026 Polyhedron *C;
1027 evalue mone;
1028 struct section *s;
1031 static void PLL_init(unsigned n, void *cb_data)
1033 struct PLL_data *data = (struct PLL_data *)cb_data;
1035 data->s = ALLOCN(struct section, n);
1038 /* Computes ceil(-coef/abs(d)) */
1039 static evalue* bv_ceil3(Value *coef, int len, Value d, Polyhedron *P)
1041 Value t;
1042 evalue *EP;
1043 Vector *val = Vector_Alloc(len);
1045 value_init(t);
1046 Vector_Oppose(coef, val->p, len);
1047 value_absolute(t, d);
1049 EP = ceiling(val->p, t, len-1, P);
1051 value_clear(t);
1052 Vector_Free(val);
1054 return EP;
1057 static void PLL_cb(Matrix *M, Value *lower, Value *upper, void *cb_data)
1059 struct PLL_data *data = (struct PLL_data *)cb_data;
1060 unsigned dim = M->NbColumns-1;
1061 Matrix *M2;
1062 Polyhedron *T;
1063 evalue *L, *U;
1065 assert(lower);
1066 assert(upper);
1068 M2 = Matrix_Copy(M);
1069 T = Constraints2Polyhedron(M2, data->MaxRays);
1070 Matrix_Free(M2);
1071 data->s[data->nd].D = DomainIntersection(T, data->C, data->MaxRays);
1072 Domain_Free(T);
1074 POL_ENSURE_VERTICES(data->s[data->nd].D);
1075 if (emptyQ(data->s[data->nd].D)) {
1076 Polyhedron_Free(data->s[data->nd].D);
1077 return;
1079 L = bv_ceil3(lower+1+1, dim-1+1, lower[0+1], data->s[data->nd].D);
1080 U = bv_ceil3(upper+1+1, dim-1+1, upper[0+1], data->s[data->nd].D);
1081 eadd(L, U);
1082 eadd(&data->mone, U);
1083 emul(&data->mone, U);
1084 data->s[data->nd].E = *U;
1085 evalue_free(L);
1086 free(U);
1087 ++data->nd;
1090 static evalue *ParamLine_Length_mod(Polyhedron *P, Polyhedron *C, unsigned MaxRays)
1092 unsigned dim = P->Dimension;
1093 unsigned nvar = dim - C->Dimension;
1094 struct PLL_data data;
1095 evalue *F;
1096 int k;
1098 assert(nvar == 1);
1100 value_init(data.mone.d);
1101 evalue_set_si(&data.mone, -1, 1);
1103 data.nd = 0;
1104 data.MaxRays = MaxRays;
1105 data.C = C;
1106 for_each_lower_upper_bound(P, PLL_init, PLL_cb, &data);
1108 free_evalue_refs(&data.mone);
1110 if (data.nd == 0) {
1111 free(data.s);
1112 return evalue_zero();
1115 F = ALLOC(evalue);
1116 value_init(F->d);
1117 value_set_si(F->d, 0);
1118 F->x.p = new_enode(partition, 2*data.nd, dim-nvar);
1119 for (k = 0; k < data.nd; ++k) {
1120 EVALUE_SET_DOMAIN(F->x.p->arr[2*k], data.s[k].D);
1121 value_clear(F->x.p->arr[2*k+1].d);
1122 F->x.p->arr[2*k+1] = data.s[k].E;
1124 free(data.s);
1126 return F;
1129 evalue* ParamLine_Length(Polyhedron *P, Polyhedron *C,
1130 struct barvinok_options *options)
1132 evalue* tmp;
1133 tmp = ParamLine_Length_mod(P, C, options->MaxRays);
1134 if (options->lookup_table) {
1135 evalue_mod2table(tmp, C->Dimension);
1136 reduce_evalue(tmp);
1138 return tmp;
1141 Bool isIdentity(Matrix *M)
1143 unsigned i, j;
1144 if (M->NbRows != M->NbColumns)
1145 return False;
1147 for (i = 0;i < M->NbRows; i ++)
1148 for (j = 0; j < M->NbColumns; j ++)
1149 if (i == j) {
1150 if(value_notone_p(M->p[i][j]))
1151 return False;
1152 } else {
1153 if(value_notzero_p(M->p[i][j]))
1154 return False;
1156 return True;
1159 void Param_Polyhedron_Print(FILE* DST, Param_Polyhedron *PP,
1160 const char **param_names)
1162 Param_Domain *P;
1163 Param_Vertices *V;
1165 for(P=PP->D;P;P=P->next) {
1167 /* prints current val. dom. */
1168 fprintf(DST, "---------------------------------------\n");
1169 fprintf(DST, "Domain :\n");
1170 Print_Domain(DST, P->Domain, param_names);
1172 /* scan the vertices */
1173 fprintf(DST, "Vertices :\n");
1174 FORALL_PVertex_in_ParamPolyhedron(V,P,PP) {
1176 /* prints each vertex */
1177 Print_Vertex(DST, V->Vertex, param_names);
1178 fprintf(DST, "\n");
1180 END_FORALL_PVertex_in_ParamPolyhedron;
1184 void Enumeration_Print(FILE *Dst, Enumeration *en, const char **params)
1186 for (; en; en = en->next) {
1187 Print_Domain(Dst, en->ValidityDomain, params);
1188 print_evalue(Dst, &en->EP, params);
1192 void Enumeration_Free(Enumeration *en)
1194 Enumeration *ee;
1196 while( en )
1198 free_evalue_refs( &(en->EP) );
1199 Domain_Free( en->ValidityDomain );
1200 ee = en ->next;
1201 free( en );
1202 en = ee;
1206 void Enumeration_mod2table(Enumeration *en, unsigned nparam)
1208 for (; en; en = en->next) {
1209 evalue_mod2table(&en->EP, nparam);
1210 reduce_evalue(&en->EP);
1214 size_t Enumeration_size(Enumeration *en)
1216 size_t s = 0;
1218 for (; en; en = en->next) {
1219 s += domain_size(en->ValidityDomain);
1220 s += evalue_size(&en->EP);
1222 return s;
1225 /* Check whether every set in D2 is included in some set of D1 */
1226 int DomainIncludes(Polyhedron *D1, Polyhedron *D2)
1228 for ( ; D2; D2 = D2->next) {
1229 Polyhedron *P1;
1230 for (P1 = D1; P1; P1 = P1->next)
1231 if (PolyhedronIncludes(P1, D2))
1232 break;
1233 if (!P1)
1234 return 0;
1236 return 1;
1239 int line_minmax(Polyhedron *I, Value *min, Value *max)
1241 int i;
1243 if (I->NbEq >= 1) {
1244 value_oppose(I->Constraint[0][2], I->Constraint[0][2]);
1245 /* There should never be a remainder here */
1246 if (value_pos_p(I->Constraint[0][1]))
1247 mpz_fdiv_q(*min, I->Constraint[0][2], I->Constraint[0][1]);
1248 else
1249 mpz_fdiv_q(*min, I->Constraint[0][2], I->Constraint[0][1]);
1250 value_assign(*max, *min);
1251 } else for (i = 0; i < I->NbConstraints; ++i) {
1252 if (value_zero_p(I->Constraint[i][1])) {
1253 Polyhedron_Free(I);
1254 return 0;
1257 value_oppose(I->Constraint[i][2], I->Constraint[i][2]);
1258 if (value_pos_p(I->Constraint[i][1]))
1259 mpz_cdiv_q(*min, I->Constraint[i][2], I->Constraint[i][1]);
1260 else
1261 mpz_fdiv_q(*max, I->Constraint[i][2], I->Constraint[i][1]);
1263 Polyhedron_Free(I);
1264 return 1;
1267 int DomainContains(Polyhedron *P, Value *list_args, int len,
1268 unsigned MaxRays, int set)
1270 int i;
1271 Value m;
1273 if (P->Dimension == len)
1274 return in_domain(P, list_args);
1276 assert(set); // assume list_args is large enough
1277 assert((P->Dimension - len) % 2 == 0);
1278 value_init(m);
1279 for (i = 0; i < P->Dimension - len; i += 2) {
1280 int j, k;
1281 for (j = 0 ; j < P->NbEq; ++j)
1282 if (value_notzero_p(P->Constraint[j][1+len+i]))
1283 break;
1284 assert(j < P->NbEq);
1285 value_absolute(m, P->Constraint[j][1+len+i]);
1286 k = First_Non_Zero(P->Constraint[j]+1, len);
1287 assert(k != -1);
1288 assert(First_Non_Zero(P->Constraint[j]+1+k+1, len - k - 1) == -1);
1289 mpz_fdiv_q(list_args[len+i], list_args[k], m);
1290 mpz_fdiv_r(list_args[len+i+1], list_args[k], m);
1292 value_clear(m);
1294 return in_domain(P, list_args);
1297 Polyhedron *DomainConcat(Polyhedron *head, Polyhedron *tail)
1299 Polyhedron *S;
1300 if (!head)
1301 return tail;
1302 for (S = head; S->next; S = S->next)
1304 S->next = tail;
1305 return head;
1308 evalue *barvinok_lexsmaller_ev(Polyhedron *P, Polyhedron *D, unsigned dim,
1309 Polyhedron *C, unsigned MaxRays)
1311 evalue *ranking;
1312 Polyhedron *RC, *RD, *Q;
1313 unsigned nparam = dim + C->Dimension;
1314 unsigned exist;
1315 Polyhedron *CA;
1317 RC = LexSmaller(P, D, dim, C, MaxRays);
1318 RD = RC->next;
1319 RC->next = NULL;
1321 exist = RD->Dimension - nparam - dim;
1322 CA = align_context(RC, RD->Dimension, MaxRays);
1323 Q = DomainIntersection(RD, CA, MaxRays);
1324 Polyhedron_Free(CA);
1325 Domain_Free(RD);
1326 Polyhedron_Free(RC);
1327 RD = Q;
1329 for (Q = RD; Q; Q = Q->next) {
1330 evalue *t;
1331 Polyhedron *next = Q->next;
1332 Q->next = 0;
1334 t = barvinok_enumerate_e(Q, exist, nparam, MaxRays);
1336 if (Q == RD)
1337 ranking = t;
1338 else {
1339 eadd(t, ranking);
1340 evalue_free(t);
1343 Q->next = next;
1346 Domain_Free(RD);
1348 return ranking;
1351 Enumeration *barvinok_lexsmaller(Polyhedron *P, Polyhedron *D, unsigned dim,
1352 Polyhedron *C, unsigned MaxRays)
1354 evalue *EP = barvinok_lexsmaller_ev(P, D, dim, C, MaxRays);
1356 return partition2enumeration(EP);
1359 /* "align" matrix to have nrows by inserting
1360 * the necessary number of rows and an equal number of columns in front
1362 Matrix *align_matrix(Matrix *M, int nrows)
1364 int i;
1365 int newrows = nrows - M->NbRows;
1366 Matrix *M2 = Matrix_Alloc(nrows, newrows + M->NbColumns);
1367 for (i = 0; i < newrows; ++i)
1368 value_set_si(M2->p[i][i], 1);
1369 for (i = 0; i < M->NbRows; ++i)
1370 Vector_Copy(M->p[i], M2->p[newrows+i]+newrows, M->NbColumns);
1371 return M2;
1374 static void print_varlist(FILE *out, int n, char **names)
1376 int i;
1377 fprintf(out, "[");
1378 for (i = 0; i < n; ++i) {
1379 if (i)
1380 fprintf(out, ",");
1381 fprintf(out, "%s", names[i]);
1383 fprintf(out, "]");
1386 static void print_term(FILE *out, Value v, int pos, int dim, int nparam,
1387 char **iter_names, char **param_names, int *first)
1389 if (value_zero_p(v)) {
1390 if (first && *first && pos >= dim + nparam)
1391 fprintf(out, "0");
1392 return;
1395 if (first) {
1396 if (!*first && value_pos_p(v))
1397 fprintf(out, "+");
1398 *first = 0;
1400 if (pos < dim + nparam) {
1401 if (value_mone_p(v))
1402 fprintf(out, "-");
1403 else if (!value_one_p(v))
1404 value_print(out, VALUE_FMT, v);
1405 if (pos < dim)
1406 fprintf(out, "%s", iter_names[pos]);
1407 else
1408 fprintf(out, "%s", param_names[pos-dim]);
1409 } else
1410 value_print(out, VALUE_FMT, v);
1413 char **util_generate_names(int n, const char *prefix)
1415 int i;
1416 int len = (prefix ? strlen(prefix) : 0) + 10;
1417 char **names = ALLOCN(char*, n);
1418 if (!names) {
1419 fprintf(stderr, "ERROR: memory overflow.\n");
1420 exit(1);
1422 for (i = 0; i < n; ++i) {
1423 names[i] = ALLOCN(char, len);
1424 if (!names[i]) {
1425 fprintf(stderr, "ERROR: memory overflow.\n");
1426 exit(1);
1428 if (!prefix)
1429 snprintf(names[i], len, "%d", i);
1430 else
1431 snprintf(names[i], len, "%s%d", prefix, i);
1434 return names;
1437 void util_free_names(int n, char **names)
1439 int i;
1440 for (i = 0; i < n; ++i)
1441 free(names[i]);
1442 free(names);
1445 void Polyhedron_pprint(FILE *out, Polyhedron *P, int dim, int nparam,
1446 char **iter_names, char **param_names)
1448 int i, j;
1449 Value tmp;
1451 assert(dim + nparam == P->Dimension);
1453 value_init(tmp);
1455 fprintf(out, "{ ");
1456 if (nparam) {
1457 print_varlist(out, nparam, param_names);
1458 fprintf(out, " -> ");
1460 print_varlist(out, dim, iter_names);
1461 fprintf(out, " : ");
1463 if (emptyQ2(P))
1464 fprintf(out, "FALSE");
1465 else for (i = 0; i < P->NbConstraints; ++i) {
1466 int first = 1;
1467 int v = First_Non_Zero(P->Constraint[i]+1, P->Dimension);
1468 if (v == -1 && value_pos_p(P->Constraint[i][0]))
1469 continue;
1470 if (i)
1471 fprintf(out, " && ");
1472 if (v == -1 && value_notzero_p(P->Constraint[i][1+P->Dimension]))
1473 fprintf(out, "FALSE");
1474 else if (value_pos_p(P->Constraint[i][v+1])) {
1475 print_term(out, P->Constraint[i][v+1], v, dim, nparam,
1476 iter_names, param_names, NULL);
1477 if (value_zero_p(P->Constraint[i][0]))
1478 fprintf(out, " = ");
1479 else
1480 fprintf(out, " >= ");
1481 for (j = v+1; j <= dim+nparam; ++j) {
1482 value_oppose(tmp, P->Constraint[i][1+j]);
1483 print_term(out, tmp, j, dim, nparam,
1484 iter_names, param_names, &first);
1486 } else {
1487 value_oppose(tmp, P->Constraint[i][1+v]);
1488 print_term(out, tmp, v, dim, nparam,
1489 iter_names, param_names, NULL);
1490 fprintf(out, " <= ");
1491 for (j = v+1; j <= dim+nparam; ++j)
1492 print_term(out, P->Constraint[i][1+j], j, dim, nparam,
1493 iter_names, param_names, &first);
1497 fprintf(out, " }\n");
1499 value_clear(tmp);
1502 /* Construct a cone over P with P placed at x_d = 1, with
1503 * x_d the coordinate of an extra dimension
1505 * It's probably a mistake to depend so much on the internal
1506 * representation. We should probably simply compute the
1507 * vertices/facets first.
1509 Polyhedron *Cone_over_Polyhedron(Polyhedron *P)
1511 unsigned NbConstraints = 0;
1512 unsigned NbRays = 0;
1513 Polyhedron *C;
1514 int i;
1516 if (POL_HAS(P, POL_INEQUALITIES))
1517 NbConstraints = P->NbConstraints + 1;
1518 if (POL_HAS(P, POL_POINTS))
1519 NbRays = P->NbRays + 1;
1521 C = Polyhedron_Alloc(P->Dimension+1, NbConstraints, NbRays);
1522 if (POL_HAS(P, POL_INEQUALITIES)) {
1523 C->NbEq = P->NbEq;
1524 for (i = 0; i < P->NbConstraints; ++i)
1525 Vector_Copy(P->Constraint[i], C->Constraint[i], P->Dimension+2);
1526 /* n >= 0 */
1527 value_set_si(C->Constraint[P->NbConstraints][0], 1);
1528 value_set_si(C->Constraint[P->NbConstraints][1+P->Dimension], 1);
1530 if (POL_HAS(P, POL_POINTS)) {
1531 C->NbBid = P->NbBid;
1532 for (i = 0; i < P->NbRays; ++i)
1533 Vector_Copy(P->Ray[i], C->Ray[i], P->Dimension+2);
1534 /* vertex 0 */
1535 value_set_si(C->Ray[P->NbRays][0], 1);
1536 value_set_si(C->Ray[P->NbRays][1+C->Dimension], 1);
1538 POL_SET(C, POL_VALID);
1539 if (POL_HAS(P, POL_INEQUALITIES))
1540 POL_SET(C, POL_INEQUALITIES);
1541 if (POL_HAS(P, POL_POINTS))
1542 POL_SET(C, POL_POINTS);
1543 if (POL_HAS(P, POL_VERTICES))
1544 POL_SET(C, POL_VERTICES);
1545 return C;
1548 /* Returns a (dim+nparam+1)x((dim-n)+nparam+1) matrix
1549 * mapping the transformed subspace back to the original space.
1550 * n is the number of equalities involving the variables
1551 * (i.e., not purely the parameters).
1552 * The remaining n coordinates in the transformed space would
1553 * have constant (parametric) values and are therefore not
1554 * included in the variables of the new space.
1556 Matrix *compress_variables(Matrix *Equalities, unsigned nparam)
1558 unsigned dim = (Equalities->NbColumns-2) - nparam;
1559 Matrix *M, *H, *Q, *U, *C, *ratH, *invH, *Ul, *T1, *T2, *T;
1560 Value mone;
1561 int n, i, j;
1562 int ok;
1564 for (n = 0; n < Equalities->NbRows; ++n)
1565 if (First_Non_Zero(Equalities->p[n]+1, dim) == -1)
1566 break;
1567 if (n == 0)
1568 return Identity(dim+nparam+1);
1569 value_init(mone);
1570 value_set_si(mone, -1);
1571 M = Matrix_Alloc(n, dim);
1572 C = Matrix_Alloc(n+1, nparam+1);
1573 for (i = 0; i < n; ++i) {
1574 Vector_Copy(Equalities->p[i]+1, M->p[i], dim);
1575 Vector_Scale(Equalities->p[i]+1+dim, C->p[i], mone, nparam+1);
1577 value_set_si(C->p[n][nparam], 1);
1578 left_hermite(M, &H, &Q, &U);
1579 Matrix_Free(M);
1580 Matrix_Free(Q);
1581 value_clear(mone);
1583 ratH = Matrix_Alloc(n+1, n+1);
1584 invH = Matrix_Alloc(n+1, n+1);
1585 for (i = 0; i < n; ++i)
1586 Vector_Copy(H->p[i], ratH->p[i], n);
1587 value_set_si(ratH->p[n][n], 1);
1588 ok = Matrix_Inverse(ratH, invH);
1589 assert(ok);
1590 Matrix_Free(H);
1591 Matrix_Free(ratH);
1592 T1 = Matrix_Alloc(n+1, nparam+1);
1593 Matrix_Product(invH, C, T1);
1594 Matrix_Free(C);
1595 Matrix_Free(invH);
1596 if (value_notone_p(T1->p[n][nparam])) {
1597 for (i = 0; i < n; ++i) {
1598 if (!mpz_divisible_p(T1->p[i][nparam], T1->p[n][nparam])) {
1599 Matrix_Free(T1);
1600 Matrix_Free(U);
1601 return NULL;
1603 /* compress_params should have taken care of this */
1604 for (j = 0; j < nparam; ++j)
1605 assert(mpz_divisible_p(T1->p[i][j], T1->p[n][nparam]));
1606 Vector_AntiScale(T1->p[i], T1->p[i], T1->p[n][nparam], nparam+1);
1608 value_set_si(T1->p[n][nparam], 1);
1610 Ul = Matrix_Alloc(dim+1, n+1);
1611 for (i = 0; i < dim; ++i)
1612 Vector_Copy(U->p[i], Ul->p[i], n);
1613 value_set_si(Ul->p[dim][n], 1);
1614 T2 = Matrix_Alloc(dim+1, nparam+1);
1615 Matrix_Product(Ul, T1, T2);
1616 Matrix_Free(Ul);
1617 Matrix_Free(T1);
1619 T = Matrix_Alloc(dim+nparam+1, (dim-n)+nparam+1);
1620 for (i = 0; i < dim; ++i) {
1621 Vector_Copy(U->p[i]+n, T->p[i], dim-n);
1622 Vector_Copy(T2->p[i], T->p[i]+dim-n, nparam+1);
1624 for (i = 0; i < nparam+1; ++i)
1625 value_set_si(T->p[dim+i][(dim-n)+i], 1);
1626 assert(value_one_p(T2->p[dim][nparam]));
1627 Matrix_Free(U);
1628 Matrix_Free(T2);
1630 return T;
1633 /* Computes the left inverse of an affine embedding M and, if Eq is not NULL,
1634 * the equalities that define the affine subspace onto which M maps
1635 * its argument.
1637 Matrix *left_inverse(Matrix *M, Matrix **Eq)
1639 int i, ok;
1640 Matrix *L, *H, *Q, *U, *ratH, *invH, *Ut, *inv;
1641 Vector *t;
1643 if (M->NbColumns == 1) {
1644 inv = Matrix_Alloc(1, M->NbRows);
1645 value_set_si(inv->p[0][M->NbRows-1], 1);
1646 if (Eq) {
1647 *Eq = Matrix_Alloc(M->NbRows-1, 1+(M->NbRows-1)+1);
1648 for (i = 0; i < M->NbRows-1; ++i) {
1649 value_oppose((*Eq)->p[i][1+i], M->p[M->NbRows-1][0]);
1650 value_assign((*Eq)->p[i][1+(M->NbRows-1)], M->p[i][0]);
1653 return inv;
1655 if (Eq)
1656 *Eq = NULL;
1657 L = Matrix_Alloc(M->NbRows-1, M->NbColumns-1);
1658 for (i = 0; i < L->NbRows; ++i)
1659 Vector_Copy(M->p[i], L->p[i], L->NbColumns);
1660 right_hermite(L, &H, &U, &Q);
1661 Matrix_Free(L);
1662 Matrix_Free(Q);
1663 t = Vector_Alloc(U->NbColumns);
1664 for (i = 0; i < U->NbColumns; ++i)
1665 value_oppose(t->p[i], M->p[i][M->NbColumns-1]);
1666 if (Eq) {
1667 *Eq = Matrix_Alloc(H->NbRows - H->NbColumns, 2 + U->NbColumns);
1668 for (i = 0; i < H->NbRows - H->NbColumns; ++i) {
1669 Vector_Copy(U->p[H->NbColumns+i], (*Eq)->p[i]+1, U->NbColumns);
1670 Inner_Product(U->p[H->NbColumns+i], t->p, U->NbColumns,
1671 (*Eq)->p[i]+1+U->NbColumns);
1674 ratH = Matrix_Alloc(H->NbColumns+1, H->NbColumns+1);
1675 invH = Matrix_Alloc(H->NbColumns+1, H->NbColumns+1);
1676 for (i = 0; i < H->NbColumns; ++i)
1677 Vector_Copy(H->p[i], ratH->p[i], H->NbColumns);
1678 value_set_si(ratH->p[ratH->NbRows-1][ratH->NbColumns-1], 1);
1679 Matrix_Free(H);
1680 ok = Matrix_Inverse(ratH, invH);
1681 assert(ok);
1682 Matrix_Free(ratH);
1683 Ut = Matrix_Alloc(invH->NbRows, U->NbColumns+1);
1684 for (i = 0; i < Ut->NbRows-1; ++i) {
1685 Vector_Copy(U->p[i], Ut->p[i], U->NbColumns);
1686 Inner_Product(U->p[i], t->p, U->NbColumns, &Ut->p[i][Ut->NbColumns-1]);
1688 Matrix_Free(U);
1689 Vector_Free(t);
1690 value_set_si(Ut->p[Ut->NbRows-1][Ut->NbColumns-1], 1);
1691 inv = Matrix_Alloc(invH->NbRows, Ut->NbColumns);
1692 Matrix_Product(invH, Ut, inv);
1693 Matrix_Free(Ut);
1694 Matrix_Free(invH);
1695 return inv;
1698 /* Check whether all rays are revlex positive in the parameters
1700 int Polyhedron_has_revlex_positive_rays(Polyhedron *P, unsigned nparam)
1702 int r;
1703 for (r = 0; r < P->NbRays; ++r) {
1704 int i;
1705 if (value_notzero_p(P->Ray[r][P->Dimension+1]))
1706 continue;
1707 for (i = P->Dimension-1; i >= P->Dimension-nparam; --i) {
1708 if (value_neg_p(P->Ray[r][i+1]))
1709 return 0;
1710 if (value_pos_p(P->Ray[r][i+1]))
1711 break;
1713 /* A ray independent of the parameters */
1714 if (i < P->Dimension-nparam)
1715 return 0;
1717 return 1;
1720 static Polyhedron *Recession_Cone(Polyhedron *P, unsigned nparam, unsigned MaxRays)
1722 int i;
1723 unsigned nvar = P->Dimension - nparam;
1724 Matrix *M = Matrix_Alloc(P->NbConstraints, 1 + nvar + 1);
1725 Polyhedron *R;
1726 for (i = 0; i < P->NbConstraints; ++i)
1727 Vector_Copy(P->Constraint[i], M->p[i], 1+nvar);
1728 R = Constraints2Polyhedron(M, MaxRays);
1729 Matrix_Free(M);
1730 return R;
1733 int Polyhedron_is_unbounded(Polyhedron *P, unsigned nparam, unsigned MaxRays)
1735 int i;
1736 int is_unbounded;
1737 Polyhedron *R = Recession_Cone(P, nparam, MaxRays);
1738 POL_ENSURE_VERTICES(R);
1739 if (R->NbBid == 0)
1740 for (i = 0; i < R->NbRays; ++i)
1741 if (value_zero_p(R->Ray[i][1+R->Dimension]))
1742 break;
1743 is_unbounded = R->NbBid > 0 || i < R->NbRays;
1744 Polyhedron_Free(R);
1745 return is_unbounded;
1748 static void SwapColumns(Value **V, int n, int i, int j)
1750 int r;
1752 for (r = 0; r < n; ++r)
1753 value_swap(V[r][i], V[r][j]);
1756 void Polyhedron_ExchangeColumns(Polyhedron *P, int Column1, int Column2)
1758 SwapColumns(P->Constraint, P->NbConstraints, Column1, Column2);
1759 SwapColumns(P->Ray, P->NbRays, Column1, Column2);
1760 if (P->NbEq) {
1761 Matrix M;
1762 Polyhedron_Matrix_View(P, &M, P->NbConstraints);
1763 Gauss(&M, P->NbEq, P->Dimension+1);
1767 /* perform transposition inline; assumes M is a square matrix */
1768 void Matrix_Transposition(Matrix *M)
1770 int i, j;
1772 assert(M->NbRows == M->NbColumns);
1773 for (i = 0; i < M->NbRows; ++i)
1774 for (j = i+1; j < M->NbColumns; ++j)
1775 value_swap(M->p[i][j], M->p[j][i]);
1778 /* Matrix "view" of first rows rows */
1779 void Polyhedron_Matrix_View(Polyhedron *P, Matrix *M, unsigned rows)
1781 M->NbRows = rows;
1782 M->NbColumns = P->Dimension+2;
1783 M->p_Init = P->p_Init;
1784 M->p = P->Constraint;
1787 int Last_Non_Zero(Value *p, unsigned len)
1789 int i;
1791 for (i = len - 1; i >= 0; --i)
1792 if (value_notzero_p(p[i]))
1793 return i;
1795 return -1;