bump version
[barvinok.git] / util.c
blob04dfee692b6afa63fece9d18bfbbea44bcf2408d
1 #include <polylib/polylibgmp.h>
2 #include <stdlib.h>
3 #include <assert.h>
4 #include "config.h"
6 #ifndef HAVE_ENUMERATE4
7 #define Polyhedron_Enumerate(a,b,c,d) Polyhedron_Enumerate(a,b,c)
8 #endif
10 void manual_count(Polyhedron *P, Value* result)
12 Polyhedron *U = Universe_Polyhedron(0);
13 Enumeration *en = Polyhedron_Enumerate(P,U,1024,NULL);
14 Value *v = compute_poly(en,NULL);
15 value_assign(*result, *v);
16 value_clear(*v);
17 free(v);
18 Enumeration_Free(en);
19 Polyhedron_Free(U);
22 #include "ev_operations.h"
23 #include <util.h>
24 #include <barvinok.h>
26 /* Return random value between 0 and max-1 inclusive
28 int random_int(int max) {
29 return (int) (((double)(max))*rand()/(RAND_MAX+1.0));
32 /* Inplace polarization
34 void Polyhedron_Polarize(Polyhedron *P)
36 unsigned NbRows = P->NbConstraints + P->NbRays;
37 int i;
38 Value **q;
40 q = (Value **)malloc(NbRows * sizeof(Value *));
41 assert(q);
42 for (i = 0; i < P->NbRays; ++i)
43 q[i] = P->Ray[i];
44 for (; i < NbRows; ++i)
45 q[i] = P->Constraint[i-P->NbRays];
46 P->NbConstraints = NbRows - P->NbConstraints;
47 P->NbRays = NbRows - P->NbRays;
48 free(P->Constraint);
49 P->Constraint = q;
50 P->Ray = q + P->NbConstraints;
54 * Rather general polar
55 * We can optimize it significantly if we assume that
56 * P includes zero
58 * Also, we calculate the polar as defined in Schrijver
59 * The opposite should probably work as well and would
60 * eliminate the need for multiplying by -1
62 Polyhedron* Polyhedron_Polar(Polyhedron *P, unsigned NbMaxRays)
64 int i;
65 Value mone;
66 unsigned dim = P->Dimension + 2;
67 Matrix *M = Matrix_Alloc(P->NbRays, dim);
69 assert(M);
70 value_init(mone);
71 value_set_si(mone, -1);
72 for (i = 0; i < P->NbRays; ++i) {
73 Vector_Scale(P->Ray[i], M->p[i], mone, dim);
74 value_multiply(M->p[i][0], M->p[i][0], mone);
75 value_multiply(M->p[i][dim-1], M->p[i][dim-1], mone);
77 P = Constraints2Polyhedron(M, NbMaxRays);
78 assert(P);
79 Matrix_Free(M);
80 value_clear(mone);
81 return P;
85 * Returns the supporting cone of P at the vertex with index v
87 Polyhedron* supporting_cone(Polyhedron *P, int v)
89 Matrix *M;
90 Value tmp;
91 int i, n, j;
92 unsigned char *supporting = (unsigned char *)malloc(P->NbConstraints);
93 unsigned dim = P->Dimension + 2;
95 assert(v >=0 && v < P->NbRays);
96 assert(value_pos_p(P->Ray[v][dim-1]));
97 assert(supporting);
99 value_init(tmp);
100 for (i = 0, n = 0; i < P->NbConstraints; ++i) {
101 Inner_Product(P->Constraint[i] + 1, P->Ray[v] + 1, dim - 1, &tmp);
102 if ((supporting[i] = value_zero_p(tmp)))
103 ++n;
105 assert(n >= dim - 2);
106 value_clear(tmp);
107 M = Matrix_Alloc(n, dim);
108 assert(M);
109 for (i = 0, j = 0; i < P->NbConstraints; ++i)
110 if (supporting[i]) {
111 value_set_si(M->p[j][dim-1], 0);
112 Vector_Copy(P->Constraint[i], M->p[j++], dim-1);
114 free(supporting);
115 P = Constraints2Polyhedron(M, P->NbRays+1);
116 assert(P);
117 Matrix_Free(M);
118 return P;
121 void value_lcm(Value i, Value j, Value* lcm)
123 Value aux;
124 value_init(aux);
125 value_multiply(aux,i,j);
126 Gcd(i,j,lcm);
127 value_division(*lcm,aux,*lcm);
128 value_clear(aux);
131 Polyhedron* supporting_cone_p(Polyhedron *P, Param_Vertices *v)
133 Matrix *M;
134 Value lcm, tmp, tmp2;
135 unsigned char *supporting = (unsigned char *)malloc(P->NbConstraints);
136 unsigned dim = P->Dimension + 2;
137 unsigned nparam = v->Vertex->NbColumns - 2;
138 unsigned nvar = dim - nparam - 2;
139 int i, n, j;
140 Vector *row;
142 assert(supporting);
143 row = Vector_Alloc(nparam+1);
144 assert(row);
145 value_init(lcm);
146 value_init(tmp);
147 value_init(tmp2);
148 value_set_si(lcm, 1);
149 for (i = 0, n = 0; i < P->NbConstraints; ++i) {
150 Vector_Set(row->p, 0, nparam+1);
151 for (j = 0 ; j < nvar; ++j) {
152 value_set_si(tmp, 1);
153 value_assign(tmp2, P->Constraint[i][j+1]);
154 if (value_ne(lcm, v->Vertex->p[j][nparam+1])) {
155 value_assign(tmp, lcm);
156 value_lcm(lcm, v->Vertex->p[j][nparam+1], &lcm);
157 value_division(tmp, lcm, tmp);
158 value_multiply(tmp2, tmp2, lcm);
159 value_division(tmp2, tmp2, v->Vertex->p[j][nparam+1]);
161 Vector_Combine(row->p, v->Vertex->p[j], row->p,
162 tmp, tmp2, nparam+1);
164 value_set_si(tmp, 1);
165 Vector_Combine(row->p, P->Constraint[i]+1+nvar, row->p, tmp, lcm, nparam+1);
166 for (j = 0; j < nparam+1; ++j)
167 if (value_notzero_p(row->p[j]))
168 break;
169 if ((supporting[i] = (j == nparam + 1)))
170 ++n;
172 assert(n >= nvar);
173 value_clear(tmp);
174 value_clear(tmp2);
175 value_clear(lcm);
176 Vector_Free(row);
177 M = Matrix_Alloc(n, nvar+2);
178 assert(M);
179 for (i = 0, j = 0; i < P->NbConstraints; ++i)
180 if (supporting[i]) {
181 value_set_si(M->p[j][nvar+1], 0);
182 Vector_Copy(P->Constraint[i], M->p[j++], nvar+1);
184 free(supporting);
185 P = Constraints2Polyhedron(M, P->NbRays+1);
186 assert(P);
187 Matrix_Free(M);
188 return P;
191 Polyhedron* triangularize_cone(Polyhedron *P, unsigned NbMaxCons)
193 const static int MAX_TRY=10;
194 int i, j, r, n, t;
195 Value tmp;
196 unsigned dim = P->Dimension;
197 Matrix *M = Matrix_Alloc(P->NbRays+1, dim+3);
198 Matrix *M2, *M3;
199 Polyhedron *L, *R, *T;
200 assert(P->NbEq == 0);
202 R = NULL;
203 value_init(tmp);
205 Vector_Set(M->p[0]+1, 0, dim+1);
206 value_set_si(M->p[0][0], 1);
207 value_set_si(M->p[0][dim+2], 1);
208 Vector_Set(M->p[P->NbRays]+1, 0, dim+2);
209 value_set_si(M->p[P->NbRays][0], 1);
210 value_set_si(M->p[P->NbRays][dim+1], 1);
212 for (i = 0, r = 1; i < P->NbRays; ++i) {
213 if (value_notzero_p(P->Ray[i][dim+1]))
214 continue;
215 Vector_Copy(P->Ray[i], M->p[r], dim+1);
216 Inner_Product(M->p[r]+1, M->p[r]+1, dim, &tmp);
217 value_assign(M->p[r][dim+1], tmp);
218 value_set_si(M->p[r][dim+2], 0);
219 ++r;
222 M3 = Matrix_Copy(M);
223 L = Rays2Polyhedron(M3, NbMaxCons);
224 Matrix_Free(M3);
226 M2 = Matrix_Alloc(dim+1, dim+2);
228 t = 1;
229 if (0) {
230 try_again:
231 /* Usually R should still be 0 */
232 Domain_Free(R);
233 Polyhedron_Free(L);
234 for (r = 1; r < P->NbRays; ++r) {
235 value_set_si(M->p[r][dim+1], random_int((t+1)*dim)+1);
237 M3 = Matrix_Copy(M);
238 L = Rays2Polyhedron(M3, NbMaxCons);
239 Matrix_Free(M3);
240 ++t;
242 assert(t <= MAX_TRY);
244 R = NULL;
245 n = 0;
247 for (i = 0; i < L->NbConstraints; ++i) {
248 if (value_negz_p(L->Constraint[i][dim+1]))
249 continue;
250 if (value_notzero_p(L->Constraint[i][dim+2]))
251 continue;
252 for (j = 1, r = 1; j < M->NbRows; ++j) {
253 Inner_Product(M->p[j]+1, L->Constraint[i]+1, dim+1, &tmp);
254 if (value_notzero_p(tmp))
255 continue;
256 if (r > dim)
257 goto try_again;
258 Vector_Copy(M->p[j]+1, M2->p[r]+1, dim);
259 value_set_si(M2->p[r][0], 1);
260 value_set_si(M2->p[r][dim+1], 0);
261 ++r;
263 assert(r == dim+1);
264 Vector_Set(M2->p[0]+1, 0, dim);
265 value_set_si(M2->p[0][0], 1);
266 value_set_si(M2->p[0][dim+1], 1);
267 T = Rays2Polyhedron(M2, P->NbConstraints+1);
268 T->next = R;
269 R = T;
270 ++n;
272 Matrix_Free(M2);
274 Polyhedron_Free(L);
275 value_clear(tmp);
276 Matrix_Free(M);
278 return R;
281 void check_triangulization(Polyhedron *P, Polyhedron *T)
283 Polyhedron *C, *D, *E, *F, *G, *U;
284 for (C = T; C; C = C->next) {
285 if (C == T)
286 U = C;
287 else
288 U = DomainConvex(DomainUnion(U, C, 100), 100);
289 for (D = C->next; D; D = D->next) {
290 F = C->next;
291 G = D->next;
292 C->next = NULL;
293 D->next = NULL;
294 E = DomainIntersection(C, D, 600);
295 assert(E->NbRays == 0 || E->NbEq >= 1);
296 Polyhedron_Free(E);
297 C->next = F;
298 D->next = G;
301 assert(PolyhedronIncludes(U, P));
302 assert(PolyhedronIncludes(P, U));
305 void Euclid(Value a, Value b, Value *x, Value *y, Value *g)
307 Value c, d, e, f, tmp;
309 value_init(c);
310 value_init(d);
311 value_init(e);
312 value_init(f);
313 value_init(tmp);
314 value_absolute(c, a);
315 value_absolute(d, b);
316 value_set_si(e, 1);
317 value_set_si(f, 0);
318 while(value_pos_p(d)) {
319 value_division(tmp, c, d);
320 value_multiply(tmp, tmp, f);
321 value_substract(e, e, tmp);
322 value_division(tmp, c, d);
323 value_multiply(tmp, tmp, d);
324 value_substract(c, c, tmp);
325 value_swap(c, d);
326 value_swap(e, f);
328 value_assign(*g, c);
329 if (value_zero_p(a))
330 value_set_si(*x, 0);
331 else if (value_pos_p(a))
332 value_assign(*x, e);
333 else value_oppose(*x, e);
334 if (value_zero_p(b))
335 value_set_si(*y, 0);
336 else {
337 value_multiply(tmp, a, *x);
338 value_substract(tmp, c, tmp);
339 value_division(*y, tmp, b);
341 value_clear(c);
342 value_clear(d);
343 value_clear(e);
344 value_clear(f);
345 value_clear(tmp);
348 Matrix * unimodular_complete(Vector *row)
350 Value g, b, c, old, tmp;
351 Matrix *m;
352 unsigned i, j;
354 value_init(b);
355 value_init(c);
356 value_init(g);
357 value_init(old);
358 value_init(tmp);
359 m = Matrix_Alloc(row->Size, row->Size);
360 for (j = 0; j < row->Size; ++j) {
361 value_assign(m->p[0][j], row->p[j]);
363 value_assign(g, row->p[0]);
364 for (i = 1; value_zero_p(g) && i < row->Size; ++i) {
365 for (j = 0; j < row->Size; ++j) {
366 if (j == i-1)
367 value_set_si(m->p[i][j], 1);
368 else
369 value_set_si(m->p[i][j], 0);
371 value_assign(g, row->p[i]);
373 for (; i < row->Size; ++i) {
374 value_assign(old, g);
375 Euclid(old, row->p[i], &c, &b, &g);
376 value_oppose(b, b);
377 for (j = 0; j < row->Size; ++j) {
378 if (j < i) {
379 value_multiply(tmp, row->p[j], b);
380 value_division(m->p[i][j], tmp, old);
381 } else if (j == i)
382 value_assign(m->p[i][j], c);
383 else
384 value_set_si(m->p[i][j], 0);
387 value_clear(b);
388 value_clear(c);
389 value_clear(g);
390 value_clear(old);
391 value_clear(tmp);
392 return m;
396 * Returns a full-dimensional polyhedron with the same number
397 * of integer points as P
399 Polyhedron *remove_equalities(Polyhedron *P)
401 Value g;
402 Vector *v;
403 Polyhedron *p = Polyhedron_Copy(P), *q;
404 unsigned dim = p->Dimension;
405 Matrix *m1, *m2;
406 int i;
408 value_init(g);
409 while (p->NbEq > 0) {
410 assert(dim > 0);
411 Vector_Gcd(p->Constraint[0]+1, dim+1, &g);
412 Vector_AntiScale(p->Constraint[0]+1, p->Constraint[0]+1, g, dim+1);
413 Vector_Gcd(p->Constraint[0]+1, dim, &g);
414 if (value_notone_p(g) && value_notmone_p(g)) {
415 Polyhedron_Free(p);
416 p = Empty_Polyhedron(0);
417 break;
419 v = Vector_Alloc(dim);
420 Vector_Copy(p->Constraint[0]+1, v->p, dim);
421 m1 = unimodular_complete(v);
422 m2 = Matrix_Alloc(dim, dim+1);
423 for (i = 0; i < dim-1 ; ++i) {
424 Vector_Copy(m1->p[i+1], m2->p[i], dim);
425 value_set_si(m2->p[i][dim], 0);
427 Vector_Set(m2->p[dim-1], 0, dim);
428 value_set_si(m2->p[dim-1][dim], 1);
429 q = Polyhedron_Image(p, m2, p->NbConstraints+1+p->NbRays);
430 Vector_Free(v);
431 Matrix_Free(m1);
432 Matrix_Free(m2);
433 Polyhedron_Free(p);
434 p = q;
435 --dim;
437 value_clear(g);
438 return p;
442 * Returns a full-dimensional polyhedron with the same number
443 * of integer points as P
444 * nvar specifies the number of variables
445 * The remaining dimensions are assumed to be parameters
446 * Destroys P
447 * factor is NbEq x (nparam+2) matrix, containing stride constraints
448 * on the parameters; column nparam is the constant;
449 * column nparam+1 is the stride
451 * if factor is NULL, only remove equalities that don't affect
452 * the number of points
454 Polyhedron *remove_equalities_p(Polyhedron *P, unsigned nvar, Matrix **factor)
456 Value g;
457 Vector *v;
458 Polyhedron *p = P, *q;
459 unsigned dim = p->Dimension;
460 Matrix *m1, *m2, *f;
461 int i, j, skip;
463 value_init(g);
464 if (factor) {
465 f = Matrix_Alloc(p->NbEq, dim-nvar+2);
466 *factor = f;
468 j = 0;
469 skip = 0;
470 while (nvar > 0 && p->NbEq - skip > 0) {
471 assert(dim > 0);
473 while (value_zero_p(p->Constraint[skip][0]) &&
474 First_Non_Zero(p->Constraint[skip]+1, nvar) == -1)
475 ++skip;
476 if (p->NbEq == skip)
477 break;
479 Vector_Gcd(p->Constraint[skip]+1, dim+1, &g);
480 Vector_AntiScale(p->Constraint[skip]+1, p->Constraint[skip]+1, g, dim+1);
481 Vector_Gcd(p->Constraint[skip]+1, nvar, &g);
482 if (!factor && value_notone_p(g) && value_notmone_p(g)) {
483 ++skip;
484 continue;
486 if (factor) {
487 Vector_Copy(p->Constraint[skip]+1+nvar, f->p[j], dim-nvar+1);
488 value_assign(f->p[j][dim-nvar+1], g);
490 v = Vector_Alloc(dim);
491 Vector_AntiScale(p->Constraint[skip]+1, v->p, g, nvar);
492 Vector_Set(v->p+nvar, 0, dim-nvar);
493 m1 = unimodular_complete(v);
494 m2 = Matrix_Alloc(dim, dim+1);
495 for (i = 0; i < dim-1 ; ++i) {
496 Vector_Copy(m1->p[i+1], m2->p[i], dim);
497 value_set_si(m2->p[i][dim], 0);
499 Vector_Set(m2->p[dim-1], 0, dim);
500 value_set_si(m2->p[dim-1][dim], 1);
501 q = Polyhedron_Image(p, m2, p->NbConstraints+1+p->NbRays);
502 Vector_Free(v);
503 Matrix_Free(m1);
504 Matrix_Free(m2);
505 Polyhedron_Free(p);
506 p = q;
507 --dim;
508 --nvar;
509 ++j;
511 value_clear(g);
512 return p;
515 struct single {
516 int nr;
517 int pos[2];
520 static void free_singles(int **singles, int dim)
522 int i;
523 for (i = 0; i < dim; ++i)
524 free(singles[i]);
525 free(singles);
528 static int **find_singles(Polyhedron *P, int dim, int max, int *nsingle)
530 int i, j, prev;
531 int **singles = (int **) malloc(dim * sizeof(int *));
532 assert(singles);
534 for (i = 0; i < dim; ++i) {
535 singles[i] = (int *) malloc((max + 1) *sizeof(int));
536 singles[i][0] = 0;
539 for (i = 0; i < P->NbConstraints; ++i) {
540 for (j = 0, prev = -1; j < dim; ++j) {
541 if (value_notzero_p(P->Constraint[i][j+1])) {
542 if (prev == -1)
543 prev = j;
544 else {
545 if (prev != -2)
546 singles[prev][0] = -1;
547 singles[j][0] = -1;
548 prev = -2;
552 if (prev >= 0 && singles[prev][0] >= 0)
553 singles[prev][++singles[prev][0]] = i;
555 *nsingle = 0;
556 for (j = 0; j < dim; ++j)
557 if (singles[j][0] > 0)
558 ++*nsingle;
559 if (!*nsingle) {
560 free_singles(singles, dim);
561 singles = 0;
563 return singles;
567 * The number of points in P is equal to factor time
568 * the number of points in the polyhedron returned.
569 * The return value is zero if no reduction can be found.
571 Polyhedron* Polyhedron_Reduce(Polyhedron *P, Value* factor)
573 int i, j, nsingle, k, p;
574 unsigned dim = P->Dimension;
575 int **singles;
577 value_set_si(*factor, 1);
579 assert (P->NbEq == 0);
581 singles = find_singles(P, dim, 2, &nsingle);
583 if (nsingle == 0)
584 return 0;
587 Value tmp, pos, neg;
588 Matrix *m = Matrix_Alloc((dim-nsingle)+1, dim+1);
590 value_init(tmp);
591 value_init(pos);
592 value_init(neg);
594 for (i = 0, j = 0; i < dim; ++i) {
595 if (singles[i][0] != 2)
596 value_set_si(m->p[j++][i], 1);
597 else {
598 for (k = 0; k <= 1; ++k) {
599 p = singles[i][1+k];
600 value_oppose(tmp, P->Constraint[p][dim+1]);
601 if (value_pos_p(P->Constraint[p][i+1]))
602 mpz_cdiv_q(pos, tmp, P->Constraint[p][i+1]);
603 else
604 mpz_fdiv_q(neg, tmp, P->Constraint[p][i+1]);
606 value_substract(tmp, neg, pos);
607 value_increment(tmp, tmp);
608 value_multiply(*factor, *factor, tmp);
611 value_set_si(m->p[dim-nsingle][dim], 1);
612 P = Polyhedron_Image(P, m, P->NbConstraints);
613 Matrix_Free(m);
614 free_singles(singles, dim);
616 value_clear(tmp);
617 value_clear(pos);
618 value_clear(neg);
621 return P;
625 * Replaces constraint a x >= c by x >= ceil(c/a)
626 * where "a" is a common factor in the coefficients
627 * old is the constraint; v points to an initialized
628 * value that this procedure can use.
629 * Return non-zero if something changed.
630 * Result is placed in new.
632 int ConstraintSimplify(Value *old, Value *new, int len, Value* v)
634 Vector_Gcd(old+1, len - 2, v);
636 if (value_one_p(*v))
637 return 0;
639 Vector_AntiScale(old+1, new+1, *v, len-2);
640 mpz_fdiv_q(new[len-1], old[len-1], *v);
641 return 1;
645 * Project on final dim dimensions
647 static Polyhedron* Polyhedron_Project(Polyhedron *P, int dim)
649 int i;
650 int remove = P->Dimension - dim;
651 Matrix *T;
652 Polyhedron *I;
654 if (P->Dimension == dim)
655 return Polyhedron_Copy(P);
657 T = Matrix_Alloc(dim+1, P->Dimension+1);
658 for (i = 0; i < dim+1; ++i)
659 value_set_si(T->p[i][i+remove], 1);
660 I = Polyhedron_Image(P, T, P->NbConstraints);
661 Matrix_Free(T);
662 return I;
665 /* Constructs a new constraint that ensures that
666 * the first constraint is (strictly) smaller than
667 * the second.
669 void smaller_constraint(Value *a, Value *b, Value *c, int pos, int shift,
670 int len, int strict, Value *tmp)
672 value_oppose(*tmp, b[pos+1]);
673 value_set_si(c[0], 1);
674 Vector_Combine(a+1+shift, b+1+shift, c+1, *tmp, a[pos+1], len-shift-1);
675 if (strict)
676 value_decrement(c[len-shift-1], c[len-shift-1]);
677 ConstraintSimplify(c, c, len-shift, tmp);
680 struct section { Polyhedron * D; evalue E; };
682 static Polyhedron* ParamPolyhedron_Reduce_mod(Polyhedron *P, unsigned nvar,
683 evalue* factor)
685 int nsingle;
686 int **singles;
687 unsigned dim = P->Dimension;
689 singles = find_singles(P, nvar, P->NbConstraints, &nsingle);
691 if (nsingle == 0)
692 return 0;
695 Polyhedron *C, *T;
696 int i, j, p, n;
697 Matrix *m = Matrix_Alloc((dim-nsingle)+1, dim+1);
698 Value g;
699 evalue mone;
700 value_init(mone.d);
701 evalue_set_si(&mone, -1, 1);
702 C = Polyhedron_Project(P, dim-nvar);
704 value_init(g);
706 for (i = 0, j = 0; i < dim; ++i) {
707 if (i >= nvar || singles[i][0] < 2)
708 value_set_si(m->p[j++][i], 1);
709 else {
710 struct section *s;
711 Matrix *M, *M2;
712 int nd = 0;
713 int k, l, k2, l2, q;
714 evalue *L, *U;
715 evalue F;
716 /* put those with positive coefficients first; number: p */
717 for (p = 0, n = singles[i][0]-1; p <= n; ) {
718 while (value_pos_p(P->Constraint[singles[i][1+p]][i+1]))
719 ++p;
720 while (value_neg_p(P->Constraint[singles[i][1+n]][i+1]))
721 --n;
722 if (p < n) {
723 int t = singles[i][1+p];
724 singles[i][1+p] = singles[i][1+n];
725 singles[i][1+n] = t;
726 ++p;
727 --n;
730 n = singles[i][0]-p;
731 assert (p >= 1 && n >= 1);
732 s = (struct section *) malloc(p * n * sizeof(struct section));
733 M = Matrix_Alloc((p-1) + (n-1), dim-nvar+2);
734 for (k = 0; k < p; ++k) {
735 for (k2 = 0; k2 < p; ++k2) {
736 if (k2 == k)
737 continue;
738 q = k2 - (k2 > k);
739 smaller_constraint(
740 P->Constraint[singles[i][1+k]],
741 P->Constraint[singles[i][1+k2]],
742 M->p[q], i, nvar, dim+2, k2 > k, &g);
744 for (l = p; l < p+n; ++l) {
745 for (l2 = p; l2 < p+n; ++l2) {
746 if (l2 == l)
747 continue;
748 q = l2-1 - (l2 > l);
749 smaller_constraint(
750 P->Constraint[singles[i][1+l2]],
751 P->Constraint[singles[i][1+l]],
752 M->p[q], i, nvar, dim+2, l2 > l, &g);
754 M2 = Matrix_Copy(M);
755 s[nd].D = Constraints2Polyhedron(M2, P->NbRays);
756 Matrix_Free(M2);
757 if (emptyQ(s[nd].D)) {
758 Polyhedron_Free(s[nd].D);
759 continue;
761 T = DomainIntersection(s[nd].D, C, 0);
762 L = bv_ceil3(P->Constraint[singles[i][1+k]]+1+nvar,
763 dim-nvar+1,
764 P->Constraint[singles[i][1+k]][i+1], T);
765 U = bv_ceil3(P->Constraint[singles[i][1+l]]+1+nvar,
766 dim-nvar+1,
767 P->Constraint[singles[i][1+l]][i+1], T);
768 Domain_Free(T);
769 eadd(L, U);
770 eadd(&mone, U);
771 emul(&mone, U);
772 s[nd].E = *U;
773 free_evalue_refs(L);
774 free(L);
775 free(U);
776 ++nd;
780 Matrix_Free(M);
782 value_init(F.d);
783 value_set_si(F.d, 0);
784 F.x.p = new_enode(partition, 2*nd, dim-nvar);
785 for (k = 0; k < nd; ++k) {
786 EVALUE_SET_DOMAIN(F.x.p->arr[2*k], s[k].D);
787 value_clear(F.x.p->arr[2*k+1].d);
788 F.x.p->arr[2*k+1] = s[k].E;
790 free(s);
792 emul(&F, factor);
793 free_evalue_refs(&F);
796 value_set_si(m->p[dim-nsingle][dim], 1);
797 P = Polyhedron_Image(P, m, P->NbConstraints);
798 Matrix_Free(m);
799 free_singles(singles, nvar);
801 value_clear(g);
803 free_evalue_refs(&mone);
804 Polyhedron_Free(C);
807 reduce_evalue(factor);
809 return P;
812 #ifdef USE_MODULO
813 Polyhedron* ParamPolyhedron_Reduce(Polyhedron *P, unsigned nvar,
814 evalue* factor)
816 return ParamPolyhedron_Reduce_mod(P, nvar, factor);
818 #else
819 Polyhedron* ParamPolyhedron_Reduce(Polyhedron *P, unsigned nvar,
820 evalue* factor)
822 Polyhedron *R;
823 evalue tmp;
824 value_init(tmp.d);
825 evalue_set_si(&tmp, 1, 1);
826 R = ParamPolyhedron_Reduce_mod(P, nvar, &tmp);
827 evalue_mod2table(&tmp, P->Dimension - nvar);
828 reduce_evalue(&tmp);
829 emul(&tmp, factor);
830 free_evalue_refs(&tmp);
831 return R;
833 #endif
835 Bool isIdentity(Matrix *M)
837 unsigned i, j;
838 if (M->NbRows != M->NbColumns)
839 return False;
841 for (i = 0;i < M->NbRows; i ++)
842 for (j = 0; j < M->NbColumns; j ++)
843 if (i == j) {
844 if(value_notone_p(M->p[i][j]))
845 return False;
846 } else {
847 if(value_notzero_p(M->p[i][j]))
848 return False;
850 return True;
853 void Param_Polyhedron_Print(FILE* DST, Param_Polyhedron *PP, char **param_names)
855 Param_Domain *P;
856 Param_Vertices *V;
858 for(P=PP->D;P;P=P->next) {
860 /* prints current val. dom. */
861 printf( "---------------------------------------\n" );
862 printf( "Domain :\n");
863 Print_Domain( stdout, P->Domain, param_names );
865 /* scan the vertices */
866 printf( "Vertices :\n");
867 FORALL_PVertex_in_ParamPolyhedron(V,P,PP) {
869 /* prints each vertex */
870 Print_Vertex( stdout, V->Vertex, param_names );
871 printf( "\n" );
873 END_FORALL_PVertex_in_ParamPolyhedron;
877 void Enumeration_Print(FILE *Dst, Enumeration *en, char **params)
879 for (; en; en = en->next) {
880 Print_Domain(Dst, en->ValidityDomain, params);
881 print_evalue(Dst, &en->EP, params);
885 void Enumeration_mod2table(Enumeration *en, unsigned nparam)
887 for (; en; en = en->next) {
888 evalue_mod2table(&en->EP, nparam);
889 reduce_evalue(&en->EP);
893 size_t Enumeration_size(Enumeration *en)
895 size_t s = 0;
897 for (; en; en = en->next) {
898 s += domain_size(en->ValidityDomain);
899 s += evalue_size(&en->EP);
901 return s;
904 void Free_ParamNames(char **params, int m)
906 while (--m >= 0)
907 free(params[m]);
908 free(params);
911 int DomainIncludes(Polyhedron *Pol1, Polyhedron *Pol2)
913 Polyhedron *P2;
914 for ( ; Pol1; Pol1 = Pol1->next) {
915 for (P2 = Pol2; P2; P2 = P2->next)
916 if (!PolyhedronIncludes(Pol1, P2))
917 break;
918 if (!P2)
919 return 1;
921 return 0;
924 static Polyhedron *p_simplify_constraints(Polyhedron *P, Vector *row,
925 Value *g, unsigned MaxRays)
927 Polyhedron *T, *R = P;
928 int len = P->Dimension+2;
929 int r;
931 /* Also look at equalities.
932 * If an equality can be "simplified" then there
933 * are no integer solutions anyway and the following loop
934 * will add a conflicting constraint
936 for (r = 0; r < R->NbConstraints; ++r) {
937 if (ConstraintSimplify(R->Constraint[r], row->p, len, g)) {
938 T = R;
939 R = AddConstraints(row->p, 1, R, MaxRays);
940 if (T != P)
941 Polyhedron_Free(T);
942 r = -1;
945 if (R != P)
946 Polyhedron_Free(P);
947 return R;
951 * Replaces constraint a x >= c by x >= ceil(c/a)
952 * where "a" is a common factor in the coefficients
953 * Destroys P and returns a newly allocated Polyhedron
954 * or just returns P in case no changes were made
956 Polyhedron *DomainConstraintSimplify(Polyhedron *P, unsigned MaxRays)
958 Polyhedron **prev;
959 int len = P->Dimension+2;
960 Vector *row = Vector_Alloc(len);
961 Value g;
962 Polyhedron *R = P, *N;
963 value_set_si(row->p[0], 1);
964 value_init(g);
966 for (prev = &R; P; P = N) {
967 Polyhedron *T;
968 N = P->next;
969 T = p_simplify_constraints(P, row, &g, MaxRays);
971 if (emptyQ(T) && prev != &R) {
972 Polyhedron_Free(T);
973 *prev = NULL;
974 continue;
977 if (T != P)
978 T->next = N;
979 *prev = T;
980 prev = &T->next;
983 if (R->next && emptyQ(R)) {
984 N = R->next;
985 Polyhedron_Free(R);
986 R = N;
989 value_clear(g);
990 Vector_Free(row);
991 return R;
994 int line_minmax(Polyhedron *I, Value *min, Value *max)
996 int i;
998 if (I->NbEq >= 1) {
999 value_oppose(I->Constraint[0][2], I->Constraint[0][2]);
1000 /* There should never be a remainder here */
1001 if (value_pos_p(I->Constraint[0][1]))
1002 mpz_fdiv_q(*min, I->Constraint[0][2], I->Constraint[0][1]);
1003 else
1004 mpz_fdiv_q(*min, I->Constraint[0][2], I->Constraint[0][1]);
1005 value_assign(*max, *min);
1006 } else for (i = 0; i < I->NbConstraints; ++i) {
1007 if (value_zero_p(I->Constraint[i][1])) {
1008 Polyhedron_Free(I);
1009 return 0;
1012 value_oppose(I->Constraint[i][2], I->Constraint[i][2]);
1013 if (value_pos_p(I->Constraint[i][1]))
1014 mpz_cdiv_q(*min, I->Constraint[i][2], I->Constraint[i][1]);
1015 else
1016 mpz_fdiv_q(*max, I->Constraint[i][2], I->Constraint[i][1]);
1018 Polyhedron_Free(I);
1019 return 1;
1022 /**
1024 PROCEDURES TO COMPUTE ENUMERATION. recursive procedure, recurse for
1025 each imbriquation
1027 @param pos index position of current loop index (1..hdim-1)
1028 @param P loop domain
1029 @param context context values for fixed indices
1030 @param exist number of existential variables
1031 @return the number of integer points in this
1032 polyhedron
1035 void count_points_e (int pos, Polyhedron *P, int exist, int nparam,
1036 Value *context, Value *res)
1038 Value LB, UB, k, c;
1040 if (emptyQ(P)) {
1041 value_set_si(*res, 0);
1042 return;
1045 value_init(LB); value_init(UB); value_init(k);
1046 value_set_si(LB,0);
1047 value_set_si(UB,0);
1049 if (lower_upper_bounds(pos,P,context,&LB,&UB) !=0) {
1050 /* Problem if UB or LB is INFINITY */
1051 value_clear(LB); value_clear(UB); value_clear(k);
1052 if (pos > P->Dimension - nparam - exist)
1053 value_set_si(*res, 1);
1054 else
1055 value_set_si(*res, -1);
1056 return;
1059 #ifdef EDEBUG1
1060 if (!P->next) {
1061 int i;
1062 for (value_assign(k,LB); value_le(k,UB); value_increment(k,k)) {
1063 fprintf(stderr, "(");
1064 for (i=1; i<pos; i++) {
1065 value_print(stderr,P_VALUE_FMT,context[i]);
1066 fprintf(stderr,",");
1068 value_print(stderr,P_VALUE_FMT,k);
1069 fprintf(stderr,")\n");
1072 #endif
1074 value_set_si(context[pos],0);
1075 if (value_lt(UB,LB)) {
1076 value_clear(LB); value_clear(UB); value_clear(k);
1077 value_set_si(*res, 0);
1078 return;
1080 if (!P->next) {
1081 if (exist)
1082 value_set_si(*res, 1);
1083 else {
1084 value_substract(k,UB,LB);
1085 value_add_int(k,k,1);
1086 value_assign(*res, k);
1088 value_clear(LB); value_clear(UB); value_clear(k);
1089 return;
1092 /*-----------------------------------------------------------------*/
1093 /* Optimization idea */
1094 /* If inner loops are not a function of k (the current index) */
1095 /* i.e. if P->Constraint[i][pos]==0 for all P following this and */
1096 /* for all i, */
1097 /* Then CNT = (UB-LB+1)*count_points(pos+1, P->next, context) */
1098 /* (skip the for loop) */
1099 /*-----------------------------------------------------------------*/
1101 value_init(c);
1102 value_set_si(*res, 0);
1103 for (value_assign(k,LB);value_le(k,UB);value_increment(k,k)) {
1104 /* Insert k in context */
1105 value_assign(context[pos],k);
1106 count_points_e(pos+1, P->next, exist, nparam, context, &c);
1107 if(value_notmone_p(c))
1108 value_addto(*res, *res, c);
1109 else {
1110 value_set_si(*res, -1);
1111 break;
1113 if (pos > P->Dimension - nparam - exist &&
1114 value_pos_p(*res))
1115 break;
1117 value_clear(c);
1119 #ifdef EDEBUG11
1120 fprintf(stderr,"%d\n",CNT);
1121 #endif
1123 /* Reset context */
1124 value_set_si(context[pos],0);
1125 value_clear(LB); value_clear(UB); value_clear(k);
1126 return;
1127 } /* count_points_e */
1129 int DomainContains(Polyhedron *P, Value *list_args, int len,
1130 unsigned MaxRays, int set)
1132 int i;
1133 Value m;
1135 if (P->Dimension == len)
1136 return in_domain(P, list_args);
1138 assert(set); // assume list_args is large enough
1139 assert((P->Dimension - len) % 2 == 0);
1140 value_init(m);
1141 for (i = 0; i < P->Dimension - len; i += 2) {
1142 int j, k;
1143 for (j = 0 ; j < P->NbEq; ++j)
1144 if (value_notzero_p(P->Constraint[j][1+len+i]))
1145 break;
1146 assert(j < P->NbEq);
1147 value_absolute(m, P->Constraint[j][1+len+i]);
1148 k = First_Non_Zero(P->Constraint[j]+1, len);
1149 assert(k != -1);
1150 assert(First_Non_Zero(P->Constraint[j]+1+k+1, len - k - 1) == -1);
1151 mpz_fdiv_q(list_args[len+i], list_args[k], m);
1152 mpz_fdiv_r(list_args[len+i+1], list_args[k], m);
1154 value_clear(m);
1156 return in_domain(P, list_args);