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 bernoulli
;
11 struct bernoulli
*bernoulli_compute(int n
)
14 Value lcm
, factor
, tmp
;
19 if (n
>= bernoulli
.size
) {
24 b
= Vector_Alloc(size
);
26 Vector_Copy(bernoulli
.b_num
->p
, b
->p
, bernoulli
.n
);
27 Vector_Free(bernoulli
.b_num
);
30 b
= Vector_Alloc(size
);
32 Vector_Copy(bernoulli
.b_den
->p
, b
->p
, bernoulli
.n
);
33 Vector_Free(bernoulli
.b_den
);
36 sum
= ALLOCN(Vector
*, size
);
37 for (i
= 0; i
< bernoulli
.n
; ++i
)
38 sum
[i
] = bernoulli
.sum
[i
];
42 bernoulli
.size
= size
;
48 for (i
= 0; i
< bernoulli
.n
; ++i
)
49 value_lcm(lcm
, bernoulli
.b_den
->p
[i
], &lcm
);
50 for (i
= bernoulli
.n
; i
<= n
; ++i
) {
52 value_set_si(bernoulli
.b_num
->p
[0], 1);
53 value_set_si(bernoulli
.b_den
->p
[0], 1);
56 value_set_si(bernoulli
.b_num
->p
[i
], 0);
57 value_set_si(factor
, -(i
+1));
58 for (j
= i
-1; j
>= 0; --j
) {
59 mpz_mul_ui(factor
, factor
, j
+1);
60 mpz_divexact_ui(factor
, factor
, i
+1-j
);
61 value_division(tmp
, lcm
, bernoulli
.b_den
->p
[j
]);
62 value_multiply(tmp
, tmp
, bernoulli
.b_num
->p
[j
]);
63 value_multiply(tmp
, tmp
, factor
);
64 value_addto(bernoulli
.b_num
->p
[i
], bernoulli
.b_num
->p
[i
], tmp
);
66 mpz_mul_ui(bernoulli
.b_den
->p
[i
], lcm
, i
+1);
67 Gcd(bernoulli
.b_num
->p
[i
], bernoulli
.b_den
->p
[i
], &tmp
);
68 if (value_notone_p(tmp
)) {
69 value_division(bernoulli
.b_num
->p
[i
], bernoulli
.b_num
->p
[i
], tmp
);
70 value_division(bernoulli
.b_den
->p
[i
], bernoulli
.b_den
->p
[i
], tmp
);
72 value_lcm(lcm
, bernoulli
.b_den
->p
[i
], &lcm
);
74 for (i
= bernoulli
.n
; i
<= n
; ++i
) {
75 bernoulli
.sum
[i
] = Vector_Alloc(i
+3);
76 value_assign(bernoulli
.sum
[i
]->p
[i
+1], lcm
);
77 mpz_mul_ui(bernoulli
.sum
[i
]->p
[i
+2], lcm
, i
+1);
78 value_set_si(factor
, 1);
79 for (j
= 1; j
<= i
; ++j
) {
80 mpz_mul_ui(factor
, factor
, i
+2-j
);
81 mpz_divexact_ui(factor
, factor
, j
);
82 value_division(bernoulli
.sum
[i
]->p
[i
+1-j
], lcm
, bernoulli
.b_den
->p
[j
]);
83 value_multiply(bernoulli
.sum
[i
]->p
[i
+1-j
],
84 bernoulli
.sum
[i
]->p
[i
+1-j
], bernoulli
.b_num
->p
[j
]);
85 value_multiply(bernoulli
.sum
[i
]->p
[i
+1-j
],
86 bernoulli
.sum
[i
]->p
[i
+1-j
], factor
);
88 Vector_Normalize(bernoulli
.sum
[i
]->p
, i
+3);
98 /* shift variables in polynomial one down */
99 static void shift(evalue
*e
)
102 if (value_notzero_p(e
->d
))
104 assert(e
->x
.p
->type
== polynomial
);
105 assert(e
->x
.p
->pos
> 1);
107 for (i
= 0; i
< e
->x
.p
->size
; ++i
)
108 shift(&e
->x
.p
->arr
[i
]);
111 static evalue
*shifted_copy(evalue
*src
)
113 evalue
*e
= ALLOC(evalue
);
120 static evalue
*power_sums(struct bernoulli
*bernoulli
, evalue
*poly
,
121 Vector
*arg
, Value denom
, int neg
, int alt_neg
)
124 evalue
*base
= affine2evalue(arg
->p
, denom
, arg
->Size
-1);
125 evalue
*sum
= evalue_zero();
127 for (i
= 1; i
< poly
->x
.p
->size
; ++i
) {
128 evalue
*term
= evalue_polynomial(bernoulli
->sum
[i
], base
);
129 evalue
*factor
= shifted_copy(&poly
->x
.p
->arr
[i
]);
131 if (alt_neg
&& (i
% 2))
134 free_evalue_refs(factor
);
135 free_evalue_refs(term
);
141 free_evalue_refs(base
);
147 struct section
{ Polyhedron
*D
; evalue
*E
; };
149 struct Bernoulli_data
{
157 static void Bernoulli_cb(Matrix
*M
, Value
*lower
, Value
*upper
, void *cb_data
)
159 struct Bernoulli_data
*data
= (struct Bernoulli_data
*)cb_data
;
162 evalue
*factor
= NULL
;
163 evalue
*linear
= NULL
;
166 unsigned dim
= M
->NbColumns
-2;
169 assert(data
->ns
< data
->size
);
172 T
= Constraints2Polyhedron(M2
, data
->MaxRays
);
175 POL_ENSURE_VERTICES(T
);
181 assert(lower
!= upper
);
183 row
= Vector_Alloc(dim
+1);
185 if (value_notzero_p(data
->e
->d
)) {
189 assert(data
->e
->x
.p
->type
== polynomial
);
190 if (data
->e
->x
.p
->pos
> 1) {
191 factor
= shifted_copy(data
->e
);
194 factor
= shifted_copy(&data
->e
->x
.p
->arr
[0]);
196 if (!EVALUE_IS_ZERO(*factor
)) {
197 value_absolute(tmp
, upper
[1]);
199 Vector_Combine(lower
+2, upper
+2, row
->p
, tmp
, lower
[1], dim
+1);
200 value_multiply(tmp
, tmp
, lower
[1]);
201 /* upper - lower + 1 */
202 value_addto(row
->p
[dim
], row
->p
[dim
], tmp
);
204 linear
= affine2evalue(row
->p
, tmp
, dim
);
205 emul(factor
, linear
);
207 linear
= evalue_zero();
210 data
->s
[data
->ns
].E
= linear
;
211 data
->s
[data
->ns
].D
= T
;
214 evalue
*poly_u
= NULL
, *poly_l
= NULL
;
216 struct bernoulli
*bernoulli
;
217 assert(data
->e
->x
.p
->type
== polynomial
);
218 assert(data
->e
->x
.p
->pos
== 1);
219 bernoulli
= bernoulli_compute(data
->e
->x
.p
->size
-1);
220 /* lower is the constraint
221 * b i - l' >= 0 i >= l'/b = l
222 * upper is the constraint
223 * -a i + u' >= 0 i <= u'/a = u
225 M2
= Matrix_Alloc(3, 2+T
->Dimension
);
226 value_set_si(M2
->p
[0][0], 1);
227 value_set_si(M2
->p
[1][0], 1);
228 value_set_si(M2
->p
[2][0], 1);
232 Vector_Oppose(lower
+2, M2
->p
[0]+1, T
->Dimension
+1);
233 value_subtract(M2
->p
[0][1+T
->Dimension
], M2
->p
[0][1+T
->Dimension
],
235 D
= AddConstraints(M2
->p_Init
, 1, T
, data
->MaxRays
);
241 Vector_Copy(upper
+2, row
->p
, dim
+1);
242 value_oppose(tmp
, upper
[1]);
243 value_addto(row
->p
[dim
], row
->p
[dim
], tmp
);
244 poly_u
= power_sums(bernoulli
, data
->e
, row
, tmp
, 0, 0);
246 Vector_Oppose(lower
+2, row
->p
, dim
+1);
247 extra
= power_sums(bernoulli
, data
->e
, row
, lower
[1], 1, 0);
251 data
->s
[data
->ns
].E
= extra
;
252 data
->s
[data
->ns
].D
= D
;
257 * 1 <= -u -u' - a >= 0
259 Vector_Oppose(upper
+2, M2
->p
[0]+1, T
->Dimension
+1);
260 value_addto(M2
->p
[0][1+T
->Dimension
], M2
->p
[0][1+T
->Dimension
],
262 D
= AddConstraints(M2
->p_Init
, 1, T
, data
->MaxRays
);
268 Vector_Copy(lower
+2, row
->p
, dim
+1);
269 value_addto(row
->p
[dim
], row
->p
[dim
], lower
[1]);
270 poly_l
= power_sums(bernoulli
, data
->e
, row
, lower
[1], 0, 1);
272 Vector_Oppose(upper
+2, row
->p
, dim
+1);
273 value_oppose(tmp
, upper
[1]);
274 extra
= power_sums(bernoulli
, data
->e
, row
, tmp
, 1, 1);
278 data
->s
[data
->ns
].E
= extra
;
279 data
->s
[data
->ns
].D
= D
;
287 Vector_Copy(upper
+2, M2
->p
[0]+1, T
->Dimension
+1);
288 Vector_Copy(lower
+2, M2
->p
[1]+1, T
->Dimension
+1);
289 D
= AddConstraints(M2
->p_Init
, 2, T
, data
->MaxRays
);
294 Vector_Copy(lower
+2, row
->p
, dim
+1);
295 value_addto(row
->p
[dim
], row
->p
[dim
], lower
[1]);
296 poly_l
= power_sums(bernoulli
, data
->e
, row
, lower
[1], 0, 1);
299 Vector_Copy(upper
+2, row
->p
, dim
+1);
300 value_oppose(tmp
, upper
[1]);
301 value_addto(row
->p
[dim
], row
->p
[dim
], tmp
);
302 poly_u
= power_sums(bernoulli
, data
->e
, row
, tmp
, 0, 0);
305 data
->s
[data
->ns
].E
= ALLOC(evalue
);
306 value_init(data
->s
[data
->ns
].E
->d
);
307 evalue_copy(data
->s
[data
->ns
].E
, poly_u
);
308 eadd(poly_l
, data
->s
[data
->ns
].E
);
309 eadd(linear
, data
->s
[data
->ns
].E
);
310 data
->s
[data
->ns
].D
= D
;
315 * l < 1 -l' + b - 1 >= 0
318 Vector_Copy(lower
+2, M2
->p
[0]+1, T
->Dimension
+1);
319 value_addto(M2
->p
[0][1+T
->Dimension
], M2
->p
[0][1+T
->Dimension
], lower
[1]);
320 value_decrement(M2
->p
[0][1+T
->Dimension
], M2
->p
[0][1+T
->Dimension
]);
321 Vector_Oppose(lower
+2, M2
->p
[1]+1, T
->Dimension
+1);
322 value_decrement(M2
->p
[1][1+T
->Dimension
], M2
->p
[1][1+T
->Dimension
]);
323 D
= AddConstraints(M2
->p_Init
, 2, T
, data
->MaxRays
);
328 Vector_Copy(upper
+2, row
->p
, dim
+1);
329 value_oppose(tmp
, upper
[1]);
330 value_addto(row
->p
[dim
], row
->p
[dim
], tmp
);
331 poly_u
= power_sums(bernoulli
, data
->e
, row
, tmp
, 0, 0);
334 eadd(linear
, poly_u
);
335 data
->s
[data
->ns
].E
= poly_u
;
337 data
->s
[data
->ns
].D
= D
;
342 * -u < 1 u' + a - 1 >= 0
343 * 0 < -u -u' - 1 >= 0
346 Vector_Copy(upper
+2, M2
->p
[0]+1, T
->Dimension
+1);
347 value_subtract(M2
->p
[0][1+T
->Dimension
], M2
->p
[0][1+T
->Dimension
],
349 value_decrement(M2
->p
[0][1+T
->Dimension
], M2
->p
[0][1+T
->Dimension
]);
350 Vector_Oppose(upper
+2, M2
->p
[1]+1, T
->Dimension
+1);
351 value_decrement(M2
->p
[1][1+T
->Dimension
], M2
->p
[1][1+T
->Dimension
]);
352 Vector_Copy(lower
+2, M2
->p
[2]+1, T
->Dimension
+1);
353 D
= AddConstraints(M2
->p_Init
, 3, T
, data
->MaxRays
);
358 Vector_Copy(lower
+2, row
->p
, dim
+1);
359 value_addto(row
->p
[dim
], row
->p
[dim
], lower
[1]);
360 poly_l
= power_sums(bernoulli
, data
->e
, row
, lower
[1], 0, 1);
363 eadd(linear
, poly_l
);
364 data
->s
[data
->ns
].E
= poly_l
;
366 data
->s
[data
->ns
].D
= D
;
373 free_evalue_refs(poly_l
);
377 free_evalue_refs(poly_u
);
380 free_evalue_refs(linear
);
383 if (factor
!= data
->e
) {
384 free_evalue_refs(factor
);
391 evalue
*Bernoulli_sum_evalue(evalue
*e
, unsigned nvar
,
392 struct barvinok_options
*options
)
394 struct Bernoulli_data data
;
396 evalue
*sum
= evalue_zero();
398 if (EVALUE_IS_ZERO(*e
))
406 assert(value_zero_p(e
->d
));
407 assert(e
->x
.p
->type
== partition
);
409 data
.size
= e
->x
.p
->size
* 2 + 16;
410 data
.s
= ALLOCN(struct section
, data
.size
);
411 data
.MaxRays
= options
->MaxRays
;
413 for (i
= 0; i
< e
->x
.p
->size
/2; ++i
) {
415 for (D
= EVALUE_DOMAIN(e
->x
.p
->arr
[2*i
]); D
; D
= D
->next
) {
416 unsigned dim
= D
->Dimension
- 1;
417 Polyhedron
*next
= D
->next
;
422 value_set_si(tmp
.d
, 0);
424 if (value_zero_p(D
->Constraint
[0][0]) &&
425 value_notzero_p(D
->Constraint
[0][1])) {
426 tmp
.x
.p
= new_enode(partition
, 2, dim
);
427 EVALUE_SET_DOMAIN(tmp
.x
.p
->arr
[0], Polyhedron_Project(D
, dim
));
428 evalue_copy(&tmp
.x
.p
->arr
[1], &e
->x
.p
->arr
[2*i
+1]);
429 reduce_evalue_in_domain(&tmp
.x
.p
->arr
[1], D
);
430 shift(&tmp
.x
.p
->arr
[1]);
433 data
.e
= &e
->x
.p
->arr
[2*i
+1];
435 for_each_lower_upper_bound(D
, Bernoulli_cb
, &data
);
438 evalue_set_si(&tmp
, 0, 1);
440 tmp
.x
.p
= new_enode(partition
, 2*data
.ns
, dim
);
441 for (j
= 0; j
< data
.ns
; ++j
) {
442 EVALUE_SET_DOMAIN(tmp
.x
.p
->arr
[2*j
], data
.s
[j
].D
);
443 value_clear(tmp
.x
.p
->arr
[2*j
+1].d
);
444 tmp
.x
.p
->arr
[2*j
+1] = *data
.s
[j
].E
;
451 evalue
*res
= Bernoulli_sum_evalue(&tmp
, nvar
-1, options
);
453 free_evalue_refs(res
);
458 free_evalue_refs(&tmp
);
469 evalue
*Bernoulli_sum(Polyhedron
*P
, Polyhedron
*C
,
470 struct barvinok_options
*options
)
476 e
.x
.p
= new_enode(partition
, 2, P
->Dimension
);
477 EVALUE_SET_DOMAIN(e
.x
.p
->arr
[0], Polyhedron_Copy(P
));
478 evalue_set_si(&e
.x
.p
->arr
[1], 1, 1);
479 sum
= Bernoulli_sum_evalue(&e
, P
->Dimension
- C
->Dimension
, options
);
480 free_evalue_refs(&e
);