laurent_old.cc: laurent_summator_old: member initializer list: base classes first
[barvinok.git] / summate.c
blob963c044512dc534d6c166a8cf5cfe76d52bb5bf3
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 unsigned nparam = C->Dimension;
471 unsigned F_var = F->Dimension - C->Dimension;
472 int i, n;
473 evalue *s1, *s2, *s;
474 evalue *ph;
476 if (!F->next) {
477 Polyhedron *CA = align_context(C, nvar+nparam, options->MaxRays);
478 Polyhedron *P = DomainIntersection(F, CA, options->MaxRays);
479 Polyhedron *Q = Polyhedron_Insert_Columns(P, nvar+nparam, extra);
480 Polyhedron_Free(CA);
481 Polyhedron_Free(F);
482 Polyhedron_Free(P);
483 evalue *sum = sum_base(Q, e, nvar, options);
484 Polyhedron_Free(Q);
485 return sum;
488 n = evalue_count_terms(e, F_var, 0);
489 ph = create_placeholder(n, nvar+nparam);
490 evalue_shift_variables(e, nvar+nparam, 1);
491 evalue_unzip_terms(e, ph, F_var, 0);
492 evalue_shift_variables(e, nvar, -(nvar-F_var));
493 evalue_reorder_terms(ph);
494 evalue_shift_variables(ph, 0, -F_var);
496 s2 = sum_factors(F->next, C, ph, nvar-F_var, extra+1, options);
497 evalue_free(ph);
498 F->next = NULL;
499 s1 = sum_factors(F, C, e, F_var, extra+1, options);
501 if (n == 1) {
502 /* remove placeholder "polynomial" */
503 reduce_evalue(s1);
504 emul(s1, s2);
505 evalue_free(s1);
506 drop_parameters(s2, nparam, 1);
507 return s2;
510 s = evalue_zero();
511 for (i = 0; i < n; ++i) {
512 evalue *t1, *t2;
513 t1 = extract_term(s1, nparam, i);
514 t2 = extract_term(s2, nparam, i);
515 emul(t1, t2);
516 eadd(t2, s);
517 evalue_free(t1);
518 evalue_free(t2);
520 evalue_free(s1);
521 evalue_free(s2);
523 drop_parameters(s, nparam, 1);
524 return s;
527 /* Perform summation over a product of factors F, obtained using
528 * variable transformation T from the original problem specification.
530 * We first perform the corresponding transformation on the polynomial E,
531 * compute the common context over all factors and then perform
532 * the actual summation over the factors.
534 static evalue *sum_product(Polyhedron *F, evalue *E, Matrix *T, unsigned nparam,
535 struct barvinok_options *options)
537 int i;
538 Matrix *T2;
539 unsigned nvar = T->NbRows;
540 Polyhedron *C;
541 evalue *sum;
543 assert(nvar == T->NbColumns);
544 T2 = Matrix_Alloc(nvar+1, nvar+1);
545 for (i = 0; i < nvar; ++i)
546 Vector_Copy(T->p[i], T2->p[i], nvar);
547 value_set_si(T2->p[nvar][nvar], 1);
549 transform_polynomial(E, T2, NULL, nvar, nparam, nvar, nparam);
551 C = Factor_Context(F, nparam, options->MaxRays);
552 if (F->Dimension == nparam) {
553 Polyhedron *T = F;
554 F = F->next;
555 T->next = NULL;
556 Polyhedron_Free(T);
558 sum = sum_factors(F, C, E, nvar, 0, options);
560 Polyhedron_Free(C);
561 Matrix_Free(T2);
562 Matrix_Free(T);
563 return sum;
566 /* Add two constraints corresponding to floor = floor(e/d),
568 * e - d t >= 0
569 * -e + d t + d-1 >= 0
571 * e is assumed to be an affine expression.
573 Polyhedron *add_floor_var(Polyhedron *P, unsigned nvar, const evalue *floor,
574 struct barvinok_options *options)
576 int i;
577 unsigned dim = P->Dimension+1;
578 Matrix *M = Matrix_Alloc(P->NbConstraints+2, 2+dim);
579 Polyhedron *CP;
580 Value *d = &M->p[0][1+nvar];
581 evalue_extract_affine(floor, M->p[0]+1, M->p[0]+1+dim, d);
582 value_oppose(*d, *d);
583 value_set_si(M->p[0][0], 1);
584 value_set_si(M->p[1][0], 1);
585 Vector_Oppose(M->p[0]+1, M->p[1]+1, M->NbColumns-1);
586 value_subtract(M->p[1][1+dim], M->p[1][1+dim], *d);
587 value_decrement(M->p[1][1+dim], M->p[1][1+dim]);
589 for (i = 0; i < P->NbConstraints; ++i) {
590 Vector_Copy(P->Constraint[i], M->p[i+2], 1+nvar);
591 Vector_Copy(P->Constraint[i]+1+nvar, M->p[i+2]+1+nvar+1, dim-nvar-1+1);
594 CP = Constraints2Polyhedron(M, options->MaxRays);
595 Matrix_Free(M);
596 return CP;
599 static evalue *evalue_add(evalue *a, evalue *b)
601 if (!a)
602 return b;
603 if (!b)
604 return a;
605 eadd(a, b);
606 evalue_free(a);
607 return b;
610 /* Compute sum of a step-polynomial over a polytope by grouping
611 * terms containing the same floor-expressions and introducing
612 * new variables for each such expression.
613 * In particular, while there is any floor-expression left,
614 * the step-polynomial is split into a polynomial containing
615 * the expression, which is then converted to a new variable,
616 * and a polynomial not containing the expression.
618 static evalue *sum_step_polynomial(Polyhedron *P, evalue *E, unsigned nvar,
619 struct barvinok_options *options)
621 evalue *floor;
622 evalue *cur = E;
623 evalue *sum = NULL;
624 evalue *t;
626 while ((floor = evalue_outer_floor(cur))) {
627 Polyhedron *CP;
628 evalue *converted;
629 evalue *converted_floor;
631 /* Ignore floors that do not depend on variables. */
632 if (value_notzero_p(floor->d) || floor->x.p->pos >= nvar+1)
633 break;
635 converted = evalue_dup(cur);
636 converted_floor = evalue_dup(floor);
637 evalue_shift_variables(converted, nvar, 1);
638 evalue_shift_variables(converted_floor, nvar, 1);
639 evalue_replace_floor(converted, converted_floor, nvar);
640 CP = add_floor_var(P, nvar, converted_floor, options);
641 evalue_free(converted_floor);
642 t = sum_step_polynomial(CP, converted, nvar+1, options);
643 evalue_free(converted);
644 Polyhedron_Free(CP);
645 sum = evalue_add(t, sum);
647 if (cur == E)
648 cur = evalue_dup(cur);
649 evalue_drop_floor(cur, floor);
650 evalue_free(floor);
652 if (floor) {
653 evalue_floor2frac(cur);
654 evalue_free(floor);
657 if (EVALUE_IS_ZERO(*cur))
658 t = NULL;
659 else {
660 Matrix *T;
661 unsigned nparam = P->Dimension - nvar;
662 Polyhedron *F = Polyhedron_Factor(P, nparam, &T, options->MaxRays);
663 if (!F)
664 t = sum_base(P, cur, nvar, options);
665 else {
666 if (cur == E)
667 cur = evalue_dup(cur);
668 t = sum_product(F, cur, T, nparam, options);
672 if (E != cur)
673 evalue_free(cur);
675 return evalue_add(t, sum);
678 evalue *barvinok_sum_over_polytope(Polyhedron *P, evalue *E, unsigned nvar,
679 struct evalue_section_array *sections,
680 struct barvinok_options *options)
682 if (P->NbEq)
683 return sum_over_polytope_with_equalities(P, E, nvar, sections, options);
685 if (nvar == 0)
686 return sum_over_polytope_0D(Polyhedron_Copy(P), evalue_dup(E));
688 if (options->summation == BV_SUM_BERNOULLI)
689 return bernoulli_summate(P, E, nvar, sections, options);
690 else if (options->summation == BV_SUM_BOX)
691 return box_summate(P, E, nvar, options->MaxRays);
693 evalue_frac2floor2(E, 0);
695 return sum_step_polynomial(P, E, nvar, options);
698 evalue *barvinok_summate(evalue *e, int nvar, struct barvinok_options *options)
700 int i;
701 struct evalue_section_array sections;
702 evalue *sum;
704 assert(nvar >= 0);
705 if (nvar == 0 || EVALUE_IS_ZERO(*e))
706 return evalue_dup(e);
708 assert(value_zero_p(e->d));
709 assert(e->x.p->type == partition);
711 evalue_section_array_init(&sections);
712 sum = evalue_zero();
714 for (i = 0; i < e->x.p->size/2; ++i) {
715 Polyhedron *D;
716 for (D = EVALUE_DOMAIN(e->x.p->arr[2*i]); D; D = D->next) {
717 Polyhedron *next = D->next;
718 evalue *tmp;
719 D->next = NULL;
721 tmp = barvinok_sum_over_polytope(D, &e->x.p->arr[2*i+1], nvar,
722 &sections, options);
723 assert(tmp);
724 eadd(tmp, sum);
725 evalue_free(tmp);
727 D->next = next;
731 free(sections.s);
733 reduce_evalue(sum);
734 return sum;
737 static __isl_give isl_pw_qpolynomial *add_unbounded_guarded_qp(
738 __isl_take isl_pw_qpolynomial *sum,
739 __isl_take isl_basic_set *bset, __isl_take isl_qpolynomial *qp)
741 int zero;
743 if (!sum || !bset || !qp)
744 goto error;
746 zero = isl_qpolynomial_is_zero(qp);
747 if (zero < 0)
748 goto error;
750 if (!zero) {
751 isl_space *dim;
752 isl_set *set;
753 isl_pw_qpolynomial *pwqp;
755 dim = isl_pw_qpolynomial_get_domain_space(sum);
756 set = isl_set_from_basic_set(isl_basic_set_copy(bset));
757 set = isl_map_domain(isl_map_from_range(set));
758 set = isl_set_reset_space(set, isl_space_copy(dim));
759 pwqp = isl_pw_qpolynomial_alloc(set, isl_qpolynomial_nan_on_domain(dim));
760 sum = isl_pw_qpolynomial_add(sum, pwqp);
763 isl_basic_set_free(bset);
764 isl_qpolynomial_free(qp);
765 return sum;
766 error:
767 isl_basic_set_free(bset);
768 isl_qpolynomial_free(qp);
769 isl_pw_qpolynomial_free(sum);
770 return NULL;
773 struct barvinok_summate_data {
774 isl_space *dim;
775 isl_qpolynomial *qp;
776 isl_pw_qpolynomial *sum;
777 int n_in;
778 int wrapping;
779 evalue *e;
780 struct evalue_section_array sections;
781 struct barvinok_options *options;
784 static isl_stat add_basic_guarded_qp(__isl_take isl_basic_set *bset, void *user)
786 struct barvinok_summate_data *data = user;
787 Polyhedron *P;
788 evalue *tmp;
789 isl_pw_qpolynomial *pwqp;
790 int bounded;
791 unsigned nvar = isl_basic_set_dim(bset, isl_dim_set);
792 isl_space *dim;
794 if (!bset)
795 return isl_stat_error;
797 bounded = isl_basic_set_is_bounded(bset);
798 if (bounded < 0)
799 goto error;
801 if (!bounded) {
802 data->sum = add_unbounded_guarded_qp(data->sum, bset,
803 isl_qpolynomial_copy(data->qp));
804 return isl_stat_ok;
807 dim = isl_basic_set_get_space(bset);
808 dim = isl_space_domain(isl_space_from_range(dim));
810 P = isl_basic_set_to_polylib(bset);
811 tmp = barvinok_sum_over_polytope(P, data->e, nvar,
812 &data->sections, data->options);
813 Polyhedron_Free(P);
814 assert(tmp);
815 pwqp = isl_pw_qpolynomial_from_evalue(dim, tmp);
816 evalue_free(tmp);
817 pwqp = isl_pw_qpolynomial_reset_domain_space(pwqp,
818 isl_space_domain(isl_space_copy(data->dim)));
819 data->sum = isl_pw_qpolynomial_add(data->sum, pwqp);
821 isl_basic_set_free(bset);
823 return isl_stat_ok;
824 error:
825 isl_basic_set_free(bset);
826 return isl_stat_error;
829 static isl_stat add_guarded_qp(__isl_take isl_set *set,
830 __isl_take isl_qpolynomial *qp, void *user)
832 isl_stat r;
833 struct barvinok_summate_data *data = user;
835 if (!set || !qp)
836 goto error;
838 data->qp = qp;
840 if (data->wrapping) {
841 unsigned nparam = isl_set_dim(set, isl_dim_param);
842 isl_qpolynomial *qp2 = isl_qpolynomial_copy(qp);
843 set = isl_set_move_dims(set, isl_dim_param, nparam,
844 isl_dim_set, 0, data->n_in);
845 qp2 = isl_qpolynomial_move_dims(qp2, isl_dim_param, nparam,
846 isl_dim_in, 0, data->n_in);
847 data->e = isl_qpolynomial_to_evalue(qp2);
848 isl_qpolynomial_free(qp2);
849 } else
850 data->e = isl_qpolynomial_to_evalue(qp);
851 if (!data->e)
852 goto error;
854 evalue_section_array_init(&data->sections);
856 set = isl_set_make_disjoint(set);
857 set = isl_set_compute_divs(set);
859 r = isl_set_foreach_basic_set(set, &add_basic_guarded_qp, data);
861 free(data->sections.s);
863 evalue_free(data->e);
865 isl_set_free(set);
866 isl_qpolynomial_free(qp);
868 return r;
869 error:
870 isl_set_free(set);
871 isl_qpolynomial_free(qp);
872 return isl_stat_error;
875 __isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_sum(
876 __isl_take isl_pw_qpolynomial *pwqp)
878 isl_ctx *ctx;
879 struct barvinok_summate_data data;
880 int options_allocated = 0;
881 int nvar;
883 data.dim = NULL;
884 data.options = NULL;
885 data.sum = NULL;
887 if (!pwqp)
888 return NULL;
890 nvar = isl_pw_qpolynomial_dim(pwqp, isl_dim_set);
892 data.dim = isl_pw_qpolynomial_get_domain_space(pwqp);
893 if (!data.dim)
894 goto error;
895 if (isl_space_is_params(data.dim))
896 isl_die(isl_pw_qpolynomial_get_ctx(pwqp), isl_error_invalid,
897 "input polynomial has no domain", goto error);
898 data.wrapping = isl_space_is_wrapping(data.dim);
899 if (data.wrapping) {
900 data.dim = isl_space_unwrap(data.dim);
901 data.n_in = isl_space_dim(data.dim, isl_dim_in);
902 nvar = isl_space_dim(data.dim, isl_dim_out);
903 } else
904 data.n_in = 0;
906 data.dim = isl_space_domain(data.dim);
907 if (nvar == 0)
908 return isl_pw_qpolynomial_reset_domain_space(pwqp, data.dim);
910 data.dim = isl_space_from_domain(data.dim);
911 data.dim = isl_space_add_dims(data.dim, isl_dim_out, 1);
912 data.sum = isl_pw_qpolynomial_zero(isl_space_copy(data.dim));
914 ctx = isl_pw_qpolynomial_get_ctx(pwqp);
915 data.options = isl_ctx_peek_barvinok_options(ctx);
916 if (!data.options) {
917 data.options = barvinok_options_new_with_defaults();
918 options_allocated = 1;
921 if (isl_pw_qpolynomial_foreach_lifted_piece(pwqp,
922 add_guarded_qp, &data) < 0)
923 goto error;
925 if (options_allocated)
926 barvinok_options_free(data.options);
928 isl_space_free(data.dim);
930 isl_pw_qpolynomial_free(pwqp);
932 return data.sum;
933 error:
934 if (options_allocated)
935 barvinok_options_free(data.options);
936 isl_pw_qpolynomial_free(pwqp);
937 isl_space_free(data.dim);
938 isl_pw_qpolynomial_free(data.sum);
939 return NULL;
942 static isl_stat pw_qpolynomial_sum(__isl_take isl_pw_qpolynomial *pwqp,
943 void *user)
945 isl_union_pw_qpolynomial **res = (isl_union_pw_qpolynomial **)user;
946 isl_pw_qpolynomial *sum;
947 isl_union_pw_qpolynomial *upwqp;
949 sum = isl_pw_qpolynomial_sum(pwqp);
950 upwqp = isl_union_pw_qpolynomial_from_pw_qpolynomial(sum);
951 *res = isl_union_pw_qpolynomial_add(*res, upwqp);
953 return isl_stat_ok;
956 __isl_give isl_union_pw_qpolynomial *isl_union_pw_qpolynomial_sum(
957 __isl_take isl_union_pw_qpolynomial *upwqp)
959 isl_space *dim;
960 isl_union_pw_qpolynomial *res;
962 dim = isl_union_pw_qpolynomial_get_space(upwqp);
963 res = isl_union_pw_qpolynomial_zero(dim);
964 if (isl_union_pw_qpolynomial_foreach_pw_qpolynomial(upwqp,
965 &pw_qpolynomial_sum, &res) < 0)
966 goto error;
967 isl_union_pw_qpolynomial_free(upwqp);
969 return res;
970 error:
971 isl_union_pw_qpolynomial_free(upwqp);
972 isl_union_pw_qpolynomial_free(res);
973 return NULL;
976 static int join_compatible(__isl_keep isl_space *space1,
977 __isl_keep isl_space *space2)
979 int m;
980 m = isl_space_match(space1, isl_dim_param, space2, isl_dim_param);
981 if (m < 0 || !m)
982 return m;
983 return isl_space_tuple_is_equal(space1, isl_dim_out,
984 space2, isl_dim_in);
987 /* Compute the intersection of the range of the map and the domain
988 * of the piecewise quasipolynomial and then sum the associated
989 * quasipolynomial over all elements in this intersection.
991 * We first introduce some unconstrained dimensions in the
992 * piecewise quasipolynomial, intersect the resulting domain
993 * with the wrapped map and then compute the sum.
995 __isl_give isl_pw_qpolynomial *isl_map_apply_pw_qpolynomial(
996 __isl_take isl_map *map, __isl_take isl_pw_qpolynomial *pwqp)
998 isl_ctx *ctx;
999 isl_set *dom;
1000 isl_space *map_dim;
1001 isl_space *pwqp_dim;
1002 unsigned n_in;
1003 int ok;
1005 ctx = isl_map_get_ctx(map);
1006 if (!ctx)
1007 goto error;
1009 map_dim = isl_map_get_space(map);
1010 pwqp_dim = isl_pw_qpolynomial_get_space(pwqp);
1011 ok = join_compatible(map_dim, pwqp_dim);
1012 isl_space_free(map_dim);
1013 isl_space_free(pwqp_dim);
1014 if (!ok)
1015 isl_die(ctx, isl_error_invalid, "incompatible dimensions",
1016 goto error);
1018 n_in = isl_map_dim(map, isl_dim_in);
1019 pwqp = isl_pw_qpolynomial_insert_dims(pwqp, isl_dim_in, 0, n_in);
1021 dom = isl_map_wrap(map);
1022 pwqp = isl_pw_qpolynomial_reset_domain_space(pwqp,
1023 isl_set_get_space(dom));
1025 pwqp = isl_pw_qpolynomial_intersect_domain(pwqp, dom);
1026 pwqp = isl_pw_qpolynomial_sum(pwqp);
1028 return pwqp;
1029 error:
1030 isl_map_free(map);
1031 isl_pw_qpolynomial_free(pwqp);
1032 return NULL;
1035 __isl_give isl_pw_qpolynomial *isl_set_apply_pw_qpolynomial(
1036 __isl_take isl_set *set, __isl_take isl_pw_qpolynomial *pwqp)
1038 isl_map *map;
1040 map = isl_map_from_range(set);
1041 pwqp = isl_map_apply_pw_qpolynomial(map, pwqp);
1042 pwqp = isl_pw_qpolynomial_project_domain_on_params(pwqp);
1043 return pwqp;
1046 struct barvinok_apply_data {
1047 isl_union_pw_qpolynomial *upwqp;
1048 isl_union_pw_qpolynomial *res;
1049 isl_map *map;
1052 static isl_stat pw_qpolynomial_apply(__isl_take isl_pw_qpolynomial *pwqp,
1053 void *user)
1055 isl_space *map_dim;
1056 isl_space *pwqp_dim;
1057 struct barvinok_apply_data *data = user;
1058 int ok;
1060 map_dim = isl_map_get_space(data->map);
1061 pwqp_dim = isl_pw_qpolynomial_get_space(pwqp);
1062 ok = join_compatible(map_dim, pwqp_dim);
1063 isl_space_free(map_dim);
1064 isl_space_free(pwqp_dim);
1066 if (ok) {
1067 isl_union_pw_qpolynomial *upwqp;
1069 pwqp = isl_map_apply_pw_qpolynomial(isl_map_copy(data->map),
1070 pwqp);
1071 upwqp = isl_union_pw_qpolynomial_from_pw_qpolynomial(pwqp);
1072 data->res = isl_union_pw_qpolynomial_add(data->res, upwqp);
1073 } else
1074 isl_pw_qpolynomial_free(pwqp);
1076 return isl_stat_ok;
1079 static isl_stat map_apply(__isl_take isl_map *map, void *user)
1081 struct barvinok_apply_data *data = user;
1082 isl_stat r;
1084 data->map = map;
1085 r = isl_union_pw_qpolynomial_foreach_pw_qpolynomial(data->upwqp,
1086 &pw_qpolynomial_apply, data);
1088 isl_map_free(map);
1089 return r;
1092 __isl_give isl_union_pw_qpolynomial *isl_union_map_apply_union_pw_qpolynomial(
1093 __isl_take isl_union_map *umap,
1094 __isl_take isl_union_pw_qpolynomial *upwqp)
1096 isl_space *dim;
1097 struct barvinok_apply_data data;
1099 upwqp = isl_union_pw_qpolynomial_align_params(upwqp,
1100 isl_union_map_get_space(umap));
1101 umap = isl_union_map_align_params(umap,
1102 isl_union_pw_qpolynomial_get_space(upwqp));
1104 data.upwqp = upwqp;
1105 dim = isl_union_pw_qpolynomial_get_space(upwqp);
1106 data.res = isl_union_pw_qpolynomial_zero(dim);
1107 if (isl_union_map_foreach_map(umap, &map_apply, &data) < 0)
1108 goto error;
1110 isl_union_map_free(umap);
1111 isl_union_pw_qpolynomial_free(upwqp);
1113 return data.res;
1114 error:
1115 isl_union_map_free(umap);
1116 isl_union_pw_qpolynomial_free(upwqp);
1117 isl_union_pw_qpolynomial_free(data.res);
1118 return NULL;
1121 struct barvinok_apply_set_data {
1122 isl_union_pw_qpolynomial *upwqp;
1123 isl_union_pw_qpolynomial *res;
1124 isl_set *set;
1127 static isl_stat pw_qpolynomial_apply_set(__isl_take isl_pw_qpolynomial *pwqp,
1128 void *user)
1130 isl_space *set_dim;
1131 isl_space *pwqp_dim;
1132 struct barvinok_apply_set_data *data = user;
1133 int ok;
1135 set_dim = isl_set_get_space(data->set);
1136 pwqp_dim = isl_pw_qpolynomial_get_space(pwqp);
1137 ok = join_compatible(set_dim, pwqp_dim);
1138 isl_space_free(set_dim);
1139 isl_space_free(pwqp_dim);
1141 if (ok) {
1142 isl_union_pw_qpolynomial *upwqp;
1144 pwqp = isl_set_apply_pw_qpolynomial(isl_set_copy(data->set),
1145 pwqp);
1146 upwqp = isl_union_pw_qpolynomial_from_pw_qpolynomial(pwqp);
1147 data->res = isl_union_pw_qpolynomial_add(data->res, upwqp);
1148 } else
1149 isl_pw_qpolynomial_free(pwqp);
1151 return isl_stat_ok;
1154 static isl_stat set_apply(__isl_take isl_set *set, void *user)
1156 struct barvinok_apply_set_data *data = user;
1157 isl_stat r;
1159 data->set = set;
1160 r = isl_union_pw_qpolynomial_foreach_pw_qpolynomial(data->upwqp,
1161 &pw_qpolynomial_apply_set, data);
1163 isl_set_free(set);
1164 return r;
1167 __isl_give isl_union_pw_qpolynomial *isl_union_set_apply_union_pw_qpolynomial(
1168 __isl_take isl_union_set *uset,
1169 __isl_take isl_union_pw_qpolynomial *upwqp)
1171 isl_space *dim;
1172 struct barvinok_apply_set_data data;
1174 upwqp = isl_union_pw_qpolynomial_align_params(upwqp,
1175 isl_union_set_get_space(uset));
1176 uset = isl_union_set_align_params(uset,
1177 isl_union_pw_qpolynomial_get_space(upwqp));
1179 data.upwqp = upwqp;
1180 dim = isl_union_pw_qpolynomial_get_space(upwqp);
1181 data.res = isl_union_pw_qpolynomial_zero(dim);
1182 if (isl_union_set_foreach_set(uset, &set_apply, &data) < 0)
1183 goto error;
1185 isl_union_set_free(uset);
1186 isl_union_pw_qpolynomial_free(upwqp);
1188 return data.res;
1189 error:
1190 isl_union_set_free(uset);
1191 isl_union_pw_qpolynomial_free(upwqp);
1192 isl_union_pw_qpolynomial_free(data.res);
1193 return NULL;
1196 evalue *evalue_sum(evalue *E, int nvar, unsigned MaxRays)
1198 evalue *sum;
1199 struct barvinok_options *options = barvinok_options_new_with_defaults();
1200 options->MaxRays = MaxRays;
1201 sum = barvinok_summate(E, nvar, options);
1202 barvinok_options_free(options);
1203 return sum;
1206 evalue *esum(evalue *e, int nvar)
1208 evalue *sum;
1209 struct barvinok_options *options = barvinok_options_new_with_defaults();
1210 sum = barvinok_summate(e, nvar, options);
1211 barvinok_options_free(options);
1212 return sum;
1215 /* Turn unweighted counting problem into "weighted" counting problem
1216 * with weight equal to 1 and call barvinok_summate on this weighted problem.
1218 evalue *barvinok_summate_unweighted(Polyhedron *P, Polyhedron *C,
1219 struct barvinok_options *options)
1221 Polyhedron *CA, *D;
1222 evalue e;
1223 evalue *sum;
1225 if (emptyQ(P) || emptyQ(C))
1226 return evalue_zero();
1228 CA = align_context(C, P->Dimension, options->MaxRays);
1229 D = DomainIntersection(P, CA, options->MaxRays);
1230 Domain_Free(CA);
1232 if (emptyQ(D)) {
1233 Domain_Free(D);
1234 return evalue_zero();
1237 value_init(e.d);
1238 e.x.p = new_enode(partition, 2, P->Dimension);
1239 EVALUE_SET_DOMAIN(e.x.p->arr[0], D);
1240 evalue_set_si(&e.x.p->arr[1], 1, 1);
1241 sum = barvinok_summate(&e, P->Dimension - C->Dimension, options);
1242 free_evalue_refs(&e);
1243 return sum;