2 #include <barvinok/options.h>
3 #include <barvinok/util.h>
6 #define ALLOC(type) (type*)malloc(sizeof(type))
7 #define ALLOCN(type,n) (type*)malloc((n) * sizeof(type))
9 static struct bernoulli_coef bernoulli_coef
;
10 static struct poly_list bernoulli
;
11 static struct poly_list faulhaber
;
13 struct bernoulli_coef
*bernoulli_coef_compute(int n
)
18 if (n
< bernoulli_coef
.n
)
19 return &bernoulli_coef
;
21 if (n
>= bernoulli_coef
.size
) {
22 int size
= 3*(n
+ 5)/2;
25 b
= Vector_Alloc(size
);
26 if (bernoulli_coef
.n
) {
27 Vector_Copy(bernoulli_coef
.num
->p
, b
->p
, bernoulli_coef
.n
);
28 Vector_Free(bernoulli_coef
.num
);
30 bernoulli_coef
.num
= b
;
31 b
= Vector_Alloc(size
);
32 if (bernoulli_coef
.n
) {
33 Vector_Copy(bernoulli_coef
.den
->p
, b
->p
, bernoulli_coef
.n
);
34 Vector_Free(bernoulli_coef
.den
);
36 bernoulli_coef
.den
= b
;
37 b
= Vector_Alloc(size
);
38 if (bernoulli_coef
.n
) {
39 Vector_Copy(bernoulli_coef
.lcm
->p
, b
->p
, bernoulli_coef
.n
);
40 Vector_Free(bernoulli_coef
.lcm
);
42 bernoulli_coef
.lcm
= b
;
44 bernoulli_coef
.size
= size
;
48 for (i
= bernoulli_coef
.n
; i
<= n
; ++i
) {
50 value_set_si(bernoulli_coef
.num
->p
[0], 1);
51 value_set_si(bernoulli_coef
.den
->p
[0], 1);
52 value_set_si(bernoulli_coef
.lcm
->p
[0], 1);
55 value_set_si(bernoulli_coef
.num
->p
[i
], 0);
56 value_set_si(factor
, -(i
+1));
57 for (j
= i
-1; j
>= 0; --j
) {
58 mpz_mul_ui(factor
, factor
, j
+1);
59 mpz_divexact_ui(factor
, factor
, i
+1-j
);
60 value_division(tmp
, bernoulli_coef
.lcm
->p
[i
-1],
61 bernoulli_coef
.den
->p
[j
]);
62 value_multiply(tmp
, tmp
, bernoulli_coef
.num
->p
[j
]);
63 value_multiply(tmp
, tmp
, factor
);
64 value_addto(bernoulli_coef
.num
->p
[i
], bernoulli_coef
.num
->p
[i
], tmp
);
66 mpz_mul_ui(bernoulli_coef
.den
->p
[i
], bernoulli_coef
.lcm
->p
[i
-1], i
+1);
67 Gcd(bernoulli_coef
.num
->p
[i
], bernoulli_coef
.den
->p
[i
], &tmp
);
68 if (value_notone_p(tmp
)) {
69 value_division(bernoulli_coef
.num
->p
[i
],
70 bernoulli_coef
.num
->p
[i
], tmp
);
71 value_division(bernoulli_coef
.den
->p
[i
],
72 bernoulli_coef
.den
->p
[i
], tmp
);
74 value_lcm(bernoulli_coef
.lcm
->p
[i
-1], bernoulli_coef
.den
->p
[i
],
75 &bernoulli_coef
.lcm
->p
[i
]);
77 bernoulli_coef
.n
= n
+1;
81 return &bernoulli_coef
;
85 * Compute either Bernoulli B_n or Faulhaber F_n polynomials.
87 * B_n = sum_{k=0}^n { n \choose k } b_k x^{n-k}
88 * F_n = 1/(n+1) sum_{k=0}^n { n+1 \choose k } b_k x^{n+1-k}
90 static struct poly_list
*bernoulli_faulhaber_compute(int n
, struct poly_list
*pl
,
95 struct bernoulli_coef
*bc
;
101 int size
= 3*(n
+ 5)/2;
104 poly
= ALLOCN(Vector
*, size
);
105 for (i
= 0; i
< pl
->n
; ++i
)
106 poly
[i
] = pl
->poly
[i
];
113 bc
= bernoulli_coef_compute(n
);
116 for (i
= pl
->n
; i
<= n
; ++i
) {
117 pl
->poly
[i
] = Vector_Alloc(i
+faulhaber
+2);
118 value_assign(pl
->poly
[i
]->p
[i
+faulhaber
], bc
->lcm
->p
[i
]);
120 mpz_mul_ui(pl
->poly
[i
]->p
[i
+2], bc
->lcm
->p
[i
], i
+1);
122 value_assign(pl
->poly
[i
]->p
[i
+1], bc
->lcm
->p
[i
]);
123 value_set_si(factor
, 1);
124 for (j
= 1; j
<= i
; ++j
) {
125 mpz_mul_ui(factor
, factor
, i
+faulhaber
+1-j
);
126 mpz_divexact_ui(factor
, factor
, j
);
127 value_division(pl
->poly
[i
]->p
[i
+faulhaber
-j
],
128 bc
->lcm
->p
[i
], bc
->den
->p
[j
]);
129 value_multiply(pl
->poly
[i
]->p
[i
+faulhaber
-j
],
130 pl
->poly
[i
]->p
[i
+faulhaber
-j
], bc
->num
->p
[j
]);
131 value_multiply(pl
->poly
[i
]->p
[i
+faulhaber
-j
],
132 pl
->poly
[i
]->p
[i
+faulhaber
-j
], factor
);
134 Vector_Normalize(pl
->poly
[i
]->p
, i
+faulhaber
+2);
142 struct poly_list
*bernoulli_compute(int n
)
144 return bernoulli_faulhaber_compute(n
, &bernoulli
, 0);
147 struct poly_list
*faulhaber_compute(int n
)
149 return bernoulli_faulhaber_compute(n
, &faulhaber
, 1);
152 /* shift variables in polynomial one down */
153 static void shift(evalue
*e
)
156 if (value_notzero_p(e
->d
))
158 assert(e
->x
.p
->type
== polynomial
);
159 assert(e
->x
.p
->pos
> 1);
161 for (i
= 0; i
< e
->x
.p
->size
; ++i
)
162 shift(&e
->x
.p
->arr
[i
]);
165 static evalue
*shifted_copy(evalue
*src
)
167 evalue
*e
= ALLOC(evalue
);
174 static evalue
*power_sums(struct poly_list
*faulhaber
, evalue
*poly
,
175 Vector
*arg
, Value denom
, int neg
, int alt_neg
)
178 evalue
*base
= affine2evalue(arg
->p
, denom
, arg
->Size
-1);
179 evalue
*sum
= evalue_zero();
181 for (i
= 1; i
< poly
->x
.p
->size
; ++i
) {
182 evalue
*term
= evalue_polynomial(faulhaber
->poly
[i
], base
);
183 evalue
*factor
= shifted_copy(&poly
->x
.p
->arr
[i
]);
185 if (alt_neg
&& (i
% 2))
188 free_evalue_refs(factor
);
189 free_evalue_refs(term
);
195 free_evalue_refs(base
);
201 struct section
{ Polyhedron
*D
; evalue
*E
; };
203 struct Bernoulli_data
{
211 static void Bernoulli_cb(Matrix
*M
, Value
*lower
, Value
*upper
, void *cb_data
)
213 struct Bernoulli_data
*data
= (struct Bernoulli_data
*)cb_data
;
216 evalue
*factor
= NULL
;
217 evalue
*linear
= NULL
;
220 unsigned dim
= M
->NbColumns
-2;
223 assert(data
->ns
< data
->size
);
226 T
= Constraints2Polyhedron(M2
, data
->MaxRays
);
229 POL_ENSURE_VERTICES(T
);
235 assert(lower
!= upper
);
237 row
= Vector_Alloc(dim
+1);
239 if (value_notzero_p(data
->e
->d
)) {
243 assert(data
->e
->x
.p
->type
== polynomial
);
244 if (data
->e
->x
.p
->pos
> 1) {
245 factor
= shifted_copy(data
->e
);
248 factor
= shifted_copy(&data
->e
->x
.p
->arr
[0]);
250 if (!EVALUE_IS_ZERO(*factor
)) {
251 value_absolute(tmp
, upper
[1]);
253 Vector_Combine(lower
+2, upper
+2, row
->p
, tmp
, lower
[1], dim
+1);
254 value_multiply(tmp
, tmp
, lower
[1]);
255 /* upper - lower + 1 */
256 value_addto(row
->p
[dim
], row
->p
[dim
], tmp
);
258 linear
= affine2evalue(row
->p
, tmp
, dim
);
259 emul(factor
, linear
);
261 linear
= evalue_zero();
264 data
->s
[data
->ns
].E
= linear
;
265 data
->s
[data
->ns
].D
= T
;
268 evalue
*poly_u
= NULL
, *poly_l
= NULL
;
270 struct poly_list
*faulhaber
;
271 assert(data
->e
->x
.p
->type
== polynomial
);
272 assert(data
->e
->x
.p
->pos
== 1);
273 faulhaber
= faulhaber_compute(data
->e
->x
.p
->size
-1);
274 /* lower is the constraint
275 * b i - l' >= 0 i >= l'/b = l
276 * upper is the constraint
277 * -a i + u' >= 0 i <= u'/a = u
279 M2
= Matrix_Alloc(3, 2+T
->Dimension
);
280 value_set_si(M2
->p
[0][0], 1);
281 value_set_si(M2
->p
[1][0], 1);
282 value_set_si(M2
->p
[2][0], 1);
286 Vector_Oppose(lower
+2, M2
->p
[0]+1, T
->Dimension
+1);
287 value_subtract(M2
->p
[0][1+T
->Dimension
], M2
->p
[0][1+T
->Dimension
],
289 D
= AddConstraints(M2
->p_Init
, 1, T
, data
->MaxRays
);
295 Vector_Copy(upper
+2, row
->p
, dim
+1);
296 value_oppose(tmp
, upper
[1]);
297 value_addto(row
->p
[dim
], row
->p
[dim
], tmp
);
298 poly_u
= power_sums(faulhaber
, data
->e
, row
, tmp
, 0, 0);
300 Vector_Oppose(lower
+2, row
->p
, dim
+1);
301 extra
= power_sums(faulhaber
, data
->e
, row
, lower
[1], 1, 0);
305 data
->s
[data
->ns
].E
= extra
;
306 data
->s
[data
->ns
].D
= D
;
311 * 1 <= -u -u' - a >= 0
313 Vector_Oppose(upper
+2, M2
->p
[0]+1, T
->Dimension
+1);
314 value_addto(M2
->p
[0][1+T
->Dimension
], M2
->p
[0][1+T
->Dimension
],
316 D
= AddConstraints(M2
->p_Init
, 1, T
, data
->MaxRays
);
322 Vector_Copy(lower
+2, row
->p
, dim
+1);
323 value_addto(row
->p
[dim
], row
->p
[dim
], lower
[1]);
324 poly_l
= power_sums(faulhaber
, data
->e
, row
, lower
[1], 0, 1);
326 Vector_Oppose(upper
+2, row
->p
, dim
+1);
327 value_oppose(tmp
, upper
[1]);
328 extra
= power_sums(faulhaber
, data
->e
, row
, tmp
, 1, 1);
332 data
->s
[data
->ns
].E
= extra
;
333 data
->s
[data
->ns
].D
= D
;
341 Vector_Copy(upper
+2, M2
->p
[0]+1, T
->Dimension
+1);
342 Vector_Copy(lower
+2, M2
->p
[1]+1, T
->Dimension
+1);
343 D
= AddConstraints(M2
->p_Init
, 2, T
, data
->MaxRays
);
348 Vector_Copy(lower
+2, row
->p
, dim
+1);
349 value_addto(row
->p
[dim
], row
->p
[dim
], lower
[1]);
350 poly_l
= power_sums(faulhaber
, data
->e
, row
, lower
[1], 0, 1);
353 Vector_Copy(upper
+2, row
->p
, dim
+1);
354 value_oppose(tmp
, upper
[1]);
355 value_addto(row
->p
[dim
], row
->p
[dim
], tmp
);
356 poly_u
= power_sums(faulhaber
, data
->e
, row
, tmp
, 0, 0);
359 data
->s
[data
->ns
].E
= ALLOC(evalue
);
360 value_init(data
->s
[data
->ns
].E
->d
);
361 evalue_copy(data
->s
[data
->ns
].E
, poly_u
);
362 eadd(poly_l
, data
->s
[data
->ns
].E
);
363 eadd(linear
, data
->s
[data
->ns
].E
);
364 data
->s
[data
->ns
].D
= D
;
369 * l < 1 -l' + b - 1 >= 0
372 Vector_Copy(lower
+2, M2
->p
[0]+1, T
->Dimension
+1);
373 value_addto(M2
->p
[0][1+T
->Dimension
], M2
->p
[0][1+T
->Dimension
], lower
[1]);
374 value_decrement(M2
->p
[0][1+T
->Dimension
], M2
->p
[0][1+T
->Dimension
]);
375 Vector_Oppose(lower
+2, M2
->p
[1]+1, T
->Dimension
+1);
376 value_decrement(M2
->p
[1][1+T
->Dimension
], M2
->p
[1][1+T
->Dimension
]);
377 D
= AddConstraints(M2
->p_Init
, 2, T
, data
->MaxRays
);
382 Vector_Copy(upper
+2, row
->p
, dim
+1);
383 value_oppose(tmp
, upper
[1]);
384 value_addto(row
->p
[dim
], row
->p
[dim
], tmp
);
385 poly_u
= power_sums(faulhaber
, data
->e
, row
, tmp
, 0, 0);
388 eadd(linear
, poly_u
);
389 data
->s
[data
->ns
].E
= poly_u
;
391 data
->s
[data
->ns
].D
= D
;
396 * -u < 1 u' + a - 1 >= 0
397 * 0 < -u -u' - 1 >= 0
400 Vector_Copy(upper
+2, M2
->p
[0]+1, T
->Dimension
+1);
401 value_subtract(M2
->p
[0][1+T
->Dimension
], M2
->p
[0][1+T
->Dimension
],
403 value_decrement(M2
->p
[0][1+T
->Dimension
], M2
->p
[0][1+T
->Dimension
]);
404 Vector_Oppose(upper
+2, M2
->p
[1]+1, T
->Dimension
+1);
405 value_decrement(M2
->p
[1][1+T
->Dimension
], M2
->p
[1][1+T
->Dimension
]);
406 Vector_Copy(lower
+2, M2
->p
[2]+1, T
->Dimension
+1);
407 D
= AddConstraints(M2
->p_Init
, 3, T
, data
->MaxRays
);
412 Vector_Copy(lower
+2, row
->p
, dim
+1);
413 value_addto(row
->p
[dim
], row
->p
[dim
], lower
[1]);
414 poly_l
= power_sums(faulhaber
, data
->e
, row
, lower
[1], 0, 1);
417 eadd(linear
, poly_l
);
418 data
->s
[data
->ns
].E
= poly_l
;
420 data
->s
[data
->ns
].D
= D
;
427 free_evalue_refs(poly_l
);
431 free_evalue_refs(poly_u
);
434 free_evalue_refs(linear
);
437 if (factor
!= data
->e
) {
438 free_evalue_refs(factor
);
445 evalue
*Bernoulli_sum_evalue(evalue
*e
, unsigned nvar
,
446 struct barvinok_options
*options
)
448 struct Bernoulli_data data
;
450 evalue
*sum
= evalue_zero();
452 if (EVALUE_IS_ZERO(*e
))
460 assert(value_zero_p(e
->d
));
461 assert(e
->x
.p
->type
== partition
);
463 data
.size
= e
->x
.p
->size
* 2 + 16;
464 data
.s
= ALLOCN(struct section
, data
.size
);
465 data
.MaxRays
= options
->MaxRays
;
467 for (i
= 0; i
< e
->x
.p
->size
/2; ++i
) {
469 for (D
= EVALUE_DOMAIN(e
->x
.p
->arr
[2*i
]); D
; D
= D
->next
) {
470 unsigned dim
= D
->Dimension
- 1;
471 Polyhedron
*next
= D
->next
;
476 value_set_si(tmp
.d
, 0);
478 if (value_zero_p(D
->Constraint
[0][0]) &&
479 value_notzero_p(D
->Constraint
[0][1])) {
480 tmp
.x
.p
= new_enode(partition
, 2, dim
);
481 EVALUE_SET_DOMAIN(tmp
.x
.p
->arr
[0], Polyhedron_Project(D
, dim
));
482 evalue_copy(&tmp
.x
.p
->arr
[1], &e
->x
.p
->arr
[2*i
+1]);
483 reduce_evalue_in_domain(&tmp
.x
.p
->arr
[1], D
);
484 shift(&tmp
.x
.p
->arr
[1]);
487 data
.e
= &e
->x
.p
->arr
[2*i
+1];
489 for_each_lower_upper_bound(D
, Bernoulli_cb
, &data
);
492 evalue_set_si(&tmp
, 0, 1);
494 tmp
.x
.p
= new_enode(partition
, 2*data
.ns
, dim
);
495 for (j
= 0; j
< data
.ns
; ++j
) {
496 EVALUE_SET_DOMAIN(tmp
.x
.p
->arr
[2*j
], data
.s
[j
].D
);
497 value_clear(tmp
.x
.p
->arr
[2*j
+1].d
);
498 tmp
.x
.p
->arr
[2*j
+1] = *data
.s
[j
].E
;
505 evalue
*res
= Bernoulli_sum_evalue(&tmp
, nvar
-1, options
);
507 free_evalue_refs(res
);
512 free_evalue_refs(&tmp
);
523 evalue
*Bernoulli_sum(Polyhedron
*P
, Polyhedron
*C
,
524 struct barvinok_options
*options
)
530 e
.x
.p
= new_enode(partition
, 2, P
->Dimension
);
531 EVALUE_SET_DOMAIN(e
.x
.p
->arr
[0], Polyhedron_Copy(P
));
532 evalue_set_si(&e
.x
.p
->arr
[1], 1, 1);
533 sum
= Bernoulli_sum_evalue(&e
, P
->Dimension
- C
->Dimension
, options
);
534 free_evalue_refs(&e
);