update isl for rename of !isl_set_dim_has_{lower,upper}_bound
[barvinok.git] / summate.c
blobb34fc063103499af6b9af6af418338bebc5bd770
1 #include <isl/map.h>
2 #include <isl_set_polylib.h>
3 #include <barvinok/options.h>
4 #include <barvinok/util.h>
5 #include "bernoulli.h"
6 #include "euler.h"
7 #include "laurent.h"
8 #include "laurent_old.h"
9 #include "summate.h"
10 #include "section_array.h"
11 #include "remove_equalities.h"
13 extern evalue *evalue_outer_floor(evalue *e);
14 extern int evalue_replace_floor(evalue *e, const evalue *floor, int var);
15 extern void evalue_drop_floor(evalue *e, const evalue *floor);
17 #define ALLOC(type) (type*)malloc(sizeof(type))
18 #define ALLOCN(type,n) (type*)malloc((n) * sizeof(type))
20 /* Apply the variable transformation specified by T and CP on
21 * the polynomial e. T expresses the old variables in terms
22 * of the new variables (and optionally also the new parameters),
23 * while CP expresses the old parameters in terms of the new
24 * parameters.
26 static void transform_polynomial(evalue *E, Matrix *T, Matrix *CP,
27 unsigned nvar, unsigned nparam,
28 unsigned new_nvar, unsigned new_nparam)
30 int j;
31 evalue **subs;
33 subs = ALLOCN(evalue *, nvar+nparam);
35 for (j = 0; j < nvar; ++j) {
36 if (T)
37 subs[j] = affine2evalue(T->p[j], T->p[T->NbRows-1][T->NbColumns-1],
38 T->NbColumns-1);
39 else
40 subs[j] = evalue_var(j);
42 for (j = 0; j < nparam; ++j) {
43 if (CP)
44 subs[nvar+j] = affine2evalue(CP->p[j], CP->p[nparam][new_nparam],
45 new_nparam);
46 else
47 subs[nvar+j] = evalue_var(j);
48 evalue_shift_variables(subs[nvar+j], 0, new_nvar);
51 evalue_substitute(E, subs);
52 reduce_evalue(E);
54 for (j = 0; j < nvar+nparam; ++j)
55 evalue_free(subs[j]);
56 free(subs);
59 static evalue *sum_with_equalities(Polyhedron *P, evalue *E,
60 unsigned nvar, struct evalue_section_array *sections,
61 struct barvinok_options *options,
62 evalue *(*base)(Polyhedron *P, evalue *E, unsigned nvar,
63 struct evalue_section_array *sections,
64 struct barvinok_options *options))
66 unsigned dim = P->Dimension;
67 unsigned new_dim, new_nparam;
68 Matrix *T = NULL, *CP = NULL;
69 evalue *sum;
71 if (emptyQ(P))
72 return evalue_zero();
74 assert(P->NbEq > 0);
76 remove_all_equalities(&P, NULL, &CP, &T, dim-nvar, options->MaxRays);
78 if (emptyQ(P)) {
79 Polyhedron_Free(P);
80 return evalue_zero();
83 new_nparam = CP ? CP->NbColumns-1 : dim - nvar;
84 new_dim = T ? T->NbColumns-1 : nvar + new_nparam;
86 /* We can avoid these substitutions if E is a constant */
87 E = evalue_dup(E);
88 transform_polynomial(E, T, CP, nvar, dim-nvar,
89 new_dim-new_nparam, new_nparam);
91 if (new_dim-new_nparam > 0) {
92 sum = base(P, E, new_dim-new_nparam, sections, options);
93 evalue_free(E);
94 Polyhedron_Free(P);
95 } else {
96 sum = ALLOC(evalue);
97 value_init(sum->d);
98 sum->x.p = new_enode(partition, 2, new_dim);
99 EVALUE_SET_DOMAIN(sum->x.p->arr[0], P);
100 value_clear(sum->x.p->arr[1].d);
101 sum->x.p->arr[1] = *E;
102 free(E);
105 if (CP) {
106 evalue_backsubstitute(sum, CP, options->MaxRays);
107 Matrix_Free(CP);
110 if (T)
111 Matrix_Free(T);
113 return sum;
116 static evalue *sum_over_polytope_with_equalities(Polyhedron *P, evalue *E,
117 unsigned nvar, struct evalue_section_array *sections,
118 struct barvinok_options *options)
120 return sum_with_equalities(P, E, nvar, sections, options,
121 &barvinok_sum_over_polytope);
124 static evalue *sum_base(Polyhedron *P, evalue *E, unsigned nvar,
125 struct barvinok_options *options);
127 static evalue *sum_base_wrap(Polyhedron *P, evalue *E, unsigned nvar,
128 struct evalue_section_array *sections, struct barvinok_options *options)
130 return sum_base(P, E, nvar, options);
133 static evalue *sum_base_with_equalities(Polyhedron *P, evalue *E,
134 unsigned nvar, struct barvinok_options *options)
136 return sum_with_equalities(P, E, nvar, NULL, options, &sum_base_wrap);
139 /* The substitutions in sum_step_polynomial may have reintroduced equalities
140 * (in particular, one of the floor expressions may be equal to one of
141 * the variables), so we need to check for them again.
143 static evalue *sum_base(Polyhedron *P, evalue *E, unsigned nvar,
144 struct barvinok_options *options)
146 if (P->NbEq)
147 return sum_base_with_equalities(P, E, nvar, options);
148 if (options->summation == BV_SUM_EULER)
149 return euler_summate(P, E, nvar, options);
150 else if (options->summation == BV_SUM_LAURENT)
151 return laurent_summate(P, E, nvar, options);
152 else if (options->summation == BV_SUM_LAURENT_OLD)
153 return laurent_summate_old(P, E, nvar, options);
154 assert(0);
157 /* Count the number of non-zero terms in e when viewed as a polynomial
158 * in only the first nvar variables. "count" is the number counted
159 * so far.
161 static int evalue_count_terms(const evalue *e, unsigned nvar, int count)
163 int i;
165 if (EVALUE_IS_ZERO(*e))
166 return count;
168 if (value_zero_p(e->d))
169 assert(e->x.p->type == polynomial);
170 if (value_notzero_p(e->d) || e->x.p->pos >= nvar+1)
171 return count+1;
173 for (i = 0; i < e->x.p->size; ++i)
174 count = evalue_count_terms(&e->x.p->arr[i], nvar, count);
176 return count;
179 /* Create placeholder structure for unzipping.
180 * A "polynomial" is created with size terms in variable pos,
181 * with each term having itself as coefficient.
183 static evalue *create_placeholder(int size, int pos)
185 int i, j;
186 evalue *E = ALLOC(evalue);
187 value_init(E->d);
188 E->x.p = new_enode(polynomial, size, pos+1);
189 for (i = 0; i < size; ++i) {
190 E->x.p->arr[i].x.p = new_enode(polynomial, i+1, pos+1);
191 for (j = 0; j < i; ++j)
192 evalue_set_si(&E->x.p->arr[i].x.p->arr[j], 0, 1);
193 evalue_set_si(&E->x.p->arr[i].x.p->arr[i], 1, 1);
195 return E;
198 /* Interchange each non-zero term in e (when viewed as a polynomial
199 * in only the first nvar variables) with a placeholder in ph (created
200 * by create_placeholder), resulting in two polynomials in the
201 * placeholder variable such that for each non-zero term in e
202 * there is a power of the placeholder variable such that the factors
203 * in the first nvar variables form the coefficient of that power in
204 * the first polynomial (e) and the factors in the remaining variables
205 * form the coefficient of that power in the second polynomial (ph).
207 static int evalue_unzip_terms(evalue *e, evalue *ph, unsigned nvar, int count)
209 int i;
211 if (EVALUE_IS_ZERO(*e))
212 return count;
214 if (value_zero_p(e->d))
215 assert(e->x.p->type == polynomial);
216 if (value_notzero_p(e->d) || e->x.p->pos >= nvar+1) {
217 evalue t = *e;
218 *e = ph->x.p->arr[count];
219 ph->x.p->arr[count] = t;
220 return count+1;
223 for (i = 0; i < e->x.p->size; ++i)
224 count = evalue_unzip_terms(&e->x.p->arr[i], ph, nvar, count);
226 return count;
229 /* Remove n variables at pos (0-based) from the polyhedron P.
230 * Each of these variables is assumed to be completely free,
231 * i.e., there is a line in the polyhedron corresponding to
232 * each of these variables.
234 static Polyhedron *Polyhedron_Remove_Columns(Polyhedron *P, unsigned pos,
235 unsigned n)
237 int i, j;
238 unsigned NbConstraints = 0;
239 unsigned NbRays = 0;
240 Polyhedron *Q;
242 if (n == 0)
243 return P;
245 assert(pos <= P->Dimension);
247 if (POL_HAS(P, POL_INEQUALITIES))
248 NbConstraints = P->NbConstraints;
249 if (POL_HAS(P, POL_POINTS))
250 NbRays = P->NbRays - n;
252 Q = Polyhedron_Alloc(P->Dimension - n, NbConstraints, NbRays);
253 if (POL_HAS(P, POL_INEQUALITIES)) {
254 Q->NbEq = P->NbEq;
255 for (i = 0; i < P->NbConstraints; ++i) {
256 Vector_Copy(P->Constraint[i], Q->Constraint[i], 1+pos);
257 Vector_Copy(P->Constraint[i]+1+pos+n, Q->Constraint[i]+1+pos,
258 Q->Dimension-pos+1);
261 if (POL_HAS(P, POL_POINTS)) {
262 Q->NbBid = P->NbBid - n;
263 for (i = 0; i < n; ++i)
264 value_set_si(Q->Ray[i][1+pos+i], 1);
265 for (i = 0, j = 0; i < P->NbRays; ++i) {
266 int line = First_Non_Zero(P->Ray[i], 1+P->Dimension+1);
267 assert(line != -1);
268 if (line-1 >= pos && line-1 < pos+n) {
269 ++j;
270 assert(j <= n);
271 continue;
273 assert(i-j < Q->NbRays);
274 Vector_Copy(P->Ray[i], Q->Ray[i-j], 1+pos);
275 Vector_Copy(P->Ray[i]+1+pos+n, Q->Ray[i-j]+1+pos,
276 Q->Dimension-pos+1);
279 POL_SET(Q, POL_VALID);
280 if (POL_HAS(P, POL_INEQUALITIES))
281 POL_SET(Q, POL_INEQUALITIES);
282 if (POL_HAS(P, POL_POINTS))
283 POL_SET(Q, POL_POINTS);
284 if (POL_HAS(P, POL_VERTICES))
285 POL_SET(Q, POL_VERTICES);
286 return Q;
289 /* Remove n variables at pos (0-based) from the union of polyhedra P.
290 * Each of these variables is assumed to be completely free,
291 * i.e., there is a line in the polyhedron corresponding to
292 * each of these variables.
294 static Polyhedron *Domain_Remove_Columns(Polyhedron *P, unsigned pos,
295 unsigned n)
297 Polyhedron *R;
298 Polyhedron **next = &R;
300 for (; P; P = P->next) {
301 *next = Polyhedron_Remove_Columns(P, pos, n);
302 next = &(*next)->next;
304 return R;
307 /* Drop n parameters starting at first from partition evalue e */
308 static void drop_parameters(evalue *e, int first, int n)
310 int i;
312 if (EVALUE_IS_ZERO(*e))
313 return;
315 assert(value_zero_p(e->d) && e->x.p->type == partition);
316 for (i = 0; i < e->x.p->size/2; ++i) {
317 Polyhedron *P = EVALUE_DOMAIN(e->x.p->arr[2*i]);
318 Polyhedron *Q = Domain_Remove_Columns(P, first, n);
319 EVALUE_SET_DOMAIN(e->x.p->arr[2*i], Q);
320 Domain_Free(P);
321 evalue_shift_variables(&e->x.p->arr[2*i+1], first, -n);
323 e->x.p->pos -= n;
326 static void extract_term_into(const evalue *src, int var, int exp, evalue *dst)
328 int i;
330 if (value_notzero_p(src->d) ||
331 src->x.p->type != polynomial ||
332 src->x.p->pos > var+1) {
333 if (exp == 0)
334 evalue_copy(dst, src);
335 else
336 evalue_set_si(dst, 0, 1);
337 return;
340 if (src->x.p->pos == var+1) {
341 if (src->x.p->size > exp)
342 evalue_copy(dst, &src->x.p->arr[exp]);
343 else
344 evalue_set_si(dst, 0, 1);
345 return;
348 dst->x.p = new_enode(polynomial, src->x.p->size, src->x.p->pos);
349 for (i = 0; i < src->x.p->size; ++i)
350 extract_term_into(&src->x.p->arr[i], var, exp,
351 &dst->x.p->arr[i]);
354 /* Extract the coefficient of var^exp.
356 static evalue *extract_term(const evalue *e, int var, int exp)
358 int i;
359 evalue *res;
361 if (EVALUE_IS_ZERO(*e))
362 return evalue_zero();
364 assert(value_zero_p(e->d) && e->x.p->type == partition);
365 res = ALLOC(evalue);
366 value_init(res->d);
367 res->x.p = new_enode(partition, e->x.p->size, e->x.p->pos);
368 for (i = 0; i < e->x.p->size/2; ++i) {
369 EVALUE_SET_DOMAIN(res->x.p->arr[2*i],
370 Domain_Copy(EVALUE_DOMAIN(e->x.p->arr[2*i])));
371 extract_term_into(&e->x.p->arr[2*i+1], var, exp,
372 &res->x.p->arr[2*i+1]);
373 reduce_evalue(&res->x.p->arr[2*i+1]);
375 return res;
378 /* Insert n free variables at pos (0-based) in the polyhedron P.
380 static Polyhedron *Polyhedron_Insert_Columns(Polyhedron *P, unsigned pos,
381 unsigned n)
383 int i;
384 unsigned NbConstraints = 0;
385 unsigned NbRays = 0;
386 Polyhedron *Q;
388 if (!P)
389 return P;
390 if (n == 0)
391 return P;
393 assert(pos <= P->Dimension);
395 if (POL_HAS(P, POL_INEQUALITIES))
396 NbConstraints = P->NbConstraints;
397 if (POL_HAS(P, POL_POINTS))
398 NbRays = P->NbRays + n;
400 Q = Polyhedron_Alloc(P->Dimension+n, NbConstraints, NbRays);
401 if (POL_HAS(P, POL_INEQUALITIES)) {
402 Q->NbEq = P->NbEq;
403 for (i = 0; i < P->NbConstraints; ++i) {
404 Vector_Copy(P->Constraint[i], Q->Constraint[i], 1+pos);
405 Vector_Copy(P->Constraint[i]+1+pos, Q->Constraint[i]+1+pos+n,
406 P->Dimension-pos+1);
409 if (POL_HAS(P, POL_POINTS)) {
410 Q->NbBid = P->NbBid + n;
411 for (i = 0; i < n; ++i)
412 value_set_si(Q->Ray[i][1+pos+i], 1);
413 for (i = 0; i < P->NbRays; ++i) {
414 Vector_Copy(P->Ray[i], Q->Ray[n+i], 1+pos);
415 Vector_Copy(P->Ray[i]+1+pos, Q->Ray[n+i]+1+pos+n,
416 P->Dimension-pos+1);
419 POL_SET(Q, POL_VALID);
420 if (POL_HAS(P, POL_INEQUALITIES))
421 POL_SET(Q, POL_INEQUALITIES);
422 if (POL_HAS(P, POL_POINTS))
423 POL_SET(Q, POL_POINTS);
424 if (POL_HAS(P, POL_VERTICES))
425 POL_SET(Q, POL_VERTICES);
426 return Q;
429 /* Perform summation of e over a list of 1 or more factors F, with context C.
430 * nvar is the total number of variables in the remaining factors.
431 * extra is the number of placeholder parameters introduced in e,
432 * but not (yet) in F or C.
434 * If there is only one factor left, F is intersected with the
435 * context C, the placeholder variables are added, and then
436 * e is summed over the resulting parametric polytope.
438 * If there is more than one factor left, we create two polynomials
439 * in a new placeholder variable (which is placed after the regular
440 * parameters, but before any previously introduced placeholder
441 * variables) that has the factors of the variables in the first
442 * factor of F and the factor of the remaining variables of
443 * each term as its coefficients.
444 * These two polynomials are then summed over their domains
445 * and afterwards the results are combined and the placeholder
446 * variable is removed again.
448 static evalue *sum_factors(Polyhedron *F, Polyhedron *C, evalue *e,
449 unsigned nvar, unsigned extra,
450 struct barvinok_options *options)
452 Polyhedron *P = F;
453 unsigned nparam = C->Dimension;
454 unsigned F_var = F->Dimension - C->Dimension;
455 int i, n;
456 evalue *s1, *s2, *s;
457 evalue *ph;
459 if (!F->next) {
460 Polyhedron *CA = align_context(C, nvar+nparam, options->MaxRays);
461 Polyhedron *P = DomainIntersection(F, CA, options->MaxRays);
462 Polyhedron *Q = Polyhedron_Insert_Columns(P, nvar+nparam, extra);
463 Polyhedron_Free(CA);
464 Polyhedron_Free(F);
465 Polyhedron_Free(P);
466 evalue *sum = sum_base(Q, e, nvar, options);
467 Polyhedron_Free(Q);
468 return sum;
471 n = evalue_count_terms(e, F_var, 0);
472 ph = create_placeholder(n, nvar+nparam);
473 evalue_shift_variables(e, nvar+nparam, 1);
474 evalue_unzip_terms(e, ph, F_var, 0);
475 evalue_shift_variables(e, nvar, -(nvar-F_var));
476 evalue_reorder_terms(ph);
477 evalue_shift_variables(ph, 0, -F_var);
479 s2 = sum_factors(F->next, C, ph, nvar-F_var, extra+1, options);
480 evalue_free(ph);
481 F->next = NULL;
482 s1 = sum_factors(F, C, e, F_var, extra+1, options);
484 if (n == 1) {
485 /* remove placeholder "polynomial" */
486 reduce_evalue(s1);
487 emul(s1, s2);
488 evalue_free(s1);
489 drop_parameters(s2, nparam, 1);
490 return s2;
493 s = evalue_zero();
494 for (i = 0; i < n; ++i) {
495 evalue *t1, *t2;
496 t1 = extract_term(s1, nparam, i);
497 t2 = extract_term(s2, nparam, i);
498 emul(t1, t2);
499 eadd(t2, s);
500 evalue_free(t1);
501 evalue_free(t2);
503 evalue_free(s1);
504 evalue_free(s2);
506 drop_parameters(s, nparam, 1);
507 return s;
510 /* Perform summation over a product of factors F, obtained using
511 * variable transformation T from the original problem specification.
513 * We first perform the corresponding transformation on the polynomial E,
514 * compute the common context over all factors and then perform
515 * the actual summation over the factors.
517 static evalue *sum_product(Polyhedron *F, evalue *E, Matrix *T, unsigned nparam,
518 struct barvinok_options *options)
520 int i;
521 Matrix *T2;
522 unsigned nvar = T->NbRows;
523 Polyhedron *C;
524 evalue *sum;
526 assert(nvar == T->NbColumns);
527 T2 = Matrix_Alloc(nvar+1, nvar+1);
528 for (i = 0; i < nvar; ++i)
529 Vector_Copy(T->p[i], T2->p[i], nvar);
530 value_set_si(T2->p[nvar][nvar], 1);
532 transform_polynomial(E, T2, NULL, nvar, nparam, nvar, nparam);
534 C = Factor_Context(F, nparam, options->MaxRays);
535 if (F->Dimension == nparam) {
536 Polyhedron *T = F;
537 F = F->next;
538 T->next = NULL;
539 Polyhedron_Free(T);
541 sum = sum_factors(F, C, E, nvar, 0, options);
543 Polyhedron_Free(C);
544 Matrix_Free(T2);
545 Matrix_Free(T);
546 return sum;
549 /* Add two constraints corresponding to floor = floor(e/d),
551 * e - d t >= 0
552 * -e + d t + d-1 >= 0
554 * e is assumed to be an affine expression.
556 Polyhedron *add_floor_var(Polyhedron *P, unsigned nvar, const evalue *floor,
557 struct barvinok_options *options)
559 int i;
560 unsigned dim = P->Dimension+1;
561 Matrix *M = Matrix_Alloc(P->NbConstraints+2, 2+dim);
562 Polyhedron *CP;
563 Value *d = &M->p[0][1+nvar];
564 evalue_extract_affine(floor, M->p[0]+1, M->p[0]+1+dim, d);
565 value_oppose(*d, *d);
566 value_set_si(M->p[0][0], 1);
567 value_set_si(M->p[1][0], 1);
568 Vector_Oppose(M->p[0]+1, M->p[1]+1, M->NbColumns-1);
569 value_subtract(M->p[1][1+dim], M->p[1][1+dim], *d);
570 value_decrement(M->p[1][1+dim], M->p[1][1+dim]);
572 for (i = 0; i < P->NbConstraints; ++i) {
573 Vector_Copy(P->Constraint[i], M->p[i+2], 1+nvar);
574 Vector_Copy(P->Constraint[i]+1+nvar, M->p[i+2]+1+nvar+1, dim-nvar-1+1);
577 CP = Constraints2Polyhedron(M, options->MaxRays);
578 Matrix_Free(M);
579 return CP;
582 static evalue *evalue_add(evalue *a, evalue *b)
584 if (!a)
585 return b;
586 if (!b)
587 return a;
588 eadd(a, b);
589 evalue_free(a);
590 return b;
593 /* Compute sum of a step-polynomial over a polytope by grouping
594 * terms containing the same floor-expressions and introducing
595 * new variables for each such expression.
596 * In particular, while there is any floor-expression left,
597 * the step-polynomial is split into a polynomial containing
598 * the expression, which is then converted to a new variable,
599 * and a polynomial not containing the expression.
601 static evalue *sum_step_polynomial(Polyhedron *P, evalue *E, unsigned nvar,
602 struct barvinok_options *options)
604 evalue *floor;
605 evalue *cur = E;
606 evalue *sum = NULL;
607 evalue *t;
609 while ((floor = evalue_outer_floor(cur))) {
610 Polyhedron *CP;
611 evalue *converted;
612 evalue *converted_floor;
614 /* Ignore floors that do not depend on variables. */
615 if (value_notzero_p(floor->d) || floor->x.p->pos >= nvar+1)
616 break;
618 converted = evalue_dup(cur);
619 converted_floor = evalue_dup(floor);
620 evalue_shift_variables(converted, nvar, 1);
621 evalue_shift_variables(converted_floor, nvar, 1);
622 evalue_replace_floor(converted, converted_floor, nvar);
623 CP = add_floor_var(P, nvar, converted_floor, options);
624 evalue_free(converted_floor);
625 t = sum_step_polynomial(CP, converted, nvar+1, options);
626 evalue_free(converted);
627 Polyhedron_Free(CP);
628 sum = evalue_add(t, sum);
630 if (cur == E)
631 cur = evalue_dup(cur);
632 evalue_drop_floor(cur, floor);
633 evalue_free(floor);
635 if (floor) {
636 evalue_floor2frac(cur);
637 evalue_free(floor);
640 if (EVALUE_IS_ZERO(*cur))
641 t = NULL;
642 else {
643 Matrix *T;
644 unsigned nparam = P->Dimension - nvar;
645 Polyhedron *F = Polyhedron_Factor(P, nparam, &T, options->MaxRays);
646 if (!F)
647 t = sum_base(P, cur, nvar, options);
648 else {
649 if (cur == E)
650 cur = evalue_dup(cur);
651 t = sum_product(F, cur, T, nparam, options);
655 if (E != cur)
656 evalue_free(cur);
658 return evalue_add(t, sum);
661 evalue *barvinok_sum_over_polytope(Polyhedron *P, evalue *E, unsigned nvar,
662 struct evalue_section_array *sections,
663 struct barvinok_options *options)
665 if (P->NbEq)
666 return sum_over_polytope_with_equalities(P, E, nvar, sections, options);
668 if (options->summation == BV_SUM_BERNOULLI)
669 return bernoulli_summate(P, E, nvar, sections, options);
670 else if (options->summation == BV_SUM_BOX)
671 return box_summate(P, E, nvar, options->MaxRays);
673 evalue_frac2floor2(E, 0);
675 return sum_step_polynomial(P, E, nvar, options);
678 evalue *barvinok_summate(evalue *e, int nvar, struct barvinok_options *options)
680 int i;
681 struct evalue_section_array sections;
682 evalue *sum;
684 assert(nvar >= 0);
685 if (nvar == 0 || EVALUE_IS_ZERO(*e))
686 return evalue_dup(e);
688 assert(value_zero_p(e->d));
689 assert(e->x.p->type == partition);
691 evalue_section_array_init(&sections);
692 sum = evalue_zero();
694 for (i = 0; i < e->x.p->size/2; ++i) {
695 Polyhedron *D;
696 for (D = EVALUE_DOMAIN(e->x.p->arr[2*i]); D; D = D->next) {
697 Polyhedron *next = D->next;
698 evalue *tmp;
699 D->next = NULL;
701 tmp = barvinok_sum_over_polytope(D, &e->x.p->arr[2*i+1], nvar,
702 &sections, options);
703 assert(tmp);
704 eadd(tmp, sum);
705 evalue_free(tmp);
707 D->next = next;
711 free(sections.s);
713 reduce_evalue(sum);
714 return sum;
717 static __isl_give isl_pw_qpolynomial *add_unbounded_guarded_qp(
718 __isl_take isl_pw_qpolynomial *sum,
719 __isl_take isl_basic_set *bset, __isl_take isl_qpolynomial *qp)
721 int zero;
723 if (!sum || !bset || !qp)
724 goto error;
726 zero = isl_qpolynomial_is_zero(qp);
727 if (zero < 0)
728 goto error;
730 if (!zero) {
731 isl_space *dim;
732 isl_set *set;
733 isl_pw_qpolynomial *pwqp;
735 dim = isl_pw_qpolynomial_get_domain_space(sum);
736 set = isl_set_from_basic_set(isl_basic_set_copy(bset));
737 set = isl_map_domain(isl_map_from_range(set));
738 set = isl_set_reset_space(set, isl_space_copy(dim));
739 pwqp = isl_pw_qpolynomial_alloc(set, isl_qpolynomial_nan_on_domain(dim));
740 sum = isl_pw_qpolynomial_add(sum, pwqp);
743 isl_basic_set_free(bset);
744 isl_qpolynomial_free(qp);
745 return sum;
746 error:
747 isl_basic_set_free(bset);
748 isl_qpolynomial_free(qp);
749 isl_pw_qpolynomial_free(sum);
750 return NULL;
753 struct barvinok_summate_data {
754 isl_space *dim;
755 __isl_take isl_qpolynomial *qp;
756 isl_pw_qpolynomial *sum;
757 int n_in;
758 int wrapping;
759 evalue *e;
760 struct evalue_section_array sections;
761 struct barvinok_options *options;
764 static int add_basic_guarded_qp(__isl_take isl_basic_set *bset, void *user)
766 struct barvinok_summate_data *data = user;
767 Polyhedron *P;
768 evalue *tmp;
769 isl_pw_qpolynomial *pwqp;
770 int bounded;
771 unsigned nparam = isl_basic_set_dim(bset, isl_dim_param);
772 unsigned nvar = isl_basic_set_dim(bset, isl_dim_set);
773 isl_space *dim;
775 if (!bset)
776 return -1;
778 bounded = isl_basic_set_is_bounded(bset);
779 if (bounded < 0)
780 goto error;
782 if (!bounded) {
783 data->sum = add_unbounded_guarded_qp(data->sum, bset,
784 isl_qpolynomial_copy(data->qp));
785 return 0;
788 dim = isl_basic_set_get_space(bset);
789 dim = isl_space_domain(isl_space_from_range(dim));
791 P = isl_basic_set_to_polylib(bset);
792 tmp = barvinok_sum_over_polytope(P, data->e, nvar,
793 &data->sections, data->options);
794 Polyhedron_Free(P);
795 assert(tmp);
796 pwqp = isl_pw_qpolynomial_from_evalue(dim, tmp);
797 evalue_free(tmp);
798 pwqp = isl_pw_qpolynomial_reset_domain_space(pwqp,
799 isl_space_domain(isl_space_copy(data->dim)));
800 data->sum = isl_pw_qpolynomial_add(data->sum, pwqp);
802 isl_basic_set_free(bset);
804 return 0;
805 error:
806 isl_basic_set_free(bset);
807 return -1;
810 static int add_guarded_qp(__isl_take isl_set *set, __isl_take isl_qpolynomial *qp,
811 void *user)
813 int r;
814 struct barvinok_summate_data *data = user;
816 if (!set || !qp)
817 goto error;
819 data->qp = qp;
821 if (data->wrapping) {
822 unsigned nparam = isl_set_dim(set, isl_dim_param);
823 isl_qpolynomial *qp2 = isl_qpolynomial_copy(qp);
824 set = isl_set_move_dims(set, isl_dim_param, nparam,
825 isl_dim_set, 0, data->n_in);
826 qp2 = isl_qpolynomial_move_dims(qp2, isl_dim_param, nparam,
827 isl_dim_in, 0, data->n_in);
828 data->e = isl_qpolynomial_to_evalue(qp2);
829 isl_qpolynomial_free(qp2);
830 } else
831 data->e = isl_qpolynomial_to_evalue(qp);
832 if (!data->e)
833 goto error;
835 evalue_section_array_init(&data->sections);
837 set = isl_set_make_disjoint(set);
838 set = isl_set_compute_divs(set);
840 r = isl_set_foreach_basic_set(set, &add_basic_guarded_qp, data);
842 free(data->sections.s);
844 evalue_free(data->e);
846 isl_set_free(set);
847 isl_qpolynomial_free(qp);
849 return r;
850 error:
851 isl_set_free(set);
852 isl_qpolynomial_free(qp);
853 return -1;
856 __isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_sum(
857 __isl_take isl_pw_qpolynomial *pwqp)
859 isl_ctx *ctx;
860 struct barvinok_summate_data data;
861 int options_allocated = 0;
862 int nvar;
864 data.dim = NULL;
865 data.options = NULL;
867 if (!pwqp)
868 return NULL;
870 nvar = isl_pw_qpolynomial_dim(pwqp, isl_dim_set);
872 data.dim = isl_pw_qpolynomial_get_domain_space(pwqp);
873 data.wrapping = isl_space_is_wrapping(data.dim);
874 if (data.wrapping) {
875 data.dim = isl_space_unwrap(data.dim);
876 data.n_in = isl_space_dim(data.dim, isl_dim_in);
877 nvar = isl_space_dim(data.dim, isl_dim_out);
878 } else
879 data.n_in = 0;
881 data.dim = isl_space_domain(data.dim);
882 if (nvar == 0)
883 return isl_pw_qpolynomial_reset_domain_space(pwqp, data.dim);
885 data.dim = isl_space_from_domain(data.dim);
886 data.dim = isl_space_add_dims(data.dim, isl_dim_out, 1);
887 data.sum = isl_pw_qpolynomial_zero(isl_space_copy(data.dim));
889 ctx = isl_pw_qpolynomial_get_ctx(pwqp);
890 data.options = isl_ctx_peek_barvinok_options(ctx);
891 if (!data.options) {
892 data.options = barvinok_options_new_with_defaults();
893 options_allocated = 1;
896 if (isl_pw_qpolynomial_foreach_lifted_piece(pwqp,
897 add_guarded_qp, &data) < 0)
898 goto error;
900 if (options_allocated)
901 barvinok_options_free(data.options);
903 isl_space_free(data.dim);
905 isl_pw_qpolynomial_free(pwqp);
907 return data.sum;
908 error:
909 if (options_allocated)
910 barvinok_options_free(data.options);
911 isl_pw_qpolynomial_free(pwqp);
912 isl_space_free(data.dim);
913 isl_pw_qpolynomial_free(data.sum);
914 return NULL;
917 static int pw_qpolynomial_sum(__isl_take isl_pw_qpolynomial *pwqp, void *user)
919 isl_union_pw_qpolynomial **res = (isl_union_pw_qpolynomial **)user;
920 isl_pw_qpolynomial *sum;
922 sum = isl_pw_qpolynomial_sum(pwqp);
923 *res = isl_union_pw_qpolynomial_add_pw_qpolynomial(*res, sum);
925 return 0;
928 __isl_give isl_union_pw_qpolynomial *isl_union_pw_qpolynomial_sum(
929 __isl_take isl_union_pw_qpolynomial *upwqp)
931 isl_space *dim;
932 isl_union_pw_qpolynomial *res;
934 dim = isl_union_pw_qpolynomial_get_space(upwqp);
935 res = isl_union_pw_qpolynomial_zero(dim);
936 if (isl_union_pw_qpolynomial_foreach_pw_qpolynomial(upwqp,
937 &pw_qpolynomial_sum, &res) < 0)
938 goto error;
939 isl_union_pw_qpolynomial_free(upwqp);
941 return res;
942 error:
943 isl_union_pw_qpolynomial_free(upwqp);
944 isl_union_pw_qpolynomial_free(res);
945 return NULL;
948 static int join_compatible(__isl_keep isl_space *dim1, __isl_keep isl_space *dim2)
950 int m;
951 m = isl_space_match(dim1, isl_dim_param, dim2, isl_dim_param);
952 if (m < 0 || !m)
953 return m;
954 return isl_space_tuple_match(dim1, isl_dim_out, dim2, isl_dim_in);
957 /* Compute the intersection of the range of the map and the domain
958 * of the piecewise quasipolynomial and then sum the associated
959 * quasipolynomial over all elements in this intersection.
961 * We first introduce some unconstrained dimensions in the
962 * piecewise quasipolynomial, intersect the resulting domain
963 * with the wrapped map and then compute the sum.
965 __isl_give isl_pw_qpolynomial *isl_map_apply_pw_qpolynomial(
966 __isl_take isl_map *map, __isl_take isl_pw_qpolynomial *pwqp)
968 isl_ctx *ctx;
969 isl_set *dom;
970 isl_space *map_dim;
971 isl_space *pwqp_dim;
972 unsigned n_in;
973 int ok;
975 ctx = isl_map_get_ctx(map);
976 if (!ctx)
977 goto error;
979 map_dim = isl_map_get_space(map);
980 pwqp_dim = isl_pw_qpolynomial_get_space(pwqp);
981 ok = join_compatible(map_dim, pwqp_dim);
982 isl_space_free(map_dim);
983 isl_space_free(pwqp_dim);
984 if (!ok)
985 isl_die(ctx, isl_error_invalid, "incompatible dimensions",
986 goto error);
988 n_in = isl_map_dim(map, isl_dim_in);
989 pwqp = isl_pw_qpolynomial_insert_dims(pwqp, isl_dim_in, 0, n_in);
991 dom = isl_map_wrap(map);
992 pwqp = isl_pw_qpolynomial_reset_domain_space(pwqp,
993 isl_set_get_space(dom));
995 pwqp = isl_pw_qpolynomial_intersect_domain(pwqp, dom);
996 pwqp = isl_pw_qpolynomial_sum(pwqp);
998 return pwqp;
999 error:
1000 isl_map_free(map);
1001 isl_pw_qpolynomial_free(pwqp);
1002 return NULL;
1005 __isl_give isl_pw_qpolynomial *isl_set_apply_pw_qpolynomial(
1006 __isl_take isl_set *set, __isl_take isl_pw_qpolynomial *pwqp)
1008 isl_map *map;
1010 map = isl_map_from_range(set);
1011 pwqp = isl_map_apply_pw_qpolynomial(map, pwqp);
1012 pwqp = isl_pw_qpolynomial_project_domain_on_params(pwqp);
1013 return pwqp;
1016 struct barvinok_apply_data {
1017 isl_union_pw_qpolynomial *upwqp;
1018 isl_union_pw_qpolynomial *res;
1019 isl_map *map;
1022 static int pw_qpolynomial_apply(__isl_take isl_pw_qpolynomial *pwqp, void *user)
1024 isl_space *map_dim;
1025 isl_space *pwqp_dim;
1026 struct barvinok_apply_data *data = user;
1027 int ok;
1029 map_dim = isl_map_get_space(data->map);
1030 pwqp_dim = isl_pw_qpolynomial_get_space(pwqp);
1031 ok = join_compatible(map_dim, pwqp_dim);
1032 isl_space_free(map_dim);
1033 isl_space_free(pwqp_dim);
1035 if (ok) {
1036 pwqp = isl_map_apply_pw_qpolynomial(isl_map_copy(data->map),
1037 pwqp);
1038 data->res = isl_union_pw_qpolynomial_add_pw_qpolynomial(
1039 data->res, pwqp);
1040 } else
1041 isl_pw_qpolynomial_free(pwqp);
1043 return 0;
1046 static int map_apply(__isl_take isl_map *map, void *user)
1048 struct barvinok_apply_data *data = user;
1049 int r;
1051 data->map = map;
1052 r = isl_union_pw_qpolynomial_foreach_pw_qpolynomial(data->upwqp,
1053 &pw_qpolynomial_apply, data);
1055 isl_map_free(map);
1056 return r;
1059 __isl_give isl_union_pw_qpolynomial *isl_union_map_apply_union_pw_qpolynomial(
1060 __isl_take isl_union_map *umap,
1061 __isl_take isl_union_pw_qpolynomial *upwqp)
1063 isl_space *dim;
1064 struct barvinok_apply_data data;
1066 upwqp = isl_union_pw_qpolynomial_align_params(upwqp,
1067 isl_union_map_get_space(umap));
1068 umap = isl_union_map_align_params(umap,
1069 isl_union_pw_qpolynomial_get_space(upwqp));
1071 data.upwqp = upwqp;
1072 dim = isl_union_pw_qpolynomial_get_space(upwqp);
1073 data.res = isl_union_pw_qpolynomial_zero(dim);
1074 if (isl_union_map_foreach_map(umap, &map_apply, &data) < 0)
1075 goto error;
1077 isl_union_map_free(umap);
1078 isl_union_pw_qpolynomial_free(upwqp);
1080 return data.res;
1081 error:
1082 isl_union_map_free(umap);
1083 isl_union_pw_qpolynomial_free(upwqp);
1084 isl_union_pw_qpolynomial_free(data.res);
1085 return NULL;
1088 struct barvinok_apply_set_data {
1089 isl_union_pw_qpolynomial *upwqp;
1090 isl_union_pw_qpolynomial *res;
1091 isl_set *set;
1094 static int pw_qpolynomial_apply_set(__isl_take isl_pw_qpolynomial *pwqp,
1095 void *user)
1097 isl_space *set_dim;
1098 isl_space *pwqp_dim;
1099 struct barvinok_apply_set_data *data = user;
1100 int ok;
1102 set_dim = isl_set_get_space(data->set);
1103 pwqp_dim = isl_pw_qpolynomial_get_space(pwqp);
1104 ok = join_compatible(set_dim, pwqp_dim);
1105 isl_space_free(set_dim);
1106 isl_space_free(pwqp_dim);
1108 if (ok) {
1109 pwqp = isl_set_apply_pw_qpolynomial(isl_set_copy(data->set),
1110 pwqp);
1111 data->res = isl_union_pw_qpolynomial_add_pw_qpolynomial(
1112 data->res, pwqp);
1113 } else
1114 isl_pw_qpolynomial_free(pwqp);
1116 return 0;
1119 static int set_apply(__isl_take isl_set *set, void *user)
1121 struct barvinok_apply_set_data *data = user;
1122 int r;
1124 data->set = set;
1125 r = isl_union_pw_qpolynomial_foreach_pw_qpolynomial(data->upwqp,
1126 &pw_qpolynomial_apply_set, data);
1128 isl_set_free(set);
1129 return r;
1132 __isl_give isl_union_pw_qpolynomial *isl_union_set_apply_union_pw_qpolynomial(
1133 __isl_take isl_union_set *uset,
1134 __isl_take isl_union_pw_qpolynomial *upwqp)
1136 isl_space *dim;
1137 struct barvinok_apply_set_data data;
1139 upwqp = isl_union_pw_qpolynomial_align_params(upwqp,
1140 isl_union_set_get_space(uset));
1141 uset = isl_union_set_align_params(uset,
1142 isl_union_pw_qpolynomial_get_space(upwqp));
1144 data.upwqp = upwqp;
1145 dim = isl_union_pw_qpolynomial_get_space(upwqp);
1146 data.res = isl_union_pw_qpolynomial_zero(dim);
1147 if (isl_union_set_foreach_set(uset, &set_apply, &data) < 0)
1148 goto error;
1150 isl_union_set_free(uset);
1151 isl_union_pw_qpolynomial_free(upwqp);
1153 return data.res;
1154 error:
1155 isl_union_set_free(uset);
1156 isl_union_pw_qpolynomial_free(upwqp);
1157 isl_union_pw_qpolynomial_free(data.res);
1158 return NULL;
1161 evalue *evalue_sum(evalue *E, int nvar, unsigned MaxRays)
1163 evalue *sum;
1164 struct barvinok_options *options = barvinok_options_new_with_defaults();
1165 options->MaxRays = MaxRays;
1166 sum = barvinok_summate(E, nvar, options);
1167 barvinok_options_free(options);
1168 return sum;
1171 evalue *esum(evalue *e, int nvar)
1173 evalue *sum;
1174 struct barvinok_options *options = barvinok_options_new_with_defaults();
1175 sum = barvinok_summate(e, nvar, options);
1176 barvinok_options_free(options);
1177 return sum;
1180 /* Turn unweighted counting problem into "weighted" counting problem
1181 * with weight equal to 1 and call barvinok_summate on this weighted problem.
1183 evalue *barvinok_summate_unweighted(Polyhedron *P, Polyhedron *C,
1184 struct barvinok_options *options)
1186 Polyhedron *CA, *D;
1187 evalue e;
1188 evalue *sum;
1190 if (emptyQ(P) || emptyQ(C))
1191 return evalue_zero();
1193 CA = align_context(C, P->Dimension, options->MaxRays);
1194 D = DomainIntersection(P, CA, options->MaxRays);
1195 Domain_Free(CA);
1197 if (emptyQ(D)) {
1198 Domain_Free(D);
1199 return evalue_zero();
1202 value_init(e.d);
1203 e.x.p = new_enode(partition, 2, P->Dimension);
1204 EVALUE_SET_DOMAIN(e.x.p->arr[0], D);
1205 evalue_set_si(&e.x.p->arr[1], 1, 1);
1206 sum = barvinok_summate(&e, P->Dimension - C->Dimension, options);
1207 free_evalue_refs(&e);
1208 return sum;