mirror of
https://github.com/Z3Prover/z3
synced 2025-04-13 04:28:17 +00:00
Add bisect_isolate_roots
Signed-off-by: Leonardo de Moura <leonardo@microsoft.com>
This commit is contained in:
parent
f70de8dd47
commit
3cc072f3a7
|
@ -79,10 +79,10 @@ namespace realclosure {
|
|||
struct interval {
|
||||
numeral m_lower;
|
||||
numeral m_upper;
|
||||
unsigned m_lower_inf:1;
|
||||
unsigned m_upper_inf:1;
|
||||
unsigned m_lower_open:1;
|
||||
unsigned m_upper_open:1;
|
||||
unsigned char m_lower_inf;
|
||||
unsigned char m_upper_inf;
|
||||
unsigned char m_lower_open;
|
||||
unsigned char m_upper_open;
|
||||
interval():m_lower_inf(true), m_upper_inf(true), m_lower_open(true), m_upper_open(true) {}
|
||||
interval(numeral & l, numeral & u):m_lower_inf(false), m_upper_inf(false), m_lower_open(true), m_upper_open(true) {
|
||||
swap(m_lower, l);
|
||||
|
@ -136,9 +136,10 @@ namespace realclosure {
|
|||
void swap(mpbqi & a, mpbqi & b) {
|
||||
swap(a.m_lower, b.m_lower);
|
||||
swap(a.m_upper, b.m_upper);
|
||||
unsigned tmp;
|
||||
tmp = a.m_lower_inf; a.m_lower_inf = b.m_lower_inf; b.m_lower_inf = tmp;
|
||||
tmp = a.m_upper_inf; a.m_upper_inf = b.m_upper_inf; b.m_upper_inf = tmp;
|
||||
std::swap(a.m_lower_inf, b.m_lower_inf);
|
||||
std::swap(a.m_upper_inf, b.m_upper_inf);
|
||||
std::swap(a.m_lower_open, b.m_lower_open);
|
||||
std::swap(a.m_upper_open, b.m_upper_open);
|
||||
}
|
||||
|
||||
// ---------------------------------
|
||||
|
@ -1729,6 +1730,14 @@ namespace realclosure {
|
|||
roots.push_back(r);
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Simpler version of add_root that does not use sign_det data-structure. That is,
|
||||
interval contains only one root of p.
|
||||
*/
|
||||
void add_root(unsigned p_sz, value * const * p, mpbqi const & interval, numeral_vector & roots) {
|
||||
add_root(p_sz, p, interval, 0, UINT_MAX, roots);
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Create (the square) matrix for sign determination of q on the roots of p.
|
||||
It builds matrix based on the number of root of p where
|
||||
|
@ -2070,7 +2079,80 @@ namespace realclosure {
|
|||
set_upper(r, aux);
|
||||
}
|
||||
}
|
||||
|
||||
struct bisect_ctx {
|
||||
unsigned m_p_sz;
|
||||
value * const * m_p;
|
||||
bool m_depends_on_infinitesimals;
|
||||
scoped_polynomial_seq & m_sturm_seq;
|
||||
numeral_vector & m_result_roots;
|
||||
bisect_ctx(unsigned p_sz, value * const * p, bool dinf, scoped_polynomial_seq & seq, numeral_vector & roots):
|
||||
m_p_sz(p_sz), m_p(p), m_depends_on_infinitesimals(dinf), m_sturm_seq(seq), m_result_roots(roots) {}
|
||||
};
|
||||
|
||||
void bisect_isolate_roots(mpbqi & interval, int lower_sv, int upper_sv, bisect_ctx & ctx) {
|
||||
SASSERT(lower_sv >= upper_sv);
|
||||
int num_roots = lower_sv - upper_sv;
|
||||
if (num_roots == 0) {
|
||||
// interval does not contain roots
|
||||
}
|
||||
else if (num_roots == 1) {
|
||||
// Sturm sequences are for half-open intervals (a, b]
|
||||
// We must check if upper is the root
|
||||
if (eval_sign_at(ctx.m_p_sz, ctx.m_p, interval.upper()) == 0) {
|
||||
// found precise root
|
||||
numeral r;
|
||||
set(r, mk_rational(interval.upper()));
|
||||
ctx.m_result_roots.push_back(r);
|
||||
}
|
||||
else {
|
||||
// interval is an isolating interval
|
||||
add_root(ctx.m_p_sz, ctx.m_p, interval, ctx.m_result_roots);
|
||||
}
|
||||
}
|
||||
else if (ctx.m_depends_on_infinitesimals && check_precision(interval, m_max_precision)) {
|
||||
// IF
|
||||
// - The polynomial depends on infinitesimals
|
||||
// - The interval contains more than one root
|
||||
// - The size of the interval is less than 1/2^m_max_precision
|
||||
// THEN
|
||||
// - We switch to expensive sign determination procedure, since
|
||||
// the roots may be infinitely close to each other.
|
||||
//
|
||||
sign_det_isolate_roots(ctx.m_p_sz, ctx.m_p, num_roots, interval, ctx.m_result_roots);
|
||||
}
|
||||
else {
|
||||
scoped_mpbq mid(bqm());
|
||||
bqm().add(interval.lower(), interval.upper(), mid);
|
||||
bqm().div2(mid);
|
||||
int mid_sv = sign_variations_at(ctx.m_sturm_seq, mid);
|
||||
scoped_mpbqi left_interval(bqim());
|
||||
scoped_mpbqi right_interval(bqim());
|
||||
set_lower(left_interval, interval.lower());
|
||||
set_upper(left_interval, mid);
|
||||
set_lower(right_interval, mid);
|
||||
set_upper(right_interval, interval.upper());
|
||||
bisect_isolate_roots(left_interval, lower_sv, mid_sv, ctx);
|
||||
bisect_isolate_roots(right_interval, mid_sv, upper_sv, ctx);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Entry point for the root isolation procedure based on bisection.
|
||||
*/
|
||||
void bisect_isolate_roots(// Input values
|
||||
unsigned p_sz, value * const * p, mpbqi & interval,
|
||||
// Extra Input values with already computed information
|
||||
scoped_polynomial_seq & sturm_seq, // sturm sequence for p
|
||||
int lower_sv, // number of sign variations at the lower bound of interval
|
||||
int upper_sv, // number of sign variations at the upper bound of interval
|
||||
// Output values
|
||||
numeral_vector & roots) {
|
||||
bool dinf = depends_on_infinitesimals(p_sz, p);
|
||||
bisect_ctx ctx(p_sz, p, dinf, sturm_seq, roots);
|
||||
bisect_isolate_roots(interval, lower_sv, upper_sv, ctx);
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Root isolation for polynomials that are
|
||||
- nonlinear (degree > 2)
|
||||
|
@ -2100,14 +2182,11 @@ namespace realclosure {
|
|||
// Compute the number of positive and negative roots
|
||||
scoped_polynomial_seq seq(*this);
|
||||
sturm_seq(n, p, seq);
|
||||
scoped_mpbqi minf_zero(bqim());
|
||||
set_lower_inf(minf_zero);
|
||||
set_upper_zero(minf_zero);
|
||||
int num_neg_roots = TaQ(seq, minf_zero);
|
||||
scoped_mpbqi zero_inf(bqim());
|
||||
set_lower_zero(zero_inf);
|
||||
set_upper_inf(zero_inf);
|
||||
int num_pos_roots = TaQ(seq, zero_inf);
|
||||
int num_sv_minus_inf = sign_variations_at_minus_inf(seq);
|
||||
int num_sv_zero = sign_variations_at_zero(seq);
|
||||
int num_sv_plus_inf = sign_variations_at_plus_inf(seq);
|
||||
int num_neg_roots = num_sv_minus_inf - num_sv_zero;
|
||||
int num_pos_roots = num_sv_zero - num_sv_plus_inf;
|
||||
TRACE("rcf_isolate",
|
||||
tout << "num_neg_roots: " << num_neg_roots << "\n";
|
||||
tout << "num_pos_roots: " << num_pos_roots << "\n";);
|
||||
|
@ -2115,13 +2194,21 @@ namespace realclosure {
|
|||
scoped_mpbqi neg_interval(bqim());
|
||||
mk_neg_interval(has_neg_lower, neg_lower_N, has_neg_upper, neg_upper_N, neg_interval);
|
||||
mk_pos_interval(has_pos_lower, pos_lower_N, has_pos_upper, pos_upper_N, pos_interval);
|
||||
|
||||
if (num_neg_roots > 0) {
|
||||
if (num_neg_roots == 1) {
|
||||
add_root(n, p, neg_interval, 0, UINT_MAX, roots);
|
||||
}
|
||||
else {
|
||||
// TODO bisection
|
||||
sign_det_isolate_roots(n, p, num_neg_roots, minf_zero, roots);
|
||||
if (has_neg_lower) {
|
||||
bisect_isolate_roots(n, p, neg_interval, seq, num_sv_minus_inf, num_sv_zero, roots);
|
||||
}
|
||||
else {
|
||||
scoped_mpbqi minf_zero(bqim());
|
||||
set_lower_inf(minf_zero);
|
||||
set_upper_zero(minf_zero);
|
||||
sign_det_isolate_roots(n, p, num_neg_roots, minf_zero, roots);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2130,8 +2217,15 @@ namespace realclosure {
|
|||
add_root(n, p, pos_interval, 0, UINT_MAX, roots);
|
||||
}
|
||||
else {
|
||||
// TODO bisection
|
||||
sign_det_isolate_roots(n, p, num_pos_roots, zero_inf, roots);
|
||||
if (has_pos_upper) {
|
||||
bisect_isolate_roots(n, p, pos_interval, seq, num_sv_zero, num_sv_plus_inf, roots);
|
||||
}
|
||||
else {
|
||||
scoped_mpbqi zero_inf(bqim());
|
||||
set_lower_zero(zero_inf);
|
||||
set_upper_inf(zero_inf);
|
||||
sign_det_isolate_roots(n, p, num_pos_roots, zero_inf, roots);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3155,6 +3249,24 @@ namespace realclosure {
|
|||
return sign_variations_at_core(seq, MPBQ, b);
|
||||
}
|
||||
|
||||
int sign_variations_at_lower(scoped_polynomial_seq & seq, mpbqi const & interval) {
|
||||
if (interval.lower_is_inf())
|
||||
return sign_variations_at_minus_inf(seq);
|
||||
else if (bqm().is_zero(interval.lower()))
|
||||
return sign_variations_at_zero(seq);
|
||||
else
|
||||
return sign_variations_at(seq, interval.lower());
|
||||
}
|
||||
|
||||
int sign_variations_at_upper(scoped_polynomial_seq & seq, mpbqi const & interval) {
|
||||
if (interval.upper_is_inf())
|
||||
return sign_variations_at_plus_inf(seq);
|
||||
else if (bqm().is_zero(interval.upper()))
|
||||
return sign_variations_at_zero(seq);
|
||||
else
|
||||
return sign_variations_at(seq, interval.upper());
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Given a polynomial Sturm sequence seq for (P; P' * Q) and an interval (a, b], it returns
|
||||
TaQ(Q, P; a, b) =
|
||||
|
@ -3165,22 +3277,7 @@ namespace realclosure {
|
|||
\remark This method ignores whether the interval end-points are closed or open.
|
||||
*/
|
||||
int TaQ(scoped_polynomial_seq & seq, mpbqi const & interval) {
|
||||
int a, b;
|
||||
if (interval.lower_is_inf())
|
||||
a = sign_variations_at_minus_inf(seq);
|
||||
else if (bqm().is_zero(interval.lower()))
|
||||
a = sign_variations_at_zero(seq);
|
||||
else
|
||||
a = sign_variations_at(seq, interval.lower());
|
||||
|
||||
if (interval.upper_is_inf())
|
||||
b = sign_variations_at_plus_inf(seq);
|
||||
else if (bqm().is_zero(interval.upper()))
|
||||
b = sign_variations_at_zero(seq);
|
||||
else
|
||||
b = sign_variations_at(seq, interval.upper());
|
||||
|
||||
return a - b;
|
||||
return sign_variations_at_lower(seq, interval) - sign_variations_at_upper(seq, interval);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -5075,3 +5172,8 @@ void pp(realclosure::manager::imp * imp, mpq const & n) {
|
|||
imp->qm().display(std::cout, n);
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
void pp(realclosure::manager::imp * imp, realclosure::extension * x) {
|
||||
imp->display_ext(std::cout, x, false);
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue