use test scripts for performing tests
[barvinok.git] / summate.c
blob3090065a28d4ebb473d5ebd98a7e3369869c2dd9
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 "summate.h"
17 #include "section_array.h"
18 #include "remove_equalities.h"
20 extern evalue *evalue_outer_floor(evalue *e);
21 extern int evalue_replace_floor(evalue *e, const evalue *floor, int var);
22 extern void evalue_drop_floor(evalue *e, const evalue *floor);
24 #define ALLOC(type) (type*)malloc(sizeof(type))
25 #define ALLOCN(type,n) (type*)malloc((n) * sizeof(type))
27 /* Apply the variable transformation specified by T and CP on
28 * the polynomial e. T expresses the old variables in terms
29 * of the new variables (and optionally also the new parameters),
30 * while CP expresses the old parameters in terms of the new
31 * parameters.
33 static void transform_polynomial(evalue *E, Matrix *T, Matrix *CP,
34 unsigned nvar, unsigned nparam,
35 unsigned new_nvar, unsigned new_nparam)
37 int j;
38 evalue **subs;
40 subs = ALLOCN(evalue *, nvar+nparam);
42 for (j = 0; j < nvar; ++j) {
43 if (T)
44 subs[j] = affine2evalue(T->p[j], T->p[T->NbRows-1][T->NbColumns-1],
45 T->NbColumns-1);
46 else
47 subs[j] = evalue_var(j);
49 for (j = 0; j < nparam; ++j) {
50 if (CP)
51 subs[nvar+j] = affine2evalue(CP->p[j], CP->p[nparam][new_nparam],
52 new_nparam);
53 else
54 subs[nvar+j] = evalue_var(j);
55 evalue_shift_variables(subs[nvar+j], 0, new_nvar);
58 evalue_substitute(E, subs);
59 reduce_evalue(E);
61 for (j = 0; j < nvar+nparam; ++j)
62 evalue_free(subs[j]);
63 free(subs);
66 /* Compute the sum of the quasi-polynomial E
67 * over a 0D (non-empty, but possibly parametric) polytope P.
69 * Consumes P and E.
71 * We simply return a partition evalue with P as domain and E as value.
73 static evalue *sum_over_polytope_0D(Polyhedron *P, evalue *E)
75 evalue *sum;
77 sum = ALLOC(evalue);
78 value_init(sum->d);
79 sum->x.p = new_enode(partition, 2, P->Dimension);
80 EVALUE_SET_DOMAIN(sum->x.p->arr[0], P);
81 value_clear(sum->x.p->arr[1].d);
82 sum->x.p->arr[1] = *E;
83 free(E);
85 return sum;
88 static evalue *sum_with_equalities(Polyhedron *P, evalue *E,
89 unsigned nvar, struct evalue_section_array *sections,
90 struct barvinok_options *options,
91 evalue *(*base)(Polyhedron *P, evalue *E, unsigned nvar,
92 struct evalue_section_array *sections,
93 struct barvinok_options *options))
95 unsigned dim = P->Dimension;
96 unsigned new_dim, new_nparam;
97 Matrix *T = NULL, *CP = NULL;
98 evalue *sum;
100 if (emptyQ(P))
101 return evalue_zero();
103 assert(P->NbEq > 0);
105 remove_all_equalities(&P, NULL, &CP, &T, dim-nvar, options->MaxRays);
107 if (emptyQ(P)) {
108 Polyhedron_Free(P);
109 return evalue_zero();
112 new_nparam = CP ? CP->NbColumns-1 : dim - nvar;
113 new_dim = T ? T->NbColumns-1 : nvar + new_nparam;
115 /* We can avoid these substitutions if E is a constant */
116 E = evalue_dup(E);
117 transform_polynomial(E, T, CP, nvar, dim-nvar,
118 new_dim-new_nparam, new_nparam);
120 if (new_dim-new_nparam > 0) {
121 sum = base(P, E, new_dim-new_nparam, sections, options);
122 evalue_free(E);
123 Polyhedron_Free(P);
124 } else {
125 sum = sum_over_polytope_0D(P, E);
128 if (CP) {
129 evalue_backsubstitute(sum, CP, options->MaxRays);
130 Matrix_Free(CP);
133 if (T)
134 Matrix_Free(T);
136 return sum;
139 static evalue *sum_over_polytope_with_equalities(Polyhedron *P, evalue *E,
140 unsigned nvar, struct evalue_section_array *sections,
141 struct barvinok_options *options)
143 return sum_with_equalities(P, E, nvar, sections, options,
144 &barvinok_sum_over_polytope);
147 static evalue *sum_base(Polyhedron *P, evalue *E, unsigned nvar,
148 struct barvinok_options *options);
150 static evalue *sum_base_wrap(Polyhedron *P, evalue *E, unsigned nvar,
151 struct evalue_section_array *sections, struct barvinok_options *options)
153 return sum_base(P, E, nvar, options);
156 static evalue *sum_base_with_equalities(Polyhedron *P, evalue *E,
157 unsigned nvar, struct barvinok_options *options)
159 return sum_with_equalities(P, E, nvar, NULL, options, &sum_base_wrap);
162 /* The substitutions in sum_step_polynomial may have reintroduced equalities
163 * (in particular, one of the floor expressions may be equal to one of
164 * the variables), so we need to check for them again.
166 static evalue *sum_base(Polyhedron *P, evalue *E, unsigned nvar,
167 struct barvinok_options *options)
169 if (P->NbEq)
170 return sum_base_with_equalities(P, E, nvar, options);
171 if (options->summation == BV_SUM_EULER)
172 return euler_summate(P, E, nvar, options);
173 else if (options->summation == BV_SUM_LAURENT)
174 return laurent_summate(P, E, nvar, options);
175 else if (options->summation == BV_SUM_LAURENT_OLD)
176 return laurent_summate_old(P, E, nvar, options);
177 assert(0);
180 /* Count the number of non-zero terms in e when viewed as a polynomial
181 * in only the first nvar variables. "count" is the number counted
182 * so far.
184 static int evalue_count_terms(const evalue *e, unsigned nvar, int count)
186 int i;
188 if (EVALUE_IS_ZERO(*e))
189 return count;
191 if (value_zero_p(e->d))
192 assert(e->x.p->type == polynomial);
193 if (value_notzero_p(e->d) || e->x.p->pos >= nvar+1)
194 return count+1;
196 for (i = 0; i < e->x.p->size; ++i)
197 count = evalue_count_terms(&e->x.p->arr[i], nvar, count);
199 return count;
202 /* Create placeholder structure for unzipping.
203 * A "polynomial" is created with size terms in variable pos,
204 * with each term having itself as coefficient.
206 static evalue *create_placeholder(int size, int pos)
208 int i, j;
209 evalue *E = ALLOC(evalue);
210 value_init(E->d);
211 E->x.p = new_enode(polynomial, size, pos+1);
212 for (i = 0; i < size; ++i) {
213 E->x.p->arr[i].x.p = new_enode(polynomial, i+1, pos+1);
214 for (j = 0; j < i; ++j)
215 evalue_set_si(&E->x.p->arr[i].x.p->arr[j], 0, 1);
216 evalue_set_si(&E->x.p->arr[i].x.p->arr[i], 1, 1);
218 return E;
221 /* Interchange each non-zero term in e (when viewed as a polynomial
222 * in only the first nvar variables) with a placeholder in ph (created
223 * by create_placeholder), resulting in two polynomials in the
224 * placeholder variable such that for each non-zero term in e
225 * there is a power of the placeholder variable such that the factors
226 * in the first nvar variables form the coefficient of that power in
227 * the first polynomial (e) and the factors in the remaining variables
228 * form the coefficient of that power in the second polynomial (ph).
230 static int evalue_unzip_terms(evalue *e, evalue *ph, unsigned nvar, int count)
232 int i;
234 if (EVALUE_IS_ZERO(*e))
235 return count;
237 if (value_zero_p(e->d))
238 assert(e->x.p->type == polynomial);
239 if (value_notzero_p(e->d) || e->x.p->pos >= nvar+1) {
240 evalue t = *e;
241 *e = ph->x.p->arr[count];
242 ph->x.p->arr[count] = t;
243 return count+1;
246 for (i = 0; i < e->x.p->size; ++i)
247 count = evalue_unzip_terms(&e->x.p->arr[i], ph, nvar, count);
249 return count;
252 /* Remove n variables at pos (0-based) from the polyhedron P.
253 * Each of these variables is assumed to be completely free,
254 * i.e., there is a line in the polyhedron corresponding to
255 * each of these variables.
257 static Polyhedron *Polyhedron_Remove_Columns(Polyhedron *P, unsigned pos,
258 unsigned n)
260 int i, j;
261 unsigned NbConstraints = 0;
262 unsigned NbRays = 0;
263 Polyhedron *Q;
265 if (n == 0)
266 return P;
268 assert(pos <= P->Dimension);
270 if (POL_HAS(P, POL_INEQUALITIES))
271 NbConstraints = P->NbConstraints;
272 if (POL_HAS(P, POL_POINTS))
273 NbRays = P->NbRays - n;
275 Q = Polyhedron_Alloc(P->Dimension - n, NbConstraints, NbRays);
276 if (POL_HAS(P, POL_INEQUALITIES)) {
277 Q->NbEq = P->NbEq;
278 for (i = 0; i < P->NbConstraints; ++i) {
279 Vector_Copy(P->Constraint[i], Q->Constraint[i], 1+pos);
280 Vector_Copy(P->Constraint[i]+1+pos+n, Q->Constraint[i]+1+pos,
281 Q->Dimension-pos+1);
284 if (POL_HAS(P, POL_POINTS)) {
285 Q->NbBid = P->NbBid - n;
286 for (i = 0; i < n; ++i)
287 value_set_si(Q->Ray[i][1+pos+i], 1);
288 for (i = 0, j = 0; i < P->NbRays; ++i) {
289 int line = First_Non_Zero(P->Ray[i], 1+P->Dimension+1);
290 assert(line != -1);
291 if (line-1 >= pos && line-1 < pos+n) {
292 ++j;
293 assert(j <= n);
294 continue;
296 assert(i-j < Q->NbRays);
297 Vector_Copy(P->Ray[i], Q->Ray[i-j], 1+pos);
298 Vector_Copy(P->Ray[i]+1+pos+n, Q->Ray[i-j]+1+pos,
299 Q->Dimension-pos+1);
302 POL_SET(Q, POL_VALID);
303 if (POL_HAS(P, POL_INEQUALITIES))
304 POL_SET(Q, POL_INEQUALITIES);
305 if (POL_HAS(P, POL_POINTS))
306 POL_SET(Q, POL_POINTS);
307 if (POL_HAS(P, POL_VERTICES))
308 POL_SET(Q, POL_VERTICES);
309 return Q;
312 /* Remove n variables at pos (0-based) from the union of polyhedra P.
313 * Each of these variables is assumed to be completely free,
314 * i.e., there is a line in the polyhedron corresponding to
315 * each of these variables.
317 static Polyhedron *Domain_Remove_Columns(Polyhedron *P, unsigned pos,
318 unsigned n)
320 Polyhedron *R;
321 Polyhedron **next = &R;
323 for (; P; P = P->next) {
324 *next = Polyhedron_Remove_Columns(P, pos, n);
325 next = &(*next)->next;
327 return R;
330 /* Drop n parameters starting at first from partition evalue e */
331 static void drop_parameters(evalue *e, int first, int n)
333 int i;
335 if (EVALUE_IS_ZERO(*e))
336 return;
338 assert(value_zero_p(e->d) && e->x.p->type == partition);
339 for (i = 0; i < e->x.p->size/2; ++i) {
340 Polyhedron *P = EVALUE_DOMAIN(e->x.p->arr[2*i]);
341 Polyhedron *Q = Domain_Remove_Columns(P, first, n);
342 EVALUE_SET_DOMAIN(e->x.p->arr[2*i], Q);
343 Domain_Free(P);
344 evalue_shift_variables(&e->x.p->arr[2*i+1], first, -n);
346 e->x.p->pos -= n;
349 static void extract_term_into(const evalue *src, int var, int exp, evalue *dst)
351 int i;
353 if (value_notzero_p(src->d) ||
354 src->x.p->type != polynomial ||
355 src->x.p->pos > var+1) {
356 if (exp == 0)
357 evalue_copy(dst, src);
358 else
359 evalue_set_si(dst, 0, 1);
360 return;
363 if (src->x.p->pos == var+1) {
364 if (src->x.p->size > exp)
365 evalue_copy(dst, &src->x.p->arr[exp]);
366 else
367 evalue_set_si(dst, 0, 1);
368 return;
371 dst->x.p = new_enode(polynomial, src->x.p->size, src->x.p->pos);
372 for (i = 0; i < src->x.p->size; ++i)
373 extract_term_into(&src->x.p->arr[i], var, exp,
374 &dst->x.p->arr[i]);
377 /* Extract the coefficient of var^exp.
379 static evalue *extract_term(const evalue *e, int var, int exp)
381 int i;
382 evalue *res;
384 if (EVALUE_IS_ZERO(*e))
385 return evalue_zero();
387 assert(value_zero_p(e->d) && e->x.p->type == partition);
388 res = ALLOC(evalue);
389 value_init(res->d);
390 res->x.p = new_enode(partition, e->x.p->size, e->x.p->pos);
391 for (i = 0; i < e->x.p->size/2; ++i) {
392 EVALUE_SET_DOMAIN(res->x.p->arr[2*i],
393 Domain_Copy(EVALUE_DOMAIN(e->x.p->arr[2*i])));
394 extract_term_into(&e->x.p->arr[2*i+1], var, exp,
395 &res->x.p->arr[2*i+1]);
396 reduce_evalue(&res->x.p->arr[2*i+1]);
398 return res;
401 /* Insert n free variables at pos (0-based) in the polyhedron P.
403 static Polyhedron *Polyhedron_Insert_Columns(Polyhedron *P, unsigned pos,
404 unsigned n)
406 int i;
407 unsigned NbConstraints = 0;
408 unsigned NbRays = 0;
409 Polyhedron *Q;
411 if (!P)
412 return P;
413 if (n == 0)
414 return P;
416 assert(pos <= P->Dimension);
418 if (POL_HAS(P, POL_INEQUALITIES))
419 NbConstraints = P->NbConstraints;
420 if (POL_HAS(P, POL_POINTS))
421 NbRays = P->NbRays + n;
423 Q = Polyhedron_Alloc(P->Dimension+n, NbConstraints, NbRays);
424 if (POL_HAS(P, POL_INEQUALITIES)) {
425 Q->NbEq = P->NbEq;
426 for (i = 0; i < P->NbConstraints; ++i) {
427 Vector_Copy(P->Constraint[i], Q->Constraint[i], 1+pos);
428 Vector_Copy(P->Constraint[i]+1+pos, Q->Constraint[i]+1+pos+n,
429 P->Dimension-pos+1);
432 if (POL_HAS(P, POL_POINTS)) {
433 Q->NbBid = P->NbBid + n;
434 for (i = 0; i < n; ++i)
435 value_set_si(Q->Ray[i][1+pos+i], 1);
436 for (i = 0; i < P->NbRays; ++i) {
437 Vector_Copy(P->Ray[i], Q->Ray[n+i], 1+pos);
438 Vector_Copy(P->Ray[i]+1+pos, Q->Ray[n+i]+1+pos+n,
439 P->Dimension-pos+1);
442 POL_SET(Q, POL_VALID);
443 if (POL_HAS(P, POL_INEQUALITIES))
444 POL_SET(Q, POL_INEQUALITIES);
445 if (POL_HAS(P, POL_POINTS))
446 POL_SET(Q, POL_POINTS);
447 if (POL_HAS(P, POL_VERTICES))
448 POL_SET(Q, POL_VERTICES);
449 return Q;
452 /* Perform summation of e over a list of 1 or more factors F, with context C.
453 * nvar is the total number of variables in the remaining factors.
454 * extra is the number of placeholder parameters introduced in e,
455 * but not (yet) in F or C.
457 * If there is only one factor left, F is intersected with the
458 * context C, the placeholder variables are added, and then
459 * e is summed over the resulting parametric polytope.
461 * If there is more than one factor left, we create two polynomials
462 * in a new placeholder variable (which is placed after the regular
463 * parameters, but before any previously introduced placeholder
464 * variables) that has the factors of the variables in the first
465 * factor of F and the factor of the remaining variables of
466 * each term as its coefficients.
467 * These two polynomials are then summed over their domains
468 * and afterwards the results are combined and the placeholder
469 * variable is removed again.
471 static evalue *sum_factors(Polyhedron *F, Polyhedron *C, evalue *e,
472 unsigned nvar, unsigned extra,
473 struct barvinok_options *options)
475 unsigned nparam = C->Dimension;
476 unsigned F_var = F->Dimension - C->Dimension;
477 int i, n;
478 evalue *s1, *s2, *s;
479 evalue *ph;
481 if (!F->next) {
482 Polyhedron *CA = align_context(C, nvar+nparam, options->MaxRays);
483 Polyhedron *P = DomainIntersection(F, CA, options->MaxRays);
484 Polyhedron *Q = Polyhedron_Insert_Columns(P, nvar+nparam, extra);
485 Polyhedron_Free(CA);
486 Polyhedron_Free(F);
487 Polyhedron_Free(P);
488 evalue *sum = sum_base(Q, e, nvar, options);
489 Polyhedron_Free(Q);
490 return sum;
493 n = evalue_count_terms(e, F_var, 0);
494 ph = create_placeholder(n, nvar+nparam);
495 evalue_shift_variables(e, nvar+nparam, 1);
496 evalue_unzip_terms(e, ph, F_var, 0);
497 evalue_shift_variables(e, nvar, -(nvar-F_var));
498 evalue_reorder_terms(ph);
499 evalue_shift_variables(ph, 0, -F_var);
501 s2 = sum_factors(F->next, C, ph, nvar-F_var, extra+1, options);
502 evalue_free(ph);
503 F->next = NULL;
504 s1 = sum_factors(F, C, e, F_var, extra+1, options);
506 if (n == 1) {
507 /* remove placeholder "polynomial" */
508 reduce_evalue(s1);
509 emul(s1, s2);
510 evalue_free(s1);
511 drop_parameters(s2, nparam, 1);
512 return s2;
515 s = evalue_zero();
516 for (i = 0; i < n; ++i) {
517 evalue *t1, *t2;
518 t1 = extract_term(s1, nparam, i);
519 t2 = extract_term(s2, nparam, i);
520 emul(t1, t2);
521 eadd(t2, s);
522 evalue_free(t1);
523 evalue_free(t2);
525 evalue_free(s1);
526 evalue_free(s2);
528 drop_parameters(s, nparam, 1);
529 return s;
532 /* Perform summation over a product of factors F, obtained using
533 * variable transformation T from the original problem specification.
535 * We first perform the corresponding transformation on the polynomial E,
536 * compute the common context over all factors and then perform
537 * the actual summation over the factors.
539 static evalue *sum_product(Polyhedron *F, evalue *E, Matrix *T, unsigned nparam,
540 struct barvinok_options *options)
542 int i;
543 Matrix *T2;
544 unsigned nvar = T->NbRows;
545 Polyhedron *C;
546 evalue *sum;
548 assert(nvar == T->NbColumns);
549 T2 = Matrix_Alloc(nvar+1, nvar+1);
550 for (i = 0; i < nvar; ++i)
551 Vector_Copy(T->p[i], T2->p[i], nvar);
552 value_set_si(T2->p[nvar][nvar], 1);
554 transform_polynomial(E, T2, NULL, nvar, nparam, nvar, nparam);
556 C = Factor_Context(F, nparam, options->MaxRays);
557 if (F->Dimension == nparam) {
558 Polyhedron *T = F;
559 F = F->next;
560 T->next = NULL;
561 Polyhedron_Free(T);
563 sum = sum_factors(F, C, E, nvar, 0, options);
565 Polyhedron_Free(C);
566 Matrix_Free(T2);
567 Matrix_Free(T);
568 return sum;
571 /* Add two constraints corresponding to floor = floor(e/d),
573 * e - d t >= 0
574 * -e + d t + d-1 >= 0
576 * e is assumed to be an affine expression.
578 Polyhedron *add_floor_var(Polyhedron *P, unsigned nvar, const evalue *floor,
579 struct barvinok_options *options)
581 int i;
582 unsigned dim = P->Dimension+1;
583 Matrix *M = Matrix_Alloc(P->NbConstraints+2, 2+dim);
584 Polyhedron *CP;
585 Value *d = &M->p[0][1+nvar];
586 evalue_extract_affine(floor, M->p[0]+1, M->p[0]+1+dim, d);
587 value_oppose(*d, *d);
588 value_set_si(M->p[0][0], 1);
589 value_set_si(M->p[1][0], 1);
590 Vector_Oppose(M->p[0]+1, M->p[1]+1, M->NbColumns-1);
591 value_subtract(M->p[1][1+dim], M->p[1][1+dim], *d);
592 value_decrement(M->p[1][1+dim], M->p[1][1+dim]);
594 for (i = 0; i < P->NbConstraints; ++i) {
595 Vector_Copy(P->Constraint[i], M->p[i+2], 1+nvar);
596 Vector_Copy(P->Constraint[i]+1+nvar, M->p[i+2]+1+nvar+1, dim-nvar-1+1);
599 CP = Constraints2Polyhedron(M, options->MaxRays);
600 Matrix_Free(M);
601 return CP;
604 static evalue *evalue_add(evalue *a, evalue *b)
606 if (!a)
607 return b;
608 if (!b)
609 return a;
610 eadd(a, b);
611 evalue_free(a);
612 return b;
615 /* Compute sum of a step-polynomial over a polytope by grouping
616 * terms containing the same floor-expressions and introducing
617 * new variables for each such expression.
618 * In particular, while there is any floor-expression left,
619 * the step-polynomial is split into a polynomial containing
620 * the expression, which is then converted to a new variable,
621 * and a polynomial not containing the expression.
623 static evalue *sum_step_polynomial(Polyhedron *P, evalue *E, unsigned nvar,
624 struct barvinok_options *options)
626 evalue *floor;
627 evalue *cur = E;
628 evalue *sum = NULL;
629 evalue *t;
631 while ((floor = evalue_outer_floor(cur))) {
632 Polyhedron *CP;
633 evalue *converted;
634 evalue *converted_floor;
636 /* Ignore floors that do not depend on variables. */
637 if (value_notzero_p(floor->d) || floor->x.p->pos >= nvar+1)
638 break;
640 converted = evalue_dup(cur);
641 converted_floor = evalue_dup(floor);
642 evalue_shift_variables(converted, nvar, 1);
643 evalue_shift_variables(converted_floor, nvar, 1);
644 evalue_replace_floor(converted, converted_floor, nvar);
645 CP = add_floor_var(P, nvar, converted_floor, options);
646 evalue_free(converted_floor);
647 t = sum_step_polynomial(CP, converted, nvar+1, options);
648 evalue_free(converted);
649 Polyhedron_Free(CP);
650 sum = evalue_add(t, sum);
652 if (cur == E)
653 cur = evalue_dup(cur);
654 evalue_drop_floor(cur, floor);
655 evalue_free(floor);
657 if (floor) {
658 evalue_floor2frac(cur);
659 evalue_free(floor);
662 if (EVALUE_IS_ZERO(*cur))
663 t = NULL;
664 else {
665 Matrix *T;
666 unsigned nparam = P->Dimension - nvar;
667 Polyhedron *F = Polyhedron_Factor(P, nparam, &T, options->MaxRays);
668 if (!F)
669 t = sum_base(P, cur, nvar, options);
670 else {
671 if (cur == E)
672 cur = evalue_dup(cur);
673 t = sum_product(F, cur, T, nparam, options);
677 if (E != cur)
678 evalue_free(cur);
680 return evalue_add(t, sum);
683 evalue *barvinok_sum_over_polytope(Polyhedron *P, evalue *E, unsigned nvar,
684 struct evalue_section_array *sections,
685 struct barvinok_options *options)
687 if (P->NbEq)
688 return sum_over_polytope_with_equalities(P, E, nvar, sections, options);
690 if (nvar == 0)
691 return sum_over_polytope_0D(Polyhedron_Copy(P), evalue_dup(E));
693 if (options->summation == BV_SUM_BERNOULLI)
694 return bernoulli_summate(P, E, nvar, sections, options);
695 else if (options->summation == BV_SUM_BOX)
696 return box_summate(P, E, nvar, options->MaxRays);
698 evalue_frac2floor2(E, 0);
700 return sum_step_polynomial(P, E, nvar, options);
703 evalue *barvinok_summate(evalue *e, int nvar, struct barvinok_options *options)
705 int i;
706 struct evalue_section_array sections;
707 evalue *sum;
709 assert(nvar >= 0);
710 if (nvar == 0 || EVALUE_IS_ZERO(*e))
711 return evalue_dup(e);
713 assert(value_zero_p(e->d));
714 assert(e->x.p->type == partition);
716 evalue_section_array_init(&sections);
717 sum = evalue_zero();
719 for (i = 0; i < e->x.p->size/2; ++i) {
720 Polyhedron *D;
721 for (D = EVALUE_DOMAIN(e->x.p->arr[2*i]); D; D = D->next) {
722 Polyhedron *next = D->next;
723 evalue *tmp;
724 D->next = NULL;
726 tmp = barvinok_sum_over_polytope(D, &e->x.p->arr[2*i+1], nvar,
727 &sections, options);
728 assert(tmp);
729 eadd(tmp, sum);
730 evalue_free(tmp);
732 D->next = next;
736 free(sections.s);
738 reduce_evalue(sum);
739 return sum;
742 static __isl_give isl_pw_qpolynomial *add_unbounded_guarded_qp(
743 __isl_take isl_pw_qpolynomial *sum,
744 __isl_take isl_basic_set *bset, __isl_take isl_qpolynomial *qp)
746 int zero;
748 if (!sum || !bset || !qp)
749 goto error;
751 zero = isl_qpolynomial_is_zero(qp);
752 if (zero < 0)
753 goto error;
755 if (!zero) {
756 isl_space *space;
757 isl_set *set;
758 isl_pw_qpolynomial *pwqp;
760 space = isl_pw_qpolynomial_get_domain_space(sum);
761 set = isl_set_from_basic_set(isl_basic_set_copy(bset));
762 set = isl_map_domain(isl_map_from_range(set));
763 set = isl_set_reset_space(set, isl_space_copy(space));
764 pwqp = isl_pw_qpolynomial_alloc(set,
765 isl_qpolynomial_nan_on_domain(space));
766 sum = isl_pw_qpolynomial_add(sum, pwqp);
769 isl_basic_set_free(bset);
770 isl_qpolynomial_free(qp);
771 return sum;
772 error:
773 isl_basic_set_free(bset);
774 isl_qpolynomial_free(qp);
775 isl_pw_qpolynomial_free(sum);
776 return NULL;
779 struct barvinok_summate_data {
780 isl_space *space;
781 isl_qpolynomial *qp;
782 isl_pw_qpolynomial *sum;
783 int n_in;
784 int wrapping;
785 evalue *e;
786 struct evalue_section_array sections;
787 struct barvinok_options *options;
790 static isl_stat add_basic_guarded_qp(__isl_take isl_basic_set *bset, void *user)
792 struct barvinok_summate_data *data = user;
793 Polyhedron *P;
794 evalue *tmp;
795 isl_pw_qpolynomial *pwqp;
796 int bounded;
797 unsigned nvar = isl_basic_set_dim(bset, isl_dim_set);
798 isl_space *space;
800 if (!bset)
801 return isl_stat_error;
803 bounded = isl_basic_set_is_bounded(bset);
804 if (bounded < 0)
805 goto error;
807 if (!bounded) {
808 data->sum = add_unbounded_guarded_qp(data->sum, bset,
809 isl_qpolynomial_copy(data->qp));
810 return isl_stat_ok;
813 space = isl_space_params(isl_basic_set_get_space(bset));
815 P = isl_basic_set_to_polylib(bset);
816 tmp = barvinok_sum_over_polytope(P, data->e, nvar,
817 &data->sections, data->options);
818 Polyhedron_Free(P);
819 assert(tmp);
820 pwqp = isl_pw_qpolynomial_from_evalue(space, tmp);
821 evalue_free(tmp);
822 pwqp = isl_pw_qpolynomial_reset_domain_space(pwqp,
823 isl_space_domain(isl_space_copy(data->space)));
824 data->sum = isl_pw_qpolynomial_add(data->sum, pwqp);
826 isl_basic_set_free(bset);
828 return isl_stat_ok;
829 error:
830 isl_basic_set_free(bset);
831 return isl_stat_error;
834 static isl_stat add_guarded_qp(__isl_take isl_set *set,
835 __isl_take isl_qpolynomial *qp, void *user)
837 isl_stat r;
838 struct barvinok_summate_data *data = user;
840 if (!set || !qp)
841 goto error;
843 data->qp = qp;
845 if (data->wrapping) {
846 unsigned nparam = isl_set_dim(set, isl_dim_param);
847 isl_qpolynomial *qp2 = isl_qpolynomial_copy(qp);
848 set = isl_set_move_dims(set, isl_dim_param, nparam,
849 isl_dim_set, 0, data->n_in);
850 qp2 = isl_qpolynomial_move_dims(qp2, isl_dim_param, nparam,
851 isl_dim_in, 0, data->n_in);
852 data->e = isl_qpolynomial_to_evalue(qp2);
853 isl_qpolynomial_free(qp2);
854 } else
855 data->e = isl_qpolynomial_to_evalue(qp);
856 if (!data->e)
857 goto error;
859 evalue_section_array_init(&data->sections);
861 set = isl_set_make_disjoint(set);
862 set = isl_set_compute_divs(set);
864 r = isl_set_foreach_basic_set(set, &add_basic_guarded_qp, data);
866 free(data->sections.s);
868 evalue_free(data->e);
870 isl_set_free(set);
871 isl_qpolynomial_free(qp);
873 return r;
874 error:
875 isl_set_free(set);
876 isl_qpolynomial_free(qp);
877 return isl_stat_error;
880 __isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_sum(
881 __isl_take isl_pw_qpolynomial *pwqp)
883 isl_ctx *ctx;
884 struct barvinok_summate_data data;
885 int options_allocated = 0;
886 int nvar;
888 data.space = NULL;
889 data.options = NULL;
890 data.sum = NULL;
892 if (!pwqp)
893 return NULL;
895 nvar = isl_pw_qpolynomial_dim(pwqp, isl_dim_set);
897 data.space = isl_pw_qpolynomial_get_domain_space(pwqp);
898 if (!data.space)
899 goto error;
900 if (isl_space_is_params(data.space))
901 isl_die(isl_pw_qpolynomial_get_ctx(pwqp), isl_error_invalid,
902 "input polynomial has no domain", goto error);
903 data.wrapping = isl_space_is_wrapping(data.space);
904 if (data.wrapping) {
905 data.space = isl_space_unwrap(data.space);
906 data.n_in = isl_space_dim(data.space, isl_dim_in);
907 nvar = isl_space_dim(data.space, isl_dim_out);
908 } else
909 data.n_in = 0;
911 data.space = isl_space_domain(data.space);
912 if (nvar == 0)
913 return isl_pw_qpolynomial_reset_domain_space(pwqp, data.space);
915 data.space = isl_space_from_domain(data.space);
916 data.space = isl_space_add_dims(data.space, isl_dim_out, 1);
917 data.sum = isl_pw_qpolynomial_zero(isl_space_copy(data.space));
919 ctx = isl_pw_qpolynomial_get_ctx(pwqp);
920 data.options = isl_ctx_peek_barvinok_options(ctx);
921 if (!data.options) {
922 data.options = barvinok_options_new_with_defaults();
923 options_allocated = 1;
926 if (isl_pw_qpolynomial_foreach_lifted_piece(pwqp,
927 add_guarded_qp, &data) < 0)
928 goto error;
930 if (options_allocated)
931 barvinok_options_free(data.options);
933 isl_space_free(data.space);
935 isl_pw_qpolynomial_free(pwqp);
937 return data.sum;
938 error:
939 if (options_allocated)
940 barvinok_options_free(data.options);
941 isl_pw_qpolynomial_free(pwqp);
942 isl_space_free(data.space);
943 isl_pw_qpolynomial_free(data.sum);
944 return NULL;
947 static isl_stat pw_qpolynomial_sum(__isl_take isl_pw_qpolynomial *pwqp,
948 void *user)
950 isl_union_pw_qpolynomial **res = (isl_union_pw_qpolynomial **)user;
951 isl_pw_qpolynomial *sum;
952 isl_union_pw_qpolynomial *upwqp;
954 sum = isl_pw_qpolynomial_sum(pwqp);
955 upwqp = isl_union_pw_qpolynomial_from_pw_qpolynomial(sum);
956 *res = isl_union_pw_qpolynomial_add(*res, upwqp);
958 return isl_stat_ok;
961 __isl_give isl_union_pw_qpolynomial *isl_union_pw_qpolynomial_sum(
962 __isl_take isl_union_pw_qpolynomial *upwqp)
964 isl_space *space;
965 isl_union_pw_qpolynomial *res;
967 space = isl_union_pw_qpolynomial_get_space(upwqp);
968 res = isl_union_pw_qpolynomial_zero(space);
969 if (isl_union_pw_qpolynomial_foreach_pw_qpolynomial(upwqp,
970 &pw_qpolynomial_sum, &res) < 0)
971 goto error;
972 isl_union_pw_qpolynomial_free(upwqp);
974 return res;
975 error:
976 isl_union_pw_qpolynomial_free(upwqp);
977 isl_union_pw_qpolynomial_free(res);
978 return NULL;
981 static int join_compatible(__isl_keep isl_space *space1,
982 __isl_keep isl_space *space2)
984 int m;
985 m = isl_space_has_equal_params(space1, space2);
986 if (m < 0 || !m)
987 return m;
988 return isl_space_tuple_is_equal(space1, isl_dim_out,
989 space2, isl_dim_in);
992 /* Compute the intersection of the range of the map and the domain
993 * of the piecewise quasipolynomial and then sum the associated
994 * quasipolynomial over all elements in this intersection.
996 * We first introduce some unconstrained dimensions in the
997 * piecewise quasipolynomial, intersect the resulting domain
998 * with the wrapped map and then compute the sum.
1000 __isl_give isl_pw_qpolynomial *isl_map_apply_pw_qpolynomial(
1001 __isl_take isl_map *map, __isl_take isl_pw_qpolynomial *pwqp)
1003 isl_ctx *ctx;
1004 isl_set *dom;
1005 isl_space *map_space;
1006 isl_space *pwqp_space;
1007 unsigned n_in;
1008 int ok;
1010 ctx = isl_map_get_ctx(map);
1011 if (!ctx)
1012 goto error;
1014 map_space = isl_map_get_space(map);
1015 pwqp_space = isl_pw_qpolynomial_get_space(pwqp);
1016 ok = join_compatible(map_space, pwqp_space);
1017 isl_space_free(map_space);
1018 isl_space_free(pwqp_space);
1019 if (!ok)
1020 isl_die(ctx, isl_error_invalid, "incompatible dimensions",
1021 goto error);
1023 n_in = isl_map_dim(map, isl_dim_in);
1024 pwqp = isl_pw_qpolynomial_insert_dims(pwqp, isl_dim_in, 0, n_in);
1026 dom = isl_map_wrap(map);
1027 pwqp = isl_pw_qpolynomial_reset_domain_space(pwqp,
1028 isl_set_get_space(dom));
1030 pwqp = isl_pw_qpolynomial_intersect_domain(pwqp, dom);
1031 pwqp = isl_pw_qpolynomial_sum(pwqp);
1033 return pwqp;
1034 error:
1035 isl_map_free(map);
1036 isl_pw_qpolynomial_free(pwqp);
1037 return NULL;
1040 __isl_give isl_pw_qpolynomial *isl_set_apply_pw_qpolynomial(
1041 __isl_take isl_set *set, __isl_take isl_pw_qpolynomial *pwqp)
1043 isl_map *map;
1045 map = isl_map_from_range(set);
1046 pwqp = isl_map_apply_pw_qpolynomial(map, pwqp);
1047 pwqp = isl_pw_qpolynomial_project_domain_on_params(pwqp);
1048 return pwqp;
1051 struct barvinok_apply_data {
1052 isl_union_pw_qpolynomial *upwqp;
1053 isl_union_pw_qpolynomial *res;
1054 isl_map *map;
1057 static isl_stat pw_qpolynomial_apply(__isl_take isl_pw_qpolynomial *pwqp,
1058 void *user)
1060 isl_space *map_space;
1061 isl_space *pwqp_space;
1062 struct barvinok_apply_data *data = user;
1063 int ok;
1065 map_space = isl_map_get_space(data->map);
1066 pwqp_space = isl_pw_qpolynomial_get_space(pwqp);
1067 ok = join_compatible(map_space, pwqp_space);
1068 isl_space_free(map_space);
1069 isl_space_free(pwqp_space);
1071 if (ok) {
1072 isl_union_pw_qpolynomial *upwqp;
1074 pwqp = isl_map_apply_pw_qpolynomial(isl_map_copy(data->map),
1075 pwqp);
1076 upwqp = isl_union_pw_qpolynomial_from_pw_qpolynomial(pwqp);
1077 data->res = isl_union_pw_qpolynomial_add(data->res, upwqp);
1078 } else
1079 isl_pw_qpolynomial_free(pwqp);
1081 return isl_stat_ok;
1084 static isl_stat map_apply(__isl_take isl_map *map, void *user)
1086 struct barvinok_apply_data *data = user;
1087 isl_stat r;
1089 data->map = map;
1090 r = isl_union_pw_qpolynomial_foreach_pw_qpolynomial(data->upwqp,
1091 &pw_qpolynomial_apply, data);
1093 isl_map_free(map);
1094 return r;
1097 __isl_give isl_union_pw_qpolynomial *isl_union_map_apply_union_pw_qpolynomial(
1098 __isl_take isl_union_map *umap,
1099 __isl_take isl_union_pw_qpolynomial *upwqp)
1101 isl_space *space;
1102 struct barvinok_apply_data data;
1104 upwqp = isl_union_pw_qpolynomial_align_params(upwqp,
1105 isl_union_map_get_space(umap));
1106 umap = isl_union_map_align_params(umap,
1107 isl_union_pw_qpolynomial_get_space(upwqp));
1109 data.upwqp = upwqp;
1110 space = isl_union_pw_qpolynomial_get_space(upwqp);
1111 data.res = isl_union_pw_qpolynomial_zero(space);
1112 if (isl_union_map_foreach_map(umap, &map_apply, &data) < 0)
1113 goto error;
1115 isl_union_map_free(umap);
1116 isl_union_pw_qpolynomial_free(upwqp);
1118 return data.res;
1119 error:
1120 isl_union_map_free(umap);
1121 isl_union_pw_qpolynomial_free(upwqp);
1122 isl_union_pw_qpolynomial_free(data.res);
1123 return NULL;
1126 struct barvinok_apply_set_data {
1127 isl_union_pw_qpolynomial *upwqp;
1128 isl_union_pw_qpolynomial *res;
1129 isl_set *set;
1132 static isl_stat pw_qpolynomial_apply_set(__isl_take isl_pw_qpolynomial *pwqp,
1133 void *user)
1135 isl_space *set_space;
1136 isl_space *pwqp_space;
1137 struct barvinok_apply_set_data *data = user;
1138 int ok;
1140 set_space = isl_set_get_space(data->set);
1141 pwqp_space = isl_pw_qpolynomial_get_space(pwqp);
1142 ok = join_compatible(set_space, pwqp_space);
1143 isl_space_free(set_space);
1144 isl_space_free(pwqp_space);
1146 if (ok) {
1147 isl_union_pw_qpolynomial *upwqp;
1149 pwqp = isl_set_apply_pw_qpolynomial(isl_set_copy(data->set),
1150 pwqp);
1151 upwqp = isl_union_pw_qpolynomial_from_pw_qpolynomial(pwqp);
1152 data->res = isl_union_pw_qpolynomial_add(data->res, upwqp);
1153 } else
1154 isl_pw_qpolynomial_free(pwqp);
1156 return isl_stat_ok;
1159 static isl_stat set_apply(__isl_take isl_set *set, void *user)
1161 struct barvinok_apply_set_data *data = user;
1162 isl_stat r;
1164 data->set = set;
1165 r = isl_union_pw_qpolynomial_foreach_pw_qpolynomial(data->upwqp,
1166 &pw_qpolynomial_apply_set, data);
1168 isl_set_free(set);
1169 return r;
1172 __isl_give isl_union_pw_qpolynomial *isl_union_set_apply_union_pw_qpolynomial(
1173 __isl_take isl_union_set *uset,
1174 __isl_take isl_union_pw_qpolynomial *upwqp)
1176 isl_space *space;
1177 struct barvinok_apply_set_data data;
1179 upwqp = isl_union_pw_qpolynomial_align_params(upwqp,
1180 isl_union_set_get_space(uset));
1181 uset = isl_union_set_align_params(uset,
1182 isl_union_pw_qpolynomial_get_space(upwqp));
1184 data.upwqp = upwqp;
1185 space = isl_union_pw_qpolynomial_get_space(upwqp);
1186 data.res = isl_union_pw_qpolynomial_zero(space);
1187 if (isl_union_set_foreach_set(uset, &set_apply, &data) < 0)
1188 goto error;
1190 isl_union_set_free(uset);
1191 isl_union_pw_qpolynomial_free(upwqp);
1193 return data.res;
1194 error:
1195 isl_union_set_free(uset);
1196 isl_union_pw_qpolynomial_free(upwqp);
1197 isl_union_pw_qpolynomial_free(data.res);
1198 return NULL;
1201 evalue *evalue_sum(evalue *E, int nvar, unsigned MaxRays)
1203 evalue *sum;
1204 struct barvinok_options *options = barvinok_options_new_with_defaults();
1205 options->MaxRays = MaxRays;
1206 sum = barvinok_summate(E, nvar, options);
1207 barvinok_options_free(options);
1208 return sum;
1211 evalue *esum(evalue *e, int nvar)
1213 evalue *sum;
1214 struct barvinok_options *options = barvinok_options_new_with_defaults();
1215 sum = barvinok_summate(e, nvar, options);
1216 barvinok_options_free(options);
1217 return sum;
1220 /* Turn unweighted counting problem into "weighted" counting problem
1221 * with weight equal to 1 and call barvinok_summate on this weighted problem.
1223 evalue *barvinok_summate_unweighted(Polyhedron *P, Polyhedron *C,
1224 struct barvinok_options *options)
1226 Polyhedron *CA, *D;
1227 evalue e;
1228 evalue *sum;
1230 if (emptyQ(P) || emptyQ(C))
1231 return evalue_zero();
1233 CA = align_context(C, P->Dimension, options->MaxRays);
1234 D = DomainIntersection(P, CA, options->MaxRays);
1235 Domain_Free(CA);
1237 if (emptyQ(D)) {
1238 Domain_Free(D);
1239 return evalue_zero();
1242 value_init(e.d);
1243 e.x.p = new_enode(partition, 2, P->Dimension);
1244 EVALUE_SET_DOMAIN(e.x.p->arr[0], D);
1245 evalue_set_si(&e.x.p->arr[1], 1, 1);
1246 sum = barvinok_summate(&e, P->Dimension - C->Dimension, options);
1247 free_evalue_refs(&e);
1248 return sum;