3 #include <bernstein/bernstein.h>
4 #include <bernstein/piecewise_lst.h>
5 #include <barvinok/barvinok.h>
6 #include <barvinok/util.h>
7 #include <barvinok/bernstein.h>
8 #include <barvinok/options.h>
9 #include "reduce_domain.h"
11 using namespace GiNaC
;
12 using namespace bernstein
;
21 ex
evalue2ex(evalue
*e
, const exvector
& vars
)
23 if (value_pos_p(e
->d
))
24 return value2numeric(e
->x
.n
)/value2numeric(e
->d
);
25 if (EVALUE_IS_NAN(*e
))
27 if (e
->x
.p
->type
!= polynomial
)
30 for (int i
= e
->x
.p
->size
-1; i
>= 0; --i
) {
31 poly
*= vars
[e
->x
.p
->pos
-1];
32 ex t
= evalue2ex(&e
->x
.p
->arr
[i
], vars
);
33 if (is_exactly_a
<fail
>(t
))
40 static int type_offset(enode
*p
)
42 return p
->type
== fractional
? 1 :
43 p
->type
== flooring
? 1 : 0;
46 typedef pair
<bool, const evalue
*> typed_evalue
;
48 static ex
evalue2ex_add_var(evalue
*e
, exvector
& extravar
,
49 vector
<typed_evalue
>& expr
, bool is_fract
)
53 for (int i
= 0; i
< expr
.size(); ++i
) {
54 if (is_fract
== expr
[i
].first
&& eequal(e
, expr
[i
].second
)) {
55 base_var
= extravar
[i
];
63 snprintf(name
, sizeof(name
), "f%c%d", is_fract
? 'r' : 'l', expr
.size());
64 extravar
.push_back(base_var
= symbol(name
));
65 expr
.push_back(typed_evalue(is_fract
, e
));
70 /* For the argument e=(f/d) of a fractional, return (d-1)/d times
71 * a variable in [0,1] (see setup_constraints).
73 static ex
evalue2ex_get_fract(evalue
*e
, exvector
& extravar
,
74 vector
<typed_evalue
>& expr
)
82 den
= value2numeric(d
);
86 ex base_var
= evalue2ex_add_var(e
, extravar
, expr
, true);
91 static ex
evalue2ex_r(const evalue
*e
, const exvector
& vars
,
92 exvector
& extravar
, vector
<typed_evalue
>& expr
,
95 if (value_notzero_p(e
->d
))
96 return value2numeric(e
->x
.n
)/value2numeric(e
->d
);
100 switch (e
->x
.p
->type
) {
102 base_var
= vars
[e
->x
.p
->pos
-1];
105 base_var
= evalue2ex_add_var(&e
->x
.p
->arr
[0], extravar
, expr
, false);
108 base_var
= evalue2ex_get_fract(&e
->x
.p
->arr
[0], extravar
, expr
);
112 return evalue2ex_r(&e
->x
.p
->arr
[VALUE_TO_INT(coset
->p
[e
->x
.p
->pos
-1])],
113 vars
, extravar
, expr
, coset
);
118 int offset
= type_offset(e
->x
.p
);
119 for (int i
= e
->x
.p
->size
-1; i
>= offset
; --i
) {
121 ex t
= evalue2ex_r(&e
->x
.p
->arr
[i
], vars
, extravar
, expr
, coset
);
122 if (is_exactly_a
<fail
>(t
))
129 /* For each t = floor(e/d), set up two constraints
132 * -e + d t + d-1 >= 0
134 * e is assumed to be an affine expression.
136 * For each t = fract(e/d), set up two constraints
141 static Matrix
*setup_constraints(const vector
<typed_evalue
> expr
, int nvar
)
143 int extra
= expr
.size();
146 Matrix
*M
= Matrix_Alloc(2*extra
, 1+extra
+nvar
+1);
147 for (int i
= 0; i
< extra
; ++i
) {
149 value_set_si(M
->p
[2*i
][0], 1);
150 value_set_si(M
->p
[2*i
][1+i
], -1);
151 value_set_si(M
->p
[2*i
][1+extra
+nvar
], 1);
152 value_set_si(M
->p
[2*i
+1][0], 1);
153 value_set_si(M
->p
[2*i
+1][1+i
], 1);
155 Value
*d
= &M
->p
[2*i
][1+i
];
156 evalue_extract_affine(expr
[i
].second
, M
->p
[2*i
]+1+extra
,
157 M
->p
[2*i
]+1+extra
+nvar
, d
);
158 value_oppose(*d
, *d
);
159 value_set_si(M
->p
[2*i
][0], -1);
160 Vector_Scale(M
->p
[2*i
], M
->p
[2*i
+1], M
->p
[2*i
][0], 1+extra
+nvar
+1);
161 value_set_si(M
->p
[2*i
][0], 1);
162 value_subtract(M
->p
[2*i
+1][1+extra
+nvar
], M
->p
[2*i
+1][1+extra
+nvar
], *d
);
163 value_decrement(M
->p
[2*i
+1][1+extra
+nvar
], M
->p
[2*i
+1][1+extra
+nvar
]);
169 static bool evalue_is_periodic(const evalue
*e
, Vector
*periods
)
172 bool is_periodic
= false;
174 if (value_notzero_p(e
->d
))
177 assert(e
->x
.p
->type
!= partition
);
178 if (e
->x
.p
->type
== periodic
) {
181 value_set_si(size
, e
->x
.p
->size
);
182 value_lcm(periods
->p
[e
->x
.p
->pos
-1], periods
->p
[e
->x
.p
->pos
-1], size
);
186 offset
= type_offset(e
->x
.p
);
187 for (i
= e
->x
.p
->size
-1; i
>= offset
; --i
)
188 is_periodic
= evalue_is_periodic(&e
->x
.p
->arr
[i
], periods
) || is_periodic
;
192 static ex
evalue2lst(const evalue
*e
, const exvector
& vars
,
193 exvector
& extravar
, vector
<typed_evalue
>& expr
,
196 Vector
*coset
= Vector_Alloc(periods
->Size
);
200 list
.append(evalue2ex_r(e
, vars
, extravar
, expr
, coset
));
201 for (i
= coset
->Size
-1; i
>= 0; --i
) {
202 value_increment(coset
->p
[i
], coset
->p
[i
]);
203 if (value_lt(coset
->p
[i
], periods
->p
[i
]))
205 value_set_si(coset
->p
[i
], 0);
214 ex
evalue2ex(const evalue
*e
, const exvector
& vars
, exvector
& floorvar
,
215 Matrix
**C
, Vector
**p
)
217 vector
<typed_evalue
> expr
;
218 Vector
*periods
= Vector_Alloc(vars
.size());
221 for (int i
= 0; i
< periods
->Size
; ++i
)
222 value_set_si(periods
->p
[i
], 1);
223 if (evalue_is_periodic(e
, periods
)) {
229 Vector_Free(periods
);
231 ex poly
= evalue2ex_r(e
, vars
, floorvar
, expr
, NULL
);
232 Matrix
*M
= setup_constraints(expr
, vars
.size());
238 /* if the evalue is a relation, we use the relation to cut off the
239 * the edges of the domain
241 static Polyhedron
*relation_domain(Polyhedron
*D
, evalue
*fr
, unsigned MaxRays
)
243 assert(value_zero_p(fr
->d
));
244 assert(fr
->x
.p
->type
== fractional
);
245 assert(fr
->x
.p
->size
== 3);
246 Matrix
*T
= Matrix_Alloc(2, D
->Dimension
+1);
247 value_set_si(T
->p
[1][D
->Dimension
], 1);
249 /* convert argument of fractional to polylib */
250 /* the argument is assumed to be linear */
251 evalue
*p
= &fr
->x
.p
->arr
[0];
252 evalue_denom(p
, &T
->p
[1][D
->Dimension
]);
253 for (;value_zero_p(p
->d
); p
= &p
->x
.p
->arr
[0]) {
254 assert(p
->x
.p
->type
== polynomial
);
255 assert(p
->x
.p
->size
== 2);
256 assert(value_notzero_p(p
->x
.p
->arr
[1].d
));
257 int pos
= p
->x
.p
->pos
- 1;
258 value_assign(T
->p
[0][pos
], p
->x
.p
->arr
[1].x
.n
);
259 value_multiply(T
->p
[0][pos
], T
->p
[0][pos
], T
->p
[1][D
->Dimension
]);
260 value_division(T
->p
[0][pos
], T
->p
[0][pos
], p
->x
.p
->arr
[1].d
);
262 int pos
= D
->Dimension
;
263 value_assign(T
->p
[0][pos
], p
->x
.n
);
264 value_multiply(T
->p
[0][pos
], T
->p
[0][pos
], T
->p
[1][D
->Dimension
]);
265 value_division(T
->p
[0][pos
], T
->p
[0][pos
], p
->d
);
267 Polyhedron
*E
= NULL
;
268 for (Polyhedron
*P
= D
; P
; P
= P
->next
) {
269 Polyhedron
*I
= Polyhedron_Image(P
, T
, MaxRays
);
270 I
= DomainConstraintSimplify(I
, MaxRays
);
271 Polyhedron
*R
= Polyhedron_Preimage(I
, T
, MaxRays
);
273 Polyhedron
*next
= P
->next
;
275 Polyhedron
*S
= DomainIntersection(P
, R
, MaxRays
);
281 E
= DomainConcat(S
, E
);
288 piecewise_lst
*evalue_bernstein_coefficients(piecewise_lst
*pl_all
, evalue
*e
,
289 Polyhedron
*ctx
, const exvector
& params
)
292 barvinok_options
*options
= barvinok_options_new_with_defaults();
293 pl
= evalue_bernstein_coefficients(pl_all
, e
, ctx
, params
, options
);
294 barvinok_options_free(options
);
298 static piecewise_lst
*bernstein_coefficients(piecewise_lst
*pl_all
,
299 Polyhedron
*D
, const ex
& poly
,
301 const exvector
& params
, const exvector
& floorvar
,
302 barvinok_options
*options
);
304 /* Recursively apply Bernstein expansion on P, optimizing over dims[i]
305 * variables in each level. The context ctx is assumed to have been adapted
306 * to the first level in the recursion.
308 static piecewise_lst
*bernstein_coefficients_recursive(piecewise_lst
*pl_all
,
309 Polyhedron
*P
, const vector
<int>& dims
, const ex
& poly
,
311 const exvector
& params
, const exvector
& vars
,
312 barvinok_options
*options
)
314 assert(dims
.size() > 0);
315 assert(ctx
->Dimension
== P
->Dimension
- dims
[0]);
318 for (int j
= 0; j
< dims
.size(); ++j
) {
320 pl_vars
.insert(pl_vars
.end(), vars
.begin()+done
, vars
.begin()+done
+dims
[j
]);
322 pl_params
.insert(pl_params
.end(), vars
.begin()+done
+dims
[j
], vars
.end());
323 pl_params
.insert(pl_params
.end(), params
.begin(), params
.end());
326 pl
= bernstein_coefficients(NULL
, P
, poly
, ctx
,
327 pl_params
, pl_vars
, options
);
329 piecewise_lst
*new_pl
= NULL
;
330 Polyhedron
*U
= Universe_Polyhedron(pl_params
.size());
332 for (int i
= 0; i
< pl
->list
.size(); ++i
) {
333 Polyhedron
*D
= pl
->list
[i
].first
;
334 lst polys
= pl
->list
[i
].second
;
335 new_pl
= bernstein_coefficients(new_pl
, D
, polys
, U
, pl_params
,
351 pl_all
->combine(*pl
);
358 static piecewise_lst
*bernstein_coefficients_full_recurse(piecewise_lst
*pl_all
,
359 Polyhedron
*P
, const ex
& poly
,
361 const exvector
& params
, const exvector
& vars
,
362 barvinok_options
*options
)
364 Polyhedron
*CR
= align_context(ctx
, P
->Dimension
-1, options
->MaxRays
);
365 vector
<int> dims(vars
.size());
366 for (int i
= 0; i
< dims
.size(); ++i
)
368 pl_all
= bernstein_coefficients_recursive(pl_all
, P
, dims
, poly
, CR
,
369 params
, vars
, options
);
375 static piecewise_lst
*bernstein_coefficients_product(piecewise_lst
*pl_all
,
376 Polyhedron
*F
, Matrix
*T
, const ex
& poly
,
378 const exvector
& params
, const exvector
& vars
,
379 barvinok_options
*options
)
383 for (Polyhedron
*G
= F
; G
; G
= G
->next
)
387 unsigned nparam
= params
.size();
388 unsigned nvar
= vars
.size();
389 unsigned constraints
;
391 Polyhedron
*C
= NULL
;
393 /* More context constraints */
394 if (F
->Dimension
== ctx
->Dimension
) {
404 M
= Matrix_Alloc(F
->NbConstraints
, 1+nvar
+nparam
+1);
405 for (int i
= 0; i
< F
->NbConstraints
; ++i
) {
406 Vector_Copy(F
->Constraint
[i
], M
->p
[i
], 1+F
->Dimension
-nparam
);
407 Vector_Copy(F
->Constraint
[i
]+1+F
->Dimension
-nparam
,
408 M
->p
[i
]+1+nvar
, nparam
+1);
410 P
= Constraints2Polyhedron(M
, options
->MaxRays
);
414 constraints
= C
? C
->NbConstraints
: 0;
415 constraints
+= ctx
->NbConstraints
;
416 for (Polyhedron
*G
= F
->next
; G
; G
= G
->next
) {
417 constraints
+= G
->NbConstraints
;
421 unsigned total_var
= nvar
-(F
->Dimension
-nparam
);
424 M
= Matrix_Alloc(constraints
, 1+total_var
+nparam
+1);
425 for (Polyhedron
*G
= F
->next
; G
; G
= G
->next
) {
426 unsigned this_var
= G
->Dimension
- nparam
;
427 for (int i
= 0; i
< G
->NbConstraints
; ++i
) {
428 value_assign(M
->p
[c
+i
][0], G
->Constraint
[i
][0]);
429 Vector_Copy(G
->Constraint
[i
]+1, M
->p
[c
+i
]+1+skip
, this_var
);
430 Vector_Copy(G
->Constraint
[i
]+1+this_var
, M
->p
[c
+i
]+1+total_var
,
433 c
+= G
->NbConstraints
;
436 assert(skip
== total_var
);
438 for (int i
= 0; i
< C
->NbConstraints
; ++i
) {
439 value_assign(M
->p
[c
+i
][0], C
->Constraint
[i
][0]);
440 Vector_Copy(C
->Constraint
[i
]+1, M
->p
[c
+i
]+1+total_var
,
443 c
+= C
->NbConstraints
;
445 for (int i
= 0; i
< ctx
->NbConstraints
; ++i
) {
446 value_assign(M
->p
[c
+i
][0], ctx
->Constraint
[i
][0]);
447 Vector_Copy(ctx
->Constraint
[i
]+1, M
->p
[c
+i
]+1+total_var
, nparam
+1);
449 PC
= Constraints2Polyhedron(M
, options
->MaxRays
);
452 exvector newvars
= constructVariableVector(nvar
, "t");
453 matrix
subs(1, nvar
);
454 for (int i
= 0; i
< nvar
; ++i
)
455 for (int j
= 0; j
< nvar
; ++j
)
456 subs(0,i
) += value2numeric(T
->p
[i
][j
]) * newvars
[j
];
458 ex newpoly
= replaceVariablesInPolynomial(poly
, vars
, subs
);
460 vector
<int> dims(factors
);
461 for (int i
= 0; F
; ++i
, F
= F
->next
)
462 dims
[i
] = F
->Dimension
-nparam
;
464 pl_all
= bernstein_coefficients_recursive(pl_all
, P
, dims
, newpoly
, PC
,
465 params
, newvars
, options
);
473 static piecewise_lst
*bernstein_coefficients_polyhedron(piecewise_lst
*pl_all
,
474 Polyhedron
*P
, const ex
& poly
,
476 const exvector
& params
, const exvector
& floorvar
,
477 barvinok_options
*options
)
479 if (Polyhedron_is_unbounded(P
, ctx
->Dimension
, options
->MaxRays
)) {
480 fprintf(stderr
, "warning: unbounded domain skipped\n");
481 Polyhedron_Print(stderr
, P_VALUE_FMT
, P
);
485 if (options
->bernstein_recurse
& BV_BERNSTEIN_FACTORS
) {
487 Polyhedron
*F
= Polyhedron_Factor(P
, ctx
->Dimension
, &T
, options
->MaxRays
);
489 pl_all
= bernstein_coefficients_product(pl_all
, F
, T
, poly
, ctx
, params
,
496 if (floorvar
.size() > 1 &&
497 options
->bernstein_recurse
& BV_BERNSTEIN_INTERVALS
)
498 return bernstein_coefficients_full_recurse(pl_all
, P
, poly
, ctx
,
499 params
, floorvar
, options
);
501 unsigned PP_MaxRays
= options
->MaxRays
;
502 if (PP_MaxRays
& POL_NO_DUAL
)
505 Param_Polyhedron
*PP
= Polyhedron2Param_Domain(P
, ctx
, PP_MaxRays
);
507 piecewise_lst
*pl
= new piecewise_lst(params
, options
->bernstein_optimize
);
510 Polyhedron
*TC
= true_context(P
, ctx
, options
->MaxRays
);
511 FORALL_REDUCED_DOMAIN(PP
, TC
, nd
, options
, i
, PD
, rVD
)
512 matrix VM
= domainVertices(PP
, PD
, params
);
513 lst coeffs
= bernsteinExpansion(VM
, poly
, floorvar
, params
);
514 pl
->add_guarded_lst(rVD
, coeffs
);
515 END_FORALL_REDUCED_DOMAIN
518 Param_Polyhedron_Free(PP
);
522 pl_all
->combine(*pl
);
529 static piecewise_lst
*bernstein_coefficients(piecewise_lst
*pl_all
,
530 Polyhedron
*D
, const ex
& poly
,
532 const exvector
& params
, const exvector
& floorvar
,
533 barvinok_options
*options
)
535 if (!D
->next
&& emptyQ2(D
))
538 for (Polyhedron
*P
= D
; P
; P
= P
->next
) {
539 /* This shouldn't happen */
542 Polyhedron
*next
= P
->next
;
544 pl_all
= bernstein_coefficients_polyhedron(pl_all
, P
, poly
, ctx
,
545 params
, floorvar
, options
);
551 /* Compute the coefficients of the polynomial corresponding to each coset
552 * on its own domain. This allows us to cut the domain on multiples of
554 * To perform the cutting for a coset "i mod n = c" we map the domain
555 * to the quotient space trough "i = i' n + c", simplify the constraints
556 * (implicitly) and then map back to the original space.
558 static piecewise_lst
*bernstein_coefficients_periodic(piecewise_lst
*pl_all
,
559 Polyhedron
*D
, const evalue
*e
,
560 Polyhedron
*ctx
, const exvector
& vars
,
561 const exvector
& params
, Vector
*periods
,
562 barvinok_options
*options
)
564 assert(D
->Dimension
== periods
->Size
);
565 Matrix
*T
= Matrix_Alloc(D
->Dimension
+1, D
->Dimension
+1);
566 Matrix
*T2
= Matrix_Alloc(D
->Dimension
+1, D
->Dimension
+1);
567 Vector
*coset
= Vector_Alloc(periods
->Size
);
569 vector
<typed_evalue
> expr
;
570 exvector allvars
= vars
;
571 allvars
.insert(allvars
.end(), params
.begin(), params
.end());
573 value_set_si(T2
->p
[D
->Dimension
][D
->Dimension
], 1);
574 for (int i
= 0; i
< D
->Dimension
; ++i
) {
575 value_assign(T
->p
[i
][i
], periods
->p
[i
]);
576 value_lcm(T2
->p
[D
->Dimension
][D
->Dimension
],
577 T2
->p
[D
->Dimension
][D
->Dimension
], periods
->p
[i
]);
579 value_set_si(T
->p
[D
->Dimension
][D
->Dimension
], 1);
580 for (int i
= 0; i
< D
->Dimension
; ++i
)
581 value_division(T2
->p
[i
][i
], T2
->p
[D
->Dimension
][D
->Dimension
],
585 ex poly
= evalue2ex_r(e
, allvars
, extravar
, expr
, coset
);
586 assert(extravar
.size() == 0);
587 assert(expr
.size() == 0);
588 Polyhedron
*E
= DomainPreimage(D
, T
, options
->MaxRays
);
589 Polyhedron
*F
= DomainPreimage(E
, T2
, options
->MaxRays
);
592 pl_all
= bernstein_coefficients(pl_all
, F
, poly
, ctx
, params
,
595 for (i
= D
->Dimension
-1; i
>= 0; --i
) {
596 value_increment(coset
->p
[i
], coset
->p
[i
]);
597 value_increment(T
->p
[i
][D
->Dimension
], T
->p
[i
][D
->Dimension
]);
598 value_subtract(T2
->p
[i
][D
->Dimension
], T2
->p
[i
][D
->Dimension
],
600 if (value_lt(coset
->p
[i
], periods
->p
[i
]))
602 value_set_si(coset
->p
[i
], 0);
603 value_set_si(T
->p
[i
][D
->Dimension
], 0);
604 value_set_si(T2
->p
[i
][D
->Dimension
], 0);
615 piecewise_lst
*bernstein_coefficients_relation(piecewise_lst
*pl_all
,
616 Polyhedron
*D
, evalue
*EP
, Polyhedron
*ctx
,
617 const exvector
& allvars
, const exvector
& vars
,
618 const exvector
& params
, barvinok_options
*options
)
620 if (value_zero_p(EP
->d
) && EP
->x
.p
->type
== relation
) {
621 Polyhedron
*E
= relation_domain(D
, &EP
->x
.p
->arr
[0], options
->MaxRays
);
623 pl_all
= bernstein_coefficients_relation(pl_all
, E
, &EP
->x
.p
->arr
[1],
624 ctx
, allvars
, vars
, params
,
628 /* In principle, we could cut off the edges of this domain too */
629 if (EP
->x
.p
->size
> 2)
630 pl_all
= bernstein_coefficients_relation(pl_all
, D
, &EP
->x
.p
->arr
[2],
631 ctx
, allvars
, vars
, params
,
639 ex poly
= evalue2ex(EP
, allvars
, floorvar
, &M
, &periods
);
640 floorvar
.insert(floorvar
.end(), vars
.begin(), vars
.end());
643 Polyhedron
*AE
= align_context(D
, M
->NbColumns
-2, options
->MaxRays
);
644 E
= DomainAddConstraints(AE
, M
, options
->MaxRays
);
648 if (is_exactly_a
<fail
>(poly
)) {
653 pl_all
= bernstein_coefficients_periodic(pl_all
, E
, EP
, ctx
, vars
,
654 params
, periods
, options
);
656 pl_all
= bernstein_coefficients(pl_all
, E
, poly
, ctx
, params
,
659 Vector_Free(periods
);
666 piecewise_lst
*evalue_bernstein_coefficients(piecewise_lst
*pl_all
, evalue
*e
,
667 Polyhedron
*ctx
, const exvector
& params
,
668 barvinok_options
*options
)
670 unsigned nparam
= ctx
->Dimension
;
671 if (EVALUE_IS_ZERO(*e
))
673 assert(value_zero_p(e
->d
));
674 assert(e
->x
.p
->type
== partition
);
675 assert(e
->x
.p
->size
>= 2);
676 unsigned nvars
= EVALUE_DOMAIN(e
->x
.p
->arr
[0])->Dimension
- nparam
;
678 exvector vars
= constructVariableVector(nvars
, "v");
679 exvector allvars
= vars
;
680 allvars
.insert(allvars
.end(), params
.begin(), params
.end());
682 for (int i
= 0; i
< e
->x
.p
->size
/2; ++i
) {
683 pl_all
= bernstein_coefficients_relation(pl_all
,
684 EVALUE_DOMAIN(e
->x
.p
->arr
[2*i
]), &e
->x
.p
->arr
[2*i
+1],
685 ctx
, allvars
, vars
, params
, options
);