assume NTL has been compiled in ISO mode
[barvinok.git] / summate.c
blobc5bc6f7af37fbcb83cb93a56c455fc1e3d0af8d9
1 #include <isl/map.h>
2 #include <isl/union_set.h>
3 #include <isl/union_map.h>
4 #include <isl_set_polylib.h>
5 #include <barvinok/options.h>
6 #include <barvinok/util.h>
7 #include "bernoulli.h"
8 #include "euler.h"
9 #include "laurent.h"
10 #include "laurent_old.h"
11 #include "summate.h"
12 #include "section_array.h"
13 #include "remove_equalities.h"
15 extern evalue *evalue_outer_floor(evalue *e);
16 extern int evalue_replace_floor(evalue *e, const evalue *floor, int var);
17 extern void evalue_drop_floor(evalue *e, const evalue *floor);
19 #define ALLOC(type) (type*)malloc(sizeof(type))
20 #define ALLOCN(type,n) (type*)malloc((n) * sizeof(type))
22 /* Apply the variable transformation specified by T and CP on
23 * the polynomial e. T expresses the old variables in terms
24 * of the new variables (and optionally also the new parameters),
25 * while CP expresses the old parameters in terms of the new
26 * parameters.
28 static void transform_polynomial(evalue *E, Matrix *T, Matrix *CP,
29 unsigned nvar, unsigned nparam,
30 unsigned new_nvar, unsigned new_nparam)
32 int j;
33 evalue **subs;
35 subs = ALLOCN(evalue *, nvar+nparam);
37 for (j = 0; j < nvar; ++j) {
38 if (T)
39 subs[j] = affine2evalue(T->p[j], T->p[T->NbRows-1][T->NbColumns-1],
40 T->NbColumns-1);
41 else
42 subs[j] = evalue_var(j);
44 for (j = 0; j < nparam; ++j) {
45 if (CP)
46 subs[nvar+j] = affine2evalue(CP->p[j], CP->p[nparam][new_nparam],
47 new_nparam);
48 else
49 subs[nvar+j] = evalue_var(j);
50 evalue_shift_variables(subs[nvar+j], 0, new_nvar);
53 evalue_substitute(E, subs);
54 reduce_evalue(E);
56 for (j = 0; j < nvar+nparam; ++j)
57 evalue_free(subs[j]);
58 free(subs);
61 /* Compute the sum of the quasi-polynomial E
62 * over a 0D (non-empty, but possibly parametric) polytope P.
64 * Consumes P and E.
66 * We simply return a partition evalue with P as domain and E as value.
68 static evalue *sum_over_polytope_0D(Polyhedron *P, evalue *E)
70 evalue *sum;
72 sum = ALLOC(evalue);
73 value_init(sum->d);
74 sum->x.p = new_enode(partition, 2, P->Dimension);
75 EVALUE_SET_DOMAIN(sum->x.p->arr[0], P);
76 value_clear(sum->x.p->arr[1].d);
77 sum->x.p->arr[1] = *E;
78 free(E);
80 return sum;
83 static evalue *sum_with_equalities(Polyhedron *P, evalue *E,
84 unsigned nvar, struct evalue_section_array *sections,
85 struct barvinok_options *options,
86 evalue *(*base)(Polyhedron *P, evalue *E, unsigned nvar,
87 struct evalue_section_array *sections,
88 struct barvinok_options *options))
90 unsigned dim = P->Dimension;
91 unsigned new_dim, new_nparam;
92 Matrix *T = NULL, *CP = NULL;
93 evalue *sum;
95 if (emptyQ(P))
96 return evalue_zero();
98 assert(P->NbEq > 0);
100 remove_all_equalities(&P, NULL, &CP, &T, dim-nvar, options->MaxRays);
102 if (emptyQ(P)) {
103 Polyhedron_Free(P);
104 return evalue_zero();
107 new_nparam = CP ? CP->NbColumns-1 : dim - nvar;
108 new_dim = T ? T->NbColumns-1 : nvar + new_nparam;
110 /* We can avoid these substitutions if E is a constant */
111 E = evalue_dup(E);
112 transform_polynomial(E, T, CP, nvar, dim-nvar,
113 new_dim-new_nparam, new_nparam);
115 if (new_dim-new_nparam > 0) {
116 sum = base(P, E, new_dim-new_nparam, sections, options);
117 evalue_free(E);
118 Polyhedron_Free(P);
119 } else {
120 sum = sum_over_polytope_0D(P, E);
123 if (CP) {
124 evalue_backsubstitute(sum, CP, options->MaxRays);
125 Matrix_Free(CP);
128 if (T)
129 Matrix_Free(T);
131 return sum;
134 static evalue *sum_over_polytope_with_equalities(Polyhedron *P, evalue *E,
135 unsigned nvar, struct evalue_section_array *sections,
136 struct barvinok_options *options)
138 return sum_with_equalities(P, E, nvar, sections, options,
139 &barvinok_sum_over_polytope);
142 static evalue *sum_base(Polyhedron *P, evalue *E, unsigned nvar,
143 struct barvinok_options *options);
145 static evalue *sum_base_wrap(Polyhedron *P, evalue *E, unsigned nvar,
146 struct evalue_section_array *sections, struct barvinok_options *options)
148 return sum_base(P, E, nvar, options);
151 static evalue *sum_base_with_equalities(Polyhedron *P, evalue *E,
152 unsigned nvar, struct barvinok_options *options)
154 return sum_with_equalities(P, E, nvar, NULL, options, &sum_base_wrap);
157 /* The substitutions in sum_step_polynomial may have reintroduced equalities
158 * (in particular, one of the floor expressions may be equal to one of
159 * the variables), so we need to check for them again.
161 static evalue *sum_base(Polyhedron *P, evalue *E, unsigned nvar,
162 struct barvinok_options *options)
164 if (P->NbEq)
165 return sum_base_with_equalities(P, E, nvar, options);
166 if (options->summation == BV_SUM_EULER)
167 return euler_summate(P, E, nvar, options);
168 else if (options->summation == BV_SUM_LAURENT)
169 return laurent_summate(P, E, nvar, options);
170 else if (options->summation == BV_SUM_LAURENT_OLD)
171 return laurent_summate_old(P, E, nvar, options);
172 assert(0);
175 /* Count the number of non-zero terms in e when viewed as a polynomial
176 * in only the first nvar variables. "count" is the number counted
177 * so far.
179 static int evalue_count_terms(const evalue *e, unsigned nvar, int count)
181 int i;
183 if (EVALUE_IS_ZERO(*e))
184 return count;
186 if (value_zero_p(e->d))
187 assert(e->x.p->type == polynomial);
188 if (value_notzero_p(e->d) || e->x.p->pos >= nvar+1)
189 return count+1;
191 for (i = 0; i < e->x.p->size; ++i)
192 count = evalue_count_terms(&e->x.p->arr[i], nvar, count);
194 return count;
197 /* Create placeholder structure for unzipping.
198 * A "polynomial" is created with size terms in variable pos,
199 * with each term having itself as coefficient.
201 static evalue *create_placeholder(int size, int pos)
203 int i, j;
204 evalue *E = ALLOC(evalue);
205 value_init(E->d);
206 E->x.p = new_enode(polynomial, size, pos+1);
207 for (i = 0; i < size; ++i) {
208 E->x.p->arr[i].x.p = new_enode(polynomial, i+1, pos+1);
209 for (j = 0; j < i; ++j)
210 evalue_set_si(&E->x.p->arr[i].x.p->arr[j], 0, 1);
211 evalue_set_si(&E->x.p->arr[i].x.p->arr[i], 1, 1);
213 return E;
216 /* Interchange each non-zero term in e (when viewed as a polynomial
217 * in only the first nvar variables) with a placeholder in ph (created
218 * by create_placeholder), resulting in two polynomials in the
219 * placeholder variable such that for each non-zero term in e
220 * there is a power of the placeholder variable such that the factors
221 * in the first nvar variables form the coefficient of that power in
222 * the first polynomial (e) and the factors in the remaining variables
223 * form the coefficient of that power in the second polynomial (ph).
225 static int evalue_unzip_terms(evalue *e, evalue *ph, unsigned nvar, int count)
227 int i;
229 if (EVALUE_IS_ZERO(*e))
230 return count;
232 if (value_zero_p(e->d))
233 assert(e->x.p->type == polynomial);
234 if (value_notzero_p(e->d) || e->x.p->pos >= nvar+1) {
235 evalue t = *e;
236 *e = ph->x.p->arr[count];
237 ph->x.p->arr[count] = t;
238 return count+1;
241 for (i = 0; i < e->x.p->size; ++i)
242 count = evalue_unzip_terms(&e->x.p->arr[i], ph, nvar, count);
244 return count;
247 /* Remove n variables at pos (0-based) from the polyhedron P.
248 * Each of these variables is assumed to be completely free,
249 * i.e., there is a line in the polyhedron corresponding to
250 * each of these variables.
252 static Polyhedron *Polyhedron_Remove_Columns(Polyhedron *P, unsigned pos,
253 unsigned n)
255 int i, j;
256 unsigned NbConstraints = 0;
257 unsigned NbRays = 0;
258 Polyhedron *Q;
260 if (n == 0)
261 return P;
263 assert(pos <= P->Dimension);
265 if (POL_HAS(P, POL_INEQUALITIES))
266 NbConstraints = P->NbConstraints;
267 if (POL_HAS(P, POL_POINTS))
268 NbRays = P->NbRays - n;
270 Q = Polyhedron_Alloc(P->Dimension - n, NbConstraints, NbRays);
271 if (POL_HAS(P, POL_INEQUALITIES)) {
272 Q->NbEq = P->NbEq;
273 for (i = 0; i < P->NbConstraints; ++i) {
274 Vector_Copy(P->Constraint[i], Q->Constraint[i], 1+pos);
275 Vector_Copy(P->Constraint[i]+1+pos+n, Q->Constraint[i]+1+pos,
276 Q->Dimension-pos+1);
279 if (POL_HAS(P, POL_POINTS)) {
280 Q->NbBid = P->NbBid - n;
281 for (i = 0; i < n; ++i)
282 value_set_si(Q->Ray[i][1+pos+i], 1);
283 for (i = 0, j = 0; i < P->NbRays; ++i) {
284 int line = First_Non_Zero(P->Ray[i], 1+P->Dimension+1);
285 assert(line != -1);
286 if (line-1 >= pos && line-1 < pos+n) {
287 ++j;
288 assert(j <= n);
289 continue;
291 assert(i-j < Q->NbRays);
292 Vector_Copy(P->Ray[i], Q->Ray[i-j], 1+pos);
293 Vector_Copy(P->Ray[i]+1+pos+n, Q->Ray[i-j]+1+pos,
294 Q->Dimension-pos+1);
297 POL_SET(Q, POL_VALID);
298 if (POL_HAS(P, POL_INEQUALITIES))
299 POL_SET(Q, POL_INEQUALITIES);
300 if (POL_HAS(P, POL_POINTS))
301 POL_SET(Q, POL_POINTS);
302 if (POL_HAS(P, POL_VERTICES))
303 POL_SET(Q, POL_VERTICES);
304 return Q;
307 /* Remove n variables at pos (0-based) from the union of polyhedra P.
308 * Each of these variables is assumed to be completely free,
309 * i.e., there is a line in the polyhedron corresponding to
310 * each of these variables.
312 static Polyhedron *Domain_Remove_Columns(Polyhedron *P, unsigned pos,
313 unsigned n)
315 Polyhedron *R;
316 Polyhedron **next = &R;
318 for (; P; P = P->next) {
319 *next = Polyhedron_Remove_Columns(P, pos, n);
320 next = &(*next)->next;
322 return R;
325 /* Drop n parameters starting at first from partition evalue e */
326 static void drop_parameters(evalue *e, int first, int n)
328 int i;
330 if (EVALUE_IS_ZERO(*e))
331 return;
333 assert(value_zero_p(e->d) && e->x.p->type == partition);
334 for (i = 0; i < e->x.p->size/2; ++i) {
335 Polyhedron *P = EVALUE_DOMAIN(e->x.p->arr[2*i]);
336 Polyhedron *Q = Domain_Remove_Columns(P, first, n);
337 EVALUE_SET_DOMAIN(e->x.p->arr[2*i], Q);
338 Domain_Free(P);
339 evalue_shift_variables(&e->x.p->arr[2*i+1], first, -n);
341 e->x.p->pos -= n;
344 static void extract_term_into(const evalue *src, int var, int exp, evalue *dst)
346 int i;
348 if (value_notzero_p(src->d) ||
349 src->x.p->type != polynomial ||
350 src->x.p->pos > var+1) {
351 if (exp == 0)
352 evalue_copy(dst, src);
353 else
354 evalue_set_si(dst, 0, 1);
355 return;
358 if (src->x.p->pos == var+1) {
359 if (src->x.p->size > exp)
360 evalue_copy(dst, &src->x.p->arr[exp]);
361 else
362 evalue_set_si(dst, 0, 1);
363 return;
366 dst->x.p = new_enode(polynomial, src->x.p->size, src->x.p->pos);
367 for (i = 0; i < src->x.p->size; ++i)
368 extract_term_into(&src->x.p->arr[i], var, exp,
369 &dst->x.p->arr[i]);
372 /* Extract the coefficient of var^exp.
374 static evalue *extract_term(const evalue *e, int var, int exp)
376 int i;
377 evalue *res;
379 if (EVALUE_IS_ZERO(*e))
380 return evalue_zero();
382 assert(value_zero_p(e->d) && e->x.p->type == partition);
383 res = ALLOC(evalue);
384 value_init(res->d);
385 res->x.p = new_enode(partition, e->x.p->size, e->x.p->pos);
386 for (i = 0; i < e->x.p->size/2; ++i) {
387 EVALUE_SET_DOMAIN(res->x.p->arr[2*i],
388 Domain_Copy(EVALUE_DOMAIN(e->x.p->arr[2*i])));
389 extract_term_into(&e->x.p->arr[2*i+1], var, exp,
390 &res->x.p->arr[2*i+1]);
391 reduce_evalue(&res->x.p->arr[2*i+1]);
393 return res;
396 /* Insert n free variables at pos (0-based) in the polyhedron P.
398 static Polyhedron *Polyhedron_Insert_Columns(Polyhedron *P, unsigned pos,
399 unsigned n)
401 int i;
402 unsigned NbConstraints = 0;
403 unsigned NbRays = 0;
404 Polyhedron *Q;
406 if (!P)
407 return P;
408 if (n == 0)
409 return P;
411 assert(pos <= P->Dimension);
413 if (POL_HAS(P, POL_INEQUALITIES))
414 NbConstraints = P->NbConstraints;
415 if (POL_HAS(P, POL_POINTS))
416 NbRays = P->NbRays + n;
418 Q = Polyhedron_Alloc(P->Dimension+n, NbConstraints, NbRays);
419 if (POL_HAS(P, POL_INEQUALITIES)) {
420 Q->NbEq = P->NbEq;
421 for (i = 0; i < P->NbConstraints; ++i) {
422 Vector_Copy(P->Constraint[i], Q->Constraint[i], 1+pos);
423 Vector_Copy(P->Constraint[i]+1+pos, Q->Constraint[i]+1+pos+n,
424 P->Dimension-pos+1);
427 if (POL_HAS(P, POL_POINTS)) {
428 Q->NbBid = P->NbBid + n;
429 for (i = 0; i < n; ++i)
430 value_set_si(Q->Ray[i][1+pos+i], 1);
431 for (i = 0; i < P->NbRays; ++i) {
432 Vector_Copy(P->Ray[i], Q->Ray[n+i], 1+pos);
433 Vector_Copy(P->Ray[i]+1+pos, Q->Ray[n+i]+1+pos+n,
434 P->Dimension-pos+1);
437 POL_SET(Q, POL_VALID);
438 if (POL_HAS(P, POL_INEQUALITIES))
439 POL_SET(Q, POL_INEQUALITIES);
440 if (POL_HAS(P, POL_POINTS))
441 POL_SET(Q, POL_POINTS);
442 if (POL_HAS(P, POL_VERTICES))
443 POL_SET(Q, POL_VERTICES);
444 return Q;
447 /* Perform summation of e over a list of 1 or more factors F, with context C.
448 * nvar is the total number of variables in the remaining factors.
449 * extra is the number of placeholder parameters introduced in e,
450 * but not (yet) in F or C.
452 * If there is only one factor left, F is intersected with the
453 * context C, the placeholder variables are added, and then
454 * e is summed over the resulting parametric polytope.
456 * If there is more than one factor left, we create two polynomials
457 * in a new placeholder variable (which is placed after the regular
458 * parameters, but before any previously introduced placeholder
459 * variables) that has the factors of the variables in the first
460 * factor of F and the factor of the remaining variables of
461 * each term as its coefficients.
462 * These two polynomials are then summed over their domains
463 * and afterwards the results are combined and the placeholder
464 * variable is removed again.
466 static evalue *sum_factors(Polyhedron *F, Polyhedron *C, evalue *e,
467 unsigned nvar, unsigned extra,
468 struct barvinok_options *options)
470 Polyhedron *P = F;
471 unsigned nparam = C->Dimension;
472 unsigned F_var = F->Dimension - C->Dimension;
473 int i, n;
474 evalue *s1, *s2, *s;
475 evalue *ph;
477 if (!F->next) {
478 Polyhedron *CA = align_context(C, nvar+nparam, options->MaxRays);
479 Polyhedron *P = DomainIntersection(F, CA, options->MaxRays);
480 Polyhedron *Q = Polyhedron_Insert_Columns(P, nvar+nparam, extra);
481 Polyhedron_Free(CA);
482 Polyhedron_Free(F);
483 Polyhedron_Free(P);
484 evalue *sum = sum_base(Q, e, nvar, options);
485 Polyhedron_Free(Q);
486 return sum;
489 n = evalue_count_terms(e, F_var, 0);
490 ph = create_placeholder(n, nvar+nparam);
491 evalue_shift_variables(e, nvar+nparam, 1);
492 evalue_unzip_terms(e, ph, F_var, 0);
493 evalue_shift_variables(e, nvar, -(nvar-F_var));
494 evalue_reorder_terms(ph);
495 evalue_shift_variables(ph, 0, -F_var);
497 s2 = sum_factors(F->next, C, ph, nvar-F_var, extra+1, options);
498 evalue_free(ph);
499 F->next = NULL;
500 s1 = sum_factors(F, C, e, F_var, extra+1, options);
502 if (n == 1) {
503 /* remove placeholder "polynomial" */
504 reduce_evalue(s1);
505 emul(s1, s2);
506 evalue_free(s1);
507 drop_parameters(s2, nparam, 1);
508 return s2;
511 s = evalue_zero();
512 for (i = 0; i < n; ++i) {
513 evalue *t1, *t2;
514 t1 = extract_term(s1, nparam, i);
515 t2 = extract_term(s2, nparam, i);
516 emul(t1, t2);
517 eadd(t2, s);
518 evalue_free(t1);
519 evalue_free(t2);
521 evalue_free(s1);
522 evalue_free(s2);
524 drop_parameters(s, nparam, 1);
525 return s;
528 /* Perform summation over a product of factors F, obtained using
529 * variable transformation T from the original problem specification.
531 * We first perform the corresponding transformation on the polynomial E,
532 * compute the common context over all factors and then perform
533 * the actual summation over the factors.
535 static evalue *sum_product(Polyhedron *F, evalue *E, Matrix *T, unsigned nparam,
536 struct barvinok_options *options)
538 int i;
539 Matrix *T2;
540 unsigned nvar = T->NbRows;
541 Polyhedron *C;
542 evalue *sum;
544 assert(nvar == T->NbColumns);
545 T2 = Matrix_Alloc(nvar+1, nvar+1);
546 for (i = 0; i < nvar; ++i)
547 Vector_Copy(T->p[i], T2->p[i], nvar);
548 value_set_si(T2->p[nvar][nvar], 1);
550 transform_polynomial(E, T2, NULL, nvar, nparam, nvar, nparam);
552 C = Factor_Context(F, nparam, options->MaxRays);
553 if (F->Dimension == nparam) {
554 Polyhedron *T = F;
555 F = F->next;
556 T->next = NULL;
557 Polyhedron_Free(T);
559 sum = sum_factors(F, C, E, nvar, 0, options);
561 Polyhedron_Free(C);
562 Matrix_Free(T2);
563 Matrix_Free(T);
564 return sum;
567 /* Add two constraints corresponding to floor = floor(e/d),
569 * e - d t >= 0
570 * -e + d t + d-1 >= 0
572 * e is assumed to be an affine expression.
574 Polyhedron *add_floor_var(Polyhedron *P, unsigned nvar, const evalue *floor,
575 struct barvinok_options *options)
577 int i;
578 unsigned dim = P->Dimension+1;
579 Matrix *M = Matrix_Alloc(P->NbConstraints+2, 2+dim);
580 Polyhedron *CP;
581 Value *d = &M->p[0][1+nvar];
582 evalue_extract_affine(floor, M->p[0]+1, M->p[0]+1+dim, d);
583 value_oppose(*d, *d);
584 value_set_si(M->p[0][0], 1);
585 value_set_si(M->p[1][0], 1);
586 Vector_Oppose(M->p[0]+1, M->p[1]+1, M->NbColumns-1);
587 value_subtract(M->p[1][1+dim], M->p[1][1+dim], *d);
588 value_decrement(M->p[1][1+dim], M->p[1][1+dim]);
590 for (i = 0; i < P->NbConstraints; ++i) {
591 Vector_Copy(P->Constraint[i], M->p[i+2], 1+nvar);
592 Vector_Copy(P->Constraint[i]+1+nvar, M->p[i+2]+1+nvar+1, dim-nvar-1+1);
595 CP = Constraints2Polyhedron(M, options->MaxRays);
596 Matrix_Free(M);
597 return CP;
600 static evalue *evalue_add(evalue *a, evalue *b)
602 if (!a)
603 return b;
604 if (!b)
605 return a;
606 eadd(a, b);
607 evalue_free(a);
608 return b;
611 /* Compute sum of a step-polynomial over a polytope by grouping
612 * terms containing the same floor-expressions and introducing
613 * new variables for each such expression.
614 * In particular, while there is any floor-expression left,
615 * the step-polynomial is split into a polynomial containing
616 * the expression, which is then converted to a new variable,
617 * and a polynomial not containing the expression.
619 static evalue *sum_step_polynomial(Polyhedron *P, evalue *E, unsigned nvar,
620 struct barvinok_options *options)
622 evalue *floor;
623 evalue *cur = E;
624 evalue *sum = NULL;
625 evalue *t;
627 while ((floor = evalue_outer_floor(cur))) {
628 Polyhedron *CP;
629 evalue *converted;
630 evalue *converted_floor;
632 /* Ignore floors that do not depend on variables. */
633 if (value_notzero_p(floor->d) || floor->x.p->pos >= nvar+1)
634 break;
636 converted = evalue_dup(cur);
637 converted_floor = evalue_dup(floor);
638 evalue_shift_variables(converted, nvar, 1);
639 evalue_shift_variables(converted_floor, nvar, 1);
640 evalue_replace_floor(converted, converted_floor, nvar);
641 CP = add_floor_var(P, nvar, converted_floor, options);
642 evalue_free(converted_floor);
643 t = sum_step_polynomial(CP, converted, nvar+1, options);
644 evalue_free(converted);
645 Polyhedron_Free(CP);
646 sum = evalue_add(t, sum);
648 if (cur == E)
649 cur = evalue_dup(cur);
650 evalue_drop_floor(cur, floor);
651 evalue_free(floor);
653 if (floor) {
654 evalue_floor2frac(cur);
655 evalue_free(floor);
658 if (EVALUE_IS_ZERO(*cur))
659 t = NULL;
660 else {
661 Matrix *T;
662 unsigned nparam = P->Dimension - nvar;
663 Polyhedron *F = Polyhedron_Factor(P, nparam, &T, options->MaxRays);
664 if (!F)
665 t = sum_base(P, cur, nvar, options);
666 else {
667 if (cur == E)
668 cur = evalue_dup(cur);
669 t = sum_product(F, cur, T, nparam, options);
673 if (E != cur)
674 evalue_free(cur);
676 return evalue_add(t, sum);
679 evalue *barvinok_sum_over_polytope(Polyhedron *P, evalue *E, unsigned nvar,
680 struct evalue_section_array *sections,
681 struct barvinok_options *options)
683 if (P->NbEq)
684 return sum_over_polytope_with_equalities(P, E, nvar, sections, options);
686 if (nvar == 0)
687 return sum_over_polytope_0D(Polyhedron_Copy(P), evalue_dup(E));
689 if (options->summation == BV_SUM_BERNOULLI)
690 return bernoulli_summate(P, E, nvar, sections, options);
691 else if (options->summation == BV_SUM_BOX)
692 return box_summate(P, E, nvar, options->MaxRays);
694 evalue_frac2floor2(E, 0);
696 return sum_step_polynomial(P, E, nvar, options);
699 evalue *barvinok_summate(evalue *e, int nvar, struct barvinok_options *options)
701 int i;
702 struct evalue_section_array sections;
703 evalue *sum;
705 assert(nvar >= 0);
706 if (nvar == 0 || EVALUE_IS_ZERO(*e))
707 return evalue_dup(e);
709 assert(value_zero_p(e->d));
710 assert(e->x.p->type == partition);
712 evalue_section_array_init(&sections);
713 sum = evalue_zero();
715 for (i = 0; i < e->x.p->size/2; ++i) {
716 Polyhedron *D;
717 for (D = EVALUE_DOMAIN(e->x.p->arr[2*i]); D; D = D->next) {
718 Polyhedron *next = D->next;
719 evalue *tmp;
720 D->next = NULL;
722 tmp = barvinok_sum_over_polytope(D, &e->x.p->arr[2*i+1], nvar,
723 &sections, options);
724 assert(tmp);
725 eadd(tmp, sum);
726 evalue_free(tmp);
728 D->next = next;
732 free(sections.s);
734 reduce_evalue(sum);
735 return sum;
738 static __isl_give isl_pw_qpolynomial *add_unbounded_guarded_qp(
739 __isl_take isl_pw_qpolynomial *sum,
740 __isl_take isl_basic_set *bset, __isl_take isl_qpolynomial *qp)
742 int zero;
744 if (!sum || !bset || !qp)
745 goto error;
747 zero = isl_qpolynomial_is_zero(qp);
748 if (zero < 0)
749 goto error;
751 if (!zero) {
752 isl_space *dim;
753 isl_set *set;
754 isl_pw_qpolynomial *pwqp;
756 dim = isl_pw_qpolynomial_get_domain_space(sum);
757 set = isl_set_from_basic_set(isl_basic_set_copy(bset));
758 set = isl_map_domain(isl_map_from_range(set));
759 set = isl_set_reset_space(set, isl_space_copy(dim));
760 pwqp = isl_pw_qpolynomial_alloc(set, isl_qpolynomial_nan_on_domain(dim));
761 sum = isl_pw_qpolynomial_add(sum, pwqp);
764 isl_basic_set_free(bset);
765 isl_qpolynomial_free(qp);
766 return sum;
767 error:
768 isl_basic_set_free(bset);
769 isl_qpolynomial_free(qp);
770 isl_pw_qpolynomial_free(sum);
771 return NULL;
774 struct barvinok_summate_data {
775 isl_space *dim;
776 __isl_take isl_qpolynomial *qp;
777 isl_pw_qpolynomial *sum;
778 int n_in;
779 int wrapping;
780 evalue *e;
781 struct evalue_section_array sections;
782 struct barvinok_options *options;
785 static isl_stat add_basic_guarded_qp(__isl_take isl_basic_set *bset, void *user)
787 struct barvinok_summate_data *data = user;
788 Polyhedron *P;
789 evalue *tmp;
790 isl_pw_qpolynomial *pwqp;
791 int bounded;
792 unsigned nparam = isl_basic_set_dim(bset, isl_dim_param);
793 unsigned nvar = isl_basic_set_dim(bset, isl_dim_set);
794 isl_space *dim;
796 if (!bset)
797 return isl_stat_error;
799 bounded = isl_basic_set_is_bounded(bset);
800 if (bounded < 0)
801 goto error;
803 if (!bounded) {
804 data->sum = add_unbounded_guarded_qp(data->sum, bset,
805 isl_qpolynomial_copy(data->qp));
806 return isl_stat_ok;
809 dim = isl_basic_set_get_space(bset);
810 dim = isl_space_domain(isl_space_from_range(dim));
812 P = isl_basic_set_to_polylib(bset);
813 tmp = barvinok_sum_over_polytope(P, data->e, nvar,
814 &data->sections, data->options);
815 Polyhedron_Free(P);
816 assert(tmp);
817 pwqp = isl_pw_qpolynomial_from_evalue(dim, tmp);
818 evalue_free(tmp);
819 pwqp = isl_pw_qpolynomial_reset_domain_space(pwqp,
820 isl_space_domain(isl_space_copy(data->dim)));
821 data->sum = isl_pw_qpolynomial_add(data->sum, pwqp);
823 isl_basic_set_free(bset);
825 return isl_stat_ok;
826 error:
827 isl_basic_set_free(bset);
828 return isl_stat_error;
831 static isl_stat add_guarded_qp(__isl_take isl_set *set,
832 __isl_take isl_qpolynomial *qp, void *user)
834 isl_stat r;
835 struct barvinok_summate_data *data = user;
837 if (!set || !qp)
838 goto error;
840 data->qp = qp;
842 if (data->wrapping) {
843 unsigned nparam = isl_set_dim(set, isl_dim_param);
844 isl_qpolynomial *qp2 = isl_qpolynomial_copy(qp);
845 set = isl_set_move_dims(set, isl_dim_param, nparam,
846 isl_dim_set, 0, data->n_in);
847 qp2 = isl_qpolynomial_move_dims(qp2, isl_dim_param, nparam,
848 isl_dim_in, 0, data->n_in);
849 data->e = isl_qpolynomial_to_evalue(qp2);
850 isl_qpolynomial_free(qp2);
851 } else
852 data->e = isl_qpolynomial_to_evalue(qp);
853 if (!data->e)
854 goto error;
856 evalue_section_array_init(&data->sections);
858 set = isl_set_make_disjoint(set);
859 set = isl_set_compute_divs(set);
861 r = isl_set_foreach_basic_set(set, &add_basic_guarded_qp, data);
863 free(data->sections.s);
865 evalue_free(data->e);
867 isl_set_free(set);
868 isl_qpolynomial_free(qp);
870 return r;
871 error:
872 isl_set_free(set);
873 isl_qpolynomial_free(qp);
874 return isl_stat_error;
877 __isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_sum(
878 __isl_take isl_pw_qpolynomial *pwqp)
880 isl_ctx *ctx;
881 struct barvinok_summate_data data;
882 int options_allocated = 0;
883 int nvar;
885 data.dim = NULL;
886 data.options = NULL;
887 data.sum = NULL;
889 if (!pwqp)
890 return NULL;
892 nvar = isl_pw_qpolynomial_dim(pwqp, isl_dim_set);
894 data.dim = isl_pw_qpolynomial_get_domain_space(pwqp);
895 if (!data.dim)
896 goto error;
897 if (isl_space_is_params(data.dim))
898 isl_die(isl_pw_qpolynomial_get_ctx(pwqp), isl_error_invalid,
899 "input polynomial has no domain", goto error);
900 data.wrapping = isl_space_is_wrapping(data.dim);
901 if (data.wrapping) {
902 data.dim = isl_space_unwrap(data.dim);
903 data.n_in = isl_space_dim(data.dim, isl_dim_in);
904 nvar = isl_space_dim(data.dim, isl_dim_out);
905 } else
906 data.n_in = 0;
908 data.dim = isl_space_domain(data.dim);
909 if (nvar == 0)
910 return isl_pw_qpolynomial_reset_domain_space(pwqp, data.dim);
912 data.dim = isl_space_from_domain(data.dim);
913 data.dim = isl_space_add_dims(data.dim, isl_dim_out, 1);
914 data.sum = isl_pw_qpolynomial_zero(isl_space_copy(data.dim));
916 ctx = isl_pw_qpolynomial_get_ctx(pwqp);
917 data.options = isl_ctx_peek_barvinok_options(ctx);
918 if (!data.options) {
919 data.options = barvinok_options_new_with_defaults();
920 options_allocated = 1;
923 if (isl_pw_qpolynomial_foreach_lifted_piece(pwqp,
924 add_guarded_qp, &data) < 0)
925 goto error;
927 if (options_allocated)
928 barvinok_options_free(data.options);
930 isl_space_free(data.dim);
932 isl_pw_qpolynomial_free(pwqp);
934 return data.sum;
935 error:
936 if (options_allocated)
937 barvinok_options_free(data.options);
938 isl_pw_qpolynomial_free(pwqp);
939 isl_space_free(data.dim);
940 isl_pw_qpolynomial_free(data.sum);
941 return NULL;
944 static isl_stat pw_qpolynomial_sum(__isl_take isl_pw_qpolynomial *pwqp,
945 void *user)
947 isl_union_pw_qpolynomial **res = (isl_union_pw_qpolynomial **)user;
948 isl_pw_qpolynomial *sum;
949 isl_union_pw_qpolynomial *upwqp;
951 sum = isl_pw_qpolynomial_sum(pwqp);
952 upwqp = isl_union_pw_qpolynomial_from_pw_qpolynomial(sum);
953 *res = isl_union_pw_qpolynomial_add(*res, upwqp);
955 return isl_stat_ok;
958 __isl_give isl_union_pw_qpolynomial *isl_union_pw_qpolynomial_sum(
959 __isl_take isl_union_pw_qpolynomial *upwqp)
961 isl_space *dim;
962 isl_union_pw_qpolynomial *res;
964 dim = isl_union_pw_qpolynomial_get_space(upwqp);
965 res = isl_union_pw_qpolynomial_zero(dim);
966 if (isl_union_pw_qpolynomial_foreach_pw_qpolynomial(upwqp,
967 &pw_qpolynomial_sum, &res) < 0)
968 goto error;
969 isl_union_pw_qpolynomial_free(upwqp);
971 return res;
972 error:
973 isl_union_pw_qpolynomial_free(upwqp);
974 isl_union_pw_qpolynomial_free(res);
975 return NULL;
978 static int join_compatible(__isl_keep isl_space *space1,
979 __isl_keep isl_space *space2)
981 int m;
982 m = isl_space_match(space1, isl_dim_param, space2, isl_dim_param);
983 if (m < 0 || !m)
984 return m;
985 return isl_space_tuple_is_equal(space1, isl_dim_out,
986 space2, isl_dim_in);
989 /* Compute the intersection of the range of the map and the domain
990 * of the piecewise quasipolynomial and then sum the associated
991 * quasipolynomial over all elements in this intersection.
993 * We first introduce some unconstrained dimensions in the
994 * piecewise quasipolynomial, intersect the resulting domain
995 * with the wrapped map and then compute the sum.
997 __isl_give isl_pw_qpolynomial *isl_map_apply_pw_qpolynomial(
998 __isl_take isl_map *map, __isl_take isl_pw_qpolynomial *pwqp)
1000 isl_ctx *ctx;
1001 isl_set *dom;
1002 isl_space *map_dim;
1003 isl_space *pwqp_dim;
1004 unsigned n_in;
1005 int ok;
1007 ctx = isl_map_get_ctx(map);
1008 if (!ctx)
1009 goto error;
1011 map_dim = isl_map_get_space(map);
1012 pwqp_dim = isl_pw_qpolynomial_get_space(pwqp);
1013 ok = join_compatible(map_dim, pwqp_dim);
1014 isl_space_free(map_dim);
1015 isl_space_free(pwqp_dim);
1016 if (!ok)
1017 isl_die(ctx, isl_error_invalid, "incompatible dimensions",
1018 goto error);
1020 n_in = isl_map_dim(map, isl_dim_in);
1021 pwqp = isl_pw_qpolynomial_insert_dims(pwqp, isl_dim_in, 0, n_in);
1023 dom = isl_map_wrap(map);
1024 pwqp = isl_pw_qpolynomial_reset_domain_space(pwqp,
1025 isl_set_get_space(dom));
1027 pwqp = isl_pw_qpolynomial_intersect_domain(pwqp, dom);
1028 pwqp = isl_pw_qpolynomial_sum(pwqp);
1030 return pwqp;
1031 error:
1032 isl_map_free(map);
1033 isl_pw_qpolynomial_free(pwqp);
1034 return NULL;
1037 __isl_give isl_pw_qpolynomial *isl_set_apply_pw_qpolynomial(
1038 __isl_take isl_set *set, __isl_take isl_pw_qpolynomial *pwqp)
1040 isl_map *map;
1042 map = isl_map_from_range(set);
1043 pwqp = isl_map_apply_pw_qpolynomial(map, pwqp);
1044 pwqp = isl_pw_qpolynomial_project_domain_on_params(pwqp);
1045 return pwqp;
1048 struct barvinok_apply_data {
1049 isl_union_pw_qpolynomial *upwqp;
1050 isl_union_pw_qpolynomial *res;
1051 isl_map *map;
1054 static isl_stat pw_qpolynomial_apply(__isl_take isl_pw_qpolynomial *pwqp,
1055 void *user)
1057 isl_space *map_dim;
1058 isl_space *pwqp_dim;
1059 struct barvinok_apply_data *data = user;
1060 int ok;
1062 map_dim = isl_map_get_space(data->map);
1063 pwqp_dim = isl_pw_qpolynomial_get_space(pwqp);
1064 ok = join_compatible(map_dim, pwqp_dim);
1065 isl_space_free(map_dim);
1066 isl_space_free(pwqp_dim);
1068 if (ok) {
1069 isl_union_pw_qpolynomial *upwqp;
1071 pwqp = isl_map_apply_pw_qpolynomial(isl_map_copy(data->map),
1072 pwqp);
1073 upwqp = isl_union_pw_qpolynomial_from_pw_qpolynomial(pwqp);
1074 data->res = isl_union_pw_qpolynomial_add(data->res, upwqp);
1075 } else
1076 isl_pw_qpolynomial_free(pwqp);
1078 return isl_stat_ok;
1081 static isl_stat map_apply(__isl_take isl_map *map, void *user)
1083 struct barvinok_apply_data *data = user;
1084 isl_stat r;
1086 data->map = map;
1087 r = isl_union_pw_qpolynomial_foreach_pw_qpolynomial(data->upwqp,
1088 &pw_qpolynomial_apply, data);
1090 isl_map_free(map);
1091 return r;
1094 __isl_give isl_union_pw_qpolynomial *isl_union_map_apply_union_pw_qpolynomial(
1095 __isl_take isl_union_map *umap,
1096 __isl_take isl_union_pw_qpolynomial *upwqp)
1098 isl_space *dim;
1099 struct barvinok_apply_data data;
1101 upwqp = isl_union_pw_qpolynomial_align_params(upwqp,
1102 isl_union_map_get_space(umap));
1103 umap = isl_union_map_align_params(umap,
1104 isl_union_pw_qpolynomial_get_space(upwqp));
1106 data.upwqp = upwqp;
1107 dim = isl_union_pw_qpolynomial_get_space(upwqp);
1108 data.res = isl_union_pw_qpolynomial_zero(dim);
1109 if (isl_union_map_foreach_map(umap, &map_apply, &data) < 0)
1110 goto error;
1112 isl_union_map_free(umap);
1113 isl_union_pw_qpolynomial_free(upwqp);
1115 return data.res;
1116 error:
1117 isl_union_map_free(umap);
1118 isl_union_pw_qpolynomial_free(upwqp);
1119 isl_union_pw_qpolynomial_free(data.res);
1120 return NULL;
1123 struct barvinok_apply_set_data {
1124 isl_union_pw_qpolynomial *upwqp;
1125 isl_union_pw_qpolynomial *res;
1126 isl_set *set;
1129 static isl_stat pw_qpolynomial_apply_set(__isl_take isl_pw_qpolynomial *pwqp,
1130 void *user)
1132 isl_space *set_dim;
1133 isl_space *pwqp_dim;
1134 struct barvinok_apply_set_data *data = user;
1135 int ok;
1137 set_dim = isl_set_get_space(data->set);
1138 pwqp_dim = isl_pw_qpolynomial_get_space(pwqp);
1139 ok = join_compatible(set_dim, pwqp_dim);
1140 isl_space_free(set_dim);
1141 isl_space_free(pwqp_dim);
1143 if (ok) {
1144 isl_union_pw_qpolynomial *upwqp;
1146 pwqp = isl_set_apply_pw_qpolynomial(isl_set_copy(data->set),
1147 pwqp);
1148 upwqp = isl_union_pw_qpolynomial_from_pw_qpolynomial(pwqp);
1149 data->res = isl_union_pw_qpolynomial_add(data->res, upwqp);
1150 } else
1151 isl_pw_qpolynomial_free(pwqp);
1153 return isl_stat_ok;
1156 static isl_stat set_apply(__isl_take isl_set *set, void *user)
1158 struct barvinok_apply_set_data *data = user;
1159 isl_stat r;
1161 data->set = set;
1162 r = isl_union_pw_qpolynomial_foreach_pw_qpolynomial(data->upwqp,
1163 &pw_qpolynomial_apply_set, data);
1165 isl_set_free(set);
1166 return r;
1169 __isl_give isl_union_pw_qpolynomial *isl_union_set_apply_union_pw_qpolynomial(
1170 __isl_take isl_union_set *uset,
1171 __isl_take isl_union_pw_qpolynomial *upwqp)
1173 isl_space *dim;
1174 struct barvinok_apply_set_data data;
1176 upwqp = isl_union_pw_qpolynomial_align_params(upwqp,
1177 isl_union_set_get_space(uset));
1178 uset = isl_union_set_align_params(uset,
1179 isl_union_pw_qpolynomial_get_space(upwqp));
1181 data.upwqp = upwqp;
1182 dim = isl_union_pw_qpolynomial_get_space(upwqp);
1183 data.res = isl_union_pw_qpolynomial_zero(dim);
1184 if (isl_union_set_foreach_set(uset, &set_apply, &data) < 0)
1185 goto error;
1187 isl_union_set_free(uset);
1188 isl_union_pw_qpolynomial_free(upwqp);
1190 return data.res;
1191 error:
1192 isl_union_set_free(uset);
1193 isl_union_pw_qpolynomial_free(upwqp);
1194 isl_union_pw_qpolynomial_free(data.res);
1195 return NULL;
1198 evalue *evalue_sum(evalue *E, int nvar, unsigned MaxRays)
1200 evalue *sum;
1201 struct barvinok_options *options = barvinok_options_new_with_defaults();
1202 options->MaxRays = MaxRays;
1203 sum = barvinok_summate(E, nvar, options);
1204 barvinok_options_free(options);
1205 return sum;
1208 evalue *esum(evalue *e, int nvar)
1210 evalue *sum;
1211 struct barvinok_options *options = barvinok_options_new_with_defaults();
1212 sum = barvinok_summate(e, nvar, options);
1213 barvinok_options_free(options);
1214 return sum;
1217 /* Turn unweighted counting problem into "weighted" counting problem
1218 * with weight equal to 1 and call barvinok_summate on this weighted problem.
1220 evalue *barvinok_summate_unweighted(Polyhedron *P, Polyhedron *C,
1221 struct barvinok_options *options)
1223 Polyhedron *CA, *D;
1224 evalue e;
1225 evalue *sum;
1227 if (emptyQ(P) || emptyQ(C))
1228 return evalue_zero();
1230 CA = align_context(C, P->Dimension, options->MaxRays);
1231 D = DomainIntersection(P, CA, options->MaxRays);
1232 Domain_Free(CA);
1234 if (emptyQ(D)) {
1235 Domain_Free(D);
1236 return evalue_zero();
1239 value_init(e.d);
1240 e.x.p = new_enode(partition, 2, P->Dimension);
1241 EVALUE_SET_DOMAIN(e.x.p->arr[0], D);
1242 evalue_set_si(&e.x.p->arr[1], 1, 1);
1243 sum = barvinok_summate(&e, P->Dimension - C->Dimension, options);
1244 free_evalue_refs(&e);
1245 return sum;