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 ALLOCN(type,n) (type*)malloc((n) * sizeof(type))
21 struct barvinok_options
*options
;
26 int test_monotonicity
;
29 piecewise_lst
*pl_all
;
33 static int type_offset(enode
*p
)
35 return p
->type
== fractional
? 1 :
36 p
->type
== flooring
? 1 :
37 p
->type
== relation
? 1 : 0;
40 /* Remove all terms from e that are not positive (sign > 0)
41 * or not negative (sign < 0)
43 static void evalue_fixed_sign_terms(evalue
*e
, int* signs
, int sign
)
48 assert(!EVALUE_IS_NAN(*e
));
49 if (value_notzero_p(e
->d
)) {
50 if (sign
* value_sign(e
->x
.n
) < 0) {
51 value_set_si(e
->x
.n
, 0);
52 value_set_si(e
->d
, 1);
57 if (e
->x
.p
->type
== relation
) {
58 for (i
= e
->x
.p
->size
-1; i
>= 1; --i
)
59 evalue_fixed_sign_terms(&e
->x
.p
->arr
[i
], signs
, sign
);
63 if (e
->x
.p
->type
== polynomial
)
64 sign_odd
*= signs
[e
->x
.p
->pos
-1];
66 offset
= type_offset(e
->x
.p
);
67 for (i
= offset
; i
< e
->x
.p
->size
; ++i
)
68 evalue_fixed_sign_terms(&e
->x
.p
->arr
[i
], signs
,
69 (i
- offset
) % 2 ? sign_odd
: sign
);
72 static void propagate_on_domain(Polyhedron
*D
, const evalue
*poly
,
73 struct range_data
*data
);
75 static evalue
*bound2evalue(Value
*bound
, unsigned dim
)
84 } else if (value_pos_p(bound
[1])) {
85 value_assign(denom
, bound
[1]);
86 b
= affine2evalue(bound
+2, denom
, dim
);
89 value_oppose(denom
, bound
[1]);
90 b
= affine2evalue(bound
+2, denom
, dim
);
98 static int evalue_is_constant(const evalue
*e
)
100 return EVALUE_IS_NAN(*e
) || value_notzero_p(e
->d
);
103 static void range_cb(Matrix
*M
, Value
*lower
, Value
*upper
, void *cb_data
)
105 struct range_data
*data
= (struct range_data
*)cb_data
;
107 unsigned dim
= M
->NbColumns
-2;
114 T
= Constraints2Polyhedron(M2
, data
->options
->MaxRays
);
117 POL_ENSURE_VERTICES(T
);
123 l
= bound2evalue(lower
, dim
);
124 u
= bound2evalue(upper
, dim
);
126 subs
= ALLOCN(evalue
*, 1+dim
);
127 for (int i
= 0; i
< dim
; ++i
)
128 subs
[1+i
] = evalue_var(i
);
130 if (evalue_is_constant(data
->poly
)) {
131 pos
= evalue_dup(data
->poly
);
132 } else if (data
->monotonicity
) {
133 pos
= evalue_dup(data
->poly
);
134 if (data
->monotonicity
* data
->sign
> 0)
138 evalue_substitute(pos
, subs
);
140 pos
= evalue_dup(data
->poly
);
141 neg
= evalue_dup(data
->poly
);
143 evalue_fixed_sign_terms(pos
, data
->signs
, data
->sign
);
144 evalue_fixed_sign_terms(neg
, data
->signs
, -data
->sign
);
147 evalue_substitute(pos
, subs
);
150 evalue_substitute(neg
, subs
);
156 for (int i
= 0; i
< dim
; ++i
)
157 evalue_free(subs
[1+i
]);
162 if (dim
== data
->nparam
) {
163 data
->pl
->add_guarded_lst(T
, lst(evalue2ex(pos
, data
->params
)));
165 propagate_on_domain(T
, pos
, data
);
172 static int has_sign(Polyhedron
*D
, evalue
*poly
, int sign
,
173 int *signs
, struct barvinok_options
*options
)
175 struct range_data data_m
;
179 data_m
.options
= options
;
181 data_m
.test_monotonicity
= 0;
182 data_m
.signs
= signs
;
184 data_m
.pl_all
= NULL
;
186 propagate_on_domain(D
, poly
, &data_m
);
188 assert(data_m
.pl_all
->list
.size() == 1);
189 assert(universeQ(data_m
.pl_all
->list
[0].first
));
190 l
= data_m
.pl_all
->list
[0].second
;
192 for (i
= 0; i
< l
.nops(); ++i
) {
193 if (is_exactly_a
<fail
>(l
.op(i
)))
195 if (sign
* l
.op(i
) < 0)
198 delete data_m
.pl_all
;
200 return i
== l
.nops();
203 /* Returns 1 if poly is monotonically increasing,
204 * -1 if poly is monotonically decreasing,
205 * 0 if no conclusion.
207 static int monotonicity(Polyhedron
*D
, const evalue
*poly
,
208 struct range_data
*data
)
216 value_set_si(one
, 1);
218 subs
= ALLOCN(evalue
*, D
->Dimension
);
219 for (int i
= 0; i
< D
->Dimension
; ++i
)
220 subs
[i
] = evalue_var(i
);
222 evalue_add_constant(subs
[0], one
);
224 diff
= evalue_dup(poly
);
225 evalue_substitute(diff
, subs
);
227 for (int i
= 0; i
< D
->Dimension
; ++i
)
228 evalue_free(subs
[i
]);
238 if (has_sign(D
, diff
, 1, data
->signs
, data
->options
))
240 else if (has_sign(D
, diff
, -1, data
->signs
, data
->options
))
247 static void propagate_on_domain(Polyhedron
*D
, const evalue
*poly
,
248 struct range_data
*data
)
250 const evalue
*save_poly
= data
->poly
;
251 int save_monotonicity
= data
->monotonicity
;
253 assert(D
->Dimension
> data
->nparam
);
255 if (data
->test_monotonicity
)
256 data
->monotonicity
= monotonicity(D
, poly
, data
);
258 data
->monotonicity
= 0;
260 if (D
->Dimension
== data
->nparam
+1)
261 data
->pl
= new piecewise_lst(data
->params
);
264 for_each_lower_upper_bound(D
, NULL
, range_cb
, data
);
266 if (D
->Dimension
== data
->nparam
+1) {
268 data
->pl_all
= data
->pl
;
270 data
->pl_all
->combine(*data
->pl
);
276 data
->poly
= save_poly
;
277 data
->monotonicity
= save_monotonicity
;
281 * Determines the sign of each variable in D.
282 * Copied from evalue.c
284 static void domain_signs(Polyhedron
*D
, int *signs
)
288 POL_ENSURE_VERTICES(D
);
289 for (j
= 0; j
< D
->Dimension
; ++j
) {
291 for (k
= 0; k
< D
->NbRays
; ++k
) {
292 signs
[j
] = value_sign(D
->Ray
[k
][1+j
]);
299 piecewise_lst
*evalue_range_propagation(piecewise_lst
*pl_all
, const evalue
*e
,
300 const exvector
& params
,
301 barvinok_options
*options
)
304 struct range_data data
;
306 if (EVALUE_IS_ZERO(*e
))
309 assert(value_zero_p(e
->d
));
310 assert(e
->x
.p
->type
== partition
);
311 assert(e
->x
.p
->size
>= 2);
312 unsigned nparam
= params
.size();
313 unsigned dim
= EVALUE_DOMAIN(e
->x
.p
->arr
[0])->Dimension
;
314 unsigned nvars
= dim
- nparam
;
321 data
.nparam
= nparam
;
322 data
.params
= params
;
323 data
.options
= options
;
324 data
.pl_all
= pl_all
;
325 if (options
->bernstein_optimize
== BV_BERNSTEIN_MIN
)
329 data
.test_monotonicity
= 1;
332 evalue_split_domains_into_orthants(e2
, options
->MaxRays
);
334 data
.signs
= (int *)alloca(sizeof(int) * dim
);
336 for (int i
= 0; i
< e2
->x
.p
->size
/2; ++i
) {
337 Polyhedron
*D
= EVALUE_DOMAIN(e2
->x
.p
->arr
[2*i
]);
338 for (Polyhedron
*P
= D
; P
; P
= P
->next
) {
339 domain_signs(P
, data
.signs
);
340 propagate_on_domain(P
, &e2
->x
.p
->arr
[2*i
+1], &data
);