remove polyhedron_range
[barvinok.git] / summate.c
blob107cccd79f73bc47bbc574e3afbde6b6bdb7e62f
1 #include <isl_set_polylib.h>
2 #include <barvinok/options.h>
3 #include <barvinok/util.h>
4 #include "bernoulli.h"
5 #include "euler.h"
6 #include "laurent.h"
7 #include "laurent_old.h"
8 #include "summate.h"
9 #include "section_array.h"
10 #include "remove_equalities.h"
12 extern evalue *evalue_outer_floor(evalue *e);
13 extern int evalue_replace_floor(evalue *e, const evalue *floor, int var);
14 extern void evalue_drop_floor(evalue *e, const evalue *floor);
16 #define ALLOC(type) (type*)malloc(sizeof(type))
17 #define ALLOCN(type,n) (type*)malloc((n) * sizeof(type))
19 /* Apply the variable transformation specified by T and CP on
20 * the polynomial e. T expresses the old variables in terms
21 * of the new variables (and optionally also the new parameters),
22 * while CP expresses the old parameters in terms of the new
23 * parameters.
25 static void transform_polynomial(evalue *E, Matrix *T, Matrix *CP,
26 unsigned nvar, unsigned nparam,
27 unsigned new_nvar, unsigned new_nparam)
29 int j;
30 evalue **subs;
32 subs = ALLOCN(evalue *, nvar+nparam);
34 for (j = 0; j < nvar; ++j) {
35 if (T)
36 subs[j] = affine2evalue(T->p[j], T->p[T->NbRows-1][T->NbColumns-1],
37 T->NbColumns-1);
38 else
39 subs[j] = evalue_var(j);
41 for (j = 0; j < nparam; ++j) {
42 if (CP)
43 subs[nvar+j] = affine2evalue(CP->p[j], CP->p[nparam][new_nparam],
44 new_nparam);
45 else
46 subs[nvar+j] = evalue_var(j);
47 evalue_shift_variables(subs[nvar+j], 0, new_nvar);
50 evalue_substitute(E, subs);
51 reduce_evalue(E);
53 for (j = 0; j < nvar+nparam; ++j)
54 evalue_free(subs[j]);
55 free(subs);
58 static evalue *sum_over_polytope_with_equalities(Polyhedron *P, evalue *E,
59 unsigned nvar,
60 struct evalue_section_array *sections,
61 struct barvinok_options *options)
63 unsigned dim = P->Dimension;
64 unsigned new_dim, new_nparam;
65 Matrix *T = NULL, *CP = NULL;
66 evalue *sum;
68 if (emptyQ(P))
69 return evalue_zero();
71 assert(P->NbEq > 0);
73 remove_all_equalities(&P, NULL, &CP, &T, dim-nvar, options->MaxRays);
75 if (emptyQ(P)) {
76 Polyhedron_Free(P);
77 return evalue_zero();
80 new_nparam = CP ? CP->NbColumns-1 : dim - nvar;
81 new_dim = T ? T->NbColumns-1 : nvar + new_nparam;
83 /* We can avoid these substitutions if E is a constant */
84 E = evalue_dup(E);
85 transform_polynomial(E, T, CP, nvar, dim-nvar,
86 new_dim-new_nparam, new_nparam);
88 if (new_dim-new_nparam > 0) {
89 sum = barvinok_sum_over_polytope(P, E, new_dim-new_nparam,
90 sections, options);
91 evalue_free(E);
92 Polyhedron_Free(P);
93 } else {
94 sum = ALLOC(evalue);
95 value_init(sum->d);
96 sum->x.p = new_enode(partition, 2, new_dim);
97 EVALUE_SET_DOMAIN(sum->x.p->arr[0], P);
98 value_clear(sum->x.p->arr[1].d);
99 sum->x.p->arr[1] = *E;
100 free(E);
103 if (CP) {
104 evalue_backsubstitute(sum, CP, options->MaxRays);
105 Matrix_Free(CP);
108 if (T)
109 Matrix_Free(T);
111 return sum;
114 static evalue *sum_base(Polyhedron *P, evalue *E, unsigned nvar,
115 struct barvinok_options *options)
117 if (options->summation == BV_SUM_EULER)
118 return euler_summate(P, E, nvar, options);
119 else if (options->summation == BV_SUM_LAURENT)
120 return laurent_summate(P, E, nvar, options);
121 else if (options->summation == BV_SUM_LAURENT_OLD)
122 return laurent_summate_old(P, E, nvar, options);
123 assert(0);
126 /* Count the number of non-zero terms in e when viewed as a polynomial
127 * in only the first nvar variables. "count" is the number counted
128 * so far.
130 static int evalue_count_terms(const evalue *e, unsigned nvar, int count)
132 int i;
134 if (EVALUE_IS_ZERO(*e))
135 return count;
137 if (value_zero_p(e->d))
138 assert(e->x.p->type == polynomial);
139 if (value_notzero_p(e->d) || e->x.p->pos >= nvar+1)
140 return count+1;
142 for (i = 0; i < e->x.p->size; ++i)
143 count = evalue_count_terms(&e->x.p->arr[i], nvar, count);
145 return count;
148 /* Create placeholder structure for unzipping.
149 * A "polynomial" is created with size terms in variable pos,
150 * with each term having itself as coefficient.
152 static evalue *create_placeholder(int size, int pos)
154 int i, j;
155 evalue *E = ALLOC(evalue);
156 value_init(E->d);
157 E->x.p = new_enode(polynomial, size, pos+1);
158 for (i = 0; i < size; ++i) {
159 E->x.p->arr[i].x.p = new_enode(polynomial, i+1, pos+1);
160 for (j = 0; j < i; ++j)
161 evalue_set_si(&E->x.p->arr[i].x.p->arr[j], 0, 1);
162 evalue_set_si(&E->x.p->arr[i].x.p->arr[i], 1, 1);
164 return E;
167 /* Interchange each non-zero term in e (when viewed as a polynomial
168 * in only the first nvar variables) with a placeholder in ph (created
169 * by create_placeholder), resulting in two polynomials in the
170 * placeholder variable such that for each non-zero term in e
171 * there is a power of the placeholder variable such that the factors
172 * in the first nvar variables form the coefficient of that power in
173 * the first polynomial (e) and the factors in the remaining variables
174 * form the coefficient of that power in the second polynomial (ph).
176 static int evalue_unzip_terms(evalue *e, evalue *ph, unsigned nvar, int count)
178 int i;
180 if (EVALUE_IS_ZERO(*e))
181 return count;
183 if (value_zero_p(e->d))
184 assert(e->x.p->type == polynomial);
185 if (value_notzero_p(e->d) || e->x.p->pos >= nvar+1) {
186 evalue t = *e;
187 *e = ph->x.p->arr[count];
188 ph->x.p->arr[count] = t;
189 return count+1;
192 for (i = 0; i < e->x.p->size; ++i)
193 count = evalue_unzip_terms(&e->x.p->arr[i], ph, nvar, count);
195 return count;
198 /* Remove n variables at pos (0-based) from the polyhedron P.
199 * Each of these variables is assumed to be completely free,
200 * i.e., there is a line in the polyhedron corresponding to
201 * each of these variables.
203 static Polyhedron *Polyhedron_Remove_Columns(Polyhedron *P, unsigned pos,
204 unsigned n)
206 int i, j;
207 unsigned NbConstraints = 0;
208 unsigned NbRays = 0;
209 Polyhedron *Q;
211 if (n == 0)
212 return P;
214 assert(pos <= P->Dimension);
216 if (POL_HAS(P, POL_INEQUALITIES))
217 NbConstraints = P->NbConstraints;
218 if (POL_HAS(P, POL_POINTS))
219 NbRays = P->NbRays - n;
221 Q = Polyhedron_Alloc(P->Dimension - n, NbConstraints, NbRays);
222 if (POL_HAS(P, POL_INEQUALITIES)) {
223 Q->NbEq = P->NbEq;
224 for (i = 0; i < P->NbConstraints; ++i) {
225 Vector_Copy(P->Constraint[i], Q->Constraint[i], 1+pos);
226 Vector_Copy(P->Constraint[i]+1+pos+n, Q->Constraint[i]+1+pos,
227 Q->Dimension-pos+1);
230 if (POL_HAS(P, POL_POINTS)) {
231 Q->NbBid = P->NbBid - n;
232 for (i = 0; i < n; ++i)
233 value_set_si(Q->Ray[i][1+pos+i], 1);
234 for (i = 0, j = 0; i < P->NbRays; ++i) {
235 int line = First_Non_Zero(P->Ray[i], 1+P->Dimension+1);
236 assert(line != -1);
237 if (line-1 >= pos && line-1 < pos+n) {
238 ++j;
239 assert(j <= n);
240 continue;
242 assert(i-j < Q->NbRays);
243 Vector_Copy(P->Ray[i], Q->Ray[i-j], 1+pos);
244 Vector_Copy(P->Ray[i]+1+pos+n, Q->Ray[i-j]+1+pos,
245 Q->Dimension-pos+1);
248 POL_SET(Q, POL_VALID);
249 if (POL_HAS(P, POL_INEQUALITIES))
250 POL_SET(Q, POL_INEQUALITIES);
251 if (POL_HAS(P, POL_POINTS))
252 POL_SET(Q, POL_POINTS);
253 if (POL_HAS(P, POL_VERTICES))
254 POL_SET(Q, POL_VERTICES);
255 return Q;
258 /* Remove n variables at pos (0-based) from the union of polyhedra P.
259 * Each of these variables is assumed to be completely free,
260 * i.e., there is a line in the polyhedron corresponding to
261 * each of these variables.
263 static Polyhedron *Domain_Remove_Columns(Polyhedron *P, unsigned pos,
264 unsigned n)
266 Polyhedron *R;
267 Polyhedron **next = &R;
269 for (; P; P = P->next) {
270 *next = Polyhedron_Remove_Columns(P, pos, n);
271 next = &(*next)->next;
273 return R;
276 /* Drop n parameters starting at first from partition evalue e */
277 static void drop_parameters(evalue *e, int first, int n)
279 int i;
281 if (EVALUE_IS_ZERO(*e))
282 return;
284 assert(value_zero_p(e->d) && e->x.p->type == partition);
285 for (i = 0; i < e->x.p->size/2; ++i) {
286 Polyhedron *P = EVALUE_DOMAIN(e->x.p->arr[2*i]);
287 Polyhedron *Q = Domain_Remove_Columns(P, first, n);
288 EVALUE_SET_DOMAIN(e->x.p->arr[2*i], Q);
289 Domain_Free(P);
290 evalue_shift_variables(&e->x.p->arr[2*i+1], first, -n);
292 e->x.p->pos -= n;
295 static void extract_term_into(const evalue *src, int var, int exp, evalue *dst)
297 int i;
299 if (value_notzero_p(src->d) ||
300 src->x.p->type != polynomial ||
301 src->x.p->pos > var+1) {
302 if (exp == 0)
303 evalue_copy(dst, src);
304 else
305 evalue_set_si(dst, 0, 1);
306 return;
309 if (src->x.p->pos == var+1) {
310 if (src->x.p->size > exp)
311 evalue_copy(dst, &src->x.p->arr[exp]);
312 else
313 evalue_set_si(dst, 0, 1);
314 return;
317 dst->x.p = new_enode(polynomial, src->x.p->size, src->x.p->pos);
318 for (i = 0; i < src->x.p->size; ++i)
319 extract_term_into(&src->x.p->arr[i], var, exp,
320 &dst->x.p->arr[i]);
323 /* Extract the coefficient of var^exp.
325 static evalue *extract_term(const evalue *e, int var, int exp)
327 int i;
328 evalue *res;
330 if (EVALUE_IS_ZERO(*e))
331 return evalue_zero();
333 assert(value_zero_p(e->d) && e->x.p->type == partition);
334 res = ALLOC(evalue);
335 value_init(res->d);
336 res->x.p = new_enode(partition, e->x.p->size, e->x.p->pos);
337 for (i = 0; i < e->x.p->size/2; ++i) {
338 EVALUE_SET_DOMAIN(res->x.p->arr[2*i],
339 Domain_Copy(EVALUE_DOMAIN(e->x.p->arr[2*i])));
340 extract_term_into(&e->x.p->arr[2*i+1], var, exp,
341 &res->x.p->arr[2*i+1]);
342 reduce_evalue(&res->x.p->arr[2*i+1]);
344 return res;
347 /* Insert n free variables at pos (0-based) in the polyhedron P.
349 static Polyhedron *Polyhedron_Insert_Columns(Polyhedron *P, unsigned pos,
350 unsigned n)
352 int i;
353 unsigned NbConstraints = 0;
354 unsigned NbRays = 0;
355 Polyhedron *Q;
357 if (!P)
358 return P;
359 if (n == 0)
360 return P;
362 assert(pos <= P->Dimension);
364 if (POL_HAS(P, POL_INEQUALITIES))
365 NbConstraints = P->NbConstraints;
366 if (POL_HAS(P, POL_POINTS))
367 NbRays = P->NbRays + n;
369 Q = Polyhedron_Alloc(P->Dimension+n, NbConstraints, NbRays);
370 if (POL_HAS(P, POL_INEQUALITIES)) {
371 Q->NbEq = P->NbEq;
372 for (i = 0; i < P->NbConstraints; ++i) {
373 Vector_Copy(P->Constraint[i], Q->Constraint[i], 1+pos);
374 Vector_Copy(P->Constraint[i]+1+pos, Q->Constraint[i]+1+pos+n,
375 P->Dimension-pos+1);
378 if (POL_HAS(P, POL_POINTS)) {
379 Q->NbBid = P->NbBid + n;
380 for (i = 0; i < n; ++i)
381 value_set_si(Q->Ray[i][1+pos+i], 1);
382 for (i = 0; i < P->NbRays; ++i) {
383 Vector_Copy(P->Ray[i], Q->Ray[n+i], 1+pos);
384 Vector_Copy(P->Ray[i]+1+pos, Q->Ray[n+i]+1+pos+n,
385 P->Dimension-pos+1);
388 POL_SET(Q, POL_VALID);
389 if (POL_HAS(P, POL_INEQUALITIES))
390 POL_SET(Q, POL_INEQUALITIES);
391 if (POL_HAS(P, POL_POINTS))
392 POL_SET(Q, POL_POINTS);
393 if (POL_HAS(P, POL_VERTICES))
394 POL_SET(Q, POL_VERTICES);
395 return Q;
398 /* Perform summation of e over a list of 1 or more factors F, with context C.
399 * nvar is the total number of variables in the remaining factors.
400 * extra is the number of placeholder parameters introduced in e,
401 * but not (yet) in F or C.
403 * If there is only one factor left, F is intersected with the
404 * context C, the placeholder variables are added, and then
405 * e is summed over the resulting parametric polytope.
407 * If there is more than one factor left, we create two polynomials
408 * in a new placeholder variable (which is placed after the regular
409 * parameters, but before any previously introduced placeholder
410 * variables) that has the factors of the variables in the first
411 * factor of F and the factor of the remaining variables of
412 * each term as its coefficients.
413 * These two polynomials are then summed over their domains
414 * and afterwards the results are combined and the placeholder
415 * variable is removed again.
417 static evalue *sum_factors(Polyhedron *F, Polyhedron *C, evalue *e,
418 unsigned nvar, unsigned extra,
419 struct barvinok_options *options)
421 Polyhedron *P = F;
422 unsigned nparam = C->Dimension;
423 unsigned F_var = F->Dimension - C->Dimension;
424 int i, n;
425 evalue *s1, *s2, *s;
426 evalue *ph;
428 if (!F->next) {
429 Polyhedron *CA = align_context(C, nvar+nparam, options->MaxRays);
430 Polyhedron *P = DomainIntersection(F, CA, options->MaxRays);
431 Polyhedron *Q = Polyhedron_Insert_Columns(P, nvar+nparam, extra);
432 Polyhedron_Free(CA);
433 Polyhedron_Free(F);
434 Polyhedron_Free(P);
435 evalue *sum = sum_base(Q, e, nvar, options);
436 Polyhedron_Free(Q);
437 return sum;
440 n = evalue_count_terms(e, F_var, 0);
441 ph = create_placeholder(n, nvar+nparam);
442 evalue_shift_variables(e, nvar+nparam, 1);
443 evalue_unzip_terms(e, ph, F_var, 0);
444 evalue_shift_variables(e, nvar, -(nvar-F_var));
445 evalue_reorder_terms(ph);
446 evalue_shift_variables(ph, 0, -F_var);
448 s2 = sum_factors(F->next, C, ph, nvar-F_var, extra+1, options);
449 evalue_free(ph);
450 F->next = NULL;
451 s1 = sum_factors(F, C, e, F_var, extra+1, options);
453 if (n == 1) {
454 /* remove placeholder "polynomial" */
455 reduce_evalue(s1);
456 emul(s1, s2);
457 evalue_free(s1);
458 drop_parameters(s2, nparam, 1);
459 return s2;
462 s = evalue_zero();
463 for (i = 0; i < n; ++i) {
464 evalue *t1, *t2;
465 t1 = extract_term(s1, nparam, i);
466 t2 = extract_term(s2, nparam, i);
467 emul(t1, t2);
468 eadd(t2, s);
469 evalue_free(t1);
470 evalue_free(t2);
472 evalue_free(s1);
473 evalue_free(s2);
475 drop_parameters(s, nparam, 1);
476 return s;
479 /* Perform summation over a product of factors F, obtained using
480 * variable transformation T from the original problem specification.
482 * We first perform the corresponding transformation on the polynomial E,
483 * compute the common context over all factors and then perform
484 * the actual summation over the factors.
486 static evalue *sum_product(Polyhedron *F, evalue *E, Matrix *T, unsigned nparam,
487 struct barvinok_options *options)
489 int i;
490 Matrix *T2;
491 unsigned nvar = T->NbRows;
492 Polyhedron *C;
493 evalue *sum;
495 assert(nvar == T->NbColumns);
496 T2 = Matrix_Alloc(nvar+1, nvar+1);
497 for (i = 0; i < nvar; ++i)
498 Vector_Copy(T->p[i], T2->p[i], nvar);
499 value_set_si(T2->p[nvar][nvar], 1);
501 transform_polynomial(E, T2, NULL, nvar, nparam, nvar, nparam);
503 C = Factor_Context(F, nparam, options->MaxRays);
504 if (F->Dimension == nparam) {
505 Polyhedron *T = F;
506 F = F->next;
507 T->next = NULL;
508 Polyhedron_Free(T);
510 sum = sum_factors(F, C, E, nvar, 0, options);
512 Polyhedron_Free(C);
513 Matrix_Free(T2);
514 Matrix_Free(T);
515 return sum;
518 /* Add two constraints corresponding to floor = floor(e/d),
520 * e - d t >= 0
521 * -e + d t + d-1 >= 0
523 * e is assumed to be an affine expression.
525 Polyhedron *add_floor_var(Polyhedron *P, unsigned nvar, const evalue *floor,
526 struct barvinok_options *options)
528 int i;
529 unsigned dim = P->Dimension+1;
530 Matrix *M = Matrix_Alloc(P->NbConstraints+2, 2+dim);
531 Polyhedron *CP;
532 Value *d = &M->p[0][1+nvar];
533 evalue_extract_affine(floor, M->p[0]+1, M->p[0]+1+dim, d);
534 value_oppose(*d, *d);
535 value_set_si(M->p[0][0], 1);
536 value_set_si(M->p[1][0], 1);
537 Vector_Oppose(M->p[0]+1, M->p[1]+1, M->NbColumns-1);
538 value_subtract(M->p[1][1+dim], M->p[1][1+dim], *d);
539 value_decrement(M->p[1][1+dim], M->p[1][1+dim]);
541 for (i = 0; i < P->NbConstraints; ++i) {
542 Vector_Copy(P->Constraint[i], M->p[i+2], 1+nvar);
543 Vector_Copy(P->Constraint[i]+1+nvar, M->p[i+2]+1+nvar+1, dim-nvar-1+1);
546 CP = Constraints2Polyhedron(M, options->MaxRays);
547 Matrix_Free(M);
548 return CP;
551 static evalue *evalue_add(evalue *a, evalue *b)
553 if (!a)
554 return b;
555 if (!b)
556 return a;
557 eadd(a, b);
558 evalue_free(a);
559 return b;
562 /* Compute sum of a step-polynomial over a polytope by grouping
563 * terms containing the same floor-expressions and introducing
564 * new variables for each such expression.
565 * In particular, while there is any floor-expression left,
566 * the step-polynomial is split into a polynomial containing
567 * the expression, which is then converted to a new variable,
568 * and a polynomial not containing the expression.
570 static evalue *sum_step_polynomial(Polyhedron *P, evalue *E, unsigned nvar,
571 struct barvinok_options *options)
573 evalue *floor;
574 evalue *cur = E;
575 evalue *sum = NULL;
576 evalue *t;
578 while ((floor = evalue_outer_floor(cur))) {
579 Polyhedron *CP;
580 evalue *converted;
581 evalue *converted_floor;
583 /* Ignore floors that do not depend on variables. */
584 if (value_notzero_p(floor->d) || floor->x.p->pos >= nvar+1)
585 break;
587 converted = evalue_dup(cur);
588 converted_floor = evalue_dup(floor);
589 evalue_shift_variables(converted, nvar, 1);
590 evalue_shift_variables(converted_floor, nvar, 1);
591 evalue_replace_floor(converted, converted_floor, nvar);
592 CP = add_floor_var(P, nvar, converted_floor, options);
593 evalue_free(converted_floor);
594 t = sum_step_polynomial(CP, converted, nvar+1, options);
595 evalue_free(converted);
596 Polyhedron_Free(CP);
597 sum = evalue_add(t, sum);
599 if (cur == E)
600 cur = evalue_dup(cur);
601 evalue_drop_floor(cur, floor);
602 evalue_free(floor);
604 if (floor) {
605 evalue_floor2frac(cur);
606 evalue_free(floor);
609 if (EVALUE_IS_ZERO(*cur))
610 t = NULL;
611 else {
612 Matrix *T;
613 unsigned nparam = P->Dimension - nvar;
614 Polyhedron *F = Polyhedron_Factor(P, nparam, &T, options->MaxRays);
615 if (!F)
616 t = sum_base(P, cur, nvar, options);
617 else {
618 if (cur == E)
619 cur = evalue_dup(cur);
620 t = sum_product(F, cur, T, nparam, options);
624 if (E != cur)
625 evalue_free(cur);
627 return evalue_add(t, sum);
630 evalue *barvinok_sum_over_polytope(Polyhedron *P, evalue *E, unsigned nvar,
631 struct evalue_section_array *sections,
632 struct barvinok_options *options)
634 if (P->NbEq)
635 return sum_over_polytope_with_equalities(P, E, nvar, sections, options);
637 if (options->summation == BV_SUM_BERNOULLI)
638 return bernoulli_summate(P, E, nvar, sections, options);
639 else if (options->summation == BV_SUM_BOX)
640 return box_summate(P, E, nvar, options->MaxRays);
642 evalue_frac2floor2(E, 0);
644 return sum_step_polynomial(P, E, nvar, options);
647 evalue *barvinok_summate(evalue *e, int nvar, struct barvinok_options *options)
649 int i;
650 struct evalue_section_array sections;
651 evalue *sum;
653 assert(nvar >= 0);
654 if (nvar == 0 || EVALUE_IS_ZERO(*e))
655 return evalue_dup(e);
657 assert(value_zero_p(e->d));
658 assert(e->x.p->type == partition);
660 evalue_section_array_init(&sections);
661 sum = evalue_zero();
663 for (i = 0; i < e->x.p->size/2; ++i) {
664 Polyhedron *D;
665 for (D = EVALUE_DOMAIN(e->x.p->arr[2*i]); D; D = D->next) {
666 Polyhedron *next = D->next;
667 evalue *tmp;
668 D->next = NULL;
670 tmp = barvinok_sum_over_polytope(D, &e->x.p->arr[2*i+1], nvar,
671 &sections, options);
672 assert(tmp);
673 eadd(tmp, sum);
674 evalue_free(tmp);
676 D->next = next;
680 free(sections.s);
682 reduce_evalue(sum);
683 return sum;
686 static __isl_give isl_pw_qpolynomial *add_unbounded_guarded_qp(
687 __isl_take isl_pw_qpolynomial *sum,
688 __isl_take isl_basic_set *bset, __isl_take isl_qpolynomial *qp)
690 int zero;
692 if (!sum || !bset || !qp)
693 goto error;
695 zero = isl_qpolynomial_is_zero(qp);
696 if (zero < 0)
697 goto error;
699 if (!zero) {
700 isl_dim *dim;
701 isl_set *set;
702 isl_pw_qpolynomial *pwqp;
704 dim = isl_pw_qpolynomial_get_dim(sum);
705 set = isl_set_from_basic_set(isl_basic_set_copy(bset));
706 set = isl_map_domain(isl_map_from_range(set));
707 set = isl_set_reset_dim(set, isl_dim_copy(dim));
708 pwqp = isl_pw_qpolynomial_alloc(set, isl_qpolynomial_nan(dim));
709 sum = isl_pw_qpolynomial_add(sum, pwqp);
712 isl_basic_set_free(bset);
713 isl_qpolynomial_free(qp);
714 return sum;
715 error:
716 isl_basic_set_free(bset);
717 isl_qpolynomial_free(qp);
718 isl_pw_qpolynomial_free(sum);
719 return NULL;
722 struct barvinok_summate_data {
723 isl_dim *dim;
724 __isl_take isl_qpolynomial *qp;
725 isl_pw_qpolynomial *sum;
726 int n_in;
727 int nvar;
728 int wrapping;
729 evalue *e;
730 struct evalue_section_array sections;
731 struct barvinok_options *options;
734 static int add_basic_guarded_qp(__isl_take isl_basic_set *bset, void *user)
736 struct barvinok_summate_data *data = user;
737 Polyhedron *P;
738 evalue *tmp;
739 isl_pw_qpolynomial *pwqp;
740 int bounded;
741 unsigned nparam = isl_basic_set_dim(bset, isl_dim_param);
742 isl_dim *dim;
744 if (!bset)
745 return -1;
747 bounded = isl_basic_set_is_bounded(bset);
748 if (bounded < 0)
749 goto error;
751 if (!bounded) {
752 data->sum = add_unbounded_guarded_qp(data->sum, bset,
753 isl_qpolynomial_copy(data->qp));
754 return 0;
757 dim = isl_basic_set_get_dim(bset);
758 dim = isl_dim_domain(isl_dim_from_range(dim));
760 P = isl_basic_set_to_polylib(bset);
761 tmp = barvinok_sum_over_polytope(P, data->e, data->nvar,
762 &data->sections, data->options);
763 Polyhedron_Free(P);
764 assert(tmp);
765 pwqp = isl_pw_qpolynomial_from_evalue(dim, tmp);
766 evalue_free(tmp);
767 pwqp = isl_pw_qpolynomial_reset_dim(pwqp, isl_dim_copy(data->dim));
768 data->sum = isl_pw_qpolynomial_add(data->sum, pwqp);
770 isl_basic_set_free(bset);
772 return 0;
773 error:
774 isl_basic_set_free(bset);
775 return -1;
778 static int add_guarded_qp(__isl_take isl_set *set, __isl_take isl_qpolynomial *qp,
779 void *user)
781 int r;
782 struct barvinok_summate_data *data = user;
784 if (!set || !qp)
785 goto error;
787 data->qp = qp;
789 if (data->wrapping) {
790 unsigned nparam = isl_set_dim(set, isl_dim_param);
791 isl_qpolynomial *qp2 = isl_qpolynomial_copy(qp);
792 set = isl_set_move_dims(set, isl_dim_param, nparam,
793 isl_dim_set, 0, data->n_in);
794 qp2 = isl_qpolynomial_move_dims(qp2, isl_dim_param, nparam,
795 isl_dim_set, 0, data->n_in);
796 data->e = isl_qpolynomial_to_evalue(qp2);
797 isl_qpolynomial_free(qp2);
798 } else
799 data->e = isl_qpolynomial_to_evalue(qp);
800 if (!data->e)
801 goto error;
803 evalue_section_array_init(&data->sections);
805 set = isl_set_make_disjoint(set);
806 set = isl_set_compute_divs(set);
808 r = isl_set_foreach_basic_set(set, &add_basic_guarded_qp, data);
810 free(data->sections.s);
812 evalue_free(data->e);
814 isl_set_free(set);
815 isl_qpolynomial_free(qp);
817 return r;
818 error:
819 isl_set_free(set);
820 isl_qpolynomial_free(qp);
821 return -1;
824 __isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_sum(
825 __isl_take isl_pw_qpolynomial *pwqp)
827 isl_ctx *ctx;
828 struct barvinok_summate_data data;
829 int options_allocated = 0;
831 data.dim = NULL;
832 data.options = NULL;
834 if (!pwqp)
835 return NULL;
837 data.nvar = isl_pw_qpolynomial_dim(pwqp, isl_dim_set);
838 if (data.nvar == 0)
839 return isl_pw_qpolynomial_drop_dims(pwqp, isl_dim_set, 0, 0);
841 data.dim = isl_pw_qpolynomial_get_dim(pwqp);
842 data.wrapping = isl_dim_is_wrapping(data.dim);
843 if (data.wrapping) {
844 data.dim = isl_dim_unwrap(data.dim);
845 data.n_in = isl_dim_size(data.dim, isl_dim_in);
846 data.nvar = isl_dim_size(data.dim, isl_dim_out);
847 data.dim = isl_dim_domain(data.dim);
848 if (data.nvar == 0)
849 return isl_pw_qpolynomial_reset_dim(pwqp, data.dim);
850 } else {
851 data.n_in = 0;
852 data.dim = isl_dim_drop(data.dim, isl_dim_set, 0, data.nvar);
855 data.sum = isl_pw_qpolynomial_zero(isl_dim_copy(data.dim));
857 ctx = isl_pw_qpolynomial_get_ctx(pwqp);
858 data.options = isl_ctx_peek_barvinok_options(ctx);
859 if (!data.options) {
860 data.options = barvinok_options_new_with_defaults();
861 options_allocated = 1;
864 if (isl_pw_qpolynomial_foreach_lifted_piece(pwqp,
865 add_guarded_qp, &data) < 0)
866 goto error;
868 if (options_allocated)
869 barvinok_options_free(data.options);
871 isl_dim_free(data.dim);
873 isl_pw_qpolynomial_free(pwqp);
875 return data.sum;
876 error:
877 if (options_allocated)
878 barvinok_options_free(data.options);
879 isl_pw_qpolynomial_free(pwqp);
880 isl_dim_free(data.dim);
881 isl_pw_qpolynomial_free(data.sum);
882 return NULL;
885 static int pw_qpolynomial_sum(__isl_take isl_pw_qpolynomial *pwqp, void *user)
887 isl_union_pw_qpolynomial **res = (isl_union_pw_qpolynomial **)user;
888 isl_pw_qpolynomial *sum;
890 sum = isl_pw_qpolynomial_sum(pwqp);
891 *res = isl_union_pw_qpolynomial_add_pw_qpolynomial(*res, sum);
893 return 0;
896 __isl_give isl_union_pw_qpolynomial *isl_union_pw_qpolynomial_sum(
897 __isl_take isl_union_pw_qpolynomial *upwqp)
899 isl_dim *dim;
900 isl_union_pw_qpolynomial *res;
902 dim = isl_union_pw_qpolynomial_get_dim(upwqp);
903 res = isl_union_pw_qpolynomial_zero(dim);
904 if (isl_union_pw_qpolynomial_foreach_pw_qpolynomial(upwqp,
905 &pw_qpolynomial_sum, &res) < 0)
906 goto error;
907 isl_union_pw_qpolynomial_free(upwqp);
909 return res;
910 error:
911 isl_union_pw_qpolynomial_free(upwqp);
912 isl_union_pw_qpolynomial_free(res);
913 return NULL;
916 static int compatible_range(__isl_keep isl_dim *dim1, __isl_keep isl_dim *dim2)
918 int m;
919 m = isl_dim_match(dim1, isl_dim_param, dim2, isl_dim_param);
920 if (m < 0 || !m)
921 return m;
922 return isl_dim_tuple_match(dim1, isl_dim_out, dim2, isl_dim_set);
925 /* Compute the intersection of the range of the map and the domain
926 * of the piecewise quasipolynomial and then sum the associated
927 * quasipolynomial over all elements in this intersection.
929 * We first introduce some unconstrained dimensions in the
930 * piecewise quasipolynomial, intersect the resulting domain
931 * with the wrapped map and then compute the sum.
933 __isl_give isl_pw_qpolynomial *isl_map_apply_pw_qpolynomial(
934 __isl_take isl_map *map, __isl_take isl_pw_qpolynomial *pwqp)
936 isl_ctx *ctx;
937 isl_set *dom;
938 isl_dim *map_dim;
939 isl_dim *pwqp_dim;
940 unsigned n_in;
941 int ok;
943 ctx = isl_map_get_ctx(map);
944 if (!ctx)
945 goto error;
947 map_dim = isl_map_get_dim(map);
948 pwqp_dim = isl_pw_qpolynomial_get_dim(pwqp);
949 ok = compatible_range(map_dim, pwqp_dim);
950 isl_dim_free(map_dim);
951 isl_dim_free(pwqp_dim);
952 if (!ok)
953 isl_die(ctx, isl_error_invalid, "incompatible dimensions",
954 goto error);
956 n_in = isl_map_dim(map, isl_dim_in);
957 pwqp = isl_pw_qpolynomial_insert_dims(pwqp, isl_dim_set, 0, n_in);
959 dom = isl_map_wrap(map);
960 pwqp = isl_pw_qpolynomial_reset_dim(pwqp, isl_set_get_dim(dom));
962 pwqp = isl_pw_qpolynomial_intersect_domain(pwqp, dom);
963 pwqp = isl_pw_qpolynomial_sum(pwqp);
965 return pwqp;
966 error:
967 isl_map_free(map);
968 isl_pw_qpolynomial_free(pwqp);
969 return NULL;
972 __isl_give isl_pw_qpolynomial *isl_set_apply_pw_qpolynomial(
973 __isl_take isl_set *set, __isl_take isl_pw_qpolynomial *pwqp)
975 isl_map *map;
977 map = isl_map_from_range(set);
978 return isl_map_apply_pw_qpolynomial(map, pwqp);
981 struct barvinok_apply_data {
982 isl_union_pw_qpolynomial *upwqp;
983 isl_union_pw_qpolynomial *res;
984 isl_map *map;
987 static int pw_qpolynomial_apply(__isl_take isl_pw_qpolynomial *pwqp, void *user)
989 isl_dim *map_dim;
990 isl_dim *pwqp_dim;
991 struct barvinok_apply_data *data = user;
992 int ok;
994 map_dim = isl_map_get_dim(data->map);
995 pwqp_dim = isl_pw_qpolynomial_get_dim(pwqp);
996 ok = compatible_range(map_dim, pwqp_dim);
997 isl_dim_free(map_dim);
998 isl_dim_free(pwqp_dim);
1000 if (ok) {
1001 pwqp = isl_map_apply_pw_qpolynomial(isl_map_copy(data->map),
1002 pwqp);
1003 data->res = isl_union_pw_qpolynomial_add_pw_qpolynomial(
1004 data->res, pwqp);
1005 } else
1006 isl_pw_qpolynomial_free(pwqp);
1008 return 0;
1011 static int map_apply(__isl_take isl_map *map, void *user)
1013 struct barvinok_apply_data *data = user;
1014 int r;
1016 data->map = map;
1017 r = isl_union_pw_qpolynomial_foreach_pw_qpolynomial(data->upwqp,
1018 &pw_qpolynomial_apply, data);
1020 isl_map_free(map);
1021 return r;
1024 __isl_give isl_union_pw_qpolynomial *isl_union_map_apply_union_pw_qpolynomial(
1025 __isl_take isl_union_map *umap,
1026 __isl_take isl_union_pw_qpolynomial *upwqp)
1028 isl_dim *dim;
1029 struct barvinok_apply_data data;
1031 upwqp = isl_union_pw_qpolynomial_align_params(upwqp,
1032 isl_union_map_get_dim(umap));
1033 umap = isl_union_map_align_params(umap,
1034 isl_union_pw_qpolynomial_get_dim(upwqp));
1036 data.upwqp = upwqp;
1037 dim = isl_union_pw_qpolynomial_get_dim(upwqp);
1038 data.res = isl_union_pw_qpolynomial_zero(dim);
1039 if (isl_union_map_foreach_map(umap, &map_apply, &data) < 0)
1040 goto error;
1042 isl_union_map_free(umap);
1043 isl_union_pw_qpolynomial_free(upwqp);
1045 return data.res;
1046 error:
1047 isl_union_map_free(umap);
1048 isl_union_pw_qpolynomial_free(upwqp);
1049 isl_union_pw_qpolynomial_free(data.res);
1050 return NULL;
1053 __isl_give isl_union_pw_qpolynomial *isl_union_set_apply_union_pw_qpolynomial(
1054 __isl_take isl_union_set *uset,
1055 __isl_take isl_union_pw_qpolynomial *upwqp)
1057 isl_union_map *umap;
1059 umap = isl_union_map_from_range(uset);
1060 return isl_union_map_apply_union_pw_qpolynomial(umap, upwqp);
1063 evalue *evalue_sum(evalue *E, int nvar, unsigned MaxRays)
1065 evalue *sum;
1066 struct barvinok_options *options = barvinok_options_new_with_defaults();
1067 options->MaxRays = MaxRays;
1068 sum = barvinok_summate(E, nvar, options);
1069 barvinok_options_free(options);
1070 return sum;
1073 evalue *esum(evalue *e, int nvar)
1075 evalue *sum;
1076 struct barvinok_options *options = barvinok_options_new_with_defaults();
1077 sum = barvinok_summate(e, nvar, options);
1078 barvinok_options_free(options);
1079 return sum;
1082 /* Turn unweighted counting problem into "weighted" counting problem
1083 * with weight equal to 1 and call barvinok_summate on this weighted problem.
1085 evalue *barvinok_summate_unweighted(Polyhedron *P, Polyhedron *C,
1086 struct barvinok_options *options)
1088 Polyhedron *CA, *D;
1089 evalue e;
1090 evalue *sum;
1092 if (emptyQ(P) || emptyQ(C))
1093 return evalue_zero();
1095 CA = align_context(C, P->Dimension, options->MaxRays);
1096 D = DomainIntersection(P, CA, options->MaxRays);
1097 Domain_Free(CA);
1099 if (emptyQ(D)) {
1100 Domain_Free(D);
1101 return evalue_zero();
1104 value_init(e.d);
1105 e.x.p = new_enode(partition, 2, P->Dimension);
1106 EVALUE_SET_DOMAIN(e.x.p->arr[0], D);
1107 evalue_set_si(&e.x.p->arr[1], 1, 1);
1108 sum = barvinok_summate(&e, P->Dimension - C->Dimension, options);
1109 free_evalue_refs(&e);
1110 return sum;