mirror of
https://github.com/Z3Prover/z3
synced 2025-04-14 21:08:46 +00:00
Complete the implementation of expensive_algebraic_poly_interval
Signed-off-by: Leonardo de Moura <leonardo@microsoft.com>
This commit is contained in:
parent
714167a378
commit
0de6b4cc92
|
@ -262,8 +262,9 @@ namespace realclosure {
|
||||||
|
|
||||||
struct sign_det {
|
struct sign_det {
|
||||||
unsigned m_ref_count; // sign_det objects may be shared between different roots of the same polynomial.
|
unsigned m_ref_count; // sign_det objects may be shared between different roots of the same polynomial.
|
||||||
mpz_matrix M; // Matrix used in the sign determination
|
mpz_matrix M_s; // Matrix used in the sign determination
|
||||||
array<polynomial> m_prs; // Polynomials associated with the rows of M
|
array<polynomial> m_prs; // Polynomials associated with the rows of M
|
||||||
|
array<int> m_taqrs; // Result of the tarski query for each polynomial in m_prs
|
||||||
array<sign_condition *> m_sign_conditions; // Sign conditions associated with the columns of M
|
array<sign_condition *> m_sign_conditions; // Sign conditions associated with the columns of M
|
||||||
array<polynomial> m_qs; // Polynomials used in the sign conditions.
|
array<polynomial> m_qs; // Polynomials used in the sign conditions.
|
||||||
sign_det():m_ref_count(0) {}
|
sign_det():m_ref_count(0) {}
|
||||||
|
@ -271,20 +272,22 @@ namespace realclosure {
|
||||||
array<polynomial> const & qs() const { return m_qs; }
|
array<polynomial> const & qs() const { return m_qs; }
|
||||||
sign_condition * sc(unsigned idx) const { return m_sign_conditions[idx]; }
|
sign_condition * sc(unsigned idx) const { return m_sign_conditions[idx]; }
|
||||||
unsigned num_roots() const { return m_prs.size(); }
|
unsigned num_roots() const { return m_prs.size(); }
|
||||||
|
array<int> const & taqrs() const { return m_taqrs; }
|
||||||
|
array<polynomial> const & prs() const { return m_prs; }
|
||||||
};
|
};
|
||||||
|
|
||||||
struct algebraic : public extension {
|
struct algebraic : public extension {
|
||||||
polynomial m_p;
|
polynomial m_p;
|
||||||
sign_det * m_sign_det; //!< != 0 if m_interval constains more than one root of m_p.
|
sign_det * m_sign_det; //!< != 0 if m_interval constains more than one root of m_p.
|
||||||
unsigned m_sdt_idx; //!< != UINT_MAX if m_sign_det != 0, in this case m_sdt_idx < m_sign_det->m_sign_conditions.size()
|
unsigned m_sc_idx; //!< != UINT_MAX if m_sign_det != 0, in this case m_sc_idx < m_sign_det->m_sign_conditions.size()
|
||||||
bool m_real; //!< True if the polynomial p does not depend on infinitesimal extensions.
|
bool m_real; //!< True if the polynomial p does not depend on infinitesimal extensions.
|
||||||
|
|
||||||
algebraic(unsigned idx):extension(ALGEBRAIC, idx), m_sign_det(0), m_sdt_idx(0), m_real(false) {}
|
algebraic(unsigned idx):extension(ALGEBRAIC, idx), m_sign_det(0), m_sc_idx(0), m_real(false) {}
|
||||||
|
|
||||||
polynomial const & p() const { return m_p; }
|
polynomial const & p() const { return m_p; }
|
||||||
bool is_real() const { return m_real; }
|
bool is_real() const { return m_real; }
|
||||||
sign_det * sdt() const { return m_sign_det; }
|
sign_det * sdt() const { return m_sign_det; }
|
||||||
unsigned sdt_idx() const { return m_sdt_idx; }
|
unsigned sc_idx() const { return m_sc_idx; }
|
||||||
unsigned num_roots_inside_interval() const { return m_sign_det == 0 ? 1 : m_sign_det->num_roots(); }
|
unsigned num_roots_inside_interval() const { return m_sign_det == 0 ? 1 : m_sign_det->num_roots(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -735,10 +738,11 @@ namespace realclosure {
|
||||||
}
|
}
|
||||||
|
|
||||||
void del_sign_det(sign_det * sd) {
|
void del_sign_det(sign_det * sd) {
|
||||||
mm().del(sd->M);
|
mm().del(sd->M_s);
|
||||||
del_sign_conditions(sd->m_sign_conditions.size(), sd->m_sign_conditions.c_ptr());
|
del_sign_conditions(sd->m_sign_conditions.size(), sd->m_sign_conditions.c_ptr());
|
||||||
sd->m_sign_conditions.finalize(allocator());
|
sd->m_sign_conditions.finalize(allocator());
|
||||||
finalize(sd->m_prs);
|
finalize(sd->m_prs);
|
||||||
|
sd->m_taqrs.finalize(allocator());
|
||||||
finalize(sd->m_qs);
|
finalize(sd->m_qs);
|
||||||
allocator().deallocate(sizeof(sign_det), sd);
|
allocator().deallocate(sizeof(sign_det), sd);
|
||||||
}
|
}
|
||||||
|
@ -1497,7 +1501,63 @@ namespace realclosure {
|
||||||
ds.push(p_prime.size(), p_prime.c_ptr());
|
ds.push(p_prime.size(), p_prime.c_ptr());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
\brief Auxiliary function for count_signs_at_zeros. (See comments at count_signs_at_zeros).
|
||||||
|
|
||||||
|
- taq_p_q contains TaQ(p, q; interval)
|
||||||
|
*/
|
||||||
|
void count_signs_at_zeros_core(// Input values
|
||||||
|
int taq_p_q,
|
||||||
|
unsigned p_sz, value * const * p, // polynomial p
|
||||||
|
unsigned q_sz, value * const * q, // polynomial q
|
||||||
|
mpbqi const & interval,
|
||||||
|
int num_roots, // number of roots of p in the given interval
|
||||||
|
// Output values
|
||||||
|
int & q_eq_0, int & q_gt_0, int & q_lt_0,
|
||||||
|
value_ref_buffer & q2) {
|
||||||
|
if (taq_p_q == num_roots) {
|
||||||
|
// q is positive in all roots of p
|
||||||
|
q_eq_0 = 0;
|
||||||
|
q_gt_0 = num_roots;
|
||||||
|
q_lt_0 = 0;
|
||||||
|
}
|
||||||
|
else if (taq_p_q == -num_roots) {
|
||||||
|
// q is negative in all roots of p
|
||||||
|
q_eq_0 = 0;
|
||||||
|
q_gt_0 = 0;
|
||||||
|
q_lt_0 = num_roots;
|
||||||
|
}
|
||||||
|
if (taq_p_q == num_roots - 1) {
|
||||||
|
// The following assignment is the only possibility
|
||||||
|
q_eq_0 = 1;
|
||||||
|
q_gt_0 = num_roots - 1;
|
||||||
|
q_lt_0 = 0;
|
||||||
|
}
|
||||||
|
else if (taq_p_q == -(num_roots - 1)) {
|
||||||
|
// The following assignment is the only possibility
|
||||||
|
q_eq_0 = 1;
|
||||||
|
q_gt_0 = 0;
|
||||||
|
q_lt_0 = num_roots - 1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Expensive case
|
||||||
|
// q2 <- q^2
|
||||||
|
mul(q_sz, q, q_sz, q, q2);
|
||||||
|
int taq_p_q2 = TaQ(p_sz, p, q2.size(), q2.c_ptr(), interval);
|
||||||
|
SASSERT(0 <= taq_p_q2 && taq_p_q2 <= num_roots);
|
||||||
|
// taq_p_q2 == q_gt_0 + q_lt_0
|
||||||
|
SASSERT((taq_p_q2 + taq_p_q) % 2 == 0);
|
||||||
|
SASSERT((taq_p_q2 - taq_p_q) % 2 == 0);
|
||||||
|
q_eq_0 = num_roots - taq_p_q2;
|
||||||
|
q_gt_0 = (taq_p_q2 + taq_p_q)/2;
|
||||||
|
q_lt_0 = (taq_p_q2 - taq_p_q)/2;
|
||||||
|
}
|
||||||
|
SASSERT(q_eq_0 + q_gt_0 + q_lt_0 == num_roots);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
\brief Given polynomials p and q, and an interval, compute the number of
|
\brief Given polynomials p and q, and an interval, compute the number of
|
||||||
roots of p in the interval such that:
|
roots of p in the interval such that:
|
||||||
|
@ -1521,47 +1581,8 @@ namespace realclosure {
|
||||||
tout << "p: "; display_poly(tout, p_sz, p); tout << "\n";
|
tout << "p: "; display_poly(tout, p_sz, p); tout << "\n";
|
||||||
tout << "q: "; display_poly(tout, q_sz, q); tout << "\n";);
|
tout << "q: "; display_poly(tout, q_sz, q); tout << "\n";);
|
||||||
SASSERT(num_roots > 0);
|
SASSERT(num_roots > 0);
|
||||||
int r1 = TaQ(p_sz, p, q_sz, q, interval);
|
int taq_p_q = TaQ(p_sz, p, q_sz, q, interval);
|
||||||
// r1 == q_gt_0 - q_lt_0
|
count_signs_at_zeros_core(taq_p_q, p_sz, p, q_sz, q, interval, num_roots, q_eq_0, q_gt_0, q_lt_0, q2);
|
||||||
SASSERT(-num_roots <= r1 && r1 <= num_roots);
|
|
||||||
if (r1 == num_roots) {
|
|
||||||
// q is positive in all roots of p
|
|
||||||
q_eq_0 = 0;
|
|
||||||
q_gt_0 = num_roots;
|
|
||||||
q_lt_0 = 0;
|
|
||||||
}
|
|
||||||
else if (r1 == -num_roots) {
|
|
||||||
// q is negative in all roots of p
|
|
||||||
q_eq_0 = 0;
|
|
||||||
q_gt_0 = 0;
|
|
||||||
q_lt_0 = num_roots;
|
|
||||||
}
|
|
||||||
else if (r1 == num_roots - 1) {
|
|
||||||
// The following assignment is the only possibility
|
|
||||||
q_eq_0 = 1;
|
|
||||||
q_gt_0 = num_roots - 1;
|
|
||||||
q_lt_0 = 0;
|
|
||||||
}
|
|
||||||
else if (r1 == -(num_roots - 1)) {
|
|
||||||
// The following assignment is the only possibility
|
|
||||||
q_eq_0 = 1;
|
|
||||||
q_gt_0 = 0;
|
|
||||||
q_lt_0 = num_roots - 1;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// Expensive case
|
|
||||||
// q2 <- q^2
|
|
||||||
mul(q_sz, q, q_sz, q, q2);
|
|
||||||
int r2 = TaQ(p_sz, p, q2.size(), q2.c_ptr(), interval);
|
|
||||||
SASSERT(0 <= r2 && r2 <= num_roots);
|
|
||||||
// r2 == q_gt_0 + q_lt_0
|
|
||||||
SASSERT((r2 + r1) % 2 == 0);
|
|
||||||
SASSERT((r2 - r1) % 2 == 0);
|
|
||||||
q_eq_0 = num_roots - r2;
|
|
||||||
q_gt_0 = (r2 + r1)/2;
|
|
||||||
q_lt_0 = (r2 - r1)/2;
|
|
||||||
}
|
|
||||||
SASSERT(q_eq_0 + q_gt_0 + q_lt_0 == num_roots);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1670,10 +1691,11 @@ namespace realclosure {
|
||||||
The new object will assume the ownership of the elements stored in M and scs.
|
The new object will assume the ownership of the elements stored in M and scs.
|
||||||
M and scs will be empty after this operation.
|
M and scs will be empty after this operation.
|
||||||
*/
|
*/
|
||||||
sign_det * mk_sign_det(mpz_matrix & M, scoped_polynomial_seq const & prs, scoped_polynomial_seq const & qs, scoped_sign_conditions & scs) {
|
sign_det * mk_sign_det(mpz_matrix & M_s, scoped_polynomial_seq const & prs, int_buffer const & taqrs, scoped_polynomial_seq const & qs, scoped_sign_conditions & scs) {
|
||||||
sign_det * r = new (allocator()) sign_det();
|
sign_det * r = new (allocator()) sign_det();
|
||||||
r->M.swap(M);
|
r->M_s.swap(M_s);
|
||||||
set_array_p(r->m_prs, prs);
|
set_array_p(r->m_prs, prs);
|
||||||
|
r->m_taqrs.set(allocator(), taqrs.size(), taqrs.c_ptr());
|
||||||
set_array_p(r->m_qs, qs);
|
set_array_p(r->m_qs, qs);
|
||||||
r->m_sign_conditions.set(allocator(), scs.size(), scs.c_ptr());
|
r->m_sign_conditions.set(allocator(), scs.size(), scs.c_ptr());
|
||||||
scs.release();
|
scs.release();
|
||||||
|
@ -1683,7 +1705,7 @@ namespace realclosure {
|
||||||
/**
|
/**
|
||||||
\brief Create a new algebraic extension
|
\brief Create a new algebraic extension
|
||||||
*/
|
*/
|
||||||
algebraic * mk_algebraic(unsigned p_sz, value * const * p, mpbqi const & interval, sign_det * sd, unsigned sdt_idx) {
|
algebraic * mk_algebraic(unsigned p_sz, value * const * p, mpbqi const & interval, sign_det * sd, unsigned sc_idx) {
|
||||||
unsigned idx = next_algebraic_idx();
|
unsigned idx = next_algebraic_idx();
|
||||||
algebraic * r = new (allocator()) algebraic(idx);
|
algebraic * r = new (allocator()) algebraic(idx);
|
||||||
m_extensions[extension::ALGEBRAIC].push_back(r);
|
m_extensions[extension::ALGEBRAIC].push_back(r);
|
||||||
|
@ -1692,22 +1714,107 @@ namespace realclosure {
|
||||||
set_interval(r->m_interval, interval);
|
set_interval(r->m_interval, interval);
|
||||||
r->m_sign_det = sd;
|
r->m_sign_det = sd;
|
||||||
inc_ref_sign_det(sd);
|
inc_ref_sign_det(sd);
|
||||||
r->m_sdt_idx = sdt_idx;
|
r->m_sc_idx = sc_idx;
|
||||||
r->m_real = is_real(p_sz, p);
|
r->m_real = is_real(p_sz, p);
|
||||||
|
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
\brief Add a new root of p that is isolated by (interval, sd, sdt_idx) to roots.
|
\brief Add a new root of p that is isolated by (interval, sd, sc_idx) to roots.
|
||||||
*/
|
*/
|
||||||
void add_root(unsigned p_sz, value * const * p, mpbqi const & interval, sign_det * sd, unsigned sdt_idx, numeral_vector & roots) {
|
void add_root(unsigned p_sz, value * const * p, mpbqi const & interval, sign_det * sd, unsigned sc_idx, numeral_vector & roots) {
|
||||||
algebraic * a = mk_algebraic(p_sz, p, interval, sd, sdt_idx);
|
algebraic * a = mk_algebraic(p_sz, p, interval, sd, sc_idx);
|
||||||
numeral r;
|
numeral r;
|
||||||
set(r, mk_rational_function_value(a));
|
set(r, mk_rational_function_value(a));
|
||||||
roots.push_back(r);
|
roots.push_back(r);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
\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
|
||||||
|
q is == 0, > 0 and < 0.
|
||||||
|
The resultant matrix is stored in M.
|
||||||
|
|
||||||
|
Return false if the sign of q is already determined, that is
|
||||||
|
only one of the q_eq_0, q_gt_0, q_lt_0 is greater than zero.
|
||||||
|
|
||||||
|
If the return value is true, then the resultant matrix M has size 2x2 or 3x3
|
||||||
|
|
||||||
|
- q_eq_0 > 0, q_gt_0 > 0, q_lt_0 == 0
|
||||||
|
M <- {{1, 1},
|
||||||
|
{0, 1}}
|
||||||
|
|
||||||
|
Meaning:
|
||||||
|
M . [ #(q == 0), #(q > 0) ]^t == [ TaQ(p, 1), TaQ(p, q) ]^t
|
||||||
|
|
||||||
|
[ ... ]^t represents a column matrix.
|
||||||
|
|
||||||
|
- q_eq_0 > 0, q_gt_0 == 0, q_lt_0 > 0
|
||||||
|
M <- {{1, 1},
|
||||||
|
{0, -1}}
|
||||||
|
|
||||||
|
Meaning:
|
||||||
|
M . [ #(q == 0), #(q < 0) ]^t == [ TaQ(p, 1), TaQ(p, q) ]^t
|
||||||
|
|
||||||
|
- q_eq_0 == 0, q_gt_0 > 0, q_lt_0 > 0
|
||||||
|
M <- {{1, 1},
|
||||||
|
{1, -1}}
|
||||||
|
|
||||||
|
Meaning:
|
||||||
|
M . [ #(q > 0), #(q < 0) ]^t == [ TaQ(p, 1), TaQ(p, q) ]^t
|
||||||
|
|
||||||
|
- q_eq_0 > 0, q_gt_0 > 0, q_lt_0 > 0
|
||||||
|
M <- {{1, 1, 1},
|
||||||
|
{0, 1, -1},
|
||||||
|
{0, 1, 1}}
|
||||||
|
|
||||||
|
Meaning:
|
||||||
|
M . [ #(q == 0), #(q > 0), #(q < 0) ]^t == [ TaQ(p, 1), TaQ(p, q), TaQ(p, q^2) ]^t
|
||||||
|
|
||||||
|
*/
|
||||||
|
bool mk_sign_det_matrix(int q_eq_0, int q_gt_0, int q_lt_0, scoped_mpz_matrix & M) {
|
||||||
|
if (q_eq_0 > 0 && q_gt_0 > 0 && q_lt_0 == 0) {
|
||||||
|
// M <- {{1, 1},
|
||||||
|
// {0, 1}}
|
||||||
|
mm().mk(2,2,M);
|
||||||
|
M.set(0,0, 1); M.set(0,1, 1);
|
||||||
|
M.set(1,0, 0); M.set(1,1, 1);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (q_eq_0 > 0 && q_gt_0 == 0 && q_lt_0 > 0) {
|
||||||
|
// M <- {{1, 1},
|
||||||
|
// {0, -1}}
|
||||||
|
mm().mk(2,2,M);
|
||||||
|
M.set(0,0, 1); M.set(0,1, 1);
|
||||||
|
M.set(1,0, 0); M.set(1,1, -1);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (q_eq_0 == 0 && q_gt_0 > 0 && q_lt_0 > 0) {
|
||||||
|
// M <- {{1, 1},
|
||||||
|
// {1, -1}}
|
||||||
|
mm().mk(2,2,M);
|
||||||
|
M.set(0,0, 1); M.set(0,1, 1);
|
||||||
|
M.set(1,0, 1); M.set(1,1, -1);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (q_eq_0 > 0 && q_gt_0 > 0 && q_lt_0 > 0) {
|
||||||
|
// M <- {{1, 1, 1},
|
||||||
|
// {0, 1, -1},
|
||||||
|
// {0, 1, 1}}
|
||||||
|
mm().mk(3,3,M);
|
||||||
|
M.set(0,0, 1); M.set(0,1, 1); M.set(0,2, 1);
|
||||||
|
M.set(1,0, 0); M.set(1,1, 1); M.set(1,2, -1);
|
||||||
|
M.set(2,0, 0); M.set(2,1, 1); M.set(2,2, 1);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Sign of q is already determined.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
\brief Isolate roots of p in the given interval using sign conditions to distinguish between them.
|
\brief Isolate roots of p in the given interval using sign conditions to distinguish between them.
|
||||||
We need this method when the polynomial contains roots that are infinitesimally close to each other.
|
We need this method when the polynomial contains roots that are infinitesimally close to each other.
|
||||||
|
@ -1796,47 +1903,12 @@ namespace realclosure {
|
||||||
TRACE("rcf_sign_det",
|
TRACE("rcf_sign_det",
|
||||||
tout << "q: "; display_poly(tout, q_sz, q); tout << "\n";
|
tout << "q: "; display_poly(tout, q_sz, q); tout << "\n";
|
||||||
tout << "#(q == 0): " << q_eq_0 << ", #(q > 0): " << q_gt_0 << ", #(q < 0): " << q_lt_0 << "\n";);
|
tout << "#(q == 0): " << q_eq_0 << ", #(q > 0): " << q_gt_0 << ", #(q < 0): " << q_lt_0 << "\n";);
|
||||||
bool use_q2;
|
|
||||||
scoped_mpz_matrix M(mm());
|
scoped_mpz_matrix M(mm());
|
||||||
if (q_eq_0 > 0 && q_gt_0 > 0 && q_lt_0 == 0) {
|
if (!mk_sign_det_matrix(q_eq_0, q_gt_0, q_lt_0, M)) {
|
||||||
// M <- {{1, 1},
|
|
||||||
// {0, 1}}
|
|
||||||
mm().mk(2,2,M);
|
|
||||||
M.set(0,0, 1); M.set(0,1, 1);
|
|
||||||
M.set(1,0, 0); M.set(1,1, 1);
|
|
||||||
use_q2 = false;
|
|
||||||
}
|
|
||||||
else if (q_eq_0 > 0 && q_gt_0 == 0 && q_lt_0 > 0) {
|
|
||||||
// M <- {{1, 1},
|
|
||||||
// {0, -1}}
|
|
||||||
mm().mk(2,2,M);
|
|
||||||
M.set(0,0, 1); M.set(0,1, 1);
|
|
||||||
M.set(1,0, 0); M.set(1,1, -1);
|
|
||||||
use_q2 = false;
|
|
||||||
}
|
|
||||||
else if (q_eq_0 == 0 && q_gt_0 > 0 && q_lt_0 > 0) {
|
|
||||||
// M <- {{1, 1},
|
|
||||||
// {1, -1}}
|
|
||||||
mm().mk(2,2,M);
|
|
||||||
M.set(0,0, 1); M.set(0,1, 1);
|
|
||||||
M.set(1,0, 1); M.set(1,1, -1);
|
|
||||||
use_q2 = false;
|
|
||||||
}
|
|
||||||
else if (q_eq_0 > 0 && q_gt_0 > 0 && q_lt_0 > 0) {
|
|
||||||
// M <- {{1, 1, 1},
|
|
||||||
// {0, 1, -1},
|
|
||||||
// {0, 1, 1}}
|
|
||||||
mm().mk(3,3,M);
|
|
||||||
M.set(0,0, 1); M.set(0,1, 1); M.set(0,2, 1);
|
|
||||||
M.set(1,0, 0); M.set(1,1, 1); M.set(1,2, -1);
|
|
||||||
M.set(2,0, 0); M.set(2,1, 1); M.set(2,2, 1);
|
|
||||||
use_q2 = true;
|
|
||||||
SASSERT(q2.size() > 0);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// skip q since its sign does not discriminate the roots of p
|
// skip q since its sign does not discriminate the roots of p
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
bool use_q2 = M.n() == 3;
|
||||||
mm().tensor_product(M_s, M, new_M_s);
|
mm().tensor_product(M_s, M, new_M_s);
|
||||||
expand_taqrs(taqrs, prs, p_sz, p, q_sz, q, use_q2, q2.size(), q2.c_ptr(), interval,
|
expand_taqrs(taqrs, prs, p_sz, p, q_sz, q, use_q2, q2.size(), q2.c_ptr(), interval,
|
||||||
// --->
|
// --->
|
||||||
|
@ -1923,7 +1995,7 @@ namespace realclosure {
|
||||||
display_poly(tout, prs.size(j), prs.coeffs(j)); tout << "\n";
|
display_poly(tout, prs.size(j), prs.coeffs(j)); tout << "\n";
|
||||||
});
|
});
|
||||||
SASSERT(M_s.n() == M_s.m()); SASSERT(M_s.n() == static_cast<unsigned>(num_roots));
|
SASSERT(M_s.n() == M_s.m()); SASSERT(M_s.n() == static_cast<unsigned>(num_roots));
|
||||||
sign_det * sd = mk_sign_det(M_s, prs, qs, scs);
|
sign_det * sd = mk_sign_det(M_s, prs, taqrs, qs, scs);
|
||||||
for (unsigned idx = 0; idx < static_cast<unsigned>(num_roots); idx++) {
|
for (unsigned idx = 0; idx < static_cast<unsigned>(num_roots); idx++) {
|
||||||
add_root(p_sz, p, interval, sd, idx, roots);
|
add_root(p_sz, p, interval, sd, idx, roots);
|
||||||
}
|
}
|
||||||
|
@ -2796,10 +2868,20 @@ namespace realclosure {
|
||||||
\brief Keep expanding the Sturm sequence starting at seq
|
\brief Keep expanding the Sturm sequence starting at seq
|
||||||
*/
|
*/
|
||||||
void sturm_seq_core(scoped_polynomial_seq & seq) {
|
void sturm_seq_core(scoped_polynomial_seq & seq) {
|
||||||
|
INC_DEPTH();
|
||||||
|
SASSERT(seq.size() >= 2);
|
||||||
|
TRACE("rcf_sturm_seq",
|
||||||
|
unsigned sz = seq.size();
|
||||||
|
tout << "sturm_seq_core [" << m_exec_depth << "]\n";
|
||||||
|
display_poly(tout, seq.size(sz-2), seq.coeffs(sz-2)); tout << "\n";
|
||||||
|
display_poly(tout, seq.size(sz-1), seq.coeffs(sz-1)); tout << "\n";);
|
||||||
value_ref_buffer r(*this);
|
value_ref_buffer r(*this);
|
||||||
while (true) {
|
while (true) {
|
||||||
unsigned sz = seq.size();
|
unsigned sz = seq.size();
|
||||||
srem(seq.size(sz-2), seq.coeffs(sz-2), seq.size(sz-1), seq.coeffs(sz-1), r);
|
srem(seq.size(sz-2), seq.coeffs(sz-2), seq.size(sz-1), seq.coeffs(sz-1), r);
|
||||||
|
TRACE("rcf_sturm_seq",
|
||||||
|
tout << "sturm_seq_core [" << m_exec_depth << "], new polynomial\n";
|
||||||
|
display_poly(tout, r.size(), r.c_ptr()); tout << "\n";);
|
||||||
if (r.empty())
|
if (r.empty())
|
||||||
return;
|
return;
|
||||||
seq.push(r.size(), r.c_ptr());
|
seq.push(r.size(), r.c_ptr());
|
||||||
|
@ -3636,12 +3718,11 @@ namespace realclosure {
|
||||||
}
|
}
|
||||||
int num_roots = x->num_roots_inside_interval();
|
int num_roots = x->num_roots_inside_interval();
|
||||||
SASSERT(x->sdt() != 0 || num_roots == 1);
|
SASSERT(x->sdt() != 0 || num_roots == 1);
|
||||||
scoped_polynomial_seq seq(*this);
|
|
||||||
polynomial const & p = x->p();
|
polynomial const & p = x->p();
|
||||||
int taq = TaQ(p.size(), p.c_ptr(), q.size(), q.c_ptr(), x->interval());
|
int taq_p_q = TaQ(p.size(), p.c_ptr(), q.size(), q.c_ptr(), x->interval());
|
||||||
if (num_roots == 1 && taq == 0)
|
if (num_roots == 1 && taq_p_q == 0)
|
||||||
return false; // q(x) is zero
|
return false; // q(x) is zero
|
||||||
if (taq == num_roots) {
|
if (taq_p_q == num_roots) {
|
||||||
// q(x) is positive
|
// q(x) is positive
|
||||||
if (is_real(q, x))
|
if (is_real(q, x))
|
||||||
refine_until_sign_determined(q, x, r);
|
refine_until_sign_determined(q, x, r);
|
||||||
|
@ -3650,7 +3731,7 @@ namespace realclosure {
|
||||||
SASSERT(!contains_zero(r));
|
SASSERT(!contains_zero(r));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else if (taq == -num_roots) {
|
else if (taq_p_q == -num_roots) {
|
||||||
// q(x) is negative
|
// q(x) is negative
|
||||||
if (is_real(q, x))
|
if (is_real(q, x))
|
||||||
refine_until_sign_determined(q, x, r);
|
refine_until_sign_determined(q, x, r);
|
||||||
|
@ -3662,12 +3743,144 @@ namespace realclosure {
|
||||||
else {
|
else {
|
||||||
SASSERT(num_roots > 1);
|
SASSERT(num_roots > 1);
|
||||||
SASSERT(x->sdt() != 0);
|
SASSERT(x->sdt() != 0);
|
||||||
|
int q_eq_0, q_gt_0, q_lt_0;
|
||||||
// TODO use sign_det data structure
|
value_ref_buffer q2(*this);
|
||||||
|
count_signs_at_zeros_core(taq_p_q, p.size(), p.c_ptr(), q.size(), q.c_ptr(), x->interval(), num_roots, q_eq_0, q_gt_0, q_lt_0, q2);
|
||||||
std::cout << "TODO\n";
|
if (q_eq_0 > 0 && q_gt_0 == 0 && q_lt_0 == 0) {
|
||||||
|
// q(x) is zero
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
else if (q_eq_0 == 0 && q_gt_0 > 0 && q_lt_0 == 0) {
|
||||||
|
// q(x) is positive
|
||||||
|
set_lower_zero(r);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (q_eq_0 == 0 && q_gt_0 == 0 && q_lt_0 > 0) {
|
||||||
|
// q(x) is negative
|
||||||
|
set_upper_zero(r);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
sign_det & sdt = *(x->sdt());
|
||||||
|
// Remark:
|
||||||
|
// By definition of algebraic and sign_det, we know that
|
||||||
|
// sdt.M_s * [1, ..., 1]^t = sdt.taqrs()^t
|
||||||
|
// That is,
|
||||||
|
// [1, ..., 1]^t = sdt.M_s^-1 * sdt.taqrs()^t
|
||||||
|
// Moreover the number of roots in x->interval() is equal to the number of rows and columns in sdt.M_s.
|
||||||
|
// The column j of std.M_s is associated with the sign condition sdt.m_scs[j].
|
||||||
|
// The row i of sdt.M_s is associated with the polynomial sdt.prs()[i].
|
||||||
|
//
|
||||||
|
// The extension x is encoded using the sign condition x->sc_idx() of std.m_scs
|
||||||
|
//
|
||||||
|
scoped_mpz_matrix M(mm());
|
||||||
|
VERIFY(mk_sign_det_matrix(q_eq_0, q_gt_0, q_lt_0, M));
|
||||||
|
bool use_q2 = M.n() == 3;
|
||||||
|
scoped_mpz_matrix new_M_s(mm());
|
||||||
|
mm().tensor_product(sdt.M_s, M, new_M_s);
|
||||||
|
array<polynomial> const & prs = sdt.prs(); // polynomials associated with the rows of M_s
|
||||||
|
array<int> const & taqrs = sdt.taqrs(); // For each i in [0, taqrs.size()) TaQ(p, prs[i]; x->interval()) == taqrs[i]
|
||||||
|
SASSERT(prs.size() == taqrs.size());
|
||||||
|
int_buffer new_taqrs;
|
||||||
|
value_ref_buffer prq(*this);
|
||||||
|
// fill new_taqrs using taqrs and the new tarski queries containing q (and q^2 when use_q2 == true).
|
||||||
|
for (unsigned i = 0; i < taqrs.size(); i++) {
|
||||||
|
// Add TaQ(p, prs[i] * 1; x->interval())
|
||||||
|
new_taqrs.push_back(taqrs[i]);
|
||||||
|
// Add TaQ(p, prs[i] * q; x->interval())
|
||||||
|
mul(prs[i].size(), prs[i].c_ptr(), q.size(), q.c_ptr(), prq);
|
||||||
|
new_taqrs.push_back(TaQ(p.size(), p.c_ptr(), prq.size(), prq.c_ptr(), x->interval()));
|
||||||
|
if (use_q2) {
|
||||||
|
// Add TaQ(p, prs[i] * q^2; x->interval())
|
||||||
|
mul(prs[i].size(), prs[i].c_ptr(), q2.size(), q2.c_ptr(), prq);
|
||||||
|
new_taqrs.push_back(TaQ(p.size(), p.c_ptr(), prq.size(), prq.c_ptr(), x->interval()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int_buffer sc_cardinalities;
|
||||||
|
sc_cardinalities.resize(new_taqrs.size());
|
||||||
|
// Solve
|
||||||
|
// new_M_s * sc_cardinalities = new_taqrs
|
||||||
|
VERIFY(mm().solve(new_M_s, sc_cardinalities.c_ptr(), new_taqrs.c_ptr()));
|
||||||
|
DEBUG_CODE({
|
||||||
|
// check if sc_cardinalities has the expected structure
|
||||||
|
// - contains only 0 or 1
|
||||||
|
// - !use_q2 IMPLIES for all i in [0, taqrs.size()) (sc_cardinalities[2*i] == 1) + (sc_cardinalities[2*i + 1] == 1) == 1
|
||||||
|
// - use_q2 IMPLIES for all i in [0, taqrs.size()) (sc_cardinalities[3*i] == 1) + (sc_cardinalities[3*i + 1] == 1) + (sc_cardinalities[3*i + 2] == 1) == 1
|
||||||
|
for (unsigned i = 0; i < sc_cardinalities.size(); i++) {
|
||||||
|
SASSERT(sc_cardinalities[i] == 0 || sc_cardinalities[i] == 1);
|
||||||
|
}
|
||||||
|
if (!use_q2) {
|
||||||
|
for (unsigned i = 0; i < taqrs.size(); i++) {
|
||||||
|
SASSERT((sc_cardinalities[2*i] == 1) + (sc_cardinalities[2*i + 1] == 1) == 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
for (unsigned i = 0; i < taqrs.size(); i++) {
|
||||||
|
SASSERT((sc_cardinalities[3*i] == 1) + (sc_cardinalities[3*i + 1] == 1) + (sc_cardinalities[3*i + 2] == 1) == 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// Remark:
|
||||||
|
// Note that we found the sign of q for every root of p in the interval x->interval() :)
|
||||||
|
unsigned sc_idx = x->sc_idx();
|
||||||
|
if (use_q2) {
|
||||||
|
if (sc_cardinalities[3*sc_idx] == 1) {
|
||||||
|
// q(x) is zero
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else if (sc_cardinalities[3*sc_idx + 1] == 1) {
|
||||||
|
// q(x) is positive
|
||||||
|
set_lower_zero(r);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
SASSERT(sc_cardinalities[3*sc_idx + 2] == 1);
|
||||||
|
// q(x) is negative
|
||||||
|
set_upper_zero(r);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (q_eq_0 == 0) {
|
||||||
|
if (sc_cardinalities[2*sc_idx] == 1) {
|
||||||
|
// q(x) is positive
|
||||||
|
set_lower_zero(r);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
SASSERT(sc_cardinalities[2*sc_idx + 1] == 1);
|
||||||
|
// q(x) is negative
|
||||||
|
set_upper_zero(r);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (q_gt_0 == 0) {
|
||||||
|
if (sc_cardinalities[2*sc_idx] == 1) {
|
||||||
|
// q(x) is zero
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
SASSERT(sc_cardinalities[2*sc_idx + 1] == 1);
|
||||||
|
// q(x) is negative
|
||||||
|
set_upper_zero(r);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
SASSERT(q_lt_0 == 0);
|
||||||
|
if (sc_cardinalities[2*sc_idx] == 1) {
|
||||||
|
// q(x) is zero
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
SASSERT(sc_cardinalities[2*sc_idx + 1] == 1);
|
||||||
|
// q(x) is positive
|
||||||
|
set_lower_zero(r);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4484,7 +4697,7 @@ namespace realclosure {
|
||||||
bqim().display(out, a->interval());
|
bqim().display(out, a->interval());
|
||||||
out << ", ";
|
out << ", ";
|
||||||
if (a->sdt() != 0)
|
if (a->sdt() != 0)
|
||||||
display_sign_conditions(out, a->sdt()->sc(a->sdt_idx()), a->sdt()->qs(), compact);
|
display_sign_conditions(out, a->sdt()->sc(a->sc_idx()), a->sdt()->qs(), compact);
|
||||||
else
|
else
|
||||||
out << "{}";
|
out << "{}";
|
||||||
out << ")";
|
out << ")";
|
||||||
|
|
Loading…
Reference in a new issue