mirror of
https://github.com/Z3Prover/z3
synced 2025-04-24 01:25:31 +00:00
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
parent
016732aa59
commit
39edf73e78
16 changed files with 222 additions and 162 deletions
|
@ -43,7 +43,7 @@ namespace nlsat {
|
|||
svector<section> m_sections;
|
||||
unsigned_vector m_sorted_sections; // refs to m_sections
|
||||
unsigned_vector m_poly_sections; // refs to m_sections
|
||||
svector<int> m_poly_signs;
|
||||
svector<polynomial::sign> m_poly_signs;
|
||||
struct poly_info {
|
||||
unsigned m_num_roots;
|
||||
unsigned m_first_section; // idx in m_poly_sections;
|
||||
|
@ -149,18 +149,18 @@ namespace nlsat {
|
|||
\brief Add polynomial with the given roots and signs.
|
||||
*/
|
||||
unsigned_vector p_section_ids;
|
||||
void add(anum_vector & roots, svector<int> & signs) {
|
||||
void add(anum_vector & roots, svector<polynomial::sign> & signs) {
|
||||
p_section_ids.reset();
|
||||
if (!roots.empty())
|
||||
merge(roots, p_section_ids);
|
||||
unsigned first_sign = m_poly_signs.size();
|
||||
unsigned first_section = m_poly_sections.size();
|
||||
unsigned num_signs = signs.size();
|
||||
unsigned num_poly_signs = signs.size();
|
||||
// Must normalize signs since we use arithmetic operations such as *
|
||||
// during evaluation.
|
||||
// Without normalization, overflows may happen, and wrong results may be produced.
|
||||
for (unsigned i = 0; i < num_signs; i++)
|
||||
m_poly_signs.push_back(normalize_sign(signs[i]));
|
||||
for (unsigned i = 0; i < num_poly_signs; i++)
|
||||
m_poly_signs.push_back(signs[i]);
|
||||
m_poly_sections.append(p_section_ids);
|
||||
m_info.push_back(poly_info(roots.size(), first_section, first_sign));
|
||||
SASSERT(check_invariant());
|
||||
|
@ -169,10 +169,10 @@ namespace nlsat {
|
|||
/**
|
||||
\brief Add constant polynomial
|
||||
*/
|
||||
void add_const(int sign) {
|
||||
void add_const(polynomial::sign sign) {
|
||||
unsigned first_sign = m_poly_signs.size();
|
||||
unsigned first_section = m_poly_sections.size();
|
||||
m_poly_signs.push_back(normalize_sign(sign));
|
||||
m_poly_signs.push_back(sign);
|
||||
m_info.push_back(poly_info(0, first_section, first_sign));
|
||||
}
|
||||
|
||||
|
@ -226,12 +226,12 @@ namespace nlsat {
|
|||
}
|
||||
|
||||
// Return the sign idx of pinfo
|
||||
int sign(poly_info const & pinfo, unsigned i) const {
|
||||
polynomial::sign sign(poly_info const & pinfo, unsigned i) const {
|
||||
return m_poly_signs[pinfo.m_first_sign + i];
|
||||
}
|
||||
|
||||
#define LINEAR_SEARCH_THRESHOLD 8
|
||||
int sign_at(unsigned info_id, unsigned c) const {
|
||||
polynomial::sign sign_at(unsigned info_id, unsigned c) const {
|
||||
poly_info const & pinfo = m_info[info_id];
|
||||
unsigned num_roots = pinfo.m_num_roots;
|
||||
if (num_roots < LINEAR_SEARCH_THRESHOLD) {
|
||||
|
@ -239,7 +239,7 @@ namespace nlsat {
|
|||
for (; i < num_roots; i++) {
|
||||
unsigned section_cell_id = cell_id(pinfo, i);
|
||||
if (section_cell_id == c)
|
||||
return 0;
|
||||
return polynomial::sign_zero;
|
||||
else if (section_cell_id > c)
|
||||
break;
|
||||
}
|
||||
|
@ -253,7 +253,7 @@ namespace nlsat {
|
|||
if (c < root_1_cell_id)
|
||||
return sign(pinfo, 0);
|
||||
else if (c == root_1_cell_id || c == root_n_cell_id)
|
||||
return 0;
|
||||
return polynomial::sign_zero;
|
||||
else if (c > root_n_cell_id)
|
||||
return sign(pinfo, num_roots);
|
||||
int low = 0;
|
||||
|
@ -272,7 +272,7 @@ namespace nlsat {
|
|||
SASSERT(low < mid && mid < high);
|
||||
unsigned mid_cell_id = cell_id(pinfo, mid);
|
||||
if (mid_cell_id == c) {
|
||||
return 0;
|
||||
return polynomial::sign_zero;
|
||||
}
|
||||
if (c < mid_cell_id) {
|
||||
high = mid;
|
||||
|
@ -319,7 +319,7 @@ namespace nlsat {
|
|||
for (unsigned j = 0; j < num_cells(); j++) {
|
||||
if (j > 0)
|
||||
out << " ";
|
||||
int s = sign_at(i, j);
|
||||
auto s = sign_at(i, j);
|
||||
if (s < 0) out << "-";
|
||||
else if (s == 0) out << "0";
|
||||
else out << "+";
|
||||
|
@ -381,11 +381,10 @@ namespace nlsat {
|
|||
|
||||
\pre All variables of p are assigned in the current interpretation.
|
||||
*/
|
||||
int eval_sign(poly * p) {
|
||||
polynomial::sign eval_sign(poly * p) {
|
||||
// TODO: check if it is useful to cache results
|
||||
SASSERT(m_assignment.is_assigned(max_var(p)));
|
||||
int r = m_am.eval_sign_at(polynomial_ref(p, m_pm), m_assignment);
|
||||
return r > 0 ? +1 : (r < 0 ? -1 : 0);
|
||||
return m_am.eval_sign_at(polynomial_ref(p, m_pm), m_assignment);
|
||||
}
|
||||
|
||||
bool satisfied(int sign, atom::kind k) {
|
||||
|
@ -450,7 +449,7 @@ namespace nlsat {
|
|||
return a->is_ineq_atom() ? eval_ineq(to_ineq_atom(a), neg) : eval_root(to_root_atom(a), neg);
|
||||
}
|
||||
|
||||
svector<int> m_add_signs_tmp;
|
||||
svector<polynomial::sign> m_add_signs_tmp;
|
||||
void add(poly * p, var x, sign_table & t) {
|
||||
SASSERT(m_pm.max_var(p) <= x);
|
||||
if (m_pm.max_var(p) < x) {
|
||||
|
@ -459,7 +458,7 @@ namespace nlsat {
|
|||
else {
|
||||
// isolate roots of p
|
||||
scoped_anum_vector & roots = m_add_roots_tmp;
|
||||
svector<int> & signs = m_add_signs_tmp;
|
||||
svector<polynomial::sign> & signs = m_add_signs_tmp;
|
||||
roots.reset();
|
||||
signs.reset();
|
||||
TRACE("nlsat_evaluator", tout << "x: " << x << " max_var(p): " << m_pm.max_var(p) << "\n";);
|
||||
|
@ -471,18 +470,18 @@ namespace nlsat {
|
|||
}
|
||||
|
||||
// Evaluate the sign of p1^e1*...*pn^en (of atom a) in cell c of table t.
|
||||
int sign_at(ineq_atom * a, sign_table const & t, unsigned c) const {
|
||||
int sign = 1;
|
||||
polynomial::sign sign_at(ineq_atom * a, sign_table const & t, unsigned c) const {
|
||||
auto sign = polynomial::sign_pos;
|
||||
unsigned num_ps = a->size();
|
||||
for (unsigned i = 0; i < num_ps; i++) {
|
||||
int curr_sign = t.sign_at(i, c);
|
||||
polynomial::sign curr_sign = t.sign_at(i, c);
|
||||
TRACE("nlsat_evaluator_bug", tout << "sign of i: " << i << " at cell " << c << "\n";
|
||||
m_pm.display(tout, a->p(i));
|
||||
tout << "\nsign: " << curr_sign << "\n";);
|
||||
if (a->is_even(i) && curr_sign < 0)
|
||||
curr_sign = 1;
|
||||
curr_sign = polynomial::sign_pos;
|
||||
sign = sign * curr_sign;
|
||||
if (sign == 0)
|
||||
if (sign == polynomial::sign_zero)
|
||||
break;
|
||||
}
|
||||
return sign;
|
||||
|
|
|
@ -197,9 +197,10 @@ namespace nlsat {
|
|||
\brief Reset m_already_added vector using m_result
|
||||
*/
|
||||
void reset_already_added() {
|
||||
SASSERT(m_result != 0);
|
||||
SASSERT(m_result != nullptr);
|
||||
for (literal lit : *m_result)
|
||||
m_already_added_literal[lit.index()] = false;
|
||||
SASSERT(check_already_added());
|
||||
}
|
||||
|
||||
|
||||
|
@ -207,9 +208,9 @@ namespace nlsat {
|
|||
\brief evaluate the given polynomial in the current interpretation.
|
||||
max_var(p) must be assigned in the current interpretation.
|
||||
*/
|
||||
int sign(polynomial_ref const & p) {
|
||||
polynomial::sign sign(polynomial_ref const & p) {
|
||||
SASSERT(max_var(p) == null_var || m_assignment.is_assigned(max_var(p)));
|
||||
int s = m_am.eval_sign_at(p, m_assignment);
|
||||
auto s = m_am.eval_sign_at(p, m_assignment);
|
||||
TRACE("nlsat_explain", tout << "p: " << p << " var: " << max_var(p) << " sign: " << s << "\n";);
|
||||
return s;
|
||||
}
|
||||
|
@ -270,7 +271,7 @@ namespace nlsat {
|
|||
polynomial_ref f(m_pm);
|
||||
for (unsigned i = 0; i < num_factors; i++) {
|
||||
f = m_factors.get(i);
|
||||
if (sign(f) == 0) {
|
||||
if (sign(f) == polynomial::sign_zero) {
|
||||
m_zero_fs.push_back(m_factors.get(i));
|
||||
m_is_even.push_back(false);
|
||||
}
|
||||
|
@ -323,7 +324,7 @@ namespace nlsat {
|
|||
return; // lc is a nonzero constant
|
||||
lc = m_pm.coeff(p, x, k, reduct);
|
||||
if (!is_zero(lc)) {
|
||||
if (sign(lc) != 0)
|
||||
if (sign(lc) != polynomial::sign_zero)
|
||||
return;
|
||||
// lc is not the zero polynomial, but it vanished in the current interpretation.
|
||||
// so we keep searching...
|
||||
|
@ -959,8 +960,9 @@ namespace nlsat {
|
|||
if (ps.empty())
|
||||
return;
|
||||
m_todo.reset();
|
||||
for (unsigned i = 0; i < ps.size(); i++)
|
||||
m_todo.insert(ps.get(i));
|
||||
for (poly* p : ps) {
|
||||
m_todo.insert(p);
|
||||
}
|
||||
var x = m_todo.remove_max_polys(ps);
|
||||
// Remark: after vanishing coefficients are eliminated, ps may not contain max_x anymore
|
||||
if (x < max_x)
|
||||
|
@ -983,8 +985,8 @@ namespace nlsat {
|
|||
}
|
||||
|
||||
bool check_already_added() const {
|
||||
for (unsigned i = 0; i < m_already_added_literal.size(); i++) {
|
||||
SASSERT(m_already_added_literal[i] == false);
|
||||
for (bool b : m_already_added_literal) {
|
||||
SASSERT(!b);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -1062,7 +1064,7 @@ namespace nlsat {
|
|||
void simplify(literal l, eq_info & info, var max, scoped_literal & new_lit) {
|
||||
bool_var b = l.var();
|
||||
atom * a = m_atoms[b];
|
||||
SASSERT(a != 0);
|
||||
SASSERT(a);
|
||||
if (a->is_root_atom()) {
|
||||
new_lit = l;
|
||||
return;
|
||||
|
@ -1091,19 +1093,24 @@ namespace nlsat {
|
|||
modified_lit = true;
|
||||
unsigned d;
|
||||
m_pm.pseudo_remainder(f, info.m_eq, info.m_x, d, new_factor);
|
||||
polynomial_ref fact(f, m_pm), eq(const_cast<poly*>(info.m_eq), m_pm);
|
||||
|
||||
TRACE("nlsat_simplify_core", tout << "d: " << d << " factor " << fact << " eq " << eq << " new factor " << new_factor << "\n";);
|
||||
// adjust sign based on sign of lc of eq
|
||||
if (d % 2 == 1 && // d is odd
|
||||
!is_even && // degree of the factor is odd
|
||||
info.m_lc_sign < 0 // lc of the eq is negative
|
||||
) {
|
||||
if (d % 2 == 1 && // d is odd
|
||||
!is_even && // degree of the factor is odd
|
||||
info.m_lc_sign < 0) { // lc of the eq is negative
|
||||
atom_sign = -atom_sign; // flipped the sign of the current literal
|
||||
TRACE("nlsat_simplify_core", tout << "odd degree\n";);
|
||||
}
|
||||
if (is_const(new_factor)) {
|
||||
int s = sign(new_factor);
|
||||
if (s == 0) {
|
||||
TRACE("nlsat_simplify_core", tout << "new factor is const\n";);
|
||||
polynomial::sign s = sign(new_factor);
|
||||
if (s == polynomial::sign_zero) {
|
||||
bool atom_val = a->get_kind() == atom::EQ;
|
||||
bool lit_val = l.sign() ? !atom_val : atom_val;
|
||||
new_lit = lit_val ? true_literal : false_literal;
|
||||
TRACE("nlsat_simplify_core", tout << "zero sign: " << info.m_lc_const << "\n";);
|
||||
if (!info.m_lc_const) {
|
||||
// We have essentially shown the current factor must be zero If the leading coefficient is not zero.
|
||||
// Note that, if the current factor is zero, then the whole polynomial is zero.
|
||||
|
@ -1115,6 +1122,7 @@ namespace nlsat {
|
|||
return;
|
||||
}
|
||||
else {
|
||||
TRACE("nlsat_simplify_core", tout << "non-zero sign: " << info.m_lc_const << "\n";);
|
||||
// We have shown the current factor is a constant MODULO the sign of the leading coefficient (of the equation used to rewrite the factor).
|
||||
if (!info.m_lc_const) {
|
||||
// If the leading coefficient is not a constant, we must store this information as an extra assumption.
|
||||
|
@ -1266,11 +1274,9 @@ namespace nlsat {
|
|||
var_vector m_select_tmp;
|
||||
ineq_atom * select_lower_stage_eq(scoped_literal_vector & C, var max) {
|
||||
var_vector & xs = m_select_tmp;
|
||||
unsigned sz = C.size();
|
||||
for (unsigned i = 0; i < sz; i++) {
|
||||
literal l = C[i];
|
||||
for (literal l : C) {
|
||||
bool_var b = l.var();
|
||||
atom * a = m_atoms[b];
|
||||
atom * a = m_atoms[b];
|
||||
if (a->is_root_atom())
|
||||
continue; // we don't rewrite root atoms
|
||||
ineq_atom * _a = to_ineq_atom(a);
|
||||
|
@ -1279,9 +1285,7 @@ namespace nlsat {
|
|||
poly * p = _a->p(j);
|
||||
xs.reset();
|
||||
m_pm.vars(p, xs);
|
||||
unsigned xs_sz = xs.size();
|
||||
for (unsigned k = 0; k < xs_sz; k++) {
|
||||
var y = xs[k];
|
||||
for (var y : xs) {
|
||||
if (y >= max)
|
||||
continue;
|
||||
atom * eq = m_x2eq[y];
|
||||
|
|
|
@ -766,7 +766,7 @@ namespace nlsat {
|
|||
TRACE("nlsat", display(tout << "check lemma: ", n, cls) << "\n";
|
||||
display(tout););
|
||||
IF_VERBOSE(0, display(verbose_stream() << "check lemma: ", n, cls) << "\n");
|
||||
for (clause* c : m_learned) IF_VERBOSE(0, display(verbose_stream() << "lemma: ", *c) << "\n");
|
||||
for (clause* c : m_learned) IF_VERBOSE(1, display(verbose_stream() << "lemma: ", *c) << "\n");
|
||||
|
||||
solver solver2(m_ctx);
|
||||
imp& checker = *(solver2.m_imp);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue