test_bound: compare polynomial bound algorithms
[barvinok/uuh.git] / bernoulli.c
blob494e9682b11a156963a3278d786b740ce844da24
1 #include <assert.h>
2 #include <barvinok/options.h>
3 #include <barvinok/util.h>
4 #include "bernoulli.h"
5 #include "lattice_point.h"
7 #define ALLOC(type) (type*)malloc(sizeof(type))
8 #define ALLOCN(type,n) (type*)malloc((n) * sizeof(type))
9 #define REALLOCN(ptr,type,n) (type*)realloc(ptr, (n) * sizeof(type))
11 static struct bernoulli_coef bernoulli_coef;
12 static struct poly_list bernoulli;
13 static struct poly_list faulhaber;
15 struct bernoulli_coef *bernoulli_coef_compute(int n)
17 int i, j;
18 Value factor, tmp;
20 if (n < bernoulli_coef.n)
21 return &bernoulli_coef;
23 if (n >= bernoulli_coef.size) {
24 int size = 3*(n + 5)/2;
25 Vector *b;
27 b = Vector_Alloc(size);
28 if (bernoulli_coef.n) {
29 Vector_Copy(bernoulli_coef.num->p, b->p, bernoulli_coef.n);
30 Vector_Free(bernoulli_coef.num);
32 bernoulli_coef.num = b;
33 b = Vector_Alloc(size);
34 if (bernoulli_coef.n) {
35 Vector_Copy(bernoulli_coef.den->p, b->p, bernoulli_coef.n);
36 Vector_Free(bernoulli_coef.den);
38 bernoulli_coef.den = b;
39 b = Vector_Alloc(size);
40 if (bernoulli_coef.n) {
41 Vector_Copy(bernoulli_coef.lcm->p, b->p, bernoulli_coef.n);
42 Vector_Free(bernoulli_coef.lcm);
44 bernoulli_coef.lcm = b;
46 bernoulli_coef.size = size;
48 value_init(factor);
49 value_init(tmp);
50 for (i = bernoulli_coef.n; i <= n; ++i) {
51 if (i == 0) {
52 value_set_si(bernoulli_coef.num->p[0], 1);
53 value_set_si(bernoulli_coef.den->p[0], 1);
54 value_set_si(bernoulli_coef.lcm->p[0], 1);
55 continue;
57 value_set_si(bernoulli_coef.num->p[i], 0);
58 value_set_si(factor, -(i+1));
59 for (j = i-1; j >= 0; --j) {
60 mpz_mul_ui(factor, factor, j+1);
61 mpz_divexact_ui(factor, factor, i+1-j);
62 value_division(tmp, bernoulli_coef.lcm->p[i-1],
63 bernoulli_coef.den->p[j]);
64 value_multiply(tmp, tmp, bernoulli_coef.num->p[j]);
65 value_multiply(tmp, tmp, factor);
66 value_addto(bernoulli_coef.num->p[i], bernoulli_coef.num->p[i], tmp);
68 mpz_mul_ui(bernoulli_coef.den->p[i], bernoulli_coef.lcm->p[i-1], i+1);
69 value_gcd(tmp, bernoulli_coef.num->p[i], bernoulli_coef.den->p[i]);
70 if (value_notone_p(tmp)) {
71 value_division(bernoulli_coef.num->p[i],
72 bernoulli_coef.num->p[i], tmp);
73 value_division(bernoulli_coef.den->p[i],
74 bernoulli_coef.den->p[i], tmp);
76 value_lcm(bernoulli_coef.lcm->p[i],
77 bernoulli_coef.lcm->p[i-1], bernoulli_coef.den->p[i]);
79 bernoulli_coef.n = n+1;
80 value_clear(factor);
81 value_clear(tmp);
83 return &bernoulli_coef;
87 * Compute either Bernoulli B_n or Faulhaber F_n polynomials.
89 * B_n = sum_{k=0}^n { n \choose k } b_k x^{n-k}
90 * F_n = 1/(n+1) sum_{k=0}^n { n+1 \choose k } b_k x^{n+1-k}
92 static struct poly_list *bernoulli_faulhaber_compute(int n, struct poly_list *pl,
93 int faulhaber)
95 int i, j;
96 Value factor;
97 struct bernoulli_coef *bc;
99 if (n < pl->n)
100 return pl;
102 if (n >= pl->size) {
103 int size = 3*(n + 5)/2;
104 Vector **poly;
106 poly = ALLOCN(Vector *, size);
107 for (i = 0; i < pl->n; ++i)
108 poly[i] = pl->poly[i];
109 free(pl->poly);
110 pl->poly = poly;
112 pl->size = size;
115 bc = bernoulli_coef_compute(n);
117 value_init(factor);
118 for (i = pl->n; i <= n; ++i) {
119 pl->poly[i] = Vector_Alloc(i+faulhaber+2);
120 value_assign(pl->poly[i]->p[i+faulhaber], bc->lcm->p[i]);
121 if (faulhaber)
122 mpz_mul_ui(pl->poly[i]->p[i+2], bc->lcm->p[i], i+1);
123 else
124 value_assign(pl->poly[i]->p[i+1], bc->lcm->p[i]);
125 value_set_si(factor, 1);
126 for (j = 1; j <= i; ++j) {
127 mpz_mul_ui(factor, factor, i+faulhaber+1-j);
128 mpz_divexact_ui(factor, factor, j);
129 value_division(pl->poly[i]->p[i+faulhaber-j],
130 bc->lcm->p[i], bc->den->p[j]);
131 value_multiply(pl->poly[i]->p[i+faulhaber-j],
132 pl->poly[i]->p[i+faulhaber-j], bc->num->p[j]);
133 value_multiply(pl->poly[i]->p[i+faulhaber-j],
134 pl->poly[i]->p[i+faulhaber-j], factor);
136 Vector_Normalize(pl->poly[i]->p, i+faulhaber+2);
138 value_clear(factor);
139 pl->n = n+1;
141 return pl;
144 struct poly_list *bernoulli_compute(int n)
146 return bernoulli_faulhaber_compute(n, &bernoulli, 0);
149 struct poly_list *faulhaber_compute(int n)
151 return bernoulli_faulhaber_compute(n, &faulhaber, 1);
154 /* shift variables in polynomial one down */
155 static void shift(evalue *e)
157 int i;
158 if (value_notzero_p(e->d))
159 return;
160 assert(e->x.p->type == polynomial || e->x.p->type == fractional);
161 if (e->x.p->type == polynomial) {
162 assert(e->x.p->pos > 1);
163 e->x.p->pos--;
165 for (i = 0; i < e->x.p->size; ++i)
166 shift(&e->x.p->arr[i]);
169 /* shift variables in polynomial n up */
170 static void unshift(evalue *e, unsigned n)
172 int i;
173 if (value_notzero_p(e->d))
174 return;
175 assert(e->x.p->type == polynomial || e->x.p->type == fractional);
176 if (e->x.p->type == polynomial)
177 e->x.p->pos += n;
178 for (i = 0; i < e->x.p->size; ++i)
179 unshift(&e->x.p->arr[i], n);
182 static evalue *shifted_copy(const evalue *src)
184 evalue *e = ALLOC(evalue);
185 value_init(e->d);
186 evalue_copy(e, src);
187 shift(e);
188 return e;
191 /* Computes the argument for the Faulhaber polynomial.
192 * If we are computing a polynomial approximation (exact == 0),
193 * then this is simply arg/denom.
194 * Otherwise, if neg == 0, then we are dealing with an upper bound
195 * and we need to compute floor(arg/denom) = arg/denom - { arg/denom }
196 * If neg == 1, then we are dealing with a lower bound
197 * and we need to compute ceil(arg/denom) = arg/denom + { -arg/denom }
199 * Modifies arg (if exact == 1).
201 static evalue *power_sums_base(Vector *arg, Value denom, int neg, int exact)
203 evalue *fract;
204 evalue *base = affine2evalue(arg->p, denom, arg->Size-1);
206 if (!exact || value_one_p(denom))
207 return base;
209 if (neg)
210 Vector_Oppose(arg->p, arg->p, arg->Size);
212 fract = fractional_part(arg->p, denom, arg->Size-1, NULL);
213 if (!neg) {
214 value_set_si(arg->p[0], -1);
215 evalue_mul(fract, arg->p[0]);
217 eadd(fract, base);
218 evalue_free(fract);
220 return base;
223 static evalue *power_sums(struct poly_list *faulhaber, const evalue *poly,
224 Vector *arg, Value denom, int neg, int alt_neg,
225 int exact)
227 int i;
228 evalue *base = power_sums_base(arg, denom, neg, exact);
229 evalue *sum = evalue_zero();
231 for (i = 1; i < poly->x.p->size; ++i) {
232 evalue *term = evalue_polynomial(faulhaber->poly[i], base);
233 evalue *factor = shifted_copy(&poly->x.p->arr[i]);
234 emul(factor, term);
235 if (alt_neg && (i % 2))
236 evalue_negate(term);
237 eadd(term, sum);
238 evalue_free(factor);
239 evalue_free(term);
241 if (neg)
242 evalue_negate(sum);
243 evalue_free(base);
245 return sum;
248 /* Given a constraint (cst_affine) a x + b y + c >= 0, compate a constraint (c)
249 * +- (b y + c) +- a >=,> 0
250 * ^ ^ ^
251 * | | strict
252 * sign_affine sign_cst
254 static void bound_constraint(Value *c, unsigned dim,
255 Value *cst_affine,
256 int sign_affine, int sign_cst, int strict)
258 if (sign_affine == -1)
259 Vector_Oppose(cst_affine+1, c, dim+1);
260 else
261 Vector_Copy(cst_affine+1, c, dim+1);
263 if (sign_cst == -1)
264 value_subtract(c[dim], c[dim], cst_affine[0]);
265 else if (sign_cst == 1)
266 value_addto(c[dim], c[dim], cst_affine[0]);
268 if (strict)
269 value_decrement(c[dim], c[dim]);
272 struct Bernoulli_data {
273 struct barvinok_options *options;
274 struct evalue_section *s;
275 int size;
276 int ns;
277 const evalue *e;
280 static evalue *compute_poly_u(evalue *poly_u, Value *upper, Vector *row,
281 unsigned dim, Value tmp,
282 struct poly_list *faulhaber,
283 struct Bernoulli_data *data)
285 int exact = data->options->approximation_method == BV_APPROX_NONE;
286 if (poly_u)
287 return poly_u;
288 Vector_Copy(upper+2, row->p, dim+1);
289 value_oppose(tmp, upper[1]);
290 value_addto(row->p[dim], row->p[dim], tmp);
291 return power_sums(faulhaber, data->e, row, tmp, 0, 0, exact);
294 static evalue *compute_poly_l(evalue *poly_l, Value *lower, Vector *row,
295 unsigned dim,
296 struct poly_list *faulhaber,
297 struct Bernoulli_data *data)
299 int exact = data->options->approximation_method == BV_APPROX_NONE;
300 if (poly_l)
301 return poly_l;
302 Vector_Copy(lower+2, row->p, dim+1);
303 value_addto(row->p[dim], row->p[dim], lower[1]);
304 return power_sums(faulhaber, data->e, row, lower[1], 0, 1, exact);
307 /* Compute sum of constant term.
309 static evalue *linear_term(const evalue *cst, Value *lower, Value *upper,
310 Vector *row, Value tmp, int exact)
312 evalue *linear;
313 unsigned dim = row->Size - 1;
315 if (EVALUE_IS_ZERO(*cst))
316 return evalue_zero();
318 if (!exact) {
319 value_absolute(tmp, upper[1]);
320 /* upper - lower */
321 Vector_Combine(lower+2, upper+2, row->p, tmp, lower[1], dim+1);
322 value_multiply(tmp, tmp, lower[1]);
323 /* upper - lower + 1 */
324 value_addto(row->p[dim], row->p[dim], tmp);
326 linear = affine2evalue(row->p, tmp, dim);
327 } else {
328 evalue *l;
330 value_absolute(tmp, upper[1]);
331 Vector_Copy(upper+2, row->p, dim+1);
332 value_addto(row->p[dim], row->p[dim], tmp);
333 /* floor(upper+1) */
334 linear = power_sums_base(row, tmp, 0, 1);
336 Vector_Copy(lower+2, row->p, dim+1);
337 /* floor(-lower) */
338 l = power_sums_base(row, lower[1], 0, 1);
340 /* floor(upper+1) + floor(-lower) = floor(upper) - ceil(lower) + 1 */
341 eadd(l, linear);
342 evalue_free(l);
345 emul(cst, linear);
346 return linear;
349 static void Bernoulli_init(unsigned n, void *cb_data)
351 struct Bernoulli_data *data = (struct Bernoulli_data *)cb_data;
352 int exact = data->options->approximation_method == BV_APPROX_NONE;
353 int cases = exact ? 3 : 5;
355 if (cases * n <= data->size)
356 return;
358 data->size = cases * (n + 16);
359 data->s = REALLOCN(data->s, struct evalue_section, data->size);
362 static void Bernoulli_cb(Matrix *M, Value *lower, Value *upper, void *cb_data);
365 * This function requires that either the lower or the upper bound
366 * represented by the constraints "lower" and "upper" is an integer
367 * affine expression.
368 * An affine substitution is performed to make this bound exactly
369 * zero, ensuring that in the recursive call to Bernoulli_cb,
370 * only one of the "cases" will apply.
372 static void transform_to_single_case(Matrix *M, Value *lower, Value *upper,
373 struct Bernoulli_data *data)
375 unsigned dim = M->NbColumns-2;
376 Vector *shadow;
377 Value a, b;
378 evalue **subs;
379 const evalue *e = data->e;
380 evalue *t;
381 int i;
383 value_init(a);
384 value_init(b);
385 subs = ALLOCN(evalue *, dim+1);
386 for (i = 0; i < dim; ++i)
387 subs[1+i] = evalue_var(1+i);
388 shadow = Vector_Alloc(2 * (2+dim+1));
389 if (value_one_p(lower[1])) {
390 /* Replace i by i + l' when b = 1 */
391 value_set_si(shadow->p[0], 1);
392 Vector_Oppose(lower+2, shadow->p+1, dim+1);
393 subs[0] = affine2evalue(shadow->p, shadow->p[0], dim+1);
394 /* new lower
395 * i >= 0
396 * new upper
397 * (-a i + u') + a (-l') >= 0
399 value_assign(shadow->p[2+dim+1+1], upper[1]);
400 value_oppose(a, upper[1]);
401 value_set_si(b, 1);
402 Vector_Combine(upper+2, lower+2, shadow->p+2+dim+1+2,
403 b, a, dim+1);
404 upper = shadow->p+2+dim+1;
405 lower = shadow->p;
406 value_set_si(lower[1], 1);
407 Vector_Set(lower+2, 0, dim+1);
408 } else {
409 /* Replace i by i + u' when a = 1 */
410 value_set_si(shadow->p[0], 1);
411 Vector_Copy(upper+2, shadow->p+1, dim+1);
412 subs[0] = affine2evalue(shadow->p, shadow->p[0], dim+1);
413 /* new lower
414 * (b i - l') + b u' >= 0
415 * new upper
416 * -i >= 0
418 value_assign(shadow->p[1], lower[1]);
419 value_set_si(a, 1);
420 value_assign(b, lower[1]);
421 Vector_Combine(upper+2, lower+2, shadow->p+2,
422 b, a, dim+1);
423 upper = shadow->p+2+dim+1;
424 lower = shadow->p;
425 value_set_si(upper[1], -1);
426 Vector_Set(upper+2, 0, dim+1);
428 value_clear(a);
429 value_clear(b);
431 t = evalue_dup(data->e);
432 evalue_substitute(t, subs);
433 reduce_evalue(t);
434 data->e = t;
435 for (i = 0; i < dim+1; ++i)
436 evalue_free(subs[i]);
437 free(subs);
439 Bernoulli_cb(M, lower, upper, data);
441 evalue_free(t);
442 data->e = e;
443 Vector_Free(shadow);
446 static void Bernoulli_cb(Matrix *M, Value *lower, Value *upper, void *cb_data)
448 struct Bernoulli_data *data = (struct Bernoulli_data *)cb_data;
449 Matrix *M2;
450 Polyhedron *T;
451 const evalue *factor = NULL;
452 evalue *linear = NULL;
453 int constant = 0;
454 Value tmp;
455 unsigned dim = M->NbColumns-2;
456 Vector *row;
457 int exact = data->options->approximation_method == BV_APPROX_NONE;
458 int cases = exact ? 3 : 5;
460 assert(lower);
461 assert(upper);
462 assert(data->ns + cases <= data->size);
464 M2 = Matrix_Copy(M);
465 T = Constraints2Polyhedron(M2, data->options->MaxRays);
466 Matrix_Free(M2);
468 POL_ENSURE_VERTICES(T);
469 if (emptyQ(T)) {
470 Polyhedron_Free(T);
471 return;
474 constant = value_notzero_p(data->e->d) ||
475 data->e->x.p->type != polynomial ||
476 data->e->x.p->pos != 1;
477 if (!constant && (value_one_p(lower[1]) || value_mone_p(upper[1]))) {
478 int single_case;
479 int lower_cst, upper_cst;
481 lower_cst = First_Non_Zero(lower+2, dim) == -1;
482 upper_cst = First_Non_Zero(upper+2, dim) == -1;
483 single_case =
484 (lower_cst && value_negz_p(lower[2+dim])) ||
485 (upper_cst && value_negz_p(upper[2+dim])) ||
486 (lower_cst && upper_cst &&
487 value_posz_p(lower[2+dim]) && value_posz_p(upper[2+dim]));
488 if (!single_case) {
489 transform_to_single_case(M, lower, upper, data);
490 Polyhedron_Free(T);
491 return;
495 assert(lower != upper);
497 row = Vector_Alloc(dim+1);
498 value_init(tmp);
499 if (value_notzero_p(data->e->d)) {
500 factor = data->e;
501 constant = 1;
502 } else {
503 if (data->e->x.p->type == polynomial && data->e->x.p->pos == 1)
504 factor = shifted_copy(&data->e->x.p->arr[0]);
505 else {
506 factor = shifted_copy(data->e);
507 constant = 1;
510 linear = linear_term(factor, lower, upper, row, tmp, exact);
512 if (constant) {
513 data->s[data->ns].E = linear;
514 data->s[data->ns].D = T;
515 ++data->ns;
516 data->options->stats->bernoulli_sums++;
517 } else {
518 evalue *poly_u = NULL, *poly_l = NULL;
519 Polyhedron *D;
520 struct poly_list *faulhaber;
521 assert(data->e->x.p->type == polynomial);
522 assert(data->e->x.p->pos == 1);
523 faulhaber = faulhaber_compute(data->e->x.p->size-1);
524 /* lower is the constraint
525 * b i - l' >= 0 i >= l'/b = l
526 * upper is the constraint
527 * -a i + u' >= 0 i <= u'/a = u
529 M2 = Matrix_Alloc(3, 2+T->Dimension);
530 value_set_si(M2->p[0][0], 1);
531 value_set_si(M2->p[1][0], 1);
532 value_set_si(M2->p[2][0], 1);
533 /* Case 1:
534 * 1 <= l l' - b >= 0
535 * 0 < l l' - 1 >= 0 if exact
537 if (exact)
538 bound_constraint(M2->p[0]+1, T->Dimension, lower+1, -1, 0, 1);
539 else
540 bound_constraint(M2->p[0]+1, T->Dimension, lower+1, -1, -1, 0);
541 D = AddConstraints(M2->p_Init, 1, T, data->options->MaxRays);
542 POL_ENSURE_VERTICES(D);
543 if (emptyQ2(D))
544 Polyhedron_Free(D);
545 else {
546 evalue *extra;
547 poly_u = compute_poly_u(poly_u, upper, row, dim, tmp,
548 faulhaber, data);
549 Vector_Oppose(lower+2, row->p, dim+1);
550 extra = power_sums(faulhaber, data->e, row, lower[1], 1, 0, exact);
551 eadd(poly_u, extra);
552 eadd(linear, extra);
554 data->s[data->ns].E = extra;
555 data->s[data->ns].D = D;
556 ++data->ns;
557 data->options->stats->bernoulli_sums++;
560 /* Case 2:
561 * 1 <= -u -u' - a >= 0
562 * 0 < -u -u' - 1 >= 0 if exact
564 if (exact)
565 bound_constraint(M2->p[0]+1, T->Dimension, upper+1, -1, 0, 1);
566 else
567 bound_constraint(M2->p[0]+1, T->Dimension, upper+1, -1, 1, 0);
568 D = AddConstraints(M2->p_Init, 1, T, data->options->MaxRays);
569 POL_ENSURE_VERTICES(D);
570 if (emptyQ2(D))
571 Polyhedron_Free(D);
572 else {
573 evalue *extra;
574 poly_l = compute_poly_l(poly_l, lower, row, dim, faulhaber, data);
575 Vector_Oppose(upper+2, row->p, dim+1);
576 value_oppose(tmp, upper[1]);
577 extra = power_sums(faulhaber, data->e, row, tmp, 1, 1, exact);
578 eadd(poly_l, extra);
579 eadd(linear, extra);
581 data->s[data->ns].E = extra;
582 data->s[data->ns].D = D;
583 ++data->ns;
584 data->options->stats->bernoulli_sums++;
587 /* Case 3:
588 * u >= 0 u' >= 0
589 * -l >= 0 -l' >= 0
591 bound_constraint(M2->p[0]+1, T->Dimension, upper+1, 1, 0, 0);
592 bound_constraint(M2->p[1]+1, T->Dimension, lower+1, 1, 0, 0);
593 D = AddConstraints(M2->p_Init, 2, T, data->options->MaxRays);
594 POL_ENSURE_VERTICES(D);
595 if (emptyQ2(D))
596 Polyhedron_Free(D);
597 else {
598 poly_l = compute_poly_l(poly_l, lower, row, dim, faulhaber, data);
599 poly_u = compute_poly_u(poly_u, upper, row, dim, tmp,
600 faulhaber, data);
602 data->s[data->ns].E = ALLOC(evalue);
603 value_init(data->s[data->ns].E->d);
604 evalue_copy(data->s[data->ns].E, poly_u);
605 eadd(poly_l, data->s[data->ns].E);
606 eadd(linear, data->s[data->ns].E);
607 data->s[data->ns].D = D;
608 ++data->ns;
609 data->options->stats->bernoulli_sums++;
612 if (!exact) {
613 /* Case 4:
614 * l < 1 -l' + b - 1 >= 0
615 * 0 < l l' - 1 >= 0
616 * u >= 1 u' - a >= 0
618 bound_constraint(M2->p[0]+1, T->Dimension, lower+1, 1, 1, 1);
619 bound_constraint(M2->p[1]+1, T->Dimension, lower+1, -1, 0, 1);
620 bound_constraint(M2->p[2]+1, T->Dimension, upper+1, 1, 1, 0);
621 D = AddConstraints(M2->p_Init, 3, T, data->options->MaxRays);
622 POL_ENSURE_VERTICES(D);
623 if (emptyQ2(D))
624 Polyhedron_Free(D);
625 else {
626 poly_u = compute_poly_u(poly_u, upper, row, dim, tmp,
627 faulhaber, data);
628 eadd(linear, poly_u);
629 data->s[data->ns].E = poly_u;
630 poly_u = NULL;
631 data->s[data->ns].D = D;
632 ++data->ns;
633 data->options->stats->bernoulli_sums++;
636 /* Case 5:
637 * -u < 1 u' + a - 1 >= 0
638 * 0 < -u -u' - 1 >= 0
639 * l <= -1 -l' - b >= 0
641 bound_constraint(M2->p[0]+1, T->Dimension, upper+1, 1, -1, 1);
642 bound_constraint(M2->p[1]+1, T->Dimension, upper+1, -1, 0, 1);
643 bound_constraint(M2->p[2]+1, T->Dimension, lower+1, 1, -1, 0);
644 D = AddConstraints(M2->p_Init, 3, T, data->options->MaxRays);
645 POL_ENSURE_VERTICES(D);
646 if (emptyQ2(D))
647 Polyhedron_Free(D);
648 else {
649 poly_l = compute_poly_l(poly_l, lower, row, dim,
650 faulhaber, data);
651 eadd(linear, poly_l);
652 data->s[data->ns].E = poly_l;
653 poly_l = NULL;
654 data->s[data->ns].D = D;
655 ++data->ns;
656 data->options->stats->bernoulli_sums++;
660 Matrix_Free(M2);
661 Polyhedron_Free(T);
662 if (poly_l)
663 evalue_free(poly_l);
664 if (poly_u)
665 evalue_free(poly_u);
666 evalue_free(linear);
668 if (factor != data->e)
669 evalue_free((evalue *)factor);
670 value_clear(tmp);
671 Vector_Free(row);
675 * Move the variable at position pos to the front by exchanging
676 * that variable with the first variable.
678 static void more_var_to_front(Polyhedron **P_p , evalue **E_p, int pos)
680 Polyhedron *P = *P_p;
681 evalue *E = *E_p;
682 unsigned dim = P->Dimension;
684 assert(pos != 0);
686 P = Polyhedron_Copy(P);
687 Polyhedron_ExchangeColumns(P, 1, 1+pos);
688 *P_p = P;
690 if (value_zero_p(E->d)) {
691 int j;
692 evalue **subs;
694 subs = ALLOCN(evalue *, dim);
695 for (j = 0; j < dim; ++j)
696 subs[j] = evalue_var(j);
697 E = subs[0];
698 subs[0] = subs[pos];
699 subs[pos] = E;
700 E = evalue_dup(*E_p);
701 evalue_substitute(E, subs);
702 for (j = 0; j < dim; ++j)
703 evalue_free(subs[j]);
704 free(subs);
705 *E_p = E;
709 static int type_offset(enode *p)
711 return p->type == fractional ? 1 :
712 p->type == flooring ? 1 : 0;
715 static void adjust_periods(evalue *e, unsigned nvar, Vector *periods)
717 for (; value_zero_p(e->d); e = &e->x.p->arr[0]) {
718 int pos;
719 assert(e->x.p->type == polynomial);
720 assert(e->x.p->size == 2);
721 assert(value_notzero_p(e->x.p->arr[1].d));
723 pos = e->x.p->pos - 1;
724 if (pos >= nvar)
725 break;
727 value_lcm(periods->p[pos], periods->p[pos], e->x.p->arr[1].d);
731 static void fractional_periods_r(evalue *e, unsigned nvar, Vector *periods)
733 int i;
735 if (value_notzero_p(e->d))
736 return;
738 assert(e->x.p->type == polynomial || e->x.p->type == fractional);
740 if (e->x.p->type == fractional)
741 adjust_periods(&e->x.p->arr[0], nvar, periods);
743 for (i = type_offset(e->x.p); i < e->x.p->size; ++i)
744 fractional_periods_r(&e->x.p->arr[i], nvar, periods);
748 * For each of the nvar variables, compute the lcm of the
749 * denominators of the coefficients of that variable in
750 * any of the fractional parts.
752 static Vector *fractional_periods(evalue *e, unsigned nvar)
754 int i;
755 Vector *periods = Vector_Alloc(nvar);
757 for (i = 0; i < nvar; ++i)
758 value_set_si(periods->p[i], 1);
760 fractional_periods_r(e, nvar, periods);
762 return periods;
765 /* Move "best" variable to sum over into the first position,
766 * possibly changing *P_p and *E_p.
768 * If there are any fractional parts (period != NULL), then we
769 * first look for a variable with the smallest lcm of denominators
770 * inside a fractional part. This denominator is assigned to period
771 * and corresponds to the number of "splinters" we need to construct
772 * at this level.
774 * Of those with this denominator (all if period == NULL or if there
775 * are no fractional parts), we select the variable with the smallest
776 * maximal coefficient, as this coefficient will become a denominator
777 * in new fractional parts (for an exact computation), which may
778 * lead to splintering in the next step.
780 static void move_best_to_front(Polyhedron **P_p, evalue **E_p, unsigned nvar,
781 Value *period)
783 Polyhedron *P = *P_p;
784 evalue *E = *E_p;
785 int i, j, best_i = -1;
786 Vector *periods;
787 Value best, max;
789 assert(nvar >= 1);
791 if (period) {
792 periods = fractional_periods(E, nvar);
793 value_assign(*period, periods->p[0]);
794 for (i = 1; i < nvar; ++i)
795 if (value_lt(periods->p[i], *period))
796 value_assign(*period, periods->p[i]);
799 value_init(best);
800 value_init(max);
802 for (i = 0; i < nvar; ++i) {
803 if (period && value_ne(*period, periods->p[i]))
804 continue;
806 value_set_si(max, 0);
808 for (j = 0; j < P->NbConstraints; ++j) {
809 if (value_zero_p(P->Constraint[j][1+i]))
810 continue;
811 if (First_Non_Zero(P->Constraint[j]+1, i) == -1 &&
812 First_Non_Zero(P->Constraint[j]+1+i+1, nvar-i-1) == -1)
813 continue;
814 if (value_abs_gt(P->Constraint[j][1+i], max))
815 value_absolute(max, P->Constraint[j][1+i]);
818 if (best_i == -1 || value_lt(max, best)) {
819 value_assign(best, max);
820 best_i = i;
824 value_clear(best);
825 value_clear(max);
827 if (period)
828 Vector_Free(periods);
830 if (best_i != 0)
831 more_var_to_front(P_p, E_p, best_i);
833 return;
836 static evalue *sum_over_polytope_base(Polyhedron *P, evalue *E, unsigned nvar,
837 struct Bernoulli_data *data,
838 struct barvinok_options *options)
840 evalue *res;
842 assert(P->NbEq == 0);
844 data->ns = 0;
845 data->e = E;
847 for_each_lower_upper_bound(P, Bernoulli_init, Bernoulli_cb, data);
849 res = evalue_from_section_array(data->s, data->ns);
851 if (nvar > 1) {
852 evalue *tmp = Bernoulli_sum_evalue(res, nvar-1, options);
853 evalue_free(res);
854 res = tmp;
857 return res;
860 static evalue *sum_over_polytope(Polyhedron *P, evalue *E, unsigned nvar,
861 struct Bernoulli_data *data,
862 struct barvinok_options *options);
864 static evalue *sum_over_polytope_with_equalities(Polyhedron *P, evalue *E,
865 unsigned nvar,
866 struct Bernoulli_data *data,
867 struct barvinok_options *options)
869 unsigned dim = P->Dimension;
870 unsigned new_dim, new_nparam;
871 Matrix *T = NULL, *CP = NULL;
872 evalue **subs;
873 evalue *sum;
874 int j;
876 if (emptyQ(P))
877 return evalue_zero();
879 assert(P->NbEq > 0);
881 remove_all_equalities(&P, NULL, &CP, &T, dim-nvar, options->MaxRays);
883 if (emptyQ(P)) {
884 Polyhedron_Free(P);
885 return evalue_zero();
888 new_nparam = CP ? CP->NbColumns-1 : dim - nvar;
889 new_dim = T ? T->NbColumns-1 : nvar + new_nparam;
891 /* We can avoid these substitutions if E is a constant */
892 subs = ALLOCN(evalue *, dim);
893 for (j = 0; j < nvar; ++j) {
894 if (T)
895 subs[j] = affine2evalue(T->p[j], T->p[nvar+new_nparam][new_dim],
896 new_dim);
897 else
898 subs[j] = evalue_var(j);
900 for (j = 0; j < dim-nvar; ++j) {
901 if (CP)
902 subs[nvar+j] = affine2evalue(CP->p[j], CP->p[dim-nvar][new_nparam],
903 new_nparam);
904 else
905 subs[nvar+j] = evalue_var(j);
906 unshift(subs[nvar+j], new_dim-new_nparam);
909 E = evalue_dup(E);
910 evalue_substitute(E, subs);
911 reduce_evalue(E);
913 for (j = 0; j < dim; ++j)
914 evalue_free(subs[j]);
915 free(subs);
917 if (new_dim-new_nparam > 0) {
918 sum = sum_over_polytope(P, E, new_dim-new_nparam, data, options);
919 evalue_free(E);
920 Polyhedron_Free(P);
921 } else {
922 sum = ALLOC(evalue);
923 value_init(sum->d);
924 sum->x.p = new_enode(partition, 2, new_dim);
925 EVALUE_SET_DOMAIN(sum->x.p->arr[0], P);
926 value_clear(sum->x.p->arr[1].d);
927 sum->x.p->arr[1] = *E;
928 free(E);
931 if (CP) {
932 evalue_backsubstitute(sum, CP, options->MaxRays);
933 Matrix_Free(CP);
936 if (T)
937 Matrix_Free(T);
939 return sum;
942 /* Splinter P into period slices along the first variable x = period y + c,
943 * 0 <= c < perdiod, * ensuring no fractional part contains the first variable,
944 * and sum over all slices.
946 static evalue *sum_over_polytope_slices(Polyhedron *P, evalue *E,
947 unsigned nvar,
948 Value period,
949 struct Bernoulli_data *data,
950 struct barvinok_options *options)
952 evalue *sum = evalue_zero();
953 evalue **subs;
954 unsigned dim = P->Dimension;
955 Matrix *T;
956 Value i;
957 Value one;
958 int j;
960 value_init(i);
961 value_init(one);
962 value_set_si(one, 1);
964 subs = ALLOCN(evalue *, dim);
966 T = Matrix_Alloc(dim+1, dim+1);
967 value_assign(T->p[0][0], period);
968 for (j = 1; j < dim+1; ++j)
969 value_set_si(T->p[j][j], 1);
971 for (j = 0; j < dim; ++j)
972 subs[j] = evalue_var(j);
973 evalue_mul(subs[0], period);
975 for (value_set_si(i, 0); value_lt(i, period); value_increment(i, i)) {
976 evalue *tmp;
977 Polyhedron *S = DomainPreimage(P, T, options->MaxRays);
978 evalue *e = evalue_dup(E);
979 evalue_substitute(e, subs);
980 reduce_evalue(e);
982 if (S->NbEq)
983 tmp = sum_over_polytope_with_equalities(S, e, nvar, data, options);
984 else
985 tmp = sum_over_polytope_base(S, e, nvar, data, options);
987 assert(tmp);
988 eadd(tmp, sum);
989 evalue_free(tmp);
991 Domain_Free(S);
992 evalue_free(e);
994 value_increment(T->p[0][dim], T->p[0][dim]);
995 evalue_add_constant(subs[0], one);
998 value_clear(i);
999 value_clear(one);
1000 Matrix_Free(T);
1001 for (j = 0; j < dim; ++j)
1002 evalue_free(subs[j]);
1003 free(subs);
1005 reduce_evalue(sum);
1006 return sum;
1009 static evalue *sum_over_polytope(Polyhedron *P, evalue *E, unsigned nvar,
1010 struct Bernoulli_data *data,
1011 struct barvinok_options *options)
1013 Polyhedron *P_orig = P;
1014 evalue *E_orig = E;
1015 Value period;
1016 evalue *sum;
1017 int exact = options->approximation_method == BV_APPROX_NONE;
1019 if (P->NbEq)
1020 return sum_over_polytope_with_equalities(P, E, nvar, data, options);
1022 value_init(period);
1024 move_best_to_front(&P, &E, nvar, exact ? &period : NULL);
1025 if (exact && value_notone_p(period))
1026 sum = sum_over_polytope_slices(P, E, nvar, period, data, options);
1027 else
1028 sum = sum_over_polytope_base(P, E, nvar, data, options);
1030 if (P != P_orig)
1031 Polyhedron_Free(P);
1032 if (E != E_orig)
1033 evalue_free(E);
1035 value_clear(period);
1037 return sum;
1040 evalue *Bernoulli_sum_evalue(evalue *e, unsigned nvar,
1041 struct barvinok_options *options)
1043 struct Bernoulli_data data;
1044 int i, j;
1045 evalue *sum = evalue_zero();
1047 if (EVALUE_IS_ZERO(*e))
1048 return sum;
1050 if (nvar == 0) {
1051 eadd(e, sum);
1052 return sum;
1055 assert(value_zero_p(e->d));
1056 assert(e->x.p->type == partition);
1058 data.size = 16;
1059 data.s = ALLOCN(struct evalue_section, data.size);
1060 data.options = options;
1062 for (i = 0; i < e->x.p->size/2; ++i) {
1063 Polyhedron *D;
1064 for (D = EVALUE_DOMAIN(e->x.p->arr[2*i]); D; D = D->next) {
1065 Polyhedron *next = D->next;
1066 evalue *tmp;
1067 D->next = NULL;
1069 tmp = sum_over_polytope(D, &e->x.p->arr[2*i+1], nvar, &data, options);
1070 assert(tmp);
1071 eadd(tmp, sum);
1072 evalue_free(tmp);
1074 D->next = next;
1078 free(data.s);
1080 reduce_evalue(sum);
1081 return sum;