2 #include <bernstein/bernstein.h>
3 #include <bernstein/maximize.h>
12 static void domainVerticesAndRays(Polyhedron
*P
, GiNaC::matrix
& VM
, GiNaC::matrix
& RM
)
14 POL_ENSURE_VERTICES(P
);
16 for (int i
= 0; i
< P
->NbRays
; ++i
) {
17 if (value_zero_p(P
->Ray
[i
][0]))
19 else if (value_zero_p(P
->Ray
[i
][1+P
->Dimension
]))
24 VM
= GiNaC::matrix(nv
, P
->Dimension
);
25 RM
= GiNaC::matrix(nr
, P
->Dimension
);
27 for (int i
= 0; i
< P
->NbRays
; ++i
) {
28 if (value_zero_p(P
->Ray
[i
][1+P
->Dimension
])) {
29 for (int j
= 0; j
< P
->Dimension
; ++j
)
30 RM(nr
,j
) = value2numeric(P
->Ray
[i
][1+j
]);
32 if (value_notzero_p(P
->Ray
[i
][0]))
34 for (int j
= 0; j
< P
->Dimension
; ++j
)
35 RM(nr
,j
) = -RM(nr
-1,j
);
39 for (int j
= 0; j
< P
->Dimension
; ++j
)
40 VM(nv
,j
) = value2numeric(P
->Ray
[i
][1+j
]) /
41 value2numeric(P
->Ray
[i
][1+P
->Dimension
]);
46 static void find_lst_minmax(const lst
& l
, ex
& m
, ex
& M
)
48 lst::const_iterator i
= l
.begin();
50 for (++i
; i
!= l
.end(); ++i
) {
58 static bool is_linear_constraint(ex constraint
, const exvector
& vars
, matrix
& linear
)
60 linear
= matrix(vars
.size()+1, 1);
62 for (int i
= 0; i
< vars
.size(); ++i
) {
63 if (cst
.degree(vars
[i
]) > 1)
65 ex c
= cst
.coeff(vars
[i
], 1);
66 if (!is_a
<numeric
>(c
))
69 cst
= cst
.coeff(vars
[i
], 0);
71 if (!is_a
<numeric
>(cst
))
73 linear(vars
.size(),0) = cst
;
77 static void find_linear_minmax(Polyhedron
*D
, matrix constraint
, ex
& m
, ex
& M
)
79 // we only care about the sign anyway
81 for (Polyhedron
*P
= D
; P
; P
= P
->next
) {
82 POL_ENSURE_VERTICES(P
);
83 for (int i
= 0; i
< P
->NbRays
; ++i
) {
85 assert(value_one_p(P
->Ray
[i
][0]));
86 for (int j
= 0; j
< P
->Dimension
+1; ++j
)
87 sum
+= value2numeric(P
->Ray
[i
][1+j
]) * constraint(j
,0);
103 static poly_sign
polynomial_sign(ex poly
, Polyhedron
*D
, const GiNaC::matrix
& VM
,
104 const GiNaC::matrix
& RM
, const exvector
& vars
,
105 bool expensive_tests
);
107 /* bernstein requires a bounded domain, so if the domain is unbounded,
108 * we need a different trick.
109 * If a parameter N has a lowerbound l, then we write the polynomial as
110 * q(N,M) * (N-l) + r(M)
111 * if the signs of q and r can be determined and if they are equal,
112 * then the whole polynomial has the same sign.
114 static poly_sign
polynomial_sign_with_rays(ex poly
, Polyhedron
*D
,
115 const GiNaC::matrix
& VM
,
116 const GiNaC::matrix
& RM
, const exvector
& vars
,
117 bool expensive_tests
)
120 for (i
= 0; i
< vars
.size(); ++i
)
121 if (poly
.degree(vars
[i
]) > 0)
123 assert(i
< vars
.size());
125 for (int j
= 1; j
< VM
.rows(); ++j
)
130 for (int j
= 0; j
< RM
.rows(); ++j
)
133 int d
= poly
.degree(vars
[i
]);
134 ex cum
= poly
.coeff(vars
[i
],d
);
137 for (--d
; d
>= 1; --d
) {
139 cum
+= poly
.coeff(vars
[i
],d
);
143 ex r
= cum
* min
+ poly
.coeff(vars
[i
], 0);
144 poly_sign s1
= polynomial_sign(q
.expand(), D
, VM
, RM
, vars
, expensive_tests
);
147 poly_sign s2
= polynomial_sign(r
, D
, VM
, RM
, vars
, expensive_tests
);
159 static ex
substitute_equalities(ex poly
, Polyhedron
*D
, const exvector
& vars
)
164 for (int i
= 0; i
< D
->NbEq
; ++i
) {
165 int pos
= First_Non_Zero(D
->Constraint
[i
]+1, D
->Dimension
);
167 ex den
= -value2numeric(D
->Constraint
[i
][1+pos
]);
168 ex s
= value2numeric(D
->Constraint
[i
][1+D
->Dimension
]) / den
;
169 for (int j
= pos
+1; j
< D
->Dimension
; ++j
) {
170 if (value_zero_p(D
->Constraint
[i
][1+j
]))
172 s
+= value2numeric(D
->Constraint
[i
][1+j
]) * vars
[j
] / den
;
174 replacements
.append(vars
[pos
] == s
);
176 poly
= poly
.subs(replacements
).expand();
180 static poly_sign
polynomial_sign(ex poly
, Polyhedron
*D
, const GiNaC::matrix
& VM
,
181 const GiNaC::matrix
& RM
, const exvector
& vars
,
182 bool expensive_tests
)
187 poly
= substitute_equalities(poly
, D
, vars
);
188 if (is_a
<numeric
>(poly
))
190 else if (is_linear_constraint(poly
, vars
, linear
))
191 find_linear_minmax(D
, linear
, minc
, maxc
);
192 else if (expensive_tests
&& RM
.rows() == 0) {
193 lst coeffs
= bernsteinExpansion(VM
, poly
, vars
, params
);
194 find_lst_minmax(coeffs
, minc
, maxc
);
196 return polynomial_sign_with_rays(poly
, D
, VM
, RM
, vars
, expensive_tests
);
197 if (maxc
<= 0 && minc
>= 0)
206 /* Combine list1 and list2 into a single list with the redundant elements
207 * removed according to sign. If sign = 1, obviously smaller elements are
208 * removed; if sign = -1, obviously bigger elements are removed; if sign = 0,
209 * no elements are removed.
210 * If list1 and list2 are the same, the whole list is checked for redundant
211 * elements. If the lists are different, the individual lists are assumed
212 * to have no redundant elements.
214 GiNaC::lst
remove_redundants(Polyhedron
*domain
, GiNaC::lst list1
, GiNaC::lst list2
,
215 const GiNaC::exvector
& vars
, int sign
)
217 bool same_list
= list1
== list2
;
219 lst::const_iterator j
, k
;
224 for (k
= list2
.begin(); k
!= list2
.end(); ++k
)
226 return list
.sort().unique();
229 int sign_better
= sign
> 0 ? positive
: negative
;
230 int sign_worse
= sign
> 0 ? negative
: positive
;
232 GiNaC::matrix VM
, RM
;
233 domainVerticesAndRays(domain
, VM
, RM
);
236 for (j
= list1
.begin(); j
!= list1
.end(); ++j
) {
237 if (same_list
&& find(removed
.begin(), removed
.end(), *j
) != removed
.end())
244 for (; k
!= (same_list
? list1
.end() : list2
.end()); ++k
) {
245 if (find(removed
.begin(), removed
.end(), *k
) != removed
.end())
248 poly_sign s
= polynomial_sign(diff
, domain
, VM
, RM
, vars
, false);
249 if (s
== zero
|| s
== sign_worse
)
251 else if (s
== sign_better
)
260 for (k
= list2
.begin(); k
!= list2
.end(); ++k
) {
261 if (find(removed
.begin(), removed
.end(), *k
) != removed
.end())
268 GiNaC::lst
maximize(Polyhedron
*domain
, GiNaC::lst coeffs
,
269 const GiNaC::exvector
& vars
)
271 GiNaC::matrix VM
, RM
;
272 domainVerticesAndRays(domain
, VM
, RM
);
273 lst::const_iterator j
, k
;
276 for (j
= coeffs
.begin(); j
!= coeffs
.end(); ++j
) {
277 if (find(removed
.begin(), removed
.end(), *j
) != removed
.end())
281 for (; k
!= coeffs
.end(); ++k
) {
282 if (find(removed
.begin(), removed
.end(), *k
) != removed
.end())
285 poly_sign s
= polynomial_sign(diff
, domain
, VM
, RM
, vars
, true);
286 if (s
== zero
|| s
== negative
)
288 else if (s
== positive
)
299 GiNaC::lst
minimize(Polyhedron
*domain
, GiNaC::lst coeffs
,
300 const GiNaC::exvector
& vars
)
302 lst negcoeffs
, negresult
, result
;
303 lst::const_iterator j
;
304 for (j
= coeffs
.begin(); j
!= coeffs
.end(); ++j
)
305 negcoeffs
.append(-*j
);
306 negresult
= maximize(domain
, negcoeffs
, vars
);
307 for (j
= negresult
.begin(); j
!= negresult
.end(); ++j
)