summate.c: sum_base: perform shared Param_Polyhedron construction
[barvinok.git] / summate.c
blob1d8a7f9f0324af9d36a78295f5b188d40a725549
1 #include <isl/space.h>
2 #include <isl/set.h>
3 #include <isl/map.h>
4 #include <isl/union_set.h>
5 #include <isl/union_map.h>
6 #include <isl/polynomial.h>
7 #include <isl_set_polylib.h>
8 #include <barvinok/isl.h>
9 #include <barvinok/polylib.h>
10 #include <barvinok/options.h>
11 #include <barvinok/util.h>
12 #include "bernoulli.h"
13 #include "euler.h"
14 #include "laurent.h"
15 #include "laurent_old.h"
16 #include "param_util.h"
17 #include "reduce_domain.h"
18 #include "summate.h"
19 #include "section_array.h"
20 #include "remove_equalities.h"
22 extern evalue *evalue_outer_floor(evalue *e);
23 extern int evalue_replace_floor(evalue *e, const evalue *floor, int var);
24 extern void evalue_drop_floor(evalue *e, const evalue *floor);
26 #define ALLOC(type) (type*)malloc(sizeof(type))
27 #define ALLOCN(type,n) (type*)malloc((n) * sizeof(type))
29 /* Apply the variable transformation specified by T and CP on
30 * the polynomial e. T expresses the old variables in terms
31 * of the new variables (and optionally also the new parameters),
32 * while CP expresses the old parameters in terms of the new
33 * parameters.
35 static void transform_polynomial(evalue *E, Matrix *T, Matrix *CP,
36 unsigned nvar, unsigned nparam,
37 unsigned new_nvar, unsigned new_nparam)
39 int j;
40 evalue **subs;
42 subs = ALLOCN(evalue *, nvar+nparam);
44 for (j = 0; j < nvar; ++j) {
45 if (T)
46 subs[j] = affine2evalue(T->p[j], T->p[T->NbRows-1][T->NbColumns-1],
47 T->NbColumns-1);
48 else
49 subs[j] = evalue_var(j);
51 for (j = 0; j < nparam; ++j) {
52 if (CP)
53 subs[nvar+j] = affine2evalue(CP->p[j], CP->p[nparam][new_nparam],
54 new_nparam);
55 else
56 subs[nvar+j] = evalue_var(j);
57 evalue_shift_variables(subs[nvar+j], 0, new_nvar);
60 evalue_substitute(E, subs);
61 reduce_evalue(E);
63 for (j = 0; j < nvar+nparam; ++j)
64 evalue_free(subs[j]);
65 free(subs);
68 /* Compute the sum of the quasi-polynomial E
69 * over a 0D (non-empty, but possibly parametric) polytope P.
71 * Consumes P and E.
73 * We simply return a partition evalue with P as domain and E as value.
75 static evalue *sum_over_polytope_0D(Polyhedron *P, evalue *E)
77 evalue *sum;
79 sum = ALLOC(evalue);
80 value_init(sum->d);
81 sum->x.p = new_enode(partition, 2, P->Dimension);
82 EVALUE_SET_DOMAIN(sum->x.p->arr[0], P);
83 value_clear(sum->x.p->arr[1].d);
84 sum->x.p->arr[1] = *E;
85 free(E);
87 return sum;
90 static evalue *sum_with_equalities(Polyhedron *P, evalue *E,
91 unsigned nvar, struct evalue_section_array *sections,
92 struct barvinok_options *options,
93 evalue *(*base)(Polyhedron *P, evalue *E, unsigned nvar,
94 struct evalue_section_array *sections,
95 struct barvinok_options *options))
97 unsigned dim = P->Dimension;
98 unsigned new_dim, new_nparam;
99 Matrix *T = NULL, *CP = NULL;
100 evalue *sum;
102 if (emptyQ(P))
103 return evalue_zero();
105 assert(P->NbEq > 0);
107 remove_all_equalities(&P, NULL, &CP, &T, dim-nvar, options->MaxRays);
109 if (emptyQ(P)) {
110 Polyhedron_Free(P);
111 return evalue_zero();
114 new_nparam = CP ? CP->NbColumns-1 : dim - nvar;
115 new_dim = T ? T->NbColumns-1 : nvar + new_nparam;
117 /* We can avoid these substitutions if E is a constant */
118 E = evalue_dup(E);
119 transform_polynomial(E, T, CP, nvar, dim-nvar,
120 new_dim-new_nparam, new_nparam);
122 if (new_dim-new_nparam > 0) {
123 sum = base(P, E, new_dim-new_nparam, sections, options);
124 evalue_free(E);
125 Polyhedron_Free(P);
126 } else {
127 sum = sum_over_polytope_0D(P, E);
130 if (CP) {
131 evalue_backsubstitute(sum, CP, options->MaxRays);
132 Matrix_Free(CP);
135 if (T)
136 Matrix_Free(T);
138 return sum;
141 static evalue *sum_over_polytope_with_equalities(Polyhedron *P, evalue *E,
142 unsigned nvar, struct evalue_section_array *sections,
143 struct barvinok_options *options)
145 return sum_with_equalities(P, E, nvar, sections, options,
146 &barvinok_sum_over_polytope);
149 static evalue *sum_base(Polyhedron *P, evalue *E, unsigned nvar,
150 struct barvinok_options *options);
152 static evalue *sum_base_wrap(Polyhedron *P, evalue *E, unsigned nvar,
153 struct evalue_section_array *sections, struct barvinok_options *options)
155 return sum_base(P, E, nvar, options);
158 static evalue *sum_base_with_equalities(Polyhedron *P, evalue *E,
159 unsigned nvar, struct barvinok_options *options)
161 return sum_with_equalities(P, E, nvar, NULL, options, &sum_base_wrap);
164 /* The substitutions in sum_step_polynomial may have reintroduced equalities
165 * (in particular, one of the floor expressions may be equal to one of
166 * the variables), so we need to check for them again.
168 static evalue *sum_base(Polyhedron *P, evalue *E, unsigned nvar,
169 struct barvinok_options *options)
171 Polyhedron *U, *TC;
172 Param_Polyhedron *PP;
173 evalue *sum;
175 if (P->NbEq)
176 return sum_base_with_equalities(P, E, nvar, options);
178 U = Universe_Polyhedron(P->Dimension - nvar);
179 PP = Polyhedron2Param_Polyhedron(P, U, options);
180 TC = true_context(P, U, options->MaxRays);
182 if (options->summation == BV_SUM_EULER)
183 sum = euler_summate(PP, TC, E, nvar, options);
184 else if (options->summation == BV_SUM_LAURENT)
185 sum = laurent_summate(PP, TC, E, nvar, options);
186 else if (options->summation == BV_SUM_LAURENT_OLD)
187 sum = laurent_summate_old(PP, TC, E, nvar, options);
188 else
189 assert(0);
191 Polyhedron_Free(TC);
192 Polyhedron_Free(U);
193 Param_Polyhedron_Free(PP);
195 return sum;
198 /* Count the number of non-zero terms in e when viewed as a polynomial
199 * in only the first nvar variables. "count" is the number counted
200 * so far.
202 static int evalue_count_terms(const evalue *e, unsigned nvar, int count)
204 int i;
206 if (EVALUE_IS_ZERO(*e))
207 return count;
209 if (value_zero_p(e->d))
210 assert(e->x.p->type == polynomial);
211 if (value_notzero_p(e->d) || e->x.p->pos >= nvar+1)
212 return count+1;
214 for (i = 0; i < e->x.p->size; ++i)
215 count = evalue_count_terms(&e->x.p->arr[i], nvar, count);
217 return count;
220 /* Create placeholder structure for unzipping.
221 * A "polynomial" is created with size terms in variable pos,
222 * with each term having itself as coefficient.
224 static evalue *create_placeholder(int size, int pos)
226 int i, j;
227 evalue *E = ALLOC(evalue);
228 value_init(E->d);
229 E->x.p = new_enode(polynomial, size, pos+1);
230 for (i = 0; i < size; ++i) {
231 E->x.p->arr[i].x.p = new_enode(polynomial, i+1, pos+1);
232 for (j = 0; j < i; ++j)
233 evalue_set_si(&E->x.p->arr[i].x.p->arr[j], 0, 1);
234 evalue_set_si(&E->x.p->arr[i].x.p->arr[i], 1, 1);
236 return E;
239 /* Interchange each non-zero term in e (when viewed as a polynomial
240 * in only the first nvar variables) with a placeholder in ph (created
241 * by create_placeholder), resulting in two polynomials in the
242 * placeholder variable such that for each non-zero term in e
243 * there is a power of the placeholder variable such that the factors
244 * in the first nvar variables form the coefficient of that power in
245 * the first polynomial (e) and the factors in the remaining variables
246 * form the coefficient of that power in the second polynomial (ph).
248 static int evalue_unzip_terms(evalue *e, evalue *ph, unsigned nvar, int count)
250 int i;
252 if (EVALUE_IS_ZERO(*e))
253 return count;
255 if (value_zero_p(e->d))
256 assert(e->x.p->type == polynomial);
257 if (value_notzero_p(e->d) || e->x.p->pos >= nvar+1) {
258 evalue t = *e;
259 *e = ph->x.p->arr[count];
260 ph->x.p->arr[count] = t;
261 return count+1;
264 for (i = 0; i < e->x.p->size; ++i)
265 count = evalue_unzip_terms(&e->x.p->arr[i], ph, nvar, count);
267 return count;
270 /* Remove n variables at pos (0-based) from the polyhedron P.
271 * Each of these variables is assumed to be completely free,
272 * i.e., there is a line in the polyhedron corresponding to
273 * each of these variables.
275 static Polyhedron *Polyhedron_Remove_Columns(Polyhedron *P, unsigned pos,
276 unsigned n)
278 int i, j;
279 unsigned NbConstraints = 0;
280 unsigned NbRays = 0;
281 Polyhedron *Q;
283 if (n == 0)
284 return P;
286 assert(pos <= P->Dimension);
288 if (POL_HAS(P, POL_INEQUALITIES))
289 NbConstraints = P->NbConstraints;
290 if (POL_HAS(P, POL_POINTS))
291 NbRays = P->NbRays - n;
293 Q = Polyhedron_Alloc(P->Dimension - n, NbConstraints, NbRays);
294 if (POL_HAS(P, POL_INEQUALITIES)) {
295 Q->NbEq = P->NbEq;
296 for (i = 0; i < P->NbConstraints; ++i) {
297 Vector_Copy(P->Constraint[i], Q->Constraint[i], 1+pos);
298 Vector_Copy(P->Constraint[i]+1+pos+n, Q->Constraint[i]+1+pos,
299 Q->Dimension-pos+1);
302 if (POL_HAS(P, POL_POINTS)) {
303 Q->NbBid = P->NbBid - n;
304 for (i = 0; i < n; ++i)
305 value_set_si(Q->Ray[i][1+pos+i], 1);
306 for (i = 0, j = 0; i < P->NbRays; ++i) {
307 int line = First_Non_Zero(P->Ray[i], 1+P->Dimension+1);
308 assert(line != -1);
309 if (line-1 >= pos && line-1 < pos+n) {
310 ++j;
311 assert(j <= n);
312 continue;
314 assert(i-j < Q->NbRays);
315 Vector_Copy(P->Ray[i], Q->Ray[i-j], 1+pos);
316 Vector_Copy(P->Ray[i]+1+pos+n, Q->Ray[i-j]+1+pos,
317 Q->Dimension-pos+1);
320 POL_SET(Q, POL_VALID);
321 if (POL_HAS(P, POL_INEQUALITIES))
322 POL_SET(Q, POL_INEQUALITIES);
323 if (POL_HAS(P, POL_POINTS))
324 POL_SET(Q, POL_POINTS);
325 if (POL_HAS(P, POL_VERTICES))
326 POL_SET(Q, POL_VERTICES);
327 return Q;
330 /* Remove n variables at pos (0-based) from the union of polyhedra P.
331 * Each of these variables is assumed to be completely free,
332 * i.e., there is a line in the polyhedron corresponding to
333 * each of these variables.
335 static Polyhedron *Domain_Remove_Columns(Polyhedron *P, unsigned pos,
336 unsigned n)
338 Polyhedron *R;
339 Polyhedron **next = &R;
341 for (; P; P = P->next) {
342 *next = Polyhedron_Remove_Columns(P, pos, n);
343 next = &(*next)->next;
345 return R;
348 /* Drop n parameters starting at first from partition evalue e */
349 static void drop_parameters(evalue *e, int first, int n)
351 int i;
353 if (EVALUE_IS_ZERO(*e))
354 return;
356 assert(value_zero_p(e->d) && e->x.p->type == partition);
357 for (i = 0; i < e->x.p->size/2; ++i) {
358 Polyhedron *P = EVALUE_DOMAIN(e->x.p->arr[2*i]);
359 Polyhedron *Q = Domain_Remove_Columns(P, first, n);
360 EVALUE_SET_DOMAIN(e->x.p->arr[2*i], Q);
361 Domain_Free(P);
362 evalue_shift_variables(&e->x.p->arr[2*i+1], first, -n);
364 e->x.p->pos -= n;
367 static void extract_term_into(const evalue *src, int var, int exp, evalue *dst)
369 int i;
371 if (value_notzero_p(src->d) ||
372 src->x.p->type != polynomial ||
373 src->x.p->pos > var+1) {
374 if (exp == 0)
375 evalue_copy(dst, src);
376 else
377 evalue_set_si(dst, 0, 1);
378 return;
381 if (src->x.p->pos == var+1) {
382 if (src->x.p->size > exp)
383 evalue_copy(dst, &src->x.p->arr[exp]);
384 else
385 evalue_set_si(dst, 0, 1);
386 return;
389 dst->x.p = new_enode(polynomial, src->x.p->size, src->x.p->pos);
390 for (i = 0; i < src->x.p->size; ++i)
391 extract_term_into(&src->x.p->arr[i], var, exp,
392 &dst->x.p->arr[i]);
395 /* Extract the coefficient of var^exp.
397 static evalue *extract_term(const evalue *e, int var, int exp)
399 int i;
400 evalue *res;
402 if (EVALUE_IS_ZERO(*e))
403 return evalue_zero();
405 assert(value_zero_p(e->d) && e->x.p->type == partition);
406 res = ALLOC(evalue);
407 value_init(res->d);
408 res->x.p = new_enode(partition, e->x.p->size, e->x.p->pos);
409 for (i = 0; i < e->x.p->size/2; ++i) {
410 EVALUE_SET_DOMAIN(res->x.p->arr[2*i],
411 Domain_Copy(EVALUE_DOMAIN(e->x.p->arr[2*i])));
412 extract_term_into(&e->x.p->arr[2*i+1], var, exp,
413 &res->x.p->arr[2*i+1]);
414 reduce_evalue(&res->x.p->arr[2*i+1]);
416 return res;
419 /* Insert n free variables at pos (0-based) in the polyhedron P.
421 static Polyhedron *Polyhedron_Insert_Columns(Polyhedron *P, unsigned pos,
422 unsigned n)
424 int i;
425 unsigned NbConstraints = 0;
426 unsigned NbRays = 0;
427 Polyhedron *Q;
429 if (!P)
430 return P;
431 if (n == 0)
432 return P;
434 assert(pos <= P->Dimension);
436 if (POL_HAS(P, POL_INEQUALITIES))
437 NbConstraints = P->NbConstraints;
438 if (POL_HAS(P, POL_POINTS))
439 NbRays = P->NbRays + n;
441 Q = Polyhedron_Alloc(P->Dimension+n, NbConstraints, NbRays);
442 if (POL_HAS(P, POL_INEQUALITIES)) {
443 Q->NbEq = P->NbEq;
444 for (i = 0; i < P->NbConstraints; ++i) {
445 Vector_Copy(P->Constraint[i], Q->Constraint[i], 1+pos);
446 Vector_Copy(P->Constraint[i]+1+pos, Q->Constraint[i]+1+pos+n,
447 P->Dimension-pos+1);
450 if (POL_HAS(P, POL_POINTS)) {
451 Q->NbBid = P->NbBid + n;
452 for (i = 0; i < n; ++i)
453 value_set_si(Q->Ray[i][1+pos+i], 1);
454 for (i = 0; i < P->NbRays; ++i) {
455 Vector_Copy(P->Ray[i], Q->Ray[n+i], 1+pos);
456 Vector_Copy(P->Ray[i]+1+pos, Q->Ray[n+i]+1+pos+n,
457 P->Dimension-pos+1);
460 POL_SET(Q, POL_VALID);
461 if (POL_HAS(P, POL_INEQUALITIES))
462 POL_SET(Q, POL_INEQUALITIES);
463 if (POL_HAS(P, POL_POINTS))
464 POL_SET(Q, POL_POINTS);
465 if (POL_HAS(P, POL_VERTICES))
466 POL_SET(Q, POL_VERTICES);
467 return Q;
470 /* Perform summation of e over a list of 1 or more factors F, with context C.
471 * nvar is the total number of variables in the remaining factors.
472 * extra is the number of placeholder parameters introduced in e,
473 * but not (yet) in F or C.
475 * If there is only one factor left, F is intersected with the
476 * context C, the placeholder variables are added, and then
477 * e is summed over the resulting parametric polytope.
479 * If there is more than one factor left, we create two polynomials
480 * in a new placeholder variable (which is placed after the regular
481 * parameters, but before any previously introduced placeholder
482 * variables) that has the factors of the variables in the first
483 * factor of F and the factor of the remaining variables of
484 * each term as its coefficients.
485 * These two polynomials are then summed over their domains
486 * and afterwards the results are combined and the placeholder
487 * variable is removed again.
489 static evalue *sum_factors(Polyhedron *F, Polyhedron *C, evalue *e,
490 unsigned nvar, unsigned extra,
491 struct barvinok_options *options)
493 unsigned nparam = C->Dimension;
494 unsigned F_var = F->Dimension - C->Dimension;
495 int i, n;
496 evalue *s1, *s2, *s;
497 evalue *ph;
499 if (!F->next) {
500 Polyhedron *CA = align_context(C, nvar+nparam, options->MaxRays);
501 Polyhedron *P = DomainIntersection(F, CA, options->MaxRays);
502 Polyhedron *Q = Polyhedron_Insert_Columns(P, nvar+nparam, extra);
503 Polyhedron_Free(CA);
504 Polyhedron_Free(F);
505 Polyhedron_Free(P);
506 evalue *sum = sum_base(Q, e, nvar, options);
507 Polyhedron_Free(Q);
508 return sum;
511 n = evalue_count_terms(e, F_var, 0);
512 ph = create_placeholder(n, nvar+nparam);
513 evalue_shift_variables(e, nvar+nparam, 1);
514 evalue_unzip_terms(e, ph, F_var, 0);
515 evalue_shift_variables(e, nvar, -(nvar-F_var));
516 evalue_reorder_terms(ph);
517 evalue_shift_variables(ph, 0, -F_var);
519 s2 = sum_factors(F->next, C, ph, nvar-F_var, extra+1, options);
520 evalue_free(ph);
521 F->next = NULL;
522 s1 = sum_factors(F, C, e, F_var, extra+1, options);
524 if (n == 1) {
525 /* remove placeholder "polynomial" */
526 reduce_evalue(s1);
527 emul(s1, s2);
528 evalue_free(s1);
529 drop_parameters(s2, nparam, 1);
530 return s2;
533 s = evalue_zero();
534 for (i = 0; i < n; ++i) {
535 evalue *t1, *t2;
536 t1 = extract_term(s1, nparam, i);
537 t2 = extract_term(s2, nparam, i);
538 emul(t1, t2);
539 eadd(t2, s);
540 evalue_free(t1);
541 evalue_free(t2);
543 evalue_free(s1);
544 evalue_free(s2);
546 drop_parameters(s, nparam, 1);
547 return s;
550 /* Perform summation over a product of factors F, obtained using
551 * variable transformation T from the original problem specification.
553 * We first perform the corresponding transformation on the polynomial E,
554 * compute the common context over all factors and then perform
555 * the actual summation over the factors.
557 static evalue *sum_product(Polyhedron *F, evalue *E, Matrix *T, unsigned nparam,
558 struct barvinok_options *options)
560 int i;
561 Matrix *T2;
562 unsigned nvar = T->NbRows;
563 Polyhedron *C;
564 evalue *sum;
566 assert(nvar == T->NbColumns);
567 T2 = Matrix_Alloc(nvar+1, nvar+1);
568 for (i = 0; i < nvar; ++i)
569 Vector_Copy(T->p[i], T2->p[i], nvar);
570 value_set_si(T2->p[nvar][nvar], 1);
572 transform_polynomial(E, T2, NULL, nvar, nparam, nvar, nparam);
574 C = Factor_Context(F, nparam, options->MaxRays);
575 if (F->Dimension == nparam) {
576 Polyhedron *T = F;
577 F = F->next;
578 T->next = NULL;
579 Polyhedron_Free(T);
581 sum = sum_factors(F, C, E, nvar, 0, options);
583 Polyhedron_Free(C);
584 Matrix_Free(T2);
585 Matrix_Free(T);
586 return sum;
589 /* Add two constraints corresponding to floor = floor(e/d),
591 * e - d t >= 0
592 * -e + d t + d-1 >= 0
594 * e is assumed to be an affine expression.
596 Polyhedron *add_floor_var(Polyhedron *P, unsigned nvar, const evalue *floor,
597 struct barvinok_options *options)
599 int i;
600 unsigned dim = P->Dimension+1;
601 Matrix *M = Matrix_Alloc(P->NbConstraints+2, 2+dim);
602 Polyhedron *CP;
603 Value *d = &M->p[0][1+nvar];
604 evalue_extract_affine(floor, M->p[0]+1, M->p[0]+1+dim, d);
605 value_oppose(*d, *d);
606 value_set_si(M->p[0][0], 1);
607 value_set_si(M->p[1][0], 1);
608 Vector_Oppose(M->p[0]+1, M->p[1]+1, M->NbColumns-1);
609 value_subtract(M->p[1][1+dim], M->p[1][1+dim], *d);
610 value_decrement(M->p[1][1+dim], M->p[1][1+dim]);
612 for (i = 0; i < P->NbConstraints; ++i) {
613 Vector_Copy(P->Constraint[i], M->p[i+2], 1+nvar);
614 Vector_Copy(P->Constraint[i]+1+nvar, M->p[i+2]+1+nvar+1, dim-nvar-1+1);
617 CP = Constraints2Polyhedron(M, options->MaxRays);
618 Matrix_Free(M);
619 return CP;
622 static evalue *evalue_add(evalue *a, evalue *b)
624 if (!a)
625 return b;
626 if (!b)
627 return a;
628 eadd(a, b);
629 evalue_free(a);
630 return b;
633 /* Compute sum of a step-polynomial over a polytope by grouping
634 * terms containing the same floor-expressions and introducing
635 * new variables for each such expression.
636 * In particular, while there is any floor-expression left,
637 * the step-polynomial is split into a polynomial containing
638 * the expression, which is then converted to a new variable,
639 * and a polynomial not containing the expression.
641 static evalue *sum_step_polynomial(Polyhedron *P, evalue *E, unsigned nvar,
642 struct barvinok_options *options)
644 evalue *floor;
645 evalue *cur = E;
646 evalue *sum = NULL;
647 evalue *t;
649 while ((floor = evalue_outer_floor(cur))) {
650 Polyhedron *CP;
651 evalue *converted;
652 evalue *converted_floor;
654 /* Ignore floors that do not depend on variables. */
655 if (value_notzero_p(floor->d) || floor->x.p->pos >= nvar+1)
656 break;
658 converted = evalue_dup(cur);
659 converted_floor = evalue_dup(floor);
660 evalue_shift_variables(converted, nvar, 1);
661 evalue_shift_variables(converted_floor, nvar, 1);
662 evalue_replace_floor(converted, converted_floor, nvar);
663 CP = add_floor_var(P, nvar, converted_floor, options);
664 evalue_free(converted_floor);
665 t = sum_step_polynomial(CP, converted, nvar+1, options);
666 evalue_free(converted);
667 Polyhedron_Free(CP);
668 sum = evalue_add(t, sum);
670 if (cur == E)
671 cur = evalue_dup(cur);
672 evalue_drop_floor(cur, floor);
673 evalue_free(floor);
675 if (floor) {
676 evalue_floor2frac(cur);
677 evalue_free(floor);
680 if (EVALUE_IS_ZERO(*cur))
681 t = NULL;
682 else {
683 Matrix *T;
684 unsigned nparam = P->Dimension - nvar;
685 Polyhedron *F = Polyhedron_Factor(P, nparam, &T, options->MaxRays);
686 if (!F)
687 t = sum_base(P, cur, nvar, options);
688 else {
689 if (cur == E)
690 cur = evalue_dup(cur);
691 t = sum_product(F, cur, T, nparam, options);
695 if (E != cur)
696 evalue_free(cur);
698 return evalue_add(t, sum);
701 evalue *barvinok_sum_over_polytope(Polyhedron *P, evalue *E, unsigned nvar,
702 struct evalue_section_array *sections,
703 struct barvinok_options *options)
705 if (P->NbEq)
706 return sum_over_polytope_with_equalities(P, E, nvar, sections, options);
708 if (nvar == 0)
709 return sum_over_polytope_0D(Polyhedron_Copy(P), evalue_dup(E));
711 if (options->summation == BV_SUM_BERNOULLI)
712 return bernoulli_summate(P, E, nvar, sections, options);
713 else if (options->summation == BV_SUM_BOX)
714 return box_summate(P, E, nvar, options->MaxRays);
716 evalue_frac2floor2(E, 0);
718 return sum_step_polynomial(P, E, nvar, options);
721 evalue *barvinok_summate(evalue *e, int nvar, struct barvinok_options *options)
723 int i;
724 struct evalue_section_array sections;
725 evalue *sum;
727 assert(nvar >= 0);
728 if (nvar == 0 || EVALUE_IS_ZERO(*e))
729 return evalue_dup(e);
731 assert(value_zero_p(e->d));
732 assert(e->x.p->type == partition);
734 evalue_section_array_init(&sections);
735 sum = evalue_zero();
737 for (i = 0; i < e->x.p->size/2; ++i) {
738 Polyhedron *D;
739 for (D = EVALUE_DOMAIN(e->x.p->arr[2*i]); D; D = D->next) {
740 Polyhedron *next = D->next;
741 evalue *tmp;
742 D->next = NULL;
744 tmp = barvinok_sum_over_polytope(D, &e->x.p->arr[2*i+1], nvar,
745 &sections, options);
746 assert(tmp);
747 eadd(tmp, sum);
748 evalue_free(tmp);
750 D->next = next;
754 free(sections.s);
756 reduce_evalue(sum);
757 return sum;
760 static __isl_give isl_pw_qpolynomial *add_unbounded_guarded_qp(
761 __isl_take isl_pw_qpolynomial *sum,
762 __isl_take isl_basic_set *bset, __isl_take isl_qpolynomial *qp)
764 int zero;
766 if (!sum || !bset || !qp)
767 goto error;
769 zero = isl_qpolynomial_is_zero(qp);
770 if (zero < 0)
771 goto error;
773 if (!zero) {
774 isl_space *space;
775 isl_set *set;
776 isl_pw_qpolynomial *pwqp;
778 space = isl_pw_qpolynomial_get_domain_space(sum);
779 set = isl_set_from_basic_set(isl_basic_set_copy(bset));
780 set = isl_map_domain(isl_map_from_range(set));
781 set = isl_set_reset_space(set, isl_space_copy(space));
782 pwqp = isl_pw_qpolynomial_alloc(set,
783 isl_qpolynomial_nan_on_domain(space));
784 sum = isl_pw_qpolynomial_add(sum, pwqp);
787 isl_basic_set_free(bset);
788 isl_qpolynomial_free(qp);
789 return sum;
790 error:
791 isl_basic_set_free(bset);
792 isl_qpolynomial_free(qp);
793 isl_pw_qpolynomial_free(sum);
794 return NULL;
797 struct barvinok_summate_data {
798 isl_space *space;
799 isl_qpolynomial *qp;
800 isl_pw_qpolynomial *sum;
801 int n_in;
802 int wrapping;
803 evalue *e;
804 struct evalue_section_array sections;
805 struct barvinok_options *options;
808 static isl_stat add_basic_guarded_qp(__isl_take isl_basic_set *bset, void *user)
810 struct barvinok_summate_data *data = user;
811 Polyhedron *P;
812 evalue *tmp;
813 isl_pw_qpolynomial *pwqp;
814 int bounded;
815 unsigned nvar = isl_basic_set_dim(bset, isl_dim_set);
816 isl_space *space;
818 if (!bset)
819 return isl_stat_error;
821 bounded = isl_basic_set_is_bounded(bset);
822 if (bounded < 0)
823 goto error;
825 if (!bounded) {
826 data->sum = add_unbounded_guarded_qp(data->sum, bset,
827 isl_qpolynomial_copy(data->qp));
828 return isl_stat_ok;
831 space = isl_space_params(isl_basic_set_get_space(bset));
833 P = isl_basic_set_to_polylib(bset);
834 tmp = barvinok_sum_over_polytope(P, data->e, nvar,
835 &data->sections, data->options);
836 Polyhedron_Free(P);
837 assert(tmp);
838 pwqp = isl_pw_qpolynomial_from_evalue(space, tmp);
839 evalue_free(tmp);
840 pwqp = isl_pw_qpolynomial_reset_domain_space(pwqp,
841 isl_space_domain(isl_space_copy(data->space)));
842 data->sum = isl_pw_qpolynomial_add(data->sum, pwqp);
844 isl_basic_set_free(bset);
846 return isl_stat_ok;
847 error:
848 isl_basic_set_free(bset);
849 return isl_stat_error;
852 static isl_stat add_guarded_qp(__isl_take isl_set *set,
853 __isl_take isl_qpolynomial *qp, void *user)
855 isl_stat r;
856 struct barvinok_summate_data *data = user;
858 if (!set || !qp)
859 goto error;
861 data->qp = qp;
863 if (data->wrapping) {
864 unsigned nparam = isl_set_dim(set, isl_dim_param);
865 isl_qpolynomial *qp2 = isl_qpolynomial_copy(qp);
866 set = isl_set_move_dims(set, isl_dim_param, nparam,
867 isl_dim_set, 0, data->n_in);
868 qp2 = isl_qpolynomial_move_dims(qp2, isl_dim_param, nparam,
869 isl_dim_in, 0, data->n_in);
870 data->e = isl_qpolynomial_to_evalue(qp2);
871 isl_qpolynomial_free(qp2);
872 } else
873 data->e = isl_qpolynomial_to_evalue(qp);
874 if (!data->e)
875 goto error;
877 evalue_section_array_init(&data->sections);
879 set = isl_set_make_disjoint(set);
880 set = isl_set_compute_divs(set);
882 r = isl_set_foreach_basic_set(set, &add_basic_guarded_qp, data);
884 free(data->sections.s);
886 evalue_free(data->e);
888 isl_set_free(set);
889 isl_qpolynomial_free(qp);
891 return r;
892 error:
893 isl_set_free(set);
894 isl_qpolynomial_free(qp);
895 return isl_stat_error;
898 __isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_sum(
899 __isl_take isl_pw_qpolynomial *pwqp)
901 isl_ctx *ctx;
902 struct barvinok_summate_data data;
903 int options_allocated = 0;
904 int nvar;
906 data.space = NULL;
907 data.options = NULL;
908 data.sum = NULL;
910 if (!pwqp)
911 return NULL;
913 nvar = isl_pw_qpolynomial_dim(pwqp, isl_dim_set);
915 data.space = isl_pw_qpolynomial_get_domain_space(pwqp);
916 if (!data.space)
917 goto error;
918 if (isl_space_is_params(data.space))
919 isl_die(isl_pw_qpolynomial_get_ctx(pwqp), isl_error_invalid,
920 "input polynomial has no domain", goto error);
921 data.wrapping = isl_space_is_wrapping(data.space);
922 if (data.wrapping) {
923 data.space = isl_space_unwrap(data.space);
924 data.n_in = isl_space_dim(data.space, isl_dim_in);
925 nvar = isl_space_dim(data.space, isl_dim_out);
926 } else
927 data.n_in = 0;
929 data.space = isl_space_domain(data.space);
930 if (nvar == 0)
931 return isl_pw_qpolynomial_reset_domain_space(pwqp, data.space);
933 data.space = isl_space_from_domain(data.space);
934 data.space = isl_space_add_dims(data.space, isl_dim_out, 1);
935 data.sum = isl_pw_qpolynomial_zero(isl_space_copy(data.space));
937 ctx = isl_pw_qpolynomial_get_ctx(pwqp);
938 data.options = isl_ctx_peek_barvinok_options(ctx);
939 if (!data.options) {
940 data.options = barvinok_options_new_with_defaults();
941 options_allocated = 1;
944 if (isl_pw_qpolynomial_foreach_lifted_piece(pwqp,
945 add_guarded_qp, &data) < 0)
946 goto error;
948 if (options_allocated)
949 barvinok_options_free(data.options);
951 isl_space_free(data.space);
953 isl_pw_qpolynomial_free(pwqp);
955 return data.sum;
956 error:
957 if (options_allocated)
958 barvinok_options_free(data.options);
959 isl_pw_qpolynomial_free(pwqp);
960 isl_space_free(data.space);
961 isl_pw_qpolynomial_free(data.sum);
962 return NULL;
965 static isl_stat pw_qpolynomial_sum(__isl_take isl_pw_qpolynomial *pwqp,
966 void *user)
968 isl_union_pw_qpolynomial **res = (isl_union_pw_qpolynomial **)user;
969 isl_pw_qpolynomial *sum;
970 isl_union_pw_qpolynomial *upwqp;
972 sum = isl_pw_qpolynomial_sum(pwqp);
973 upwqp = isl_union_pw_qpolynomial_from_pw_qpolynomial(sum);
974 *res = isl_union_pw_qpolynomial_add(*res, upwqp);
976 return isl_stat_ok;
979 __isl_give isl_union_pw_qpolynomial *isl_union_pw_qpolynomial_sum(
980 __isl_take isl_union_pw_qpolynomial *upwqp)
982 isl_space *space;
983 isl_union_pw_qpolynomial *res;
985 space = isl_union_pw_qpolynomial_get_space(upwqp);
986 res = isl_union_pw_qpolynomial_zero(space);
987 if (isl_union_pw_qpolynomial_foreach_pw_qpolynomial(upwqp,
988 &pw_qpolynomial_sum, &res) < 0)
989 goto error;
990 isl_union_pw_qpolynomial_free(upwqp);
992 return res;
993 error:
994 isl_union_pw_qpolynomial_free(upwqp);
995 isl_union_pw_qpolynomial_free(res);
996 return NULL;
999 static int join_compatible(__isl_keep isl_space *space1,
1000 __isl_keep isl_space *space2)
1002 int m;
1003 m = isl_space_has_equal_params(space1, space2);
1004 if (m < 0 || !m)
1005 return m;
1006 return isl_space_tuple_is_equal(space1, isl_dim_out,
1007 space2, isl_dim_in);
1010 /* Compute the intersection of the range of the map and the domain
1011 * of the piecewise quasipolynomial and then sum the associated
1012 * quasipolynomial over all elements in this intersection.
1014 * We first introduce some unconstrained dimensions in the
1015 * piecewise quasipolynomial, intersect the resulting domain
1016 * with the wrapped map and then compute the sum.
1018 __isl_give isl_pw_qpolynomial *isl_map_apply_pw_qpolynomial(
1019 __isl_take isl_map *map, __isl_take isl_pw_qpolynomial *pwqp)
1021 isl_ctx *ctx;
1022 isl_set *dom;
1023 isl_space *map_space;
1024 isl_space *pwqp_space;
1025 unsigned n_in;
1026 int ok;
1028 ctx = isl_map_get_ctx(map);
1029 if (!ctx)
1030 goto error;
1032 map_space = isl_map_get_space(map);
1033 pwqp_space = isl_pw_qpolynomial_get_space(pwqp);
1034 ok = join_compatible(map_space, pwqp_space);
1035 isl_space_free(map_space);
1036 isl_space_free(pwqp_space);
1037 if (!ok)
1038 isl_die(ctx, isl_error_invalid, "incompatible dimensions",
1039 goto error);
1041 n_in = isl_map_dim(map, isl_dim_in);
1042 pwqp = isl_pw_qpolynomial_insert_dims(pwqp, isl_dim_in, 0, n_in);
1044 dom = isl_map_wrap(map);
1045 pwqp = isl_pw_qpolynomial_reset_domain_space(pwqp,
1046 isl_set_get_space(dom));
1048 pwqp = isl_pw_qpolynomial_intersect_domain(pwqp, dom);
1049 pwqp = isl_pw_qpolynomial_sum(pwqp);
1051 return pwqp;
1052 error:
1053 isl_map_free(map);
1054 isl_pw_qpolynomial_free(pwqp);
1055 return NULL;
1058 __isl_give isl_pw_qpolynomial *isl_set_apply_pw_qpolynomial(
1059 __isl_take isl_set *set, __isl_take isl_pw_qpolynomial *pwqp)
1061 isl_map *map;
1063 map = isl_map_from_range(set);
1064 pwqp = isl_map_apply_pw_qpolynomial(map, pwqp);
1065 pwqp = isl_pw_qpolynomial_project_domain_on_params(pwqp);
1066 return pwqp;
1069 struct barvinok_apply_data {
1070 isl_union_pw_qpolynomial *upwqp;
1071 isl_union_pw_qpolynomial *res;
1072 isl_map *map;
1075 static isl_stat pw_qpolynomial_apply(__isl_take isl_pw_qpolynomial *pwqp,
1076 void *user)
1078 isl_space *map_space;
1079 isl_space *pwqp_space;
1080 struct barvinok_apply_data *data = user;
1081 int ok;
1083 map_space = isl_map_get_space(data->map);
1084 pwqp_space = isl_pw_qpolynomial_get_space(pwqp);
1085 ok = join_compatible(map_space, pwqp_space);
1086 isl_space_free(map_space);
1087 isl_space_free(pwqp_space);
1089 if (ok) {
1090 isl_union_pw_qpolynomial *upwqp;
1092 pwqp = isl_map_apply_pw_qpolynomial(isl_map_copy(data->map),
1093 pwqp);
1094 upwqp = isl_union_pw_qpolynomial_from_pw_qpolynomial(pwqp);
1095 data->res = isl_union_pw_qpolynomial_add(data->res, upwqp);
1096 } else
1097 isl_pw_qpolynomial_free(pwqp);
1099 return isl_stat_ok;
1102 static isl_stat map_apply(__isl_take isl_map *map, void *user)
1104 struct barvinok_apply_data *data = user;
1105 isl_stat r;
1107 data->map = map;
1108 r = isl_union_pw_qpolynomial_foreach_pw_qpolynomial(data->upwqp,
1109 &pw_qpolynomial_apply, data);
1111 isl_map_free(map);
1112 return r;
1115 __isl_give isl_union_pw_qpolynomial *isl_union_map_apply_union_pw_qpolynomial(
1116 __isl_take isl_union_map *umap,
1117 __isl_take isl_union_pw_qpolynomial *upwqp)
1119 isl_space *space;
1120 struct barvinok_apply_data data;
1122 upwqp = isl_union_pw_qpolynomial_align_params(upwqp,
1123 isl_union_map_get_space(umap));
1124 umap = isl_union_map_align_params(umap,
1125 isl_union_pw_qpolynomial_get_space(upwqp));
1127 data.upwqp = upwqp;
1128 space = isl_union_pw_qpolynomial_get_space(upwqp);
1129 data.res = isl_union_pw_qpolynomial_zero(space);
1130 if (isl_union_map_foreach_map(umap, &map_apply, &data) < 0)
1131 goto error;
1133 isl_union_map_free(umap);
1134 isl_union_pw_qpolynomial_free(upwqp);
1136 return data.res;
1137 error:
1138 isl_union_map_free(umap);
1139 isl_union_pw_qpolynomial_free(upwqp);
1140 isl_union_pw_qpolynomial_free(data.res);
1141 return NULL;
1144 struct barvinok_apply_set_data {
1145 isl_union_pw_qpolynomial *upwqp;
1146 isl_union_pw_qpolynomial *res;
1147 isl_set *set;
1150 static isl_stat pw_qpolynomial_apply_set(__isl_take isl_pw_qpolynomial *pwqp,
1151 void *user)
1153 isl_space *set_space;
1154 isl_space *pwqp_space;
1155 struct barvinok_apply_set_data *data = user;
1156 int ok;
1158 set_space = isl_set_get_space(data->set);
1159 pwqp_space = isl_pw_qpolynomial_get_space(pwqp);
1160 ok = join_compatible(set_space, pwqp_space);
1161 isl_space_free(set_space);
1162 isl_space_free(pwqp_space);
1164 if (ok) {
1165 isl_union_pw_qpolynomial *upwqp;
1167 pwqp = isl_set_apply_pw_qpolynomial(isl_set_copy(data->set),
1168 pwqp);
1169 upwqp = isl_union_pw_qpolynomial_from_pw_qpolynomial(pwqp);
1170 data->res = isl_union_pw_qpolynomial_add(data->res, upwqp);
1171 } else
1172 isl_pw_qpolynomial_free(pwqp);
1174 return isl_stat_ok;
1177 static isl_stat set_apply(__isl_take isl_set *set, void *user)
1179 struct barvinok_apply_set_data *data = user;
1180 isl_stat r;
1182 data->set = set;
1183 r = isl_union_pw_qpolynomial_foreach_pw_qpolynomial(data->upwqp,
1184 &pw_qpolynomial_apply_set, data);
1186 isl_set_free(set);
1187 return r;
1190 __isl_give isl_union_pw_qpolynomial *isl_union_set_apply_union_pw_qpolynomial(
1191 __isl_take isl_union_set *uset,
1192 __isl_take isl_union_pw_qpolynomial *upwqp)
1194 isl_space *space;
1195 struct barvinok_apply_set_data data;
1197 upwqp = isl_union_pw_qpolynomial_align_params(upwqp,
1198 isl_union_set_get_space(uset));
1199 uset = isl_union_set_align_params(uset,
1200 isl_union_pw_qpolynomial_get_space(upwqp));
1202 data.upwqp = upwqp;
1203 space = isl_union_pw_qpolynomial_get_space(upwqp);
1204 data.res = isl_union_pw_qpolynomial_zero(space);
1205 if (isl_union_set_foreach_set(uset, &set_apply, &data) < 0)
1206 goto error;
1208 isl_union_set_free(uset);
1209 isl_union_pw_qpolynomial_free(upwqp);
1211 return data.res;
1212 error:
1213 isl_union_set_free(uset);
1214 isl_union_pw_qpolynomial_free(upwqp);
1215 isl_union_pw_qpolynomial_free(data.res);
1216 return NULL;
1219 evalue *evalue_sum(evalue *E, int nvar, unsigned MaxRays)
1221 evalue *sum;
1222 struct barvinok_options *options = barvinok_options_new_with_defaults();
1223 options->MaxRays = MaxRays;
1224 sum = barvinok_summate(E, nvar, options);
1225 barvinok_options_free(options);
1226 return sum;
1229 evalue *esum(evalue *e, int nvar)
1231 evalue *sum;
1232 struct barvinok_options *options = barvinok_options_new_with_defaults();
1233 sum = barvinok_summate(e, nvar, options);
1234 barvinok_options_free(options);
1235 return sum;
1238 /* Turn unweighted counting problem into "weighted" counting problem
1239 * with weight equal to 1 and call barvinok_summate on this weighted problem.
1241 evalue *barvinok_summate_unweighted(Polyhedron *P, Polyhedron *C,
1242 struct barvinok_options *options)
1244 Polyhedron *CA, *D;
1245 evalue e;
1246 evalue *sum;
1248 if (emptyQ(P) || emptyQ(C))
1249 return evalue_zero();
1251 CA = align_context(C, P->Dimension, options->MaxRays);
1252 D = DomainIntersection(P, CA, options->MaxRays);
1253 Domain_Free(CA);
1255 if (emptyQ(D)) {
1256 Domain_Free(D);
1257 return evalue_zero();
1260 value_init(e.d);
1261 e.x.p = new_enode(partition, 2, P->Dimension);
1262 EVALUE_SET_DOMAIN(e.x.p->arr[0], D);
1263 evalue_set_si(&e.x.p->arr[1], 1, 1);
1264 sum = barvinok_summate(&e, P->Dimension - C->Dimension, options);
1265 free_evalue_refs(&e);
1266 return sum;