barvinok 0.41.8
[barvinok.git] / summate.c
blob9eb50ace273a9c70ab4e4fc322701a5f712e807a
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.
167 * Similarly, the construction of the Param_Polyhedron may involve
168 * some simplification that exposes one or more equality constraints.
170 static evalue *sum_base(Polyhedron *P, evalue *E, unsigned nvar,
171 struct barvinok_options *options)
173 Polyhedron *U, *TC;
174 Param_Polyhedron *PP;
175 evalue *sum;
177 if (P->NbEq)
178 return sum_base_with_equalities(P, E, nvar, options);
180 U = Universe_Polyhedron(P->Dimension - nvar);
181 PP = Polyhedron2Param_Polyhedron(P, U, options);
182 if (Param_Polyhedron_Is_Lower_Dimensional(PP)) {
183 P = Param_Polyhedron2Polyhedron(PP, options);
184 Polyhedron_Free(U);
185 Param_Polyhedron_Free(PP);
186 sum = sum_base_with_equalities(P, E, nvar, options);
187 Polyhedron_Free(P);
188 return sum;
190 TC = true_context(P, U, options->MaxRays);
192 if (options->summation == BV_SUM_EULER)
193 sum = euler_summate(PP, TC, E, nvar, options);
194 else if (options->summation == BV_SUM_LAURENT)
195 sum = laurent_summate(PP, TC, E, nvar, options);
196 else if (options->summation == BV_SUM_LAURENT_OLD)
197 sum = laurent_summate_old(PP, TC, E, nvar, options);
198 else
199 assert(0);
201 Polyhedron_Free(TC);
202 Polyhedron_Free(U);
203 Param_Polyhedron_Free(PP);
205 return sum;
208 /* Count the number of non-zero terms in e when viewed as a polynomial
209 * in only the first nvar variables. "count" is the number counted
210 * so far.
212 static int evalue_count_terms(const evalue *e, unsigned nvar, int count)
214 int i;
216 if (EVALUE_IS_ZERO(*e))
217 return count;
219 if (value_zero_p(e->d))
220 assert(e->x.p->type == polynomial);
221 if (value_notzero_p(e->d) || e->x.p->pos >= nvar+1)
222 return count+1;
224 for (i = 0; i < e->x.p->size; ++i)
225 count = evalue_count_terms(&e->x.p->arr[i], nvar, count);
227 return count;
230 /* Create placeholder structure for unzipping.
231 * A "polynomial" is created with size terms in variable pos,
232 * with each term having itself as coefficient.
234 static evalue *create_placeholder(int size, int pos)
236 int i, j;
237 evalue *E = ALLOC(evalue);
238 value_init(E->d);
239 E->x.p = new_enode(polynomial, size, pos+1);
240 for (i = 0; i < size; ++i) {
241 E->x.p->arr[i].x.p = new_enode(polynomial, i+1, pos+1);
242 for (j = 0; j < i; ++j)
243 evalue_set_si(&E->x.p->arr[i].x.p->arr[j], 0, 1);
244 evalue_set_si(&E->x.p->arr[i].x.p->arr[i], 1, 1);
246 return E;
249 /* Interchange each non-zero term in e (when viewed as a polynomial
250 * in only the first nvar variables) with a placeholder in ph (created
251 * by create_placeholder), resulting in two polynomials in the
252 * placeholder variable such that for each non-zero term in e
253 * there is a power of the placeholder variable such that the factors
254 * in the first nvar variables form the coefficient of that power in
255 * the first polynomial (e) and the factors in the remaining variables
256 * form the coefficient of that power in the second polynomial (ph).
258 static int evalue_unzip_terms(evalue *e, evalue *ph, unsigned nvar, int count)
260 int i;
262 if (EVALUE_IS_ZERO(*e))
263 return count;
265 if (value_zero_p(e->d))
266 assert(e->x.p->type == polynomial);
267 if (value_notzero_p(e->d) || e->x.p->pos >= nvar+1) {
268 evalue t = *e;
269 *e = ph->x.p->arr[count];
270 ph->x.p->arr[count] = t;
271 return count+1;
274 for (i = 0; i < e->x.p->size; ++i)
275 count = evalue_unzip_terms(&e->x.p->arr[i], ph, nvar, count);
277 return count;
280 /* Remove n variables at pos (0-based) from the polyhedron P.
281 * Each of these variables is assumed to be completely free,
282 * i.e., there is a line in the polyhedron corresponding to
283 * each of these variables.
285 static Polyhedron *Polyhedron_Remove_Columns(Polyhedron *P, unsigned pos,
286 unsigned n)
288 int i, j;
289 unsigned NbConstraints = 0;
290 unsigned NbRays = 0;
291 Polyhedron *Q;
293 if (n == 0)
294 return P;
296 assert(pos <= P->Dimension);
298 if (POL_HAS(P, POL_INEQUALITIES))
299 NbConstraints = P->NbConstraints;
300 if (POL_HAS(P, POL_POINTS))
301 NbRays = P->NbRays - n;
303 Q = Polyhedron_Alloc(P->Dimension - n, NbConstraints, NbRays);
304 if (POL_HAS(P, POL_INEQUALITIES)) {
305 Q->NbEq = P->NbEq;
306 for (i = 0; i < P->NbConstraints; ++i) {
307 Vector_Copy(P->Constraint[i], Q->Constraint[i], 1+pos);
308 Vector_Copy(P->Constraint[i]+1+pos+n, Q->Constraint[i]+1+pos,
309 Q->Dimension-pos+1);
312 if (POL_HAS(P, POL_POINTS)) {
313 Q->NbBid = P->NbBid - n;
314 for (i = 0; i < n; ++i)
315 value_set_si(Q->Ray[i][1+pos+i], 1);
316 for (i = 0, j = 0; i < P->NbRays; ++i) {
317 int line = First_Non_Zero(P->Ray[i], 1+P->Dimension+1);
318 assert(line != -1);
319 if (line-1 >= pos && line-1 < pos+n) {
320 ++j;
321 assert(j <= n);
322 continue;
324 assert(i-j < Q->NbRays);
325 Vector_Copy(P->Ray[i], Q->Ray[i-j], 1+pos);
326 Vector_Copy(P->Ray[i]+1+pos+n, Q->Ray[i-j]+1+pos,
327 Q->Dimension-pos+1);
330 POL_SET(Q, POL_VALID);
331 if (POL_HAS(P, POL_INEQUALITIES))
332 POL_SET(Q, POL_INEQUALITIES);
333 if (POL_HAS(P, POL_POINTS))
334 POL_SET(Q, POL_POINTS);
335 if (POL_HAS(P, POL_VERTICES))
336 POL_SET(Q, POL_VERTICES);
337 return Q;
340 /* Remove n variables at pos (0-based) from the union of polyhedra P.
341 * Each of these variables is assumed to be completely free,
342 * i.e., there is a line in the polyhedron corresponding to
343 * each of these variables.
345 static Polyhedron *Domain_Remove_Columns(Polyhedron *P, unsigned pos,
346 unsigned n)
348 Polyhedron *R;
349 Polyhedron **next = &R;
351 for (; P; P = P->next) {
352 *next = Polyhedron_Remove_Columns(P, pos, n);
353 next = &(*next)->next;
355 return R;
358 /* Drop n parameters starting at first from partition evalue e */
359 static void drop_parameters(evalue *e, int first, int n)
361 int i;
363 if (EVALUE_IS_ZERO(*e))
364 return;
366 assert(value_zero_p(e->d) && e->x.p->type == partition);
367 for (i = 0; i < e->x.p->size/2; ++i) {
368 Polyhedron *P = EVALUE_DOMAIN(e->x.p->arr[2*i]);
369 Polyhedron *Q = Domain_Remove_Columns(P, first, n);
370 EVALUE_SET_DOMAIN(e->x.p->arr[2*i], Q);
371 Domain_Free(P);
372 evalue_shift_variables(&e->x.p->arr[2*i+1], first, -n);
374 e->x.p->pos -= n;
377 static void extract_term_into(const evalue *src, int var, int exp, evalue *dst)
379 int i;
381 if (value_notzero_p(src->d) ||
382 src->x.p->type != polynomial ||
383 src->x.p->pos > var+1) {
384 if (exp == 0)
385 evalue_copy(dst, src);
386 else
387 evalue_set_si(dst, 0, 1);
388 return;
391 if (src->x.p->pos == var+1) {
392 if (src->x.p->size > exp)
393 evalue_copy(dst, &src->x.p->arr[exp]);
394 else
395 evalue_set_si(dst, 0, 1);
396 return;
399 dst->x.p = new_enode(polynomial, src->x.p->size, src->x.p->pos);
400 for (i = 0; i < src->x.p->size; ++i)
401 extract_term_into(&src->x.p->arr[i], var, exp,
402 &dst->x.p->arr[i]);
405 /* Extract the coefficient of var^exp.
407 static evalue *extract_term(const evalue *e, int var, int exp)
409 int i;
410 evalue *res;
412 if (EVALUE_IS_ZERO(*e))
413 return evalue_zero();
415 assert(value_zero_p(e->d) && e->x.p->type == partition);
416 res = ALLOC(evalue);
417 value_init(res->d);
418 res->x.p = new_enode(partition, e->x.p->size, e->x.p->pos);
419 for (i = 0; i < e->x.p->size/2; ++i) {
420 EVALUE_SET_DOMAIN(res->x.p->arr[2*i],
421 Domain_Copy(EVALUE_DOMAIN(e->x.p->arr[2*i])));
422 extract_term_into(&e->x.p->arr[2*i+1], var, exp,
423 &res->x.p->arr[2*i+1]);
424 reduce_evalue(&res->x.p->arr[2*i+1]);
426 return res;
429 /* Insert n free variables at pos (0-based) in the polyhedron P.
431 static Polyhedron *Polyhedron_Insert_Columns(Polyhedron *P, unsigned pos,
432 unsigned n)
434 int i;
435 unsigned NbConstraints = 0;
436 unsigned NbRays = 0;
437 Polyhedron *Q;
439 if (!P)
440 return P;
441 if (n == 0)
442 return P;
444 assert(pos <= P->Dimension);
446 if (POL_HAS(P, POL_INEQUALITIES))
447 NbConstraints = P->NbConstraints;
448 if (POL_HAS(P, POL_POINTS))
449 NbRays = P->NbRays + n;
451 Q = Polyhedron_Alloc(P->Dimension+n, NbConstraints, NbRays);
452 if (POL_HAS(P, POL_INEQUALITIES)) {
453 Q->NbEq = P->NbEq;
454 for (i = 0; i < P->NbConstraints; ++i) {
455 Vector_Copy(P->Constraint[i], Q->Constraint[i], 1+pos);
456 Vector_Copy(P->Constraint[i]+1+pos, Q->Constraint[i]+1+pos+n,
457 P->Dimension-pos+1);
460 if (POL_HAS(P, POL_POINTS)) {
461 Q->NbBid = P->NbBid + n;
462 for (i = 0; i < n; ++i)
463 value_set_si(Q->Ray[i][1+pos+i], 1);
464 for (i = 0; i < P->NbRays; ++i) {
465 Vector_Copy(P->Ray[i], Q->Ray[n+i], 1+pos);
466 Vector_Copy(P->Ray[i]+1+pos, Q->Ray[n+i]+1+pos+n,
467 P->Dimension-pos+1);
470 POL_SET(Q, POL_VALID);
471 if (POL_HAS(P, POL_INEQUALITIES))
472 POL_SET(Q, POL_INEQUALITIES);
473 if (POL_HAS(P, POL_POINTS))
474 POL_SET(Q, POL_POINTS);
475 if (POL_HAS(P, POL_VERTICES))
476 POL_SET(Q, POL_VERTICES);
477 return Q;
480 /* Perform summation of e over a list of 1 or more factors F, with context C.
481 * nvar is the total number of variables in the remaining factors.
482 * extra is the number of placeholder parameters introduced in e,
483 * but not (yet) in F or C.
485 * If there is only one factor left, F is intersected with the
486 * context C, the placeholder variables are added, and then
487 * e is summed over the resulting parametric polytope.
489 * If there is more than one factor left, we create two polynomials
490 * in a new placeholder variable (which is placed after the regular
491 * parameters, but before any previously introduced placeholder
492 * variables) that has the factors of the variables in the first
493 * factor of F and the factor of the remaining variables of
494 * each term as its coefficients.
495 * These two polynomials are then summed over their domains
496 * and afterwards the results are combined and the placeholder
497 * variable is removed again.
499 static evalue *sum_factors(Polyhedron *F, Polyhedron *C, evalue *e,
500 unsigned nvar, unsigned extra,
501 struct barvinok_options *options)
503 unsigned nparam = C->Dimension;
504 unsigned F_var = F->Dimension - C->Dimension;
505 int i, n;
506 evalue *s1, *s2, *s;
507 evalue *ph;
509 if (!F->next) {
510 Polyhedron *CA = align_context(C, nvar+nparam, options->MaxRays);
511 Polyhedron *P = DomainIntersection(F, CA, options->MaxRays);
512 Polyhedron *Q = Polyhedron_Insert_Columns(P, nvar+nparam, extra);
513 Polyhedron_Free(CA);
514 Polyhedron_Free(F);
515 Polyhedron_Free(P);
516 evalue *sum = sum_base(Q, e, nvar, options);
517 Polyhedron_Free(Q);
518 return sum;
521 n = evalue_count_terms(e, F_var, 0);
522 ph = create_placeholder(n, nvar+nparam);
523 evalue_shift_variables(e, nvar+nparam, 1);
524 evalue_unzip_terms(e, ph, F_var, 0);
525 evalue_shift_variables(e, nvar, -(nvar-F_var));
526 evalue_reorder_terms(ph);
527 evalue_shift_variables(ph, 0, -F_var);
529 s2 = sum_factors(F->next, C, ph, nvar-F_var, extra+1, options);
530 evalue_free(ph);
531 F->next = NULL;
532 s1 = sum_factors(F, C, e, F_var, extra+1, options);
534 if (n == 1) {
535 /* remove placeholder "polynomial" */
536 reduce_evalue(s1);
537 emul(s1, s2);
538 evalue_free(s1);
539 drop_parameters(s2, nparam, 1);
540 return s2;
543 s = evalue_zero();
544 for (i = 0; i < n; ++i) {
545 evalue *t1, *t2;
546 t1 = extract_term(s1, nparam, i);
547 t2 = extract_term(s2, nparam, i);
548 emul(t1, t2);
549 eadd(t2, s);
550 evalue_free(t1);
551 evalue_free(t2);
553 evalue_free(s1);
554 evalue_free(s2);
556 drop_parameters(s, nparam, 1);
557 return s;
560 /* Perform summation over a product of factors F, obtained using
561 * variable transformation T from the original problem specification.
563 * We first perform the corresponding transformation on the polynomial E,
564 * compute the common context over all factors and then perform
565 * the actual summation over the factors.
567 static evalue *sum_product(Polyhedron *F, evalue *E, Matrix *T, unsigned nparam,
568 struct barvinok_options *options)
570 int i;
571 Matrix *T2;
572 unsigned nvar = T->NbRows;
573 Polyhedron *C;
574 evalue *sum;
576 assert(nvar == T->NbColumns);
577 T2 = Matrix_Alloc(nvar+1, nvar+1);
578 for (i = 0; i < nvar; ++i)
579 Vector_Copy(T->p[i], T2->p[i], nvar);
580 value_set_si(T2->p[nvar][nvar], 1);
582 transform_polynomial(E, T2, NULL, nvar, nparam, nvar, nparam);
584 C = Factor_Context(F, nparam, options->MaxRays);
585 if (F->Dimension == nparam) {
586 Polyhedron *T = F;
587 F = F->next;
588 T->next = NULL;
589 Polyhedron_Free(T);
591 sum = sum_factors(F, C, E, nvar, 0, options);
593 Polyhedron_Free(C);
594 Matrix_Free(T2);
595 Matrix_Free(T);
596 return sum;
599 /* Add two constraints corresponding to floor = floor(e/d),
601 * e - d t >= 0
602 * -e + d t + d-1 >= 0
604 * e is assumed to be an affine expression.
606 Polyhedron *add_floor_var(Polyhedron *P, unsigned nvar, const evalue *floor,
607 struct barvinok_options *options)
609 int i;
610 unsigned dim = P->Dimension+1;
611 Matrix *M = Matrix_Alloc(P->NbConstraints+2, 2+dim);
612 Polyhedron *CP;
613 Value *d = &M->p[0][1+nvar];
614 evalue_extract_affine(floor, M->p[0]+1, M->p[0]+1+dim, d);
615 value_oppose(*d, *d);
616 value_set_si(M->p[0][0], 1);
617 value_set_si(M->p[1][0], 1);
618 Vector_Oppose(M->p[0]+1, M->p[1]+1, M->NbColumns-1);
619 value_subtract(M->p[1][1+dim], M->p[1][1+dim], *d);
620 value_decrement(M->p[1][1+dim], M->p[1][1+dim]);
622 for (i = 0; i < P->NbConstraints; ++i) {
623 Vector_Copy(P->Constraint[i], M->p[i+2], 1+nvar);
624 Vector_Copy(P->Constraint[i]+1+nvar, M->p[i+2]+1+nvar+1, dim-nvar-1+1);
627 CP = Constraints2Polyhedron(M, options->MaxRays);
628 Matrix_Free(M);
629 return CP;
632 static evalue *evalue_add(evalue *a, evalue *b)
634 if (!a)
635 return b;
636 if (!b)
637 return a;
638 eadd(a, b);
639 evalue_free(a);
640 return b;
643 /* Compute sum of a step-polynomial over a polytope by grouping
644 * terms containing the same floor-expressions and introducing
645 * new variables for each such expression.
646 * In particular, while there is any floor-expression left,
647 * the step-polynomial is split into a polynomial containing
648 * the expression, which is then converted to a new variable,
649 * and a polynomial not containing the expression.
651 static evalue *sum_step_polynomial(Polyhedron *P, evalue *E, unsigned nvar,
652 struct barvinok_options *options)
654 evalue *floor;
655 evalue *cur = E;
656 evalue *sum = NULL;
657 evalue *t;
659 while ((floor = evalue_outer_floor(cur))) {
660 Polyhedron *CP;
661 evalue *converted;
662 evalue *converted_floor;
664 /* Ignore floors that do not depend on variables. */
665 if (value_notzero_p(floor->d) || floor->x.p->pos >= nvar+1)
666 break;
668 converted = evalue_dup(cur);
669 converted_floor = evalue_dup(floor);
670 evalue_shift_variables(converted, nvar, 1);
671 evalue_shift_variables(converted_floor, nvar, 1);
672 evalue_replace_floor(converted, converted_floor, nvar);
673 CP = add_floor_var(P, nvar, converted_floor, options);
674 evalue_free(converted_floor);
675 t = sum_step_polynomial(CP, converted, nvar+1, options);
676 evalue_free(converted);
677 Polyhedron_Free(CP);
678 sum = evalue_add(t, sum);
680 if (cur == E)
681 cur = evalue_dup(cur);
682 evalue_drop_floor(cur, floor);
683 evalue_free(floor);
685 if (floor) {
686 evalue_floor2frac(cur);
687 evalue_free(floor);
690 if (EVALUE_IS_ZERO(*cur))
691 t = NULL;
692 else {
693 Matrix *T;
694 unsigned nparam = P->Dimension - nvar;
695 Polyhedron *F = Polyhedron_Factor(P, nparam, &T, options->MaxRays);
696 if (!F)
697 t = sum_base(P, cur, nvar, options);
698 else {
699 if (cur == E)
700 cur = evalue_dup(cur);
701 t = sum_product(F, cur, T, nparam, options);
705 if (E != cur)
706 evalue_free(cur);
708 return evalue_add(t, sum);
711 evalue *barvinok_sum_over_polytope(Polyhedron *P, evalue *E, unsigned nvar,
712 struct evalue_section_array *sections,
713 struct barvinok_options *options)
715 if (P->NbEq)
716 return sum_over_polytope_with_equalities(P, E, nvar, sections, options);
718 if (nvar == 0)
719 return sum_over_polytope_0D(Polyhedron_Copy(P), evalue_dup(E));
721 if (options->summation == BV_SUM_BERNOULLI)
722 return bernoulli_summate(P, E, nvar, sections, options);
723 else if (options->summation == BV_SUM_BOX)
724 return box_summate(P, E, nvar, options);
726 evalue_frac2floor2(E, 0);
728 return sum_step_polynomial(P, E, nvar, options);
731 evalue *barvinok_summate(evalue *e, int nvar, struct barvinok_options *options)
733 int i;
734 struct evalue_section_array sections;
735 evalue *sum;
737 assert(nvar >= 0);
738 if (nvar == 0 || EVALUE_IS_ZERO(*e))
739 return evalue_dup(e);
741 assert(value_zero_p(e->d));
742 assert(e->x.p->type == partition);
744 evalue_section_array_init(&sections);
745 sum = evalue_zero();
747 for (i = 0; i < e->x.p->size/2; ++i) {
748 Polyhedron *D;
749 for (D = EVALUE_DOMAIN(e->x.p->arr[2*i]); D; D = D->next) {
750 Polyhedron *next = D->next;
751 evalue *tmp;
752 D->next = NULL;
754 tmp = barvinok_sum_over_polytope(D, &e->x.p->arr[2*i+1], nvar,
755 &sections, options);
756 assert(tmp);
757 eadd(tmp, sum);
758 evalue_free(tmp);
760 D->next = next;
764 free(sections.s);
766 reduce_evalue(sum);
767 return sum;
770 static __isl_give isl_pw_qpolynomial *add_unbounded_guarded_qp(
771 __isl_take isl_pw_qpolynomial *sum,
772 __isl_take isl_basic_set *bset, __isl_take isl_qpolynomial *qp)
774 int zero;
776 if (!sum || !bset || !qp)
777 goto error;
779 zero = isl_qpolynomial_is_zero(qp);
780 if (zero < 0)
781 goto error;
783 if (!zero) {
784 isl_space *space;
785 isl_set *set;
786 isl_pw_qpolynomial *pwqp;
788 space = isl_pw_qpolynomial_get_domain_space(sum);
789 set = isl_set_from_basic_set(isl_basic_set_copy(bset));
790 set = isl_map_domain(isl_map_from_range(set));
791 set = isl_set_reset_space(set, isl_space_copy(space));
792 pwqp = isl_pw_qpolynomial_alloc(set,
793 isl_qpolynomial_nan_on_domain(space));
794 sum = isl_pw_qpolynomial_add(sum, pwqp);
797 isl_basic_set_free(bset);
798 isl_qpolynomial_free(qp);
799 return sum;
800 error:
801 isl_basic_set_free(bset);
802 isl_qpolynomial_free(qp);
803 isl_pw_qpolynomial_free(sum);
804 return NULL;
807 struct barvinok_summate_data {
808 isl_space *space;
809 isl_qpolynomial *qp;
810 isl_pw_qpolynomial *sum;
811 int n_in;
812 int wrapping;
813 evalue *e;
814 struct evalue_section_array sections;
815 struct barvinok_options *options;
818 static isl_stat add_basic_guarded_qp(__isl_take isl_basic_set *bset, void *user)
820 struct barvinok_summate_data *data = user;
821 Polyhedron *P;
822 evalue *tmp;
823 isl_pw_qpolynomial *pwqp;
824 int bounded;
825 unsigned nvar = isl_basic_set_dim(bset, isl_dim_set);
826 isl_space *space;
828 if (!bset)
829 return isl_stat_error;
831 bounded = isl_basic_set_is_bounded(bset);
832 if (bounded < 0)
833 goto error;
835 if (!bounded) {
836 data->sum = add_unbounded_guarded_qp(data->sum, bset,
837 isl_qpolynomial_copy(data->qp));
838 return isl_stat_ok;
841 space = isl_space_params(isl_basic_set_get_space(bset));
843 P = isl_basic_set_to_polylib(bset);
844 tmp = barvinok_sum_over_polytope(P, data->e, nvar,
845 &data->sections, data->options);
846 Polyhedron_Free(P);
847 assert(tmp);
848 pwqp = isl_pw_qpolynomial_from_evalue(space, tmp);
849 evalue_free(tmp);
850 pwqp = isl_pw_qpolynomial_reset_domain_space(pwqp,
851 isl_space_domain(isl_space_copy(data->space)));
852 data->sum = isl_pw_qpolynomial_add(data->sum, pwqp);
854 isl_basic_set_free(bset);
856 return isl_stat_ok;
857 error:
858 isl_basic_set_free(bset);
859 return isl_stat_error;
862 static isl_stat add_guarded_qp(__isl_take isl_set *set,
863 __isl_take isl_qpolynomial *qp, void *user)
865 isl_stat r;
866 struct barvinok_summate_data *data = user;
868 if (!set || !qp)
869 goto error;
871 data->qp = qp;
873 if (data->wrapping) {
874 unsigned nparam = isl_set_dim(set, isl_dim_param);
875 isl_qpolynomial *qp2 = isl_qpolynomial_copy(qp);
876 set = isl_set_move_dims(set, isl_dim_param, nparam,
877 isl_dim_set, 0, data->n_in);
878 qp2 = isl_qpolynomial_move_dims(qp2, isl_dim_param, nparam,
879 isl_dim_in, 0, data->n_in);
880 data->e = isl_qpolynomial_to_evalue(qp2);
881 isl_qpolynomial_free(qp2);
882 } else
883 data->e = isl_qpolynomial_to_evalue(qp);
884 if (!data->e)
885 goto error;
887 evalue_section_array_init(&data->sections);
889 set = isl_set_make_disjoint(set);
890 set = isl_set_compute_divs(set);
892 r = isl_set_foreach_basic_set(set, &add_basic_guarded_qp, data);
894 free(data->sections.s);
896 evalue_free(data->e);
898 isl_set_free(set);
899 isl_qpolynomial_free(qp);
901 return r;
902 error:
903 isl_set_free(set);
904 isl_qpolynomial_free(qp);
905 return isl_stat_error;
908 __isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_sum(
909 __isl_take isl_pw_qpolynomial *pwqp)
911 isl_ctx *ctx;
912 struct barvinok_summate_data data;
913 int options_allocated = 0;
914 int nvar;
916 data.space = NULL;
917 data.options = NULL;
918 data.sum = NULL;
920 if (!pwqp)
921 return NULL;
923 nvar = isl_pw_qpolynomial_dim(pwqp, isl_dim_set);
925 data.space = isl_pw_qpolynomial_get_domain_space(pwqp);
926 if (!data.space)
927 goto error;
928 if (isl_space_is_params(data.space))
929 isl_die(isl_pw_qpolynomial_get_ctx(pwqp), isl_error_invalid,
930 "input polynomial has no domain", goto error);
931 data.wrapping = isl_space_is_wrapping(data.space);
932 if (data.wrapping) {
933 data.space = isl_space_unwrap(data.space);
934 data.n_in = isl_space_dim(data.space, isl_dim_in);
935 nvar = isl_space_dim(data.space, isl_dim_out);
936 } else
937 data.n_in = 0;
939 data.space = isl_space_domain(data.space);
940 if (nvar == 0)
941 return isl_pw_qpolynomial_reset_domain_space(pwqp, data.space);
943 data.space = isl_space_from_domain(data.space);
944 data.space = isl_space_add_dims(data.space, isl_dim_out, 1);
945 data.sum = isl_pw_qpolynomial_zero(isl_space_copy(data.space));
947 ctx = isl_pw_qpolynomial_get_ctx(pwqp);
948 data.options = isl_ctx_peek_barvinok_options(ctx);
949 if (!data.options) {
950 data.options = barvinok_options_new_with_defaults();
951 options_allocated = 1;
954 if (isl_pw_qpolynomial_foreach_lifted_piece(pwqp,
955 add_guarded_qp, &data) < 0)
956 goto error;
958 if (options_allocated)
959 barvinok_options_free(data.options);
961 isl_space_free(data.space);
963 isl_pw_qpolynomial_free(pwqp);
965 return data.sum;
966 error:
967 if (options_allocated)
968 barvinok_options_free(data.options);
969 isl_pw_qpolynomial_free(pwqp);
970 isl_space_free(data.space);
971 isl_pw_qpolynomial_free(data.sum);
972 return NULL;
975 static isl_stat pw_qpolynomial_sum(__isl_take isl_pw_qpolynomial *pwqp,
976 void *user)
978 isl_union_pw_qpolynomial **res = (isl_union_pw_qpolynomial **)user;
979 isl_pw_qpolynomial *sum;
980 isl_union_pw_qpolynomial *upwqp;
982 sum = isl_pw_qpolynomial_sum(pwqp);
983 upwqp = isl_union_pw_qpolynomial_from_pw_qpolynomial(sum);
984 *res = isl_union_pw_qpolynomial_add(*res, upwqp);
986 return isl_stat_ok;
989 __isl_give isl_union_pw_qpolynomial *isl_union_pw_qpolynomial_sum(
990 __isl_take isl_union_pw_qpolynomial *upwqp)
992 isl_space *space;
993 isl_union_pw_qpolynomial *res;
995 space = isl_union_pw_qpolynomial_get_space(upwqp);
996 res = isl_union_pw_qpolynomial_zero(space);
997 if (isl_union_pw_qpolynomial_foreach_pw_qpolynomial(upwqp,
998 &pw_qpolynomial_sum, &res) < 0)
999 goto error;
1000 isl_union_pw_qpolynomial_free(upwqp);
1002 return res;
1003 error:
1004 isl_union_pw_qpolynomial_free(upwqp);
1005 isl_union_pw_qpolynomial_free(res);
1006 return NULL;
1009 static int join_compatible(__isl_keep isl_space *space1,
1010 __isl_keep isl_space *space2)
1012 int m;
1013 m = isl_space_has_equal_params(space1, space2);
1014 if (m < 0 || !m)
1015 return m;
1016 return isl_space_tuple_is_equal(space1, isl_dim_out,
1017 space2, isl_dim_in);
1020 /* Compute the intersection of the range of the map and the domain
1021 * of the piecewise quasipolynomial and then sum the associated
1022 * quasipolynomial over all elements in this intersection.
1024 * We first introduce some unconstrained dimensions in the
1025 * piecewise quasipolynomial, intersect the resulting domain
1026 * with the wrapped map and then compute the sum.
1028 __isl_give isl_pw_qpolynomial *isl_map_apply_pw_qpolynomial(
1029 __isl_take isl_map *map, __isl_take isl_pw_qpolynomial *pwqp)
1031 isl_ctx *ctx;
1032 isl_set *dom;
1033 isl_space *map_space;
1034 isl_space *pwqp_space;
1035 unsigned n_in;
1036 int ok;
1038 ctx = isl_map_get_ctx(map);
1039 if (!ctx)
1040 goto error;
1042 map_space = isl_map_get_space(map);
1043 pwqp_space = isl_pw_qpolynomial_get_space(pwqp);
1044 ok = join_compatible(map_space, pwqp_space);
1045 isl_space_free(map_space);
1046 isl_space_free(pwqp_space);
1047 if (!ok)
1048 isl_die(ctx, isl_error_invalid, "incompatible dimensions",
1049 goto error);
1051 n_in = isl_map_dim(map, isl_dim_in);
1052 pwqp = isl_pw_qpolynomial_insert_dims(pwqp, isl_dim_in, 0, n_in);
1054 dom = isl_map_wrap(map);
1055 pwqp = isl_pw_qpolynomial_reset_domain_space(pwqp,
1056 isl_set_get_space(dom));
1058 pwqp = isl_pw_qpolynomial_intersect_domain(pwqp, dom);
1059 pwqp = isl_pw_qpolynomial_sum(pwqp);
1061 return pwqp;
1062 error:
1063 isl_map_free(map);
1064 isl_pw_qpolynomial_free(pwqp);
1065 return NULL;
1068 __isl_give isl_pw_qpolynomial *isl_set_apply_pw_qpolynomial(
1069 __isl_take isl_set *set, __isl_take isl_pw_qpolynomial *pwqp)
1071 isl_map *map;
1073 map = isl_map_from_range(set);
1074 pwqp = isl_map_apply_pw_qpolynomial(map, pwqp);
1075 pwqp = isl_pw_qpolynomial_project_domain_on_params(pwqp);
1076 return pwqp;
1079 struct barvinok_apply_data {
1080 isl_union_pw_qpolynomial *upwqp;
1081 isl_union_pw_qpolynomial *res;
1082 isl_map *map;
1085 static isl_stat pw_qpolynomial_apply(__isl_take isl_pw_qpolynomial *pwqp,
1086 void *user)
1088 isl_space *map_space;
1089 isl_space *pwqp_space;
1090 struct barvinok_apply_data *data = user;
1091 int ok;
1093 map_space = isl_map_get_space(data->map);
1094 pwqp_space = isl_pw_qpolynomial_get_space(pwqp);
1095 ok = join_compatible(map_space, pwqp_space);
1096 isl_space_free(map_space);
1097 isl_space_free(pwqp_space);
1099 if (ok) {
1100 isl_union_pw_qpolynomial *upwqp;
1102 pwqp = isl_map_apply_pw_qpolynomial(isl_map_copy(data->map),
1103 pwqp);
1104 upwqp = isl_union_pw_qpolynomial_from_pw_qpolynomial(pwqp);
1105 data->res = isl_union_pw_qpolynomial_add(data->res, upwqp);
1106 } else
1107 isl_pw_qpolynomial_free(pwqp);
1109 return isl_stat_ok;
1112 static isl_stat map_apply(__isl_take isl_map *map, void *user)
1114 struct barvinok_apply_data *data = user;
1115 isl_stat r;
1117 data->map = map;
1118 r = isl_union_pw_qpolynomial_foreach_pw_qpolynomial(data->upwqp,
1119 &pw_qpolynomial_apply, data);
1121 isl_map_free(map);
1122 return r;
1125 __isl_give isl_union_pw_qpolynomial *isl_union_map_apply_union_pw_qpolynomial(
1126 __isl_take isl_union_map *umap,
1127 __isl_take isl_union_pw_qpolynomial *upwqp)
1129 isl_space *space;
1130 struct barvinok_apply_data data;
1132 upwqp = isl_union_pw_qpolynomial_align_params(upwqp,
1133 isl_union_map_get_space(umap));
1134 umap = isl_union_map_align_params(umap,
1135 isl_union_pw_qpolynomial_get_space(upwqp));
1137 data.upwqp = upwqp;
1138 space = isl_union_pw_qpolynomial_get_space(upwqp);
1139 data.res = isl_union_pw_qpolynomial_zero(space);
1140 if (isl_union_map_foreach_map(umap, &map_apply, &data) < 0)
1141 goto error;
1143 isl_union_map_free(umap);
1144 isl_union_pw_qpolynomial_free(upwqp);
1146 return data.res;
1147 error:
1148 isl_union_map_free(umap);
1149 isl_union_pw_qpolynomial_free(upwqp);
1150 isl_union_pw_qpolynomial_free(data.res);
1151 return NULL;
1154 struct barvinok_apply_set_data {
1155 isl_union_pw_qpolynomial *upwqp;
1156 isl_union_pw_qpolynomial *res;
1157 isl_set *set;
1160 static isl_stat pw_qpolynomial_apply_set(__isl_take isl_pw_qpolynomial *pwqp,
1161 void *user)
1163 isl_space *set_space;
1164 isl_space *pwqp_space;
1165 struct barvinok_apply_set_data *data = user;
1166 int ok;
1168 set_space = isl_set_get_space(data->set);
1169 pwqp_space = isl_pw_qpolynomial_get_space(pwqp);
1170 ok = join_compatible(set_space, pwqp_space);
1171 isl_space_free(set_space);
1172 isl_space_free(pwqp_space);
1174 if (ok) {
1175 isl_union_pw_qpolynomial *upwqp;
1177 pwqp = isl_set_apply_pw_qpolynomial(isl_set_copy(data->set),
1178 pwqp);
1179 upwqp = isl_union_pw_qpolynomial_from_pw_qpolynomial(pwqp);
1180 data->res = isl_union_pw_qpolynomial_add(data->res, upwqp);
1181 } else
1182 isl_pw_qpolynomial_free(pwqp);
1184 return isl_stat_ok;
1187 static isl_stat set_apply(__isl_take isl_set *set, void *user)
1189 struct barvinok_apply_set_data *data = user;
1190 isl_stat r;
1192 data->set = set;
1193 r = isl_union_pw_qpolynomial_foreach_pw_qpolynomial(data->upwqp,
1194 &pw_qpolynomial_apply_set, data);
1196 isl_set_free(set);
1197 return r;
1200 __isl_give isl_union_pw_qpolynomial *isl_union_set_apply_union_pw_qpolynomial(
1201 __isl_take isl_union_set *uset,
1202 __isl_take isl_union_pw_qpolynomial *upwqp)
1204 isl_space *space;
1205 struct barvinok_apply_set_data data;
1207 upwqp = isl_union_pw_qpolynomial_align_params(upwqp,
1208 isl_union_set_get_space(uset));
1209 uset = isl_union_set_align_params(uset,
1210 isl_union_pw_qpolynomial_get_space(upwqp));
1212 data.upwqp = upwqp;
1213 space = isl_union_pw_qpolynomial_get_space(upwqp);
1214 data.res = isl_union_pw_qpolynomial_zero(space);
1215 if (isl_union_set_foreach_set(uset, &set_apply, &data) < 0)
1216 goto error;
1218 isl_union_set_free(uset);
1219 isl_union_pw_qpolynomial_free(upwqp);
1221 return data.res;
1222 error:
1223 isl_union_set_free(uset);
1224 isl_union_pw_qpolynomial_free(upwqp);
1225 isl_union_pw_qpolynomial_free(data.res);
1226 return NULL;
1229 evalue *evalue_sum(evalue *E, int nvar, unsigned MaxRays)
1231 evalue *sum;
1232 struct barvinok_options *options = barvinok_options_new_with_defaults();
1233 options->MaxRays = MaxRays;
1234 sum = barvinok_summate(E, nvar, options);
1235 barvinok_options_free(options);
1236 return sum;
1239 evalue *esum(evalue *e, int nvar)
1241 evalue *sum;
1242 struct barvinok_options *options = barvinok_options_new_with_defaults();
1243 sum = barvinok_summate(e, nvar, options);
1244 barvinok_options_free(options);
1245 return sum;
1248 /* Turn unweighted counting problem into "weighted" counting problem
1249 * with weight equal to 1 and call barvinok_summate on this weighted problem.
1251 evalue *barvinok_summate_unweighted(Polyhedron *P, Polyhedron *C,
1252 struct barvinok_options *options)
1254 Polyhedron *CA, *D;
1255 evalue e;
1256 evalue *sum;
1258 if (emptyQ(P) || emptyQ(C))
1259 return evalue_zero();
1261 CA = align_context(C, P->Dimension, options->MaxRays);
1262 D = DomainIntersection(P, CA, options->MaxRays);
1263 Domain_Free(CA);
1265 if (emptyQ(D)) {
1266 Domain_Free(D);
1267 return evalue_zero();
1270 value_init(e.d);
1271 e.x.p = new_enode(partition, 2, P->Dimension);
1272 EVALUE_SET_DOMAIN(e.x.p->arr[0], D);
1273 evalue_set_si(&e.x.p->arr[1], 1, 1);
1274 sum = barvinok_summate(&e, P->Dimension - C->Dimension, options);
1275 free_evalue_refs(&e);
1276 return sum;