isl_pw_qpolynomial_sum: simplify construction of target space
[barvinok.git] / util.c
blob4b099ca89abfdd7ad681914ea069f82ee3262279
1 #include <stdlib.h>
2 #include <assert.h>
3 #include <isl_set_polylib.h>
4 #include <barvinok/util.h>
5 #include <barvinok/options.h>
6 #include <polylib/ranking.h>
7 #include "config.h"
8 #include "lattice_point.h"
10 #define ALLOC(type) (type*)malloc(sizeof(type))
11 #define ALLOCN(type,n) (type*)malloc((n) * sizeof(type))
13 #ifdef __GNUC__
14 #define NALLOC(p,n) p = (typeof(p))malloc((n) * sizeof(*p))
15 #else
16 #define NALLOC(p,n) p = (void *)malloc((n) * sizeof(*p))
17 #endif
19 void manual_count(Polyhedron *P, Value* result)
21 isl_ctx *ctx = isl_ctx_alloc();
22 isl_space *dim;
23 isl_set *set;
24 isl_int v;
25 int nvar = P->Dimension;
26 int r;
28 dim = isl_space_set_alloc(ctx, 0, nvar);
29 set = isl_set_new_from_polylib(P, dim);
31 isl_int_init(v);
32 r = isl_set_count(set, &v);
33 isl_int_get_gmp(v, *result);
34 isl_int_clear(v);
36 isl_set_free(set);
37 isl_ctx_free(ctx);
39 assert(r >= 0);
42 #include <barvinok/evalue.h>
43 #include <barvinok/util.h>
44 #include <barvinok/barvinok.h>
46 /* Return random value between 0 and max-1 inclusive
48 int random_int(int max) {
49 return (int) (((double)(max))*rand()/(RAND_MAX+1.0));
52 Polyhedron *Polyhedron_Read(unsigned MaxRays)
54 int vertices = 0;
55 unsigned NbRows, NbColumns;
56 Matrix *M;
57 Polyhedron *P;
58 char s[128];
60 while (fgets(s, sizeof(s), stdin)) {
61 if (*s == '#')
62 continue;
63 if (strncasecmp(s, "vertices", sizeof("vertices")-1) == 0)
64 vertices = 1;
65 if (sscanf(s, "%u %u", &NbRows, &NbColumns) == 2)
66 break;
68 if (feof(stdin))
69 return NULL;
70 M = Matrix_Alloc(NbRows,NbColumns);
71 Matrix_Read_Input(M);
72 if (vertices)
73 P = Rays2Polyhedron(M, MaxRays);
74 else
75 P = Constraints2Polyhedron(M, MaxRays);
76 Matrix_Free(M);
77 return P;
80 /* Inplace polarization
82 void Polyhedron_Polarize(Polyhedron *P)
84 unsigned NbRows = P->NbConstraints + P->NbRays;
85 int i;
86 Value **q;
88 q = (Value **)malloc(NbRows * sizeof(Value *));
89 assert(q);
90 for (i = 0; i < P->NbRays; ++i)
91 q[i] = P->Ray[i];
92 for (; i < NbRows; ++i)
93 q[i] = P->Constraint[i-P->NbRays];
94 P->NbConstraints = NbRows - P->NbConstraints;
95 P->NbRays = NbRows - P->NbRays;
96 free(P->Constraint);
97 P->Constraint = q;
98 P->Ray = q + P->NbConstraints;
102 * Rather general polar
103 * We can optimize it significantly if we assume that
104 * P includes zero
106 * Also, we calculate the polar as defined in Schrijver
107 * The opposite should probably work as well and would
108 * eliminate the need for multiplying by -1
110 Polyhedron* Polyhedron_Polar(Polyhedron *P, unsigned NbMaxRays)
112 int i;
113 Value mone;
114 unsigned dim = P->Dimension + 2;
115 Matrix *M = Matrix_Alloc(P->NbRays, dim);
117 assert(M);
118 value_init(mone);
119 value_set_si(mone, -1);
120 for (i = 0; i < P->NbRays; ++i) {
121 Vector_Scale(P->Ray[i], M->p[i], mone, dim);
122 value_multiply(M->p[i][0], M->p[i][0], mone);
123 value_multiply(M->p[i][dim-1], M->p[i][dim-1], mone);
125 P = Constraints2Polyhedron(M, NbMaxRays);
126 assert(P);
127 Matrix_Free(M);
128 value_clear(mone);
129 return P;
133 * Returns the supporting cone of P at the vertex with index v
135 Polyhedron* supporting_cone(Polyhedron *P, int v)
137 Matrix *M;
138 Value tmp;
139 int i, n, j;
140 unsigned char *supporting = (unsigned char *)malloc(P->NbConstraints);
141 unsigned dim = P->Dimension + 2;
143 assert(v >=0 && v < P->NbRays);
144 assert(value_pos_p(P->Ray[v][dim-1]));
145 assert(supporting);
147 value_init(tmp);
148 for (i = 0, n = 0; i < P->NbConstraints; ++i) {
149 Inner_Product(P->Constraint[i] + 1, P->Ray[v] + 1, dim - 1, &tmp);
150 if ((supporting[i] = value_zero_p(tmp)))
151 ++n;
153 assert(n >= dim - 2);
154 value_clear(tmp);
155 M = Matrix_Alloc(n, dim);
156 assert(M);
157 for (i = 0, j = 0; i < P->NbConstraints; ++i)
158 if (supporting[i]) {
159 value_set_si(M->p[j][dim-1], 0);
160 Vector_Copy(P->Constraint[i], M->p[j++], dim-1);
162 free(supporting);
163 P = Constraints2Polyhedron(M, P->NbRays+1);
164 assert(P);
165 Matrix_Free(M);
166 return P;
169 #define INT_BITS (sizeof(unsigned) * 8)
171 unsigned *supporting_constraints(Matrix *Constraints, Param_Vertices *v, int *n)
173 Value lcm, tmp, tmp2;
174 unsigned dim = Constraints->NbColumns;
175 unsigned nparam = v->Vertex->NbColumns - 2;
176 unsigned nvar = dim - nparam - 2;
177 int len = (Constraints->NbRows+INT_BITS-1)/INT_BITS;
178 unsigned *supporting = (unsigned *)calloc(len, sizeof(unsigned));
179 int i, j;
180 Vector *row;
181 int ix;
182 unsigned bx;
184 assert(supporting);
185 row = Vector_Alloc(nparam+1);
186 assert(row);
187 value_init(lcm);
188 value_init(tmp);
189 value_init(tmp2);
190 value_set_si(lcm, 1);
191 for (i = 0, *n = 0, ix = 0, bx = MSB; i < Constraints->NbRows; ++i) {
192 Vector_Set(row->p, 0, nparam+1);
193 for (j = 0 ; j < nvar; ++j) {
194 value_set_si(tmp, 1);
195 value_assign(tmp2, Constraints->p[i][j+1]);
196 if (value_ne(lcm, v->Vertex->p[j][nparam+1])) {
197 value_assign(tmp, lcm);
198 value_lcm(lcm, lcm, v->Vertex->p[j][nparam+1]);
199 value_division(tmp, lcm, tmp);
200 value_multiply(tmp2, tmp2, lcm);
201 value_division(tmp2, tmp2, v->Vertex->p[j][nparam+1]);
203 Vector_Combine(row->p, v->Vertex->p[j], row->p,
204 tmp, tmp2, nparam+1);
206 value_set_si(tmp, 1);
207 Vector_Combine(row->p, Constraints->p[i]+1+nvar, row->p, tmp, lcm, nparam+1);
208 for (j = 0; j < nparam+1; ++j)
209 if (value_notzero_p(row->p[j]))
210 break;
211 if (j == nparam + 1) {
212 supporting[ix] |= bx;
213 ++*n;
215 NEXT(ix, bx);
217 assert(*n >= nvar);
218 value_clear(tmp);
219 value_clear(tmp2);
220 value_clear(lcm);
221 Vector_Free(row);
223 return supporting;
226 Polyhedron* supporting_cone_p(Polyhedron *P, Param_Vertices *v)
228 Matrix *M;
229 unsigned dim = P->Dimension + 2;
230 unsigned nparam = v->Vertex->NbColumns - 2;
231 unsigned nvar = dim - nparam - 2;
232 int i, n, j;
233 int ix;
234 unsigned bx;
235 unsigned *supporting;
236 Matrix View;
238 Polyhedron_Matrix_View(P, &View, P->NbConstraints);
239 supporting = supporting_constraints(&View, v, &n);
240 M = Matrix_Alloc(n, nvar+2);
241 assert(M);
242 for (i = 0, j = 0, ix = 0, bx = MSB; i < P->NbConstraints; ++i) {
243 if (supporting[ix] & bx) {
244 value_set_si(M->p[j][nvar+1], 0);
245 Vector_Copy(P->Constraint[i], M->p[j++], nvar+1);
247 NEXT(ix, bx);
249 free(supporting);
250 P = Constraints2Polyhedron(M, P->NbRays+1);
251 assert(P);
252 Matrix_Free(M);
253 return P;
256 Polyhedron* triangulate_cone(Polyhedron *P, unsigned NbMaxCons)
258 struct barvinok_options *options = barvinok_options_new_with_defaults();
259 options->MaxRays = NbMaxCons;
260 P = triangulate_cone_with_options(P, options);
261 barvinok_options_free(options);
262 return P;
265 Polyhedron* triangulate_cone_with_options(Polyhedron *P,
266 struct barvinok_options *options)
268 const static int MAX_TRY=10;
269 int i, j, r, n, t;
270 Value tmp;
271 unsigned dim = P->Dimension;
272 Matrix *M = Matrix_Alloc(P->NbRays+1, dim+3);
273 Matrix *M2, *M3;
274 Polyhedron *L, *R, *T;
275 assert(P->NbEq == 0);
277 L = NULL;
278 R = NULL;
279 value_init(tmp);
281 Vector_Set(M->p[0]+1, 0, dim+1);
282 value_set_si(M->p[0][0], 1);
283 value_set_si(M->p[0][dim+2], 1);
284 Vector_Set(M->p[P->NbRays]+1, 0, dim+2);
285 value_set_si(M->p[P->NbRays][0], 1);
286 value_set_si(M->p[P->NbRays][dim+1], 1);
288 for (i = 0, r = 1; i < P->NbRays; ++i) {
289 if (value_notzero_p(P->Ray[i][dim+1]))
290 continue;
291 Vector_Copy(P->Ray[i], M->p[r], dim+1);
292 value_set_si(M->p[r][dim+2], 0);
293 ++r;
296 M2 = Matrix_Alloc(dim+1, dim+2);
298 t = 0;
299 if (options->try_Delaunay_triangulation) {
300 /* Delaunay triangulation */
301 for (r = 1; r < P->NbRays; ++r) {
302 Inner_Product(M->p[r]+1, M->p[r]+1, dim, &tmp);
303 value_assign(M->p[r][dim+1], tmp);
305 M3 = Matrix_Copy(M);
306 L = Rays2Polyhedron(M3, options->MaxRays);
307 Matrix_Free(M3);
308 ++t;
309 } else {
310 try_again:
311 /* Usually R should still be 0 */
312 Domain_Free(R);
313 Polyhedron_Free(L);
314 for (r = 1; r < P->NbRays; ++r) {
315 value_set_si(M->p[r][dim+1], random_int((t+1)*dim*P->NbRays)+1);
317 M3 = Matrix_Copy(M);
318 L = Rays2Polyhedron(M3, options->MaxRays);
319 Matrix_Free(M3);
320 ++t;
322 assert(t <= MAX_TRY);
324 R = NULL;
325 n = 0;
327 POL_ENSURE_FACETS(L);
328 for (i = 0; i < L->NbConstraints; ++i) {
329 /* Ignore perpendicular facets, i.e., facets with 0 z-coordinate */
330 if (value_negz_p(L->Constraint[i][dim+1]))
331 continue;
332 if (value_notzero_p(L->Constraint[i][dim+2]))
333 continue;
334 for (j = 1, r = 1; j < M->NbRows; ++j) {
335 Inner_Product(M->p[j]+1, L->Constraint[i]+1, dim+1, &tmp);
336 if (value_notzero_p(tmp))
337 continue;
338 if (r > dim)
339 goto try_again;
340 Vector_Copy(M->p[j]+1, M2->p[r]+1, dim);
341 value_set_si(M2->p[r][0], 1);
342 value_set_si(M2->p[r][dim+1], 0);
343 ++r;
345 assert(r == dim+1);
346 Vector_Set(M2->p[0]+1, 0, dim);
347 value_set_si(M2->p[0][0], 1);
348 value_set_si(M2->p[0][dim+1], 1);
349 T = Rays2Polyhedron(M2, P->NbConstraints+1);
350 T->next = R;
351 R = T;
352 ++n;
354 Matrix_Free(M2);
356 Polyhedron_Free(L);
357 value_clear(tmp);
358 Matrix_Free(M);
360 return R;
363 void check_triangulization(Polyhedron *P, Polyhedron *T)
365 Polyhedron *C, *D, *E, *F, *G, *U;
366 for (C = T; C; C = C->next) {
367 if (C == T)
368 U = C;
369 else
370 U = DomainConvex(DomainUnion(U, C, 100), 100);
371 for (D = C->next; D; D = D->next) {
372 F = C->next;
373 G = D->next;
374 C->next = NULL;
375 D->next = NULL;
376 E = DomainIntersection(C, D, 600);
377 assert(E->NbRays == 0 || E->NbEq >= 1);
378 Polyhedron_Free(E);
379 C->next = F;
380 D->next = G;
383 assert(PolyhedronIncludes(U, P));
384 assert(PolyhedronIncludes(P, U));
387 /* Computes x, y and g such that g = gcd(a,b) and a*x+b*y = g */
388 void Extended_Euclid(Value a, Value b, Value *x, Value *y, Value *g)
390 Value c, d, e, f, tmp;
392 value_init(c);
393 value_init(d);
394 value_init(e);
395 value_init(f);
396 value_init(tmp);
397 value_absolute(c, a);
398 value_absolute(d, b);
399 value_set_si(e, 1);
400 value_set_si(f, 0);
401 while(value_pos_p(d)) {
402 value_division(tmp, c, d);
403 value_multiply(tmp, tmp, f);
404 value_subtract(e, e, tmp);
405 value_division(tmp, c, d);
406 value_multiply(tmp, tmp, d);
407 value_subtract(c, c, tmp);
408 value_swap(c, d);
409 value_swap(e, f);
411 value_assign(*g, c);
412 if (value_zero_p(a))
413 value_set_si(*x, 0);
414 else if (value_pos_p(a))
415 value_assign(*x, e);
416 else value_oppose(*x, e);
417 if (value_zero_p(b))
418 value_set_si(*y, 0);
419 else {
420 value_multiply(tmp, a, *x);
421 value_subtract(tmp, c, tmp);
422 value_division(*y, tmp, b);
424 value_clear(c);
425 value_clear(d);
426 value_clear(e);
427 value_clear(f);
428 value_clear(tmp);
431 static int unimodular_complete_1(Matrix *m)
433 Value g, b, c, old, tmp;
434 unsigned i, j;
435 int ok;
437 value_init(b);
438 value_init(c);
439 value_init(g);
440 value_init(old);
441 value_init(tmp);
442 value_assign(g, m->p[0][0]);
443 for (i = 1; value_zero_p(g) && i < m->NbColumns; ++i) {
444 for (j = 0; j < m->NbColumns; ++j) {
445 if (j == i-1)
446 value_set_si(m->p[i][j], 1);
447 else
448 value_set_si(m->p[i][j], 0);
450 value_assign(g, m->p[0][i]);
452 for (; i < m->NbColumns; ++i) {
453 value_assign(old, g);
454 Extended_Euclid(old, m->p[0][i], &c, &b, &g);
455 value_oppose(b, b);
456 for (j = 0; j < m->NbColumns; ++j) {
457 if (j < i) {
458 value_multiply(tmp, m->p[0][j], b);
459 value_division(m->p[i][j], tmp, old);
460 } else if (j == i)
461 value_assign(m->p[i][j], c);
462 else
463 value_set_si(m->p[i][j], 0);
466 ok = value_one_p(g);
467 value_clear(b);
468 value_clear(c);
469 value_clear(g);
470 value_clear(old);
471 value_clear(tmp);
472 return ok;
475 int unimodular_complete(Matrix *M, int row)
477 int r;
478 int ok = 1;
479 Matrix *H, *Q, *U;
481 if (row == 1)
482 return unimodular_complete_1(M);
484 left_hermite(M, &H, &Q, &U);
485 Matrix_Free(U);
486 for (r = 0; ok && r < row; ++r)
487 if (value_notone_p(H->p[r][r]))
488 ok = 0;
489 Matrix_Free(H);
490 for (r = row; r < M->NbRows; ++r)
491 Vector_Copy(Q->p[r], M->p[r], M->NbColumns);
492 Matrix_Free(Q);
493 return ok;
497 * left_hermite may leave positive entries below the main diagonal in H.
498 * This function postprocesses the output of left_hermite to make
499 * the non-zero entries below the main diagonal negative.
501 void neg_left_hermite(Matrix *A, Matrix **H_p, Matrix **Q_p, Matrix **U_p)
503 int row, col, i, j;
504 Matrix *H, *U, *Q;
506 left_hermite(A, &H, &Q, &U);
507 *H_p = H;
508 *Q_p = Q;
509 *U_p = U;
511 for (row = 0, col = 0; col < H->NbColumns; ++col, ++row) {
512 while (value_zero_p(H->p[row][col]))
513 ++row;
514 for (i = 0; i < col; ++i) {
515 if (value_negz_p(H->p[row][i]))
516 continue;
518 /* subtract column col from column i in H and U */
519 for (j = 0; j < H->NbRows; ++j)
520 value_subtract(H->p[j][i], H->p[j][i], H->p[j][col]);
521 for (j = 0; j < U->NbRows; ++j)
522 value_subtract(U->p[j][i], U->p[j][i], U->p[j][col]);
524 /* add row i to row col in Q */
525 for (j = 0; j < Q->NbColumns; ++j)
526 value_addto(Q->p[col][j], Q->p[col][j], Q->p[i][j]);
532 * Returns a full-dimensional polyhedron with the same number
533 * of integer points as P
535 Polyhedron *remove_equalities(Polyhedron *P, unsigned MaxRays)
537 Matrix M;
538 Matrix *T;
539 Polyhedron *Q = Polyhedron_Copy(P);
540 unsigned dim = P->Dimension;
542 if (Q->NbEq == 0)
543 return Q;
545 Q = DomainConstraintSimplify(Q, MaxRays);
546 if (emptyQ2(Q))
547 return Q;
549 Polyhedron_Matrix_View(Q, &M, Q->NbEq);
550 T = compress_variables(&M, 0);
552 if (!T)
553 P = NULL;
554 else {
555 P = Polyhedron_Preimage(Q, T, MaxRays);
556 Matrix_Free(T);
559 Polyhedron_Free(Q);
561 return P;
565 * Returns a full-dimensional polyhedron with the same number
566 * of integer points as P
567 * nvar specifies the number of variables
568 * The remaining dimensions are assumed to be parameters
569 * Destroys P
570 * factor is NbEq x (nparam+2) matrix, containing stride constraints
571 * on the parameters; column nparam is the constant;
572 * column nparam+1 is the stride
574 * if factor is NULL, only remove equalities that don't affect
575 * the number of points
577 Polyhedron *remove_equalities_p(Polyhedron *P, unsigned nvar, Matrix **factor,
578 unsigned MaxRays)
580 Value g;
581 Polyhedron *Q;
582 unsigned dim = P->Dimension;
583 Matrix *m1, *m2, *f;
584 int i, j;
586 if (P->NbEq == 0)
587 return P;
589 m1 = Matrix_Alloc(nvar, nvar);
590 P = DomainConstraintSimplify(P, MaxRays);
591 if (factor) {
592 f = Matrix_Alloc(P->NbEq, dim-nvar+2);
593 *factor = f;
595 value_init(g);
596 for (i = 0, j = 0; i < P->NbEq; ++i) {
597 if (First_Non_Zero(P->Constraint[i]+1, nvar) == -1)
598 continue;
600 Vector_Gcd(P->Constraint[i]+1, nvar, &g);
601 if (!factor && value_notone_p(g))
602 continue;
604 if (factor) {
605 Vector_Copy(P->Constraint[i]+1+nvar, f->p[j], dim-nvar+1);
606 value_assign(f->p[j][dim-nvar+1], g);
609 Vector_Copy(P->Constraint[i]+1, m1->p[j], nvar);
611 ++j;
613 value_clear(g);
615 unimodular_complete(m1, j);
617 m2 = Matrix_Alloc(dim+1-j, dim+1);
618 for (i = 0; i < nvar-j ; ++i)
619 Vector_Copy(m1->p[i+j], m2->p[i], nvar);
620 Matrix_Free(m1);
621 for (i = nvar-j; i <= dim-j; ++i)
622 value_set_si(m2->p[i][i+j], 1);
624 Q = Polyhedron_Image(P, m2, MaxRays);
625 Matrix_Free(m2);
626 Polyhedron_Free(P);
628 return Q;
631 void Line_Length(Polyhedron *P, Value *len)
633 Value tmp, pos, neg;
634 int p = 0, n = 0;
635 int i;
637 assert(P->Dimension == 1);
639 if (P->NbEq > 0) {
640 if (mpz_divisible_p(P->Constraint[0][2], P->Constraint[0][1]))
641 value_set_si(*len, 1);
642 else
643 value_set_si(*len, 0);
644 return;
647 value_init(tmp);
648 value_init(pos);
649 value_init(neg);
651 for (i = 0; i < P->NbConstraints; ++i) {
652 value_oppose(tmp, P->Constraint[i][2]);
653 if (value_pos_p(P->Constraint[i][1])) {
654 mpz_cdiv_q(tmp, tmp, P->Constraint[i][1]);
655 if (!p || value_gt(tmp, pos))
656 value_assign(pos, tmp);
657 p = 1;
658 } else if (value_neg_p(P->Constraint[i][1])) {
659 mpz_fdiv_q(tmp, tmp, P->Constraint[i][1]);
660 if (!n || value_lt(tmp, neg))
661 value_assign(neg, tmp);
662 n = 1;
664 if (n && p) {
665 value_subtract(tmp, neg, pos);
666 value_increment(*len, tmp);
667 } else
668 value_set_si(*len, -1);
671 value_clear(tmp);
672 value_clear(pos);
673 value_clear(neg);
676 /* Update group[k] to the group column k belongs to.
677 * When merging two groups, only the group of the current
678 * group leader is changed. Here we change the group of
679 * the other members to also point to the group that the
680 * old group leader now points to.
682 static void update_group(int *group, int *cnt, int k)
684 int g = group[k];
685 while (cnt[g] == 0)
686 g = group[g];
687 group[k] = g;
691 * Factors the polyhedron P into polyhedra Q_i such that
692 * the number of integer points in P is equal to the product
693 * of the number of integer points in the individual Q_i
695 * If no factors can be found, NULL is returned.
696 * Otherwise, a linked list of the factors is returned.
698 * If there are factors and if T is not NULL, then a matrix will be
699 * returned through T expressing the old variables in terms of the
700 * new variables as they appear in the sequence of factors.
702 * The algorithm works by first computing the Hermite normal form
703 * and then grouping columns linked by one or more constraints together,
704 * where a constraints "links" two or more columns if the constraint
705 * has nonzero coefficients in the columns.
707 Polyhedron* Polyhedron_Factor(Polyhedron *P, unsigned nparam, Matrix **T,
708 unsigned NbMaxRays)
710 int i, j, k;
711 Matrix *M, *H, *Q, *U;
712 int *pos; /* for each column: row position of pivot */
713 int *group; /* group to which a column belongs */
714 int *cnt; /* number of columns in the group */
715 int *rowgroup; /* group to which a constraint belongs */
716 int nvar = P->Dimension - nparam;
717 Polyhedron *F = NULL;
719 if (nvar <= 1)
720 return NULL;
722 NALLOC(pos, nvar);
723 NALLOC(group, nvar);
724 NALLOC(cnt, nvar);
725 NALLOC(rowgroup, P->NbConstraints);
727 M = Matrix_Alloc(P->NbConstraints, nvar);
728 for (i = 0; i < P->NbConstraints; ++i)
729 Vector_Copy(P->Constraint[i]+1, M->p[i], nvar);
730 left_hermite(M, &H, &Q, &U);
731 Matrix_Free(M);
732 Matrix_Free(Q);
734 for (i = 0; i < P->NbConstraints; ++i)
735 rowgroup[i] = -1;
736 for (i = 0, j = 0; i < H->NbColumns; ++i) {
737 for ( ; j < H->NbRows; ++j)
738 if (value_notzero_p(H->p[j][i]))
739 break;
740 pos[i] = j;
742 for (i = 0; i < nvar; ++i) {
743 group[i] = i;
744 cnt[i] = 1;
746 for (i = 0; i < H->NbColumns && cnt[0] < nvar; ++i) {
747 if (pos[i] == H->NbRows)
748 continue; /* A line direction */
749 if (rowgroup[pos[i]] == -1)
750 rowgroup[pos[i]] = i;
751 for (j = pos[i]+1; j < H->NbRows; ++j) {
752 if (value_zero_p(H->p[j][i]))
753 continue;
754 if (rowgroup[j] != -1)
755 continue;
756 rowgroup[j] = group[i];
757 for (k = i+1; k < H->NbColumns && j >= pos[k]; ++k) {
758 update_group(group, cnt, k);
759 update_group(group, cnt, i);
760 if (group[k] != group[i] && value_notzero_p(H->p[j][k])) {
761 assert(cnt[group[k]] != 0);
762 assert(cnt[group[i]] != 0);
763 if (group[i] < group[k]) {
764 cnt[group[i]] += cnt[group[k]];
765 cnt[group[k]] = 0;
766 group[group[k]] = group[i];
767 } else {
768 cnt[group[k]] += cnt[group[i]];
769 cnt[group[i]] = 0;
770 group[group[i]] = group[k];
777 if (cnt[0] != nvar) {
778 /* Extract out pure context constraints separately */
779 Polyhedron **next = &F;
780 int tot_d = 0;
781 if (T)
782 *T = Matrix_Alloc(nvar, nvar);
783 for (i = nparam ? -1 : 0; i < nvar; ++i) {
784 int d;
786 if (i == -1) {
787 for (j = 0, k = 0; j < P->NbConstraints; ++j)
788 if (rowgroup[j] == -1) {
789 if (First_Non_Zero(P->Constraint[j]+1+nvar,
790 nparam) == -1)
791 rowgroup[j] = -2;
792 else
793 ++k;
795 if (k == 0)
796 continue;
797 d = 0;
798 } else {
799 if (cnt[i] == 0)
800 continue;
801 d = cnt[i];
802 for (j = 0, k = 0; j < P->NbConstraints; ++j)
803 if (rowgroup[j] >= 0 && group[rowgroup[j]] == i) {
804 rowgroup[j] = i;
805 ++k;
809 if (T)
810 for (j = 0; j < nvar; ++j) {
811 int l, m;
812 for (l = 0, m = 0; m < d; ++l) {
813 if (group[l] != i)
814 continue;
815 value_assign((*T)->p[j][tot_d+m++], U->p[j][l]);
819 M = Matrix_Alloc(k, d+nparam+2);
820 for (j = 0, k = 0; j < P->NbConstraints; ++j) {
821 int l, m;
822 if (rowgroup[j] != i)
823 continue;
824 value_assign(M->p[k][0], P->Constraint[j][0]);
825 for (l = 0, m = 0; m < d; ++l) {
826 if (group[l] != i)
827 continue;
828 value_assign(M->p[k][1+m++], H->p[j][l]);
830 Vector_Copy(P->Constraint[j]+1+nvar, M->p[k]+1+m, nparam+1);
831 ++k;
833 *next = Constraints2Polyhedron(M, NbMaxRays);
834 next = &(*next)->next;
835 Matrix_Free(M);
836 tot_d += d;
839 Matrix_Free(U);
840 Matrix_Free(H);
841 free(pos);
842 free(group);
843 free(cnt);
844 free(rowgroup);
845 return F;
848 /* Computes the intersection of the contexts of a list of factors */
849 Polyhedron *Factor_Context(Polyhedron *F, unsigned nparam, unsigned MaxRays)
851 Polyhedron *Q;
852 Polyhedron *C = NULL;
854 for (Q = F; Q; Q = Q->next) {
855 Polyhedron *QC = Q;
856 Polyhedron *next = Q->next;
857 Q->next = NULL;
859 if (Q->Dimension != nparam)
860 QC = Polyhedron_Project(Q, nparam);
862 if (!C)
863 C = Q == QC ? Polyhedron_Copy(QC) : QC;
864 else {
865 Polyhedron *C2 = C;
866 C = DomainIntersection(C, QC, MaxRays);
867 Polyhedron_Free(C2);
868 if (QC != Q)
869 Polyhedron_Free(QC);
871 Q->next = next;
873 return C;
877 * Project on final dim dimensions
879 Polyhedron* Polyhedron_Project(Polyhedron *P, int dim)
881 int i;
882 int remove = P->Dimension - dim;
883 Matrix *T;
884 Polyhedron *I;
886 if (P->Dimension == dim)
887 return Polyhedron_Copy(P);
889 T = Matrix_Alloc(dim+1, P->Dimension+1);
890 for (i = 0; i < dim+1; ++i)
891 value_set_si(T->p[i][i+remove], 1);
892 I = Polyhedron_Image(P, T, P->NbConstraints);
893 Matrix_Free(T);
894 return I;
897 /* Constructs a new constraint that ensures that
898 * the first constraint is (strictly) smaller than
899 * the second.
901 static void smaller_constraint(Value *a, Value *b, Value *c, int pos, int shift,
902 int len, int strict, Value *tmp)
904 value_oppose(*tmp, b[pos+1]);
905 value_set_si(c[0], 1);
906 Vector_Combine(a+1+shift, b+1+shift, c+1, *tmp, a[pos+1], len-shift-1);
907 if (strict)
908 value_decrement(c[len-shift-1], c[len-shift-1]);
909 ConstraintSimplify(c, c, len-shift, tmp);
913 /* For each pair of lower and upper bounds on the first variable,
914 * calls fn with the set of constraints on the remaining variables
915 * where these bounds are active, i.e., (stricly) larger/smaller than
916 * the other lower/upper bounds, the lower and upper bound and the
917 * call back data.
919 * If the first variable is equal to an affine combination of the
920 * other variables then fn is called with both lower and upper
921 * pointing to the corresponding equality.
923 * If there is no lower (or upper) bound, then NULL is passed
924 * as the corresponding bound.
926 void for_each_lower_upper_bound(Polyhedron *P,
927 for_each_lower_upper_bound_init init,
928 for_each_lower_upper_bound_fn fn,
929 void *cb_data)
931 unsigned dim = P->Dimension;
932 Matrix *M;
933 int *pos;
934 int i, j, p, n, z;
935 int k, l, k2, l2, q;
936 Value g;
938 if (value_zero_p(P->Constraint[0][0]) &&
939 value_notzero_p(P->Constraint[0][1])) {
940 M = Matrix_Alloc(P->NbConstraints-1, dim-1+2);
941 for (i = 1; i < P->NbConstraints; ++i) {
942 value_assign(M->p[i-1][0], P->Constraint[i][0]);
943 Vector_Copy(P->Constraint[i]+2, M->p[i-1]+1, dim);
945 if (init)
946 init(1, cb_data);
947 fn(M, P->Constraint[0], P->Constraint[0], cb_data);
948 Matrix_Free(M);
949 return;
952 value_init(g);
953 pos = ALLOCN(int, P->NbConstraints);
955 for (i = 0, z = 0; i < P->NbConstraints; ++i)
956 if (value_zero_p(P->Constraint[i][1]))
957 pos[P->NbConstraints-1 - z++] = i;
958 /* put those with positive coefficients first; number: p */
959 for (i = 0, p = 0, n = P->NbConstraints-z-1; i < P->NbConstraints; ++i)
960 if (value_pos_p(P->Constraint[i][1]))
961 pos[p++] = i;
962 else if (value_neg_p(P->Constraint[i][1]))
963 pos[n--] = i;
964 n = P->NbConstraints-z-p;
966 if (init)
967 init(p*n, cb_data);
969 M = Matrix_Alloc((p ? p-1 : 0) + (n ? n-1 : 0) + z + 1, dim-1+2);
970 for (i = 0; i < z; ++i) {
971 value_assign(M->p[i][0], P->Constraint[pos[P->NbConstraints-1 - i]][0]);
972 Vector_Copy(P->Constraint[pos[P->NbConstraints-1 - i]]+2,
973 M->p[i]+1, dim);
975 for (k = p ? 0 : -1; k < p; ++k) {
976 for (k2 = 0; k2 < p; ++k2) {
977 if (k2 == k)
978 continue;
979 q = 1 + z + k2 - (k2 > k);
980 smaller_constraint(
981 P->Constraint[pos[k]],
982 P->Constraint[pos[k2]],
983 M->p[q], 0, 1, dim+2, k2 > k, &g);
985 for (l = n ? p : p-1; l < p+n; ++l) {
986 Value *lower;
987 Value *upper;
988 for (l2 = p; l2 < p+n; ++l2) {
989 if (l2 == l)
990 continue;
991 q = 1 + z + l2-1 - (l2 > l);
992 smaller_constraint(
993 P->Constraint[pos[l2]],
994 P->Constraint[pos[l]],
995 M->p[q], 0, 1, dim+2, l2 > l, &g);
997 if (p && n)
998 smaller_constraint(P->Constraint[pos[k]],
999 P->Constraint[pos[l]],
1000 M->p[z], 0, 1, dim+2, 0, &g);
1001 lower = p ? P->Constraint[pos[k]] : NULL;
1002 upper = n ? P->Constraint[pos[l]] : NULL;
1003 fn(M, lower, upper, cb_data);
1006 Matrix_Free(M);
1008 free(pos);
1009 value_clear(g);
1012 struct section { Polyhedron * D; evalue E; };
1014 struct PLL_data {
1015 int nd;
1016 unsigned MaxRays;
1017 Polyhedron *C;
1018 evalue mone;
1019 struct section *s;
1022 static void PLL_init(unsigned n, void *cb_data)
1024 struct PLL_data *data = (struct PLL_data *)cb_data;
1026 data->s = ALLOCN(struct section, n);
1029 /* Computes ceil(-coef/abs(d)) */
1030 static evalue* bv_ceil3(Value *coef, int len, Value d, Polyhedron *P)
1032 Value t;
1033 evalue *EP, *f;
1034 Vector *val = Vector_Alloc(len);
1036 value_init(t);
1037 Vector_Oppose(coef, val->p, len);
1038 value_absolute(t, d);
1040 EP = ceiling(val->p, t, len-1, P);
1042 value_clear(t);
1043 Vector_Free(val);
1045 return EP;
1048 static void PLL_cb(Matrix *M, Value *lower, Value *upper, void *cb_data)
1050 struct PLL_data *data = (struct PLL_data *)cb_data;
1051 unsigned dim = M->NbColumns-1;
1052 Matrix *M2;
1053 Polyhedron *T;
1054 evalue *L, *U;
1056 assert(lower);
1057 assert(upper);
1059 M2 = Matrix_Copy(M);
1060 T = Constraints2Polyhedron(M2, data->MaxRays);
1061 Matrix_Free(M2);
1062 data->s[data->nd].D = DomainIntersection(T, data->C, data->MaxRays);
1063 Domain_Free(T);
1065 POL_ENSURE_VERTICES(data->s[data->nd].D);
1066 if (emptyQ(data->s[data->nd].D)) {
1067 Polyhedron_Free(data->s[data->nd].D);
1068 return;
1070 L = bv_ceil3(lower+1+1, dim-1+1, lower[0+1], data->s[data->nd].D);
1071 U = bv_ceil3(upper+1+1, dim-1+1, upper[0+1], data->s[data->nd].D);
1072 eadd(L, U);
1073 eadd(&data->mone, U);
1074 emul(&data->mone, U);
1075 data->s[data->nd].E = *U;
1076 evalue_free(L);
1077 free(U);
1078 ++data->nd;
1081 static evalue *ParamLine_Length_mod(Polyhedron *P, Polyhedron *C, unsigned MaxRays)
1083 unsigned dim = P->Dimension;
1084 unsigned nvar = dim - C->Dimension;
1085 struct PLL_data data;
1086 evalue *F;
1087 int k;
1089 assert(nvar == 1);
1091 value_init(data.mone.d);
1092 evalue_set_si(&data.mone, -1, 1);
1094 data.nd = 0;
1095 data.MaxRays = MaxRays;
1096 data.C = C;
1097 for_each_lower_upper_bound(P, PLL_init, PLL_cb, &data);
1099 F = ALLOC(evalue);
1100 value_init(F->d);
1101 value_set_si(F->d, 0);
1102 F->x.p = new_enode(partition, 2*data.nd, dim-nvar);
1103 for (k = 0; k < data.nd; ++k) {
1104 EVALUE_SET_DOMAIN(F->x.p->arr[2*k], data.s[k].D);
1105 value_clear(F->x.p->arr[2*k+1].d);
1106 F->x.p->arr[2*k+1] = data.s[k].E;
1108 free(data.s);
1110 free_evalue_refs(&data.mone);
1112 return F;
1115 evalue* ParamLine_Length(Polyhedron *P, Polyhedron *C,
1116 struct barvinok_options *options)
1118 evalue* tmp;
1119 tmp = ParamLine_Length_mod(P, C, options->MaxRays);
1120 if (options->lookup_table) {
1121 evalue_mod2table(tmp, C->Dimension);
1122 reduce_evalue(tmp);
1124 return tmp;
1127 Bool isIdentity(Matrix *M)
1129 unsigned i, j;
1130 if (M->NbRows != M->NbColumns)
1131 return False;
1133 for (i = 0;i < M->NbRows; i ++)
1134 for (j = 0; j < M->NbColumns; j ++)
1135 if (i == j) {
1136 if(value_notone_p(M->p[i][j]))
1137 return False;
1138 } else {
1139 if(value_notzero_p(M->p[i][j]))
1140 return False;
1142 return True;
1145 void Param_Polyhedron_Print(FILE* DST, Param_Polyhedron *PP,
1146 const char **param_names)
1148 Param_Domain *P;
1149 Param_Vertices *V;
1151 for(P=PP->D;P;P=P->next) {
1153 /* prints current val. dom. */
1154 fprintf(DST, "---------------------------------------\n");
1155 fprintf(DST, "Domain :\n");
1156 Print_Domain(DST, P->Domain, param_names);
1158 /* scan the vertices */
1159 fprintf(DST, "Vertices :\n");
1160 FORALL_PVertex_in_ParamPolyhedron(V,P,PP) {
1162 /* prints each vertex */
1163 Print_Vertex(DST, V->Vertex, param_names);
1164 fprintf(DST, "\n");
1166 END_FORALL_PVertex_in_ParamPolyhedron;
1170 void Enumeration_Print(FILE *Dst, Enumeration *en, const char **params)
1172 for (; en; en = en->next) {
1173 Print_Domain(Dst, en->ValidityDomain, params);
1174 print_evalue(Dst, &en->EP, params);
1178 void Enumeration_Free(Enumeration *en)
1180 Enumeration *ee;
1182 while( en )
1184 free_evalue_refs( &(en->EP) );
1185 Domain_Free( en->ValidityDomain );
1186 ee = en ->next;
1187 free( en );
1188 en = ee;
1192 void Enumeration_mod2table(Enumeration *en, unsigned nparam)
1194 for (; en; en = en->next) {
1195 evalue_mod2table(&en->EP, nparam);
1196 reduce_evalue(&en->EP);
1200 size_t Enumeration_size(Enumeration *en)
1202 size_t s = 0;
1204 for (; en; en = en->next) {
1205 s += domain_size(en->ValidityDomain);
1206 s += evalue_size(&en->EP);
1208 return s;
1211 /* Check whether every set in D2 is included in some set of D1 */
1212 int DomainIncludes(Polyhedron *D1, Polyhedron *D2)
1214 for ( ; D2; D2 = D2->next) {
1215 Polyhedron *P1;
1216 for (P1 = D1; P1; P1 = P1->next)
1217 if (PolyhedronIncludes(P1, D2))
1218 break;
1219 if (!P1)
1220 return 0;
1222 return 1;
1225 int line_minmax(Polyhedron *I, Value *min, Value *max)
1227 int i;
1229 if (I->NbEq >= 1) {
1230 value_oppose(I->Constraint[0][2], I->Constraint[0][2]);
1231 /* There should never be a remainder here */
1232 if (value_pos_p(I->Constraint[0][1]))
1233 mpz_fdiv_q(*min, I->Constraint[0][2], I->Constraint[0][1]);
1234 else
1235 mpz_fdiv_q(*min, I->Constraint[0][2], I->Constraint[0][1]);
1236 value_assign(*max, *min);
1237 } else for (i = 0; i < I->NbConstraints; ++i) {
1238 if (value_zero_p(I->Constraint[i][1])) {
1239 Polyhedron_Free(I);
1240 return 0;
1243 value_oppose(I->Constraint[i][2], I->Constraint[i][2]);
1244 if (value_pos_p(I->Constraint[i][1]))
1245 mpz_cdiv_q(*min, I->Constraint[i][2], I->Constraint[i][1]);
1246 else
1247 mpz_fdiv_q(*max, I->Constraint[i][2], I->Constraint[i][1]);
1249 Polyhedron_Free(I);
1250 return 1;
1253 int DomainContains(Polyhedron *P, Value *list_args, int len,
1254 unsigned MaxRays, int set)
1256 int i;
1257 Value m;
1259 if (P->Dimension == len)
1260 return in_domain(P, list_args);
1262 assert(set); // assume list_args is large enough
1263 assert((P->Dimension - len) % 2 == 0);
1264 value_init(m);
1265 for (i = 0; i < P->Dimension - len; i += 2) {
1266 int j, k;
1267 for (j = 0 ; j < P->NbEq; ++j)
1268 if (value_notzero_p(P->Constraint[j][1+len+i]))
1269 break;
1270 assert(j < P->NbEq);
1271 value_absolute(m, P->Constraint[j][1+len+i]);
1272 k = First_Non_Zero(P->Constraint[j]+1, len);
1273 assert(k != -1);
1274 assert(First_Non_Zero(P->Constraint[j]+1+k+1, len - k - 1) == -1);
1275 mpz_fdiv_q(list_args[len+i], list_args[k], m);
1276 mpz_fdiv_r(list_args[len+i+1], list_args[k], m);
1278 value_clear(m);
1280 return in_domain(P, list_args);
1283 Polyhedron *DomainConcat(Polyhedron *head, Polyhedron *tail)
1285 Polyhedron *S;
1286 if (!head)
1287 return tail;
1288 for (S = head; S->next; S = S->next)
1290 S->next = tail;
1291 return head;
1294 evalue *barvinok_lexsmaller_ev(Polyhedron *P, Polyhedron *D, unsigned dim,
1295 Polyhedron *C, unsigned MaxRays)
1297 evalue *ranking;
1298 Polyhedron *RC, *RD, *Q;
1299 unsigned nparam = dim + C->Dimension;
1300 unsigned exist;
1301 Polyhedron *CA;
1303 RC = LexSmaller(P, D, dim, C, MaxRays);
1304 RD = RC->next;
1305 RC->next = NULL;
1307 exist = RD->Dimension - nparam - dim;
1308 CA = align_context(RC, RD->Dimension, MaxRays);
1309 Q = DomainIntersection(RD, CA, MaxRays);
1310 Polyhedron_Free(CA);
1311 Domain_Free(RD);
1312 Polyhedron_Free(RC);
1313 RD = Q;
1315 for (Q = RD; Q; Q = Q->next) {
1316 evalue *t;
1317 Polyhedron *next = Q->next;
1318 Q->next = 0;
1320 t = barvinok_enumerate_e(Q, exist, nparam, MaxRays);
1322 if (Q == RD)
1323 ranking = t;
1324 else {
1325 eadd(t, ranking);
1326 evalue_free(t);
1329 Q->next = next;
1332 Domain_Free(RD);
1334 return ranking;
1337 Enumeration *barvinok_lexsmaller(Polyhedron *P, Polyhedron *D, unsigned dim,
1338 Polyhedron *C, unsigned MaxRays)
1340 evalue *EP = barvinok_lexsmaller_ev(P, D, dim, C, MaxRays);
1342 return partition2enumeration(EP);
1345 /* "align" matrix to have nrows by inserting
1346 * the necessary number of rows and an equal number of columns in front
1348 Matrix *align_matrix(Matrix *M, int nrows)
1350 int i;
1351 int newrows = nrows - M->NbRows;
1352 Matrix *M2 = Matrix_Alloc(nrows, newrows + M->NbColumns);
1353 for (i = 0; i < newrows; ++i)
1354 value_set_si(M2->p[i][i], 1);
1355 for (i = 0; i < M->NbRows; ++i)
1356 Vector_Copy(M->p[i], M2->p[newrows+i]+newrows, M->NbColumns);
1357 return M2;
1360 static void print_varlist(FILE *out, int n, char **names)
1362 int i;
1363 fprintf(out, "[");
1364 for (i = 0; i < n; ++i) {
1365 if (i)
1366 fprintf(out, ",");
1367 fprintf(out, "%s", names[i]);
1369 fprintf(out, "]");
1372 static void print_term(FILE *out, Value v, int pos, int dim, int nparam,
1373 char **iter_names, char **param_names, int *first)
1375 if (value_zero_p(v)) {
1376 if (first && *first && pos >= dim + nparam)
1377 fprintf(out, "0");
1378 return;
1381 if (first) {
1382 if (!*first && value_pos_p(v))
1383 fprintf(out, "+");
1384 *first = 0;
1386 if (pos < dim + nparam) {
1387 if (value_mone_p(v))
1388 fprintf(out, "-");
1389 else if (!value_one_p(v))
1390 value_print(out, VALUE_FMT, v);
1391 if (pos < dim)
1392 fprintf(out, "%s", iter_names[pos]);
1393 else
1394 fprintf(out, "%s", param_names[pos-dim]);
1395 } else
1396 value_print(out, VALUE_FMT, v);
1399 char **util_generate_names(int n, const char *prefix)
1401 int i;
1402 int len = (prefix ? strlen(prefix) : 0) + 10;
1403 char **names = ALLOCN(char*, n);
1404 if (!names) {
1405 fprintf(stderr, "ERROR: memory overflow.\n");
1406 exit(1);
1408 for (i = 0; i < n; ++i) {
1409 names[i] = ALLOCN(char, len);
1410 if (!names[i]) {
1411 fprintf(stderr, "ERROR: memory overflow.\n");
1412 exit(1);
1414 if (!prefix)
1415 snprintf(names[i], len, "%d", i);
1416 else
1417 snprintf(names[i], len, "%s%d", prefix, i);
1420 return names;
1423 void util_free_names(int n, char **names)
1425 int i;
1426 for (i = 0; i < n; ++i)
1427 free(names[i]);
1428 free(names);
1431 void Polyhedron_pprint(FILE *out, Polyhedron *P, int dim, int nparam,
1432 char **iter_names, char **param_names)
1434 int i, j;
1435 Value tmp;
1437 assert(dim + nparam == P->Dimension);
1439 value_init(tmp);
1441 fprintf(out, "{ ");
1442 if (nparam) {
1443 print_varlist(out, nparam, param_names);
1444 fprintf(out, " -> ");
1446 print_varlist(out, dim, iter_names);
1447 fprintf(out, " : ");
1449 if (emptyQ2(P))
1450 fprintf(out, "FALSE");
1451 else for (i = 0; i < P->NbConstraints; ++i) {
1452 int first = 1;
1453 int v = First_Non_Zero(P->Constraint[i]+1, P->Dimension);
1454 if (v == -1 && value_pos_p(P->Constraint[i][0]))
1455 continue;
1456 if (i)
1457 fprintf(out, " && ");
1458 if (v == -1 && value_notzero_p(P->Constraint[i][1+P->Dimension]))
1459 fprintf(out, "FALSE");
1460 else if (value_pos_p(P->Constraint[i][v+1])) {
1461 print_term(out, P->Constraint[i][v+1], v, dim, nparam,
1462 iter_names, param_names, NULL);
1463 if (value_zero_p(P->Constraint[i][0]))
1464 fprintf(out, " = ");
1465 else
1466 fprintf(out, " >= ");
1467 for (j = v+1; j <= dim+nparam; ++j) {
1468 value_oppose(tmp, P->Constraint[i][1+j]);
1469 print_term(out, tmp, j, dim, nparam,
1470 iter_names, param_names, &first);
1472 } else {
1473 value_oppose(tmp, P->Constraint[i][1+v]);
1474 print_term(out, tmp, v, dim, nparam,
1475 iter_names, param_names, NULL);
1476 fprintf(out, " <= ");
1477 for (j = v+1; j <= dim+nparam; ++j)
1478 print_term(out, P->Constraint[i][1+j], j, dim, nparam,
1479 iter_names, param_names, &first);
1483 fprintf(out, " }\n");
1485 value_clear(tmp);
1488 /* Construct a cone over P with P placed at x_d = 1, with
1489 * x_d the coordinate of an extra dimension
1491 * It's probably a mistake to depend so much on the internal
1492 * representation. We should probably simply compute the
1493 * vertices/facets first.
1495 Polyhedron *Cone_over_Polyhedron(Polyhedron *P)
1497 unsigned NbConstraints = 0;
1498 unsigned NbRays = 0;
1499 Polyhedron *C;
1500 int i;
1502 if (POL_HAS(P, POL_INEQUALITIES))
1503 NbConstraints = P->NbConstraints + 1;
1504 if (POL_HAS(P, POL_POINTS))
1505 NbRays = P->NbRays + 1;
1507 C = Polyhedron_Alloc(P->Dimension+1, NbConstraints, NbRays);
1508 if (POL_HAS(P, POL_INEQUALITIES)) {
1509 C->NbEq = P->NbEq;
1510 for (i = 0; i < P->NbConstraints; ++i)
1511 Vector_Copy(P->Constraint[i], C->Constraint[i], P->Dimension+2);
1512 /* n >= 0 */
1513 value_set_si(C->Constraint[P->NbConstraints][0], 1);
1514 value_set_si(C->Constraint[P->NbConstraints][1+P->Dimension], 1);
1516 if (POL_HAS(P, POL_POINTS)) {
1517 C->NbBid = P->NbBid;
1518 for (i = 0; i < P->NbRays; ++i)
1519 Vector_Copy(P->Ray[i], C->Ray[i], P->Dimension+2);
1520 /* vertex 0 */
1521 value_set_si(C->Ray[P->NbRays][0], 1);
1522 value_set_si(C->Ray[P->NbRays][1+C->Dimension], 1);
1524 POL_SET(C, POL_VALID);
1525 if (POL_HAS(P, POL_INEQUALITIES))
1526 POL_SET(C, POL_INEQUALITIES);
1527 if (POL_HAS(P, POL_POINTS))
1528 POL_SET(C, POL_POINTS);
1529 if (POL_HAS(P, POL_VERTICES))
1530 POL_SET(C, POL_VERTICES);
1531 return C;
1534 /* Returns a (dim+nparam+1)x((dim-n)+nparam+1) matrix
1535 * mapping the transformed subspace back to the original space.
1536 * n is the number of equalities involving the variables
1537 * (i.e., not purely the parameters).
1538 * The remaining n coordinates in the transformed space would
1539 * have constant (parametric) values and are therefore not
1540 * included in the variables of the new space.
1542 Matrix *compress_variables(Matrix *Equalities, unsigned nparam)
1544 unsigned dim = (Equalities->NbColumns-2) - nparam;
1545 Matrix *M, *H, *Q, *U, *C, *ratH, *invH, *Ul, *T1, *T2, *T;
1546 Value mone;
1547 int n, i, j;
1548 int ok;
1550 for (n = 0; n < Equalities->NbRows; ++n)
1551 if (First_Non_Zero(Equalities->p[n]+1, dim) == -1)
1552 break;
1553 if (n == 0)
1554 return Identity(dim+nparam+1);
1555 value_init(mone);
1556 value_set_si(mone, -1);
1557 M = Matrix_Alloc(n, dim);
1558 C = Matrix_Alloc(n+1, nparam+1);
1559 for (i = 0; i < n; ++i) {
1560 Vector_Copy(Equalities->p[i]+1, M->p[i], dim);
1561 Vector_Scale(Equalities->p[i]+1+dim, C->p[i], mone, nparam+1);
1563 value_set_si(C->p[n][nparam], 1);
1564 left_hermite(M, &H, &Q, &U);
1565 Matrix_Free(M);
1566 Matrix_Free(Q);
1567 value_clear(mone);
1569 ratH = Matrix_Alloc(n+1, n+1);
1570 invH = Matrix_Alloc(n+1, n+1);
1571 for (i = 0; i < n; ++i)
1572 Vector_Copy(H->p[i], ratH->p[i], n);
1573 value_set_si(ratH->p[n][n], 1);
1574 ok = Matrix_Inverse(ratH, invH);
1575 assert(ok);
1576 Matrix_Free(H);
1577 Matrix_Free(ratH);
1578 T1 = Matrix_Alloc(n+1, nparam+1);
1579 Matrix_Product(invH, C, T1);
1580 Matrix_Free(C);
1581 Matrix_Free(invH);
1582 if (value_notone_p(T1->p[n][nparam])) {
1583 for (i = 0; i < n; ++i) {
1584 if (!mpz_divisible_p(T1->p[i][nparam], T1->p[n][nparam])) {
1585 Matrix_Free(T1);
1586 Matrix_Free(U);
1587 return NULL;
1589 /* compress_params should have taken care of this */
1590 for (j = 0; j < nparam; ++j)
1591 assert(mpz_divisible_p(T1->p[i][j], T1->p[n][nparam]));
1592 Vector_AntiScale(T1->p[i], T1->p[i], T1->p[n][nparam], nparam+1);
1594 value_set_si(T1->p[n][nparam], 1);
1596 Ul = Matrix_Alloc(dim+1, n+1);
1597 for (i = 0; i < dim; ++i)
1598 Vector_Copy(U->p[i], Ul->p[i], n);
1599 value_set_si(Ul->p[dim][n], 1);
1600 T2 = Matrix_Alloc(dim+1, nparam+1);
1601 Matrix_Product(Ul, T1, T2);
1602 Matrix_Free(Ul);
1603 Matrix_Free(T1);
1605 T = Matrix_Alloc(dim+nparam+1, (dim-n)+nparam+1);
1606 for (i = 0; i < dim; ++i) {
1607 Vector_Copy(U->p[i]+n, T->p[i], dim-n);
1608 Vector_Copy(T2->p[i], T->p[i]+dim-n, nparam+1);
1610 for (i = 0; i < nparam+1; ++i)
1611 value_set_si(T->p[dim+i][(dim-n)+i], 1);
1612 assert(value_one_p(T2->p[dim][nparam]));
1613 Matrix_Free(U);
1614 Matrix_Free(T2);
1616 return T;
1619 /* Computes the left inverse of an affine embedding M and, if Eq is not NULL,
1620 * the equalities that define the affine subspace onto which M maps
1621 * its argument.
1623 Matrix *left_inverse(Matrix *M, Matrix **Eq)
1625 int i, ok;
1626 Matrix *L, *H, *Q, *U, *ratH, *invH, *Ut, *inv;
1627 Vector *t;
1629 if (M->NbColumns == 1) {
1630 inv = Matrix_Alloc(1, M->NbRows);
1631 value_set_si(inv->p[0][M->NbRows-1], 1);
1632 if (Eq) {
1633 *Eq = Matrix_Alloc(M->NbRows-1, 1+(M->NbRows-1)+1);
1634 for (i = 0; i < M->NbRows-1; ++i) {
1635 value_oppose((*Eq)->p[i][1+i], M->p[M->NbRows-1][0]);
1636 value_assign((*Eq)->p[i][1+(M->NbRows-1)], M->p[i][0]);
1639 return inv;
1641 if (Eq)
1642 *Eq = NULL;
1643 L = Matrix_Alloc(M->NbRows-1, M->NbColumns-1);
1644 for (i = 0; i < L->NbRows; ++i)
1645 Vector_Copy(M->p[i], L->p[i], L->NbColumns);
1646 right_hermite(L, &H, &U, &Q);
1647 Matrix_Free(L);
1648 Matrix_Free(Q);
1649 t = Vector_Alloc(U->NbColumns);
1650 for (i = 0; i < U->NbColumns; ++i)
1651 value_oppose(t->p[i], M->p[i][M->NbColumns-1]);
1652 if (Eq) {
1653 *Eq = Matrix_Alloc(H->NbRows - H->NbColumns, 2 + U->NbColumns);
1654 for (i = 0; i < H->NbRows - H->NbColumns; ++i) {
1655 Vector_Copy(U->p[H->NbColumns+i], (*Eq)->p[i]+1, U->NbColumns);
1656 Inner_Product(U->p[H->NbColumns+i], t->p, U->NbColumns,
1657 (*Eq)->p[i]+1+U->NbColumns);
1660 ratH = Matrix_Alloc(H->NbColumns+1, H->NbColumns+1);
1661 invH = Matrix_Alloc(H->NbColumns+1, H->NbColumns+1);
1662 for (i = 0; i < H->NbColumns; ++i)
1663 Vector_Copy(H->p[i], ratH->p[i], H->NbColumns);
1664 value_set_si(ratH->p[ratH->NbRows-1][ratH->NbColumns-1], 1);
1665 Matrix_Free(H);
1666 ok = Matrix_Inverse(ratH, invH);
1667 assert(ok);
1668 Matrix_Free(ratH);
1669 Ut = Matrix_Alloc(invH->NbRows, U->NbColumns+1);
1670 for (i = 0; i < Ut->NbRows-1; ++i) {
1671 Vector_Copy(U->p[i], Ut->p[i], U->NbColumns);
1672 Inner_Product(U->p[i], t->p, U->NbColumns, &Ut->p[i][Ut->NbColumns-1]);
1674 Matrix_Free(U);
1675 Vector_Free(t);
1676 value_set_si(Ut->p[Ut->NbRows-1][Ut->NbColumns-1], 1);
1677 inv = Matrix_Alloc(invH->NbRows, Ut->NbColumns);
1678 Matrix_Product(invH, Ut, inv);
1679 Matrix_Free(Ut);
1680 Matrix_Free(invH);
1681 return inv;
1684 /* Check whether all rays are revlex positive in the parameters
1686 int Polyhedron_has_revlex_positive_rays(Polyhedron *P, unsigned nparam)
1688 int r;
1689 for (r = 0; r < P->NbRays; ++r) {
1690 int i;
1691 if (value_notzero_p(P->Ray[r][P->Dimension+1]))
1692 continue;
1693 for (i = P->Dimension-1; i >= P->Dimension-nparam; --i) {
1694 if (value_neg_p(P->Ray[r][i+1]))
1695 return 0;
1696 if (value_pos_p(P->Ray[r][i+1]))
1697 break;
1699 /* A ray independent of the parameters */
1700 if (i < P->Dimension-nparam)
1701 return 0;
1703 return 1;
1706 static Polyhedron *Recession_Cone(Polyhedron *P, unsigned nparam, unsigned MaxRays)
1708 int i;
1709 unsigned nvar = P->Dimension - nparam;
1710 Matrix *M = Matrix_Alloc(P->NbConstraints, 1 + nvar + 1);
1711 Polyhedron *R;
1712 for (i = 0; i < P->NbConstraints; ++i)
1713 Vector_Copy(P->Constraint[i], M->p[i], 1+nvar);
1714 R = Constraints2Polyhedron(M, MaxRays);
1715 Matrix_Free(M);
1716 return R;
1719 int Polyhedron_is_unbounded(Polyhedron *P, unsigned nparam, unsigned MaxRays)
1721 int i;
1722 int is_unbounded;
1723 Polyhedron *R = Recession_Cone(P, nparam, MaxRays);
1724 POL_ENSURE_VERTICES(R);
1725 if (R->NbBid == 0)
1726 for (i = 0; i < R->NbRays; ++i)
1727 if (value_zero_p(R->Ray[i][1+R->Dimension]))
1728 break;
1729 is_unbounded = R->NbBid > 0 || i < R->NbRays;
1730 Polyhedron_Free(R);
1731 return is_unbounded;
1734 static void SwapColumns(Value **V, int n, int i, int j)
1736 int r;
1738 for (r = 0; r < n; ++r)
1739 value_swap(V[r][i], V[r][j]);
1742 void Polyhedron_ExchangeColumns(Polyhedron *P, int Column1, int Column2)
1744 SwapColumns(P->Constraint, P->NbConstraints, Column1, Column2);
1745 SwapColumns(P->Ray, P->NbRays, Column1, Column2);
1746 if (P->NbEq) {
1747 Matrix M;
1748 Polyhedron_Matrix_View(P, &M, P->NbConstraints);
1749 Gauss(&M, P->NbEq, P->Dimension+1);
1753 /* perform transposition inline; assumes M is a square matrix */
1754 void Matrix_Transposition(Matrix *M)
1756 int i, j;
1758 assert(M->NbRows == M->NbColumns);
1759 for (i = 0; i < M->NbRows; ++i)
1760 for (j = i+1; j < M->NbColumns; ++j)
1761 value_swap(M->p[i][j], M->p[j][i]);
1764 /* Matrix "view" of first rows rows */
1765 void Polyhedron_Matrix_View(Polyhedron *P, Matrix *M, unsigned rows)
1767 M->NbRows = rows;
1768 M->NbColumns = P->Dimension+2;
1769 M->p_Init = P->p_Init;
1770 M->p = P->Constraint;
1773 int Last_Non_Zero(Value *p, unsigned len)
1775 int i;
1777 for (i = len - 1; i >= 0; --i)
1778 if (value_notzero_p(p[i]))
1779 return i;
1781 return -1;