3 #include <bernstein/bernstein.h>
4 #include <bernstein/maximize.h>
13 static void domainVerticesAndRays(Polyhedron
*P
, GiNaC::matrix
& VM
, GiNaC::matrix
& RM
)
15 POL_ENSURE_VERTICES(P
);
17 for (int i
= 0; i
< P
->NbRays
; ++i
) {
18 if (value_zero_p(P
->Ray
[i
][0]))
20 else if (value_zero_p(P
->Ray
[i
][1+P
->Dimension
]))
25 VM
= GiNaC::matrix(nv
, P
->Dimension
);
26 RM
= GiNaC::matrix(nr
, P
->Dimension
);
28 for (int i
= 0; i
< P
->NbRays
; ++i
) {
29 if (value_zero_p(P
->Ray
[i
][1+P
->Dimension
])) {
30 for (int j
= 0; j
< P
->Dimension
; ++j
)
31 RM(nr
,j
) = value2numeric(P
->Ray
[i
][1+j
]);
33 if (value_notzero_p(P
->Ray
[i
][0]))
35 for (int j
= 0; j
< P
->Dimension
; ++j
)
36 RM(nr
,j
) = -RM(nr
-1,j
);
40 for (int j
= 0; j
< P
->Dimension
; ++j
)
41 VM(nv
,j
) = value2numeric(P
->Ray
[i
][1+j
]) /
42 value2numeric(P
->Ray
[i
][1+P
->Dimension
]);
47 static void find_lst_minmax(const lst
& l
, ex
& m
, ex
& M
)
49 lst::const_iterator i
= l
.begin();
51 for (++i
; i
!= l
.end(); ++i
) {
59 static bool is_linear_constraint(ex constraint
, const exvector
& vars
, matrix
& linear
)
61 linear
= matrix(vars
.size()+1, 1);
63 for (int i
= 0; i
< vars
.size(); ++i
) {
64 if (cst
.degree(vars
[i
]) > 1)
66 ex c
= cst
.coeff(vars
[i
], 1);
67 if (!is_a
<numeric
>(c
))
70 cst
= cst
.coeff(vars
[i
], 0);
72 if (!is_a
<numeric
>(cst
))
74 linear(vars
.size(),0) = cst
;
78 static void find_linear_minmax(Polyhedron
*D
, matrix constraint
, ex
& m
, ex
& M
)
80 // we only care about the sign anyway
82 for (Polyhedron
*P
= D
; P
; P
= P
->next
) {
83 POL_ENSURE_VERTICES(P
);
84 for (int i
= 0; i
< P
->NbRays
; ++i
) {
86 assert(value_one_p(P
->Ray
[i
][0]));
87 for (int j
= 0; j
< P
->Dimension
+1; ++j
)
88 sum
+= value2numeric(P
->Ray
[i
][1+j
]) * constraint(j
,0);
104 static poly_sign
polynomial_sign(ex poly
, Polyhedron
*D
, const GiNaC::matrix
& VM
,
105 const GiNaC::matrix
& RM
, const exvector
& vars
,
106 bool expensive_tests
);
108 /* bernstein requires a bounded domain, so if the domain is unbounded,
109 * we need a different trick.
110 * If a parameter N has a lowerbound l, then we write the polynomial as
111 * q(N,M) * (N-l) + r(M)
112 * if the signs of q and r can be determined and if they are equal,
113 * then the whole polynomial has the same sign.
115 static poly_sign
polynomial_sign_with_rays(ex poly
, Polyhedron
*D
,
116 const GiNaC::matrix
& VM
,
117 const GiNaC::matrix
& RM
, const exvector
& vars
,
118 bool expensive_tests
)
121 for (i
= 0; i
< vars
.size(); ++i
)
122 if (poly
.degree(vars
[i
]) > 0)
124 assert(i
< vars
.size());
126 for (int j
= 1; j
< VM
.rows(); ++j
)
131 for (int j
= 0; j
< RM
.rows(); ++j
)
134 int d
= poly
.degree(vars
[i
]);
135 ex cum
= poly
.coeff(vars
[i
],d
);
138 for (--d
; d
>= 1; --d
) {
140 cum
+= poly
.coeff(vars
[i
],d
);
144 ex r
= cum
* min
+ poly
.coeff(vars
[i
], 0);
145 poly_sign s1
= polynomial_sign(q
.expand(), D
, VM
, RM
, vars
, expensive_tests
);
148 poly_sign s2
= polynomial_sign(r
, D
, VM
, RM
, vars
, expensive_tests
);
160 static ex
substitute_equalities(ex poly
, Polyhedron
*D
, const exvector
& vars
)
165 for (int i
= 0; i
< D
->NbEq
; ++i
) {
166 int pos
= First_Non_Zero(D
->Constraint
[i
]+1, D
->Dimension
);
168 ex den
= -value2numeric(D
->Constraint
[i
][1+pos
]);
169 ex s
= value2numeric(D
->Constraint
[i
][1+D
->Dimension
]) / den
;
170 for (int j
= pos
+1; j
< D
->Dimension
; ++j
) {
171 if (value_zero_p(D
->Constraint
[i
][1+j
]))
173 s
+= value2numeric(D
->Constraint
[i
][1+j
]) * vars
[j
] / den
;
175 replacements
.append(vars
[pos
] == s
);
177 poly
= poly
.subs(replacements
).expand();
181 static poly_sign
polynomial_sign(ex poly
, Polyhedron
*D
, const GiNaC::matrix
& VM
,
182 const GiNaC::matrix
& RM
, const exvector
& vars
,
183 bool expensive_tests
)
188 poly
= substitute_equalities(poly
, D
, vars
);
189 if (is_a
<numeric
>(poly
))
191 else if (is_linear_constraint(poly
, vars
, linear
))
192 find_linear_minmax(D
, linear
, minc
, maxc
);
193 else if (expensive_tests
&& RM
.rows() == 0) {
194 lst coeffs
= bernsteinExpansion(VM
, poly
, vars
, params
);
195 find_lst_minmax(coeffs
, minc
, maxc
);
197 return polynomial_sign_with_rays(poly
, D
, VM
, RM
, vars
, expensive_tests
);
198 if (maxc
<= 0 && minc
>= 0)
207 /* Combine list1 and list2 into a single list with the redundant elements
208 * removed according to sign. If sign = 1, obviously smaller elements are
209 * removed; if sign = -1, obviously bigger elements are removed; if sign = 0,
210 * no elements are removed.
211 * If list1 and list2 are the same, the whole list is checked for redundant
212 * elements. If the lists are different, the individual lists are assumed
213 * to have no redundant elements.
215 GiNaC::lst
remove_redundants(Polyhedron
*domain
, GiNaC::lst list1
, GiNaC::lst list2
,
216 const GiNaC::exvector
& vars
, int sign
)
218 bool same_list
= list1
== list2
;
220 lst::const_iterator j
, k
;
225 for (k
= list2
.begin(); k
!= list2
.end(); ++k
)
227 return list
.sort().unique();
230 int sign_better
= sign
> 0 ? positive
: negative
;
231 int sign_worse
= sign
> 0 ? negative
: positive
;
233 GiNaC::matrix VM
, RM
;
234 domainVerticesAndRays(domain
, VM
, RM
);
237 for (j
= list1
.begin(); j
!= list1
.end(); ++j
) {
238 if (same_list
&& find(removed
.begin(), removed
.end(), *j
) != removed
.end())
245 for (; k
!= (same_list
? list1
.end() : list2
.end()); ++k
) {
246 if (find(removed
.begin(), removed
.end(), *k
) != removed
.end())
249 poly_sign s
= polynomial_sign(diff
, domain
, VM
, RM
, vars
, false);
250 if (s
== zero
|| s
== sign_worse
)
252 else if (s
== sign_better
)
261 for (k
= list2
.begin(); k
!= list2
.end(); ++k
) {
262 if (find(removed
.begin(), removed
.end(), *k
) != removed
.end())
269 GiNaC::lst
maximize(Polyhedron
*domain
, GiNaC::lst coeffs
,
270 const GiNaC::exvector
& vars
)
272 GiNaC::matrix VM
, RM
;
273 domainVerticesAndRays(domain
, VM
, RM
);
274 lst::const_iterator j
, k
;
277 for (j
= coeffs
.begin(); j
!= coeffs
.end(); ++j
) {
278 if (find(removed
.begin(), removed
.end(), *j
) != removed
.end())
282 for (; k
!= coeffs
.end(); ++k
) {
283 if (find(removed
.begin(), removed
.end(), *k
) != removed
.end())
286 poly_sign s
= polynomial_sign(diff
, domain
, VM
, RM
, vars
, true);
287 if (s
== zero
|| s
== negative
)
289 else if (s
== positive
)
300 GiNaC::lst
minimize(Polyhedron
*domain
, GiNaC::lst coeffs
,
301 const GiNaC::exvector
& vars
)
303 lst negcoeffs
, negresult
, result
;
304 lst::const_iterator j
;
305 for (j
= coeffs
.begin(); j
!= coeffs
.end(); ++j
)
306 negcoeffs
.append(-*j
);
307 negresult
= maximize(domain
, negcoeffs
, vars
);
308 for (j
= negresult
.begin(); j
!= negresult
.end(); ++j
)