2 #include <bernstein/bernstein.h>
3 #include <bernstein/piecewise_lst.h>
4 #include <barvinok/barvinok.h>
5 #include <barvinok/util.h>
6 #include <barvinok/bernstein.h>
7 #include <barvinok/options.h>
10 using namespace bernstein
;
19 ex
evalue2ex(evalue
*e
, const exvector
& vars
)
21 if (value_notzero_p(e
->d
))
22 return value2numeric(e
->x
.n
)/value2numeric(e
->d
);
23 if (e
->x
.p
->type
!= polynomial
)
26 for (int i
= e
->x
.p
->size
-1; i
>= 0; --i
) {
27 poly
*= vars
[e
->x
.p
->pos
-1];
28 ex t
= evalue2ex(&e
->x
.p
->arr
[i
], vars
);
29 if (is_exactly_a
<fail
>(t
))
36 static int type_offset(enode
*p
)
38 return p
->type
== fractional
? 1 :
39 p
->type
== flooring
? 1 : 0;
42 typedef pair
<bool, const evalue
*> typed_evalue
;
44 static ex
evalue2ex_add_var(evalue
*e
, exvector
& extravar
,
45 vector
<typed_evalue
>& expr
, bool is_fract
)
49 for (int i
= 0; i
< expr
.size(); ++i
) {
50 if (is_fract
== expr
[i
].first
&& eequal(e
, expr
[i
].second
)) {
51 base_var
= extravar
[i
];
59 snprintf(name
, sizeof(name
), "f%c%d", is_fract
? 'r' : 'l', expr
.size());
60 extravar
.push_back(base_var
= symbol(name
));
61 expr
.push_back(typed_evalue(is_fract
, e
));
66 static ex
evalue2ex_r(const evalue
*e
, const exvector
& vars
,
67 exvector
& extravar
, vector
<typed_evalue
>& expr
,
70 if (value_notzero_p(e
->d
))
71 return value2numeric(e
->x
.n
)/value2numeric(e
->d
);
75 switch (e
->x
.p
->type
) {
77 base_var
= vars
[e
->x
.p
->pos
-1];
80 base_var
= evalue2ex_add_var(&e
->x
.p
->arr
[0], extravar
, expr
, false);
83 base_var
= evalue2ex_add_var(&e
->x
.p
->arr
[0], extravar
, expr
, true);
87 return evalue2ex_r(&e
->x
.p
->arr
[VALUE_TO_INT(coset
->p
[e
->x
.p
->pos
-1])],
88 vars
, extravar
, expr
, coset
);
93 int offset
= type_offset(e
->x
.p
);
94 for (int i
= e
->x
.p
->size
-1; i
>= offset
; --i
) {
96 ex t
= evalue2ex_r(&e
->x
.p
->arr
[i
], vars
, extravar
, expr
, coset
);
97 if (is_exactly_a
<fail
>(t
))
104 /* For each t = floor(e/d), set up two constraints
107 * -e + d t + d-1 >= 0
109 * e is assumed to be an affine expression.
111 * For each t = fract(e/d), set up two constraints
116 static Matrix
*setup_constraints(const vector
<typed_evalue
> expr
, int nvar
)
118 int extra
= expr
.size();
121 Matrix
*M
= Matrix_Alloc(2*extra
, 1+extra
+nvar
+1);
122 for (int i
= 0; i
< extra
; ++i
) {
123 Value
*d
= &M
->p
[2*i
][1+i
];
125 evalue_denom(expr
[i
].second
, d
);
127 value_set_si(M
->p
[2*i
][0], 1);
128 value_decrement(M
->p
[2*i
][1+extra
+nvar
], *d
);
129 value_oppose(*d
, *d
);
130 value_set_si(M
->p
[2*i
+1][0], 1);
131 value_set_si(M
->p
[2*i
+1][1+i
], 1);
134 for (e
= expr
[i
].second
; value_zero_p(e
->d
); e
= &e
->x
.p
->arr
[0]) {
135 assert(e
->x
.p
->type
== polynomial
);
136 assert(e
->x
.p
->size
== 2);
137 evalue
*c
= &e
->x
.p
->arr
[1];
138 value_multiply(M
->p
[2*i
][1+extra
+e
->x
.p
->pos
-1], *d
, c
->x
.n
);
139 value_division(M
->p
[2*i
][1+extra
+e
->x
.p
->pos
-1],
140 M
->p
[2*i
][1+extra
+e
->x
.p
->pos
-1], c
->d
);
142 value_multiply(M
->p
[2*i
][1+extra
+nvar
], *d
, e
->x
.n
);
143 value_division(M
->p
[2*i
][1+extra
+nvar
], M
->p
[2*i
][1+extra
+nvar
], e
->d
);
144 value_oppose(*d
, *d
);
145 value_set_si(M
->p
[2*i
][0], -1);
146 Vector_Scale(M
->p
[2*i
], M
->p
[2*i
+1], M
->p
[2*i
][0], 1+extra
+nvar
+1);
147 value_set_si(M
->p
[2*i
][0], 1);
148 value_subtract(M
->p
[2*i
+1][1+extra
+nvar
], M
->p
[2*i
+1][1+extra
+nvar
], *d
);
149 value_decrement(M
->p
[2*i
+1][1+extra
+nvar
], M
->p
[2*i
+1][1+extra
+nvar
]);
155 static bool evalue_is_periodic(const evalue
*e
, Vector
*periods
)
158 bool is_periodic
= false;
160 if (value_notzero_p(e
->d
))
163 assert(e
->x
.p
->type
!= partition
);
164 if (e
->x
.p
->type
== periodic
) {
167 value_set_si(size
, e
->x
.p
->size
);
168 value_lcm(periods
->p
[e
->x
.p
->pos
-1], size
, &periods
->p
[e
->x
.p
->pos
-1]);
172 offset
= type_offset(e
->x
.p
);
173 for (i
= e
->x
.p
->size
-1; i
>= offset
; --i
)
174 is_periodic
= evalue_is_periodic(&e
->x
.p
->arr
[i
], periods
) || is_periodic
;
178 static ex
evalue2lst(const evalue
*e
, const exvector
& vars
,
179 exvector
& extravar
, vector
<typed_evalue
>& expr
,
182 Vector
*coset
= Vector_Alloc(periods
->Size
);
186 list
.append(evalue2ex_r(e
, vars
, extravar
, expr
, coset
));
187 for (i
= coset
->Size
-1; i
>= 0; --i
) {
188 value_increment(coset
->p
[i
], coset
->p
[i
]);
189 if (value_lt(coset
->p
[i
], periods
->p
[i
]))
191 value_set_si(coset
->p
[i
], 0);
200 ex
evalue2ex(const evalue
*e
, const exvector
& vars
, exvector
& floorvar
,
201 Matrix
**C
, Vector
**p
)
203 vector
<typed_evalue
> expr
;
204 Vector
*periods
= Vector_Alloc(vars
.size());
207 for (int i
= 0; i
< periods
->Size
; ++i
)
208 value_set_si(periods
->p
[i
], 1);
209 if (evalue_is_periodic(e
, periods
)) {
215 Vector_Free(periods
);
217 ex poly
= evalue2ex_r(e
, vars
, floorvar
, expr
, NULL
);
218 Matrix
*M
= setup_constraints(expr
, vars
.size());
224 /* if the evalue is a relation, we use the relation to cut off the
225 * the edges of the domain
227 static void evalue_extract_poly(evalue
*e
, int i
, Polyhedron
**D
, evalue
**poly
,
230 *D
= EVALUE_DOMAIN(e
->x
.p
->arr
[2*i
]);
231 *poly
= e
= &e
->x
.p
->arr
[2*i
+1];
232 if (value_notzero_p(e
->d
))
234 if (e
->x
.p
->type
!= relation
)
236 if (e
->x
.p
->size
> 2)
238 evalue
*fr
= &e
->x
.p
->arr
[0];
239 assert(value_zero_p(fr
->d
));
240 assert(fr
->x
.p
->type
== fractional
);
241 assert(fr
->x
.p
->size
== 3);
242 Matrix
*T
= Matrix_Alloc(2, (*D
)->Dimension
+1);
243 value_set_si(T
->p
[1][(*D
)->Dimension
], 1);
245 /* convert argument of fractional to polylib */
246 /* the argument is assumed to be linear */
247 evalue
*p
= &fr
->x
.p
->arr
[0];
248 evalue_denom(p
, &T
->p
[1][(*D
)->Dimension
]);
249 for (;value_zero_p(p
->d
); p
= &p
->x
.p
->arr
[0]) {
250 assert(p
->x
.p
->type
== polynomial
);
251 assert(p
->x
.p
->size
== 2);
252 assert(value_notzero_p(p
->x
.p
->arr
[1].d
));
253 int pos
= p
->x
.p
->pos
- 1;
254 value_assign(T
->p
[0][pos
], p
->x
.p
->arr
[1].x
.n
);
255 value_multiply(T
->p
[0][pos
], T
->p
[0][pos
], T
->p
[1][(*D
)->Dimension
]);
256 value_division(T
->p
[0][pos
], T
->p
[0][pos
], p
->x
.p
->arr
[1].d
);
258 int pos
= (*D
)->Dimension
;
259 value_assign(T
->p
[0][pos
], p
->x
.n
);
260 value_multiply(T
->p
[0][pos
], T
->p
[0][pos
], T
->p
[1][(*D
)->Dimension
]);
261 value_division(T
->p
[0][pos
], T
->p
[0][pos
], p
->d
);
263 Polyhedron
*E
= NULL
;
264 for (Polyhedron
*P
= *D
; P
; P
= P
->next
) {
265 Polyhedron
*I
= Polyhedron_Image(P
, T
, MaxRays
);
266 I
= DomainConstraintSimplify(I
, MaxRays
);
267 Polyhedron
*R
= Polyhedron_Preimage(I
, T
, MaxRays
);
269 Polyhedron
*next
= P
->next
;
271 Polyhedron
*S
= DomainIntersection(P
, R
, MaxRays
);
277 E
= DomainConcat(S
, E
);
282 *poly
= &e
->x
.p
->arr
[1];
285 piecewise_lst
*evalue_bernstein_coefficients(piecewise_lst
*pl_all
, evalue
*e
,
286 Polyhedron
*ctx
, const exvector
& params
)
289 barvinok_options
*options
= barvinok_options_new_with_defaults();
290 pl
= evalue_bernstein_coefficients(pl_all
, e
, ctx
, params
, options
);
291 barvinok_options_free(options
);
295 static piecewise_lst
*bernstein_coefficients(piecewise_lst
*pl_all
,
296 Polyhedron
*D
, const ex
& poly
,
298 const exvector
& params
, const exvector
& floorvar
,
299 barvinok_options
*options
)
301 unsigned PP_MaxRays
= options
->MaxRays
;
302 if (PP_MaxRays
& POL_NO_DUAL
)
305 for (Polyhedron
*P
= D
; P
; P
= P
->next
) {
306 Param_Polyhedron
*PP
;
307 Polyhedron
*next
= P
->next
;
308 piecewise_lst
*pl
= new piecewise_lst(params
);
311 PP
= Polyhedron2Param_Domain(P
, ctx
, PP_MaxRays
);
312 for (Param_Domain
*Q
= PP
->D
; Q
; Q
= Q
->next
) {
313 matrix VM
= domainVertices(PP
, Q
, params
);
314 lst coeffs
= bernsteinExpansion(VM
, poly
, floorvar
, params
);
315 pl
->list
.push_back(guarded_lst(Polyhedron_Copy(Q
->Domain
), coeffs
));
317 Param_Polyhedron_Free(PP
);
321 pl_all
->combine(*pl
);
329 /* Compute the coefficients of the polynomial corresponding to each coset
330 * on its own domain. This allows us to cut the domain on multiples of
332 * To perform the cutting for a coset "i mod n = c" we map the domain
333 * to the quotient space trough "i = i' n + c", simplify the constraints
334 * (implicitly) and then map back to the original space.
336 static piecewise_lst
*bernstein_coefficients_periodic(piecewise_lst
*pl_all
,
337 Polyhedron
*D
, const evalue
*e
,
338 Polyhedron
*ctx
, const exvector
& vars
,
339 const exvector
& params
, Vector
*periods
,
340 barvinok_options
*options
)
342 assert(D
->Dimension
== periods
->Size
);
343 Matrix
*T
= Matrix_Alloc(D
->Dimension
+1, D
->Dimension
+1);
344 Matrix
*T2
= Matrix_Alloc(D
->Dimension
+1, D
->Dimension
+1);
345 Vector
*coset
= Vector_Alloc(periods
->Size
);
347 vector
<typed_evalue
> expr
;
348 exvector allvars
= vars
;
349 allvars
.insert(allvars
.end(), params
.begin(), params
.end());
351 value_set_si(T2
->p
[D
->Dimension
][D
->Dimension
], 1);
352 for (int i
= 0; i
< D
->Dimension
; ++i
) {
353 value_assign(T
->p
[i
][i
], periods
->p
[i
]);
354 value_lcm(T2
->p
[D
->Dimension
][D
->Dimension
], periods
->p
[i
],
355 &T2
->p
[D
->Dimension
][D
->Dimension
]);
357 value_set_si(T
->p
[D
->Dimension
][D
->Dimension
], 1);
358 for (int i
= 0; i
< D
->Dimension
; ++i
)
359 value_division(T2
->p
[i
][i
], T2
->p
[D
->Dimension
][D
->Dimension
],
363 ex poly
= evalue2ex_r(e
, allvars
, extravar
, expr
, coset
);
364 assert(extravar
.size() == 0);
365 assert(expr
.size() == 0);
366 Polyhedron
*E
= DomainPreimage(D
, T
, options
->MaxRays
);
367 Polyhedron
*F
= DomainPreimage(E
, T2
, options
->MaxRays
);
370 pl_all
= bernstein_coefficients(pl_all
, F
, poly
, ctx
, params
,
373 for (i
= D
->Dimension
-1; i
>= 0; --i
) {
374 value_increment(coset
->p
[i
], coset
->p
[i
]);
375 value_increment(T
->p
[i
][D
->Dimension
], T
->p
[i
][D
->Dimension
]);
376 value_subtract(T2
->p
[i
][D
->Dimension
], T2
->p
[i
][D
->Dimension
],
378 if (value_lt(coset
->p
[i
], periods
->p
[i
]))
380 value_set_si(coset
->p
[i
], 0);
381 value_set_si(T
->p
[i
][D
->Dimension
], 0);
382 value_set_si(T2
->p
[i
][D
->Dimension
], 0);
393 piecewise_lst
*evalue_bernstein_coefficients(piecewise_lst
*pl_all
, evalue
*e
,
394 Polyhedron
*ctx
, const exvector
& params
,
395 barvinok_options
*options
)
397 unsigned nparam
= ctx
->Dimension
;
398 if (EVALUE_IS_ZERO(*e
))
400 assert(value_zero_p(e
->d
));
401 assert(e
->x
.p
->type
== partition
);
402 assert(e
->x
.p
->size
>= 2);
403 unsigned nvars
= EVALUE_DOMAIN(e
->x
.p
->arr
[0])->Dimension
- nparam
;
405 exvector vars
= constructVariableVector(nvars
, "v");
406 exvector allvars
= vars
;
407 allvars
.insert(allvars
.end(), params
.begin(), params
.end());
409 for (int i
= 0; i
< e
->x
.p
->size
/2; ++i
) {
416 evalue_extract_poly(e
, i
, &E
, &EP
, options
->MaxRays
);
417 ex poly
= evalue2ex(EP
, allvars
, floorvar
, &M
, &periods
);
418 floorvar
.insert(floorvar
.end(), vars
.begin(), vars
.end());
420 Polyhedron
*AE
= align_context(E
, M
->NbColumns
-2, options
->MaxRays
);
421 if (E
!= EVALUE_DOMAIN(e
->x
.p
->arr
[2*i
]))
423 E
= DomainAddConstraints(AE
, M
, options
->MaxRays
);
427 if (is_exactly_a
<fail
>(poly
)) {
428 if (E
!= EVALUE_DOMAIN(e
->x
.p
->arr
[2*i
]))
434 pl_all
= bernstein_coefficients_periodic(pl_all
, E
, EP
, ctx
, vars
,
435 params
, periods
, options
);
437 pl_all
= bernstein_coefficients(pl_all
, E
, poly
, ctx
, params
,
440 Vector_Free(periods
);
441 if (E
!= EVALUE_DOMAIN(e
->x
.p
->arr
[2*i
]))