2 #include <bernstein/bernstein.h>
3 #include <bernstein/piecewise_lst.h>
4 #include <barvinok/bernstein.h>
5 #include <barvinok/options.h>
6 #include <barvinok/polylib.h>
7 #include <barvinok/util.h>
8 #include <barvinok/evalue.h>
11 using namespace GiNaC
;
12 using namespace bernstein
;
13 using namespace barvinok
;
18 #define ALLOC(type) (type*)malloc(sizeof(type))
19 #define ALLOCN(type,n) (type*)malloc((n) * sizeof(type))
22 struct barvinok_options
*options
;
27 int test_monotonicity
;
30 piecewise_lst
*pl_all
;
34 static int type_offset(enode
*p
)
36 return p
->type
== fractional
? 1 :
37 p
->type
== flooring
? 1 :
38 p
->type
== relation
? 1 : 0;
41 /* Remove all terms from e that are not positive (sign > 0)
42 * or not negative (sign < 0)
44 static void evalue_fixed_sign_terms(evalue
*e
, int* signs
, int sign
)
49 assert(!EVALUE_IS_NAN(*e
));
50 if (value_notzero_p(e
->d
)) {
51 if (sign
* value_sign(e
->x
.n
) < 0) {
52 value_set_si(e
->x
.n
, 0);
53 value_set_si(e
->d
, 1);
58 if (e
->x
.p
->type
== relation
) {
59 for (i
= e
->x
.p
->size
-1; i
>= 1; --i
)
60 evalue_fixed_sign_terms(&e
->x
.p
->arr
[i
], signs
, sign
);
64 if (e
->x
.p
->type
== polynomial
)
65 sign_odd
*= signs
[e
->x
.p
->pos
-1];
67 offset
= type_offset(e
->x
.p
);
68 for (i
= offset
; i
< e
->x
.p
->size
; ++i
)
69 evalue_fixed_sign_terms(&e
->x
.p
->arr
[i
], signs
,
70 (i
- offset
) % 2 ? sign_odd
: sign
);
73 static void propagate_on_domain(Polyhedron
*D
, const evalue
*poly
,
74 struct range_data
*data
);
76 static evalue
*bound2evalue(Value
*bound
, unsigned dim
)
85 } else if (value_pos_p(bound
[1])) {
86 value_assign(denom
, bound
[1]);
87 b
= affine2evalue(bound
+2, denom
, dim
);
90 value_oppose(denom
, bound
[1]);
91 b
= affine2evalue(bound
+2, denom
, dim
);
99 static int evalue_is_constant(const evalue
*e
)
101 return EVALUE_IS_NAN(*e
) || value_notzero_p(e
->d
);
104 static void range_cb(Matrix
*M
, Value
*lower
, Value
*upper
, void *cb_data
)
106 struct range_data
*data
= (struct range_data
*)cb_data
;
108 unsigned dim
= M
->NbColumns
-2;
115 T
= Constraints2Polyhedron(M2
, data
->options
->MaxRays
);
118 POL_ENSURE_VERTICES(T
);
124 l
= bound2evalue(lower
, dim
);
125 u
= bound2evalue(upper
, dim
);
127 subs
= ALLOCN(evalue
*, 1+dim
);
128 for (int i
= 0; i
< dim
; ++i
)
129 subs
[1+i
] = evalue_var(i
);
131 if (evalue_is_constant(data
->poly
)) {
132 pos
= evalue_dup(data
->poly
);
133 } else if (data
->monotonicity
) {
134 pos
= evalue_dup(data
->poly
);
135 if (data
->monotonicity
* data
->sign
> 0)
139 evalue_substitute(pos
, subs
);
141 pos
= evalue_dup(data
->poly
);
142 neg
= evalue_dup(data
->poly
);
144 evalue_fixed_sign_terms(pos
, data
->signs
, data
->sign
);
145 evalue_fixed_sign_terms(neg
, data
->signs
, -data
->sign
);
148 evalue_substitute(pos
, subs
);
151 evalue_substitute(neg
, subs
);
157 for (int i
= 0; i
< dim
; ++i
)
158 evalue_free(subs
[1+i
]);
163 if (dim
== data
->nparam
) {
164 data
->pl
->add_guarded_lst(T
, lst(evalue2ex(pos
, data
->params
)));
166 propagate_on_domain(T
, pos
, data
);
173 static int has_sign(Polyhedron
*D
, evalue
*poly
, int sign
,
174 int *signs
, struct barvinok_options
*options
)
176 struct range_data data_m
;
180 data_m
.options
= options
;
182 data_m
.test_monotonicity
= 0;
183 data_m
.signs
= signs
;
185 data_m
.pl_all
= NULL
;
187 propagate_on_domain(D
, poly
, &data_m
);
189 assert(data_m
.pl_all
->list
.size() == 1);
190 assert(universeQ(data_m
.pl_all
->list
[0].first
));
191 l
= data_m
.pl_all
->list
[0].second
;
193 for (i
= 0; i
< l
.nops(); ++i
) {
194 if (is_exactly_a
<fail
>(l
.op(i
)))
196 if (sign
* l
.op(i
) < 0)
199 delete data_m
.pl_all
;
201 return i
== l
.nops();
204 /* Returns 1 if poly is monotonically increasing,
205 * -1 if poly is monotonically decreasing,
206 * 0 if no conclusion.
208 static int monotonicity(Polyhedron
*D
, const evalue
*poly
,
209 struct range_data
*data
)
217 value_set_si(one
, 1);
219 subs
= ALLOCN(evalue
*, D
->Dimension
);
220 for (int i
= 0; i
< D
->Dimension
; ++i
)
221 subs
[i
] = evalue_var(i
);
223 evalue_add_constant(subs
[0], one
);
225 diff
= evalue_dup(poly
);
226 evalue_substitute(diff
, subs
);
228 for (int i
= 0; i
< D
->Dimension
; ++i
)
229 evalue_free(subs
[i
]);
239 if (has_sign(D
, diff
, 1, data
->signs
, data
->options
))
241 else if (has_sign(D
, diff
, -1, data
->signs
, data
->options
))
248 static void propagate_on_domain(Polyhedron
*D
, const evalue
*poly
,
249 struct range_data
*data
)
251 const evalue
*save_poly
= data
->poly
;
252 int save_monotonicity
= data
->monotonicity
;
254 assert(D
->Dimension
> data
->nparam
);
256 if (data
->test_monotonicity
)
257 data
->monotonicity
= monotonicity(D
, poly
, data
);
259 data
->monotonicity
= 0;
261 if (D
->Dimension
== data
->nparam
+1)
262 data
->pl
= new piecewise_lst(data
->params
);
265 for_each_lower_upper_bound(D
, NULL
, range_cb
, data
);
267 if (D
->Dimension
== data
->nparam
+1) {
269 data
->pl_all
= data
->pl
;
271 data
->pl_all
->combine(*data
->pl
);
277 data
->poly
= save_poly
;
278 data
->monotonicity
= save_monotonicity
;
282 * Determines the sign of each variable in D.
283 * Copied from evalue.c
285 static void domain_signs(Polyhedron
*D
, int *signs
)
289 POL_ENSURE_VERTICES(D
);
290 for (j
= 0; j
< D
->Dimension
; ++j
) {
292 for (k
= 0; k
< D
->NbRays
; ++k
) {
293 signs
[j
] = value_sign(D
->Ray
[k
][1+j
]);
300 static evalue
*ex2evalue(const ex
& poly
, const exvector
& params
, int pos
)
302 if (pos
>= params
.size()) {
303 evalue
*c
= ALLOC(evalue
);
306 assert(is_a
<numeric
>(poly
));
307 numeric2value(ex_to
<numeric
>(poly
).numer(), c
->x
.n
);
308 numeric2value(ex_to
<numeric
>(poly
).denom(), c
->d
);
312 evalue
*v
= evalue_var(pos
);
313 evalue
*sum
= ex2evalue(poly
.coeff(params
[pos
], poly
.degree(params
[pos
])),
315 for (int i
= poly
.degree(params
[pos
])-1; i
>= 0; --i
) {
316 evalue
*t
= ex2evalue(poly
.coeff(params
[pos
], i
), params
, pos
+1);
325 /* Returns true is poly is no better than any of those from begin to end */
326 static int is_no_better(const ex
& poly
, const lst::const_iterator
& begin
,
327 const lst::const_iterator
& end
, const exvector
& params
,
328 int sign
, Polyhedron
*D
,
329 int *signs
, barvinok_options
*options
)
331 lst::const_iterator k
;
334 for (k
= begin
; k
!= end
; ++k
) {
336 diff
= diff
.expand();
337 evalue
*e
= ex2evalue(diff
, params
, 0);
338 no_better
= has_sign(D
, e
, sign
, signs
, options
);
346 static void remove_redundants(piecewise_lst
*pl
, const exvector
& params
,
347 barvinok_options
*options
)
352 int *signs
= (int *)alloca(sizeof(int) * params
.size());
354 for (int i
= 0; i
< pl
->list
.size(); ++i
) {
355 Polyhedron
*D
= pl
->list
[i
].first
;
356 lst todo
= pl
->list
[i
].second
;
358 lst::const_iterator j
, k
;
360 domain_signs(D
, signs
);
362 for (j
= todo
.begin(); j
!= todo
.end(); ++j
) {
364 if (is_no_better(*j
, k
, todo
.end(), params
,
365 pl
->sign
, D
, signs
, options
))
368 if (is_no_better(*j
, newlist
.begin(), newlist
.end(),
369 params
, pl
->sign
, D
, signs
, options
))
374 pl
->list
[i
].second
= newlist
;
378 piecewise_lst
*evalue_range_propagation(piecewise_lst
*pl_all
, const evalue
*e
,
379 const exvector
& params
,
380 barvinok_options
*options
)
383 struct range_data data
;
385 if (EVALUE_IS_ZERO(*e
))
388 assert(value_zero_p(e
->d
));
389 assert(e
->x
.p
->type
== partition
);
390 assert(e
->x
.p
->size
>= 2);
391 unsigned nparam
= params
.size();
392 unsigned dim
= EVALUE_DOMAIN(e
->x
.p
->arr
[0])->Dimension
;
393 unsigned nvars
= dim
- nparam
;
400 data
.nparam
= nparam
;
401 data
.params
= params
;
402 data
.options
= options
;
403 data
.pl_all
= pl_all
;
404 if (options
->bernstein_optimize
== BV_BERNSTEIN_MIN
)
408 data
.test_monotonicity
= 1;
411 evalue_split_domains_into_orthants(e2
, options
->MaxRays
);
413 data
.signs
= (int *)alloca(sizeof(int) * dim
);
415 for (int i
= 0; i
< e2
->x
.p
->size
/2; ++i
) {
416 Polyhedron
*D
= EVALUE_DOMAIN(e2
->x
.p
->arr
[2*i
]);
417 for (Polyhedron
*P
= D
; P
; P
= P
->next
) {
418 domain_signs(P
, data
.signs
);
419 propagate_on_domain(P
, &e2
->x
.p
->arr
[2*i
+1], &data
);
424 data
.pl_all
->sign
= options
->bernstein_optimize
;
425 remove_redundants(data
.pl_all
, params
, options
);