3 #include <bernstein/bernstein.h>
4 #include <bernstein/piecewise_lst.h>
5 #include <barvinok/bernstein.h>
6 #include <barvinok/options.h>
7 #include <barvinok/polylib.h>
8 #include <barvinok/util.h>
9 #include <barvinok/evalue.h>
10 #include "ex_convert.h"
13 using namespace GiNaC
;
14 using namespace bernstein
;
15 using namespace barvinok
;
20 #define ALLOCN(type,n) (type*)malloc((n) * sizeof(type))
23 struct barvinok_options
*options
;
28 int test_monotonicity
;
31 piecewise_lst
*pl_all
;
35 static int type_offset(enode
*p
)
37 return p
->type
== fractional
? 1 :
38 p
->type
== flooring
? 1 :
39 p
->type
== relation
? 1 : 0;
42 /* Remove all terms from e that are not positive (sign > 0)
43 * or not negative (sign < 0)
45 static void evalue_fixed_sign_terms(evalue
*e
, int* signs
, int sign
)
50 assert(!EVALUE_IS_NAN(*e
));
51 if (value_notzero_p(e
->d
)) {
52 if (sign
* value_sign(e
->x
.n
) < 0) {
53 value_set_si(e
->x
.n
, 0);
54 value_set_si(e
->d
, 1);
59 if (e
->x
.p
->type
== relation
) {
60 for (i
= e
->x
.p
->size
-1; i
>= 1; --i
)
61 evalue_fixed_sign_terms(&e
->x
.p
->arr
[i
], signs
, sign
);
65 if (e
->x
.p
->type
== polynomial
)
66 sign_odd
*= signs
[e
->x
.p
->pos
-1];
68 offset
= type_offset(e
->x
.p
);
69 for (i
= offset
; i
< e
->x
.p
->size
; ++i
)
70 evalue_fixed_sign_terms(&e
->x
.p
->arr
[i
], signs
,
71 (i
- offset
) % 2 ? sign_odd
: sign
);
74 static void propagate_on_domain(Polyhedron
*D
, const evalue
*poly
,
75 struct range_data
*data
);
77 static evalue
*bound2evalue(Value
*bound
, unsigned dim
)
86 } else if (value_pos_p(bound
[1])) {
87 value_assign(denom
, bound
[1]);
88 b
= affine2evalue(bound
+2, denom
, dim
);
91 value_oppose(denom
, bound
[1]);
92 b
= affine2evalue(bound
+2, denom
, dim
);
100 static int evalue_is_constant(const evalue
*e
)
102 return EVALUE_IS_NAN(*e
) || value_notzero_p(e
->d
);
105 static void range_cb(Matrix
*M
, Value
*lower
, Value
*upper
, void *cb_data
)
107 struct range_data
*data
= (struct range_data
*)cb_data
;
109 unsigned dim
= M
->NbColumns
-2;
116 T
= Constraints2Polyhedron(M2
, data
->options
->MaxRays
);
119 POL_ENSURE_VERTICES(T
);
125 l
= bound2evalue(lower
, dim
);
126 u
= bound2evalue(upper
, dim
);
128 subs
= ALLOCN(evalue
*, 1+dim
);
129 for (int i
= 0; i
< dim
; ++i
)
130 subs
[1+i
] = evalue_var(i
);
132 if (evalue_is_constant(data
->poly
)) {
133 pos
= evalue_dup(data
->poly
);
134 } else if (data
->monotonicity
) {
135 pos
= evalue_dup(data
->poly
);
136 if (data
->monotonicity
* data
->sign
> 0)
140 evalue_substitute(pos
, subs
);
142 pos
= evalue_dup(data
->poly
);
143 neg
= evalue_dup(data
->poly
);
145 evalue_fixed_sign_terms(pos
, data
->signs
, data
->sign
);
146 evalue_fixed_sign_terms(neg
, data
->signs
, -data
->sign
);
149 evalue_substitute(pos
, subs
);
152 evalue_substitute(neg
, subs
);
158 for (int i
= 0; i
< dim
; ++i
)
159 evalue_free(subs
[1+i
]);
164 if (dim
== data
->nparam
) {
165 data
->pl
->add_guarded_lst(T
, lst(evalue2ex(pos
, data
->params
)));
167 propagate_on_domain(T
, pos
, data
);
174 static int has_sign(Polyhedron
*D
, evalue
*poly
, int sign
,
175 int *signs
, struct barvinok_options
*options
)
177 struct range_data data_m
;
181 data_m
.options
= options
;
183 data_m
.test_monotonicity
= 0;
184 data_m
.signs
= signs
;
186 data_m
.pl_all
= NULL
;
188 propagate_on_domain(D
, poly
, &data_m
);
190 assert(data_m
.pl_all
->list
.size() == 1);
191 assert(universeQ(data_m
.pl_all
->list
[0].first
));
192 l
= data_m
.pl_all
->list
[0].second
;
194 for (i
= 0; i
< l
.nops(); ++i
) {
195 if (is_exactly_a
<fail
>(l
.op(i
)))
197 if (sign
* l
.op(i
) < 0)
200 delete data_m
.pl_all
;
202 return i
== l
.nops();
205 /* Returns 1 if poly is monotonically increasing,
206 * -1 if poly is monotonically decreasing,
207 * 0 if no conclusion.
209 static int monotonicity(Polyhedron
*D
, const evalue
*poly
,
210 struct range_data
*data
)
218 value_set_si(one
, 1);
220 subs
= ALLOCN(evalue
*, D
->Dimension
);
221 for (int i
= 0; i
< D
->Dimension
; ++i
)
222 subs
[i
] = evalue_var(i
);
224 evalue_add_constant(subs
[0], one
);
226 diff
= evalue_dup(poly
);
227 evalue_substitute(diff
, subs
);
229 for (int i
= 0; i
< D
->Dimension
; ++i
)
230 evalue_free(subs
[i
]);
240 if (has_sign(D
, diff
, 1, data
->signs
, data
->options
))
242 else if (has_sign(D
, diff
, -1, data
->signs
, data
->options
))
249 static void propagate_on_domain(Polyhedron
*D
, const evalue
*poly
,
250 struct range_data
*data
)
252 const evalue
*save_poly
= data
->poly
;
253 int save_monotonicity
= data
->monotonicity
;
255 assert(D
->Dimension
> data
->nparam
);
257 if (data
->test_monotonicity
)
258 data
->monotonicity
= monotonicity(D
, poly
, data
);
260 data
->monotonicity
= 0;
262 if (D
->Dimension
== data
->nparam
+1)
263 data
->pl
= new piecewise_lst(data
->params
);
266 for_each_lower_upper_bound(D
, NULL
, range_cb
, data
);
268 if (D
->Dimension
== data
->nparam
+1) {
270 data
->pl_all
= data
->pl
;
272 data
->pl_all
->combine(*data
->pl
);
278 data
->poly
= save_poly
;
279 data
->monotonicity
= save_monotonicity
;
283 * Determines the sign of each variable in D.
284 * Copied from evalue.c
286 static void domain_signs(Polyhedron
*D
, int *signs
)
290 POL_ENSURE_VERTICES(D
);
291 for (j
= 0; j
< D
->Dimension
; ++j
) {
293 for (k
= 0; k
< D
->NbRays
; ++k
) {
294 signs
[j
] = value_sign(D
->Ray
[k
][1+j
]);
301 /* Returns true is poly is no better than any of those from begin to end */
302 static int is_no_better(const ex
& poly
, const lst::const_iterator
& begin
,
303 const lst::const_iterator
& end
, const exvector
& params
,
304 int sign
, Polyhedron
*D
,
305 int *signs
, barvinok_options
*options
)
307 lst::const_iterator k
;
310 for (k
= begin
; k
!= end
; ++k
) {
312 diff
= diff
.expand();
313 evalue
*e
= ex2evalue(diff
, params
);
314 no_better
= has_sign(D
, e
, sign
, signs
, options
);
322 static void remove_redundants(piecewise_lst
*pl
, const exvector
& params
,
323 barvinok_options
*options
)
328 int *signs
= (int *)alloca(sizeof(int) * params
.size());
330 for (int i
= 0; i
< pl
->list
.size(); ++i
) {
331 Polyhedron
*D
= pl
->list
[i
].first
;
332 lst todo
= pl
->list
[i
].second
;
334 lst::const_iterator j
, k
;
336 domain_signs(D
, signs
);
338 for (j
= todo
.begin(); j
!= todo
.end(); ++j
) {
340 if (is_no_better(*j
, k
, todo
.end(), params
,
341 pl
->sign
, D
, signs
, options
))
344 if (is_no_better(*j
, newlist
.begin(), newlist
.end(),
345 params
, pl
->sign
, D
, signs
, options
))
350 pl
->list
[i
].second
= newlist
;
354 piecewise_lst
*evalue_range_propagation(piecewise_lst
*pl_all
, const evalue
*e
,
355 const exvector
& params
,
356 barvinok_options
*options
)
359 struct range_data data
;
361 if (EVALUE_IS_ZERO(*e
))
364 assert(value_zero_p(e
->d
));
365 assert(e
->x
.p
->type
== partition
);
366 assert(e
->x
.p
->size
>= 2);
367 unsigned nparam
= params
.size();
368 unsigned dim
= EVALUE_DOMAIN(e
->x
.p
->arr
[0])->Dimension
;
369 unsigned nvars
= dim
- nparam
;
376 data
.nparam
= nparam
;
377 data
.params
= params
;
378 data
.options
= options
;
379 data
.pl_all
= pl_all
;
380 if (options
->bernstein_optimize
== BV_BERNSTEIN_MIN
)
384 data
.test_monotonicity
= 1;
387 evalue_split_domains_into_orthants(e2
, options
->MaxRays
);
389 data
.signs
= (int *)alloca(sizeof(int) * dim
);
391 for (int i
= 0; i
< e2
->x
.p
->size
/2; ++i
) {
392 Polyhedron
*D
= EVALUE_DOMAIN(e2
->x
.p
->arr
[2*i
]);
393 for (Polyhedron
*P
= D
; P
; P
= P
->next
) {
394 domain_signs(P
, data
.signs
);
395 propagate_on_domain(P
, &e2
->x
.p
->arr
[2*i
+1], &data
);
400 data
.pl_all
->sign
= options
->bernstein_optimize
;
401 remove_redundants(data
.pl_all
, params
, options
);