mirror of
https://github.com/Z3Prover/z3
synced 2026-07-02 21:36:09 +00:00
Port throttle and soundness fixes from master
- Fix soundness: pop incomplete lemma from m_lemmas on add_lemma failure - Gracefully handle root atoms in add_lemma - Throttle check_assignment with failure counter (decrement on success) - Add arith.nl.nra_check_assignment parameter Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
parent
77d81de03f
commit
6c27140bc9
4 changed files with 62 additions and 41 deletions
|
|
@ -1330,10 +1330,14 @@ lbool core::check(unsigned level) {
|
||||||
return l_false;
|
return l_false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (no_effect()) {
|
if (no_effect() && params().arith_nl_nra_check_assignment() && m_check_assignment_fail_cnt < 10) {
|
||||||
scoped_limits sl(m_reslim);
|
scoped_limits sl(m_reslim);
|
||||||
sl.push_child(&m_nra_lim);
|
sl.push_child(&m_nra_lim);
|
||||||
ret = m_nra.check_assignment();
|
ret = m_nra.check_assignment();
|
||||||
|
if (ret != l_true)
|
||||||
|
++m_check_assignment_fail_cnt;
|
||||||
|
else
|
||||||
|
--m_check_assignment_fail_cnt;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (no_effect() && should_run_bounded_nlsat())
|
if (no_effect() && should_run_bounded_nlsat())
|
||||||
|
|
|
||||||
|
|
@ -63,6 +63,7 @@ class core {
|
||||||
|
|
||||||
unsigned m_nlsat_delay = 0;
|
unsigned m_nlsat_delay = 0;
|
||||||
unsigned m_nlsat_delay_bound = 0;
|
unsigned m_nlsat_delay_bound = 0;
|
||||||
|
unsigned m_check_assignment_fail_cnt = 0;
|
||||||
|
|
||||||
bool should_run_bounded_nlsat();
|
bool should_run_bounded_nlsat();
|
||||||
lbool bounded_nlsat();
|
lbool bounded_nlsat();
|
||||||
|
|
|
||||||
|
|
@ -448,48 +448,63 @@ struct solver::imp {
|
||||||
lbool add_lemma(nlsat::literal_vector const &clause) {
|
lbool add_lemma(nlsat::literal_vector const &clause) {
|
||||||
u_map<lp::lpvar> nl2lp = reverse_lp2nl();
|
u_map<lp::lpvar> nl2lp = reverse_lp2nl();
|
||||||
polynomial::manager &pm = m_nlsat->pm();
|
polynomial::manager &pm = m_nlsat->pm();
|
||||||
nla::lemma_builder lemma(m_nla_core, __FUNCTION__);
|
lbool result = l_false;
|
||||||
for (nlsat::literal l : clause) {
|
{
|
||||||
if (m_literal2constraint.get((~l).index(), lp::null_ci) != lp::null_ci) {
|
nla::lemma_builder lemma(m_nla_core, __FUNCTION__);
|
||||||
auto ci = m_literal2constraint[(~l).index()];
|
for (nlsat::literal l : clause) {
|
||||||
lp::explanation ex;
|
if (m_literal2constraint.get((~l).index(), lp::null_ci) != lp::null_ci) {
|
||||||
ex.push_back(ci);
|
auto ci = m_literal2constraint[(~l).index()];
|
||||||
lemma &= ex;
|
lp::explanation ex;
|
||||||
continue;
|
ex.push_back(ci);
|
||||||
}
|
lemma &= ex;
|
||||||
nlsat::atom *a = m_nlsat->bool_var2atom(l.var());
|
continue;
|
||||||
SASSERT(!a->is_root_atom());
|
}
|
||||||
SASSERT(a->is_ineq_atom());
|
nlsat::atom *a = m_nlsat->bool_var2atom(l.var());
|
||||||
auto &ia = *to_ineq_atom(a);
|
if (a->is_root_atom()) {
|
||||||
if (ia.size() != 1) {
|
result = l_undef;
|
||||||
return l_undef; // factored polynomials not handled here
|
break;
|
||||||
}
|
}
|
||||||
polynomial::polynomial const *p = ia.p(0);
|
SASSERT(a->is_ineq_atom());
|
||||||
rational bound(0);
|
auto &ia = *to_ineq_atom(a);
|
||||||
lp::lar_term t;
|
if (ia.size() != 1) {
|
||||||
process_polynomial_check_assignment(p, bound, nl2lp, t);
|
result = l_undef; // factored polynomials not handled here
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
polynomial::polynomial const *p = ia.p(0);
|
||||||
|
rational bound(0);
|
||||||
|
lp::lar_term t;
|
||||||
|
process_polynomial_check_assignment(p, bound, nl2lp, t);
|
||||||
|
|
||||||
nla::ineq inq(lp::lconstraint_kind::EQ, t, bound); // initial value overwritten in cases below
|
nla::ineq inq(lp::lconstraint_kind::EQ, t, bound); // initial value overwritten in cases below
|
||||||
switch (a->get_kind()) {
|
switch (a->get_kind()) {
|
||||||
case nlsat::atom::EQ:
|
case nlsat::atom::EQ:
|
||||||
inq = nla::ineq(l.sign() ? lp::lconstraint_kind::NE : lp::lconstraint_kind::EQ, t, bound);
|
inq = nla::ineq(l.sign() ? lp::lconstraint_kind::NE : lp::lconstraint_kind::EQ, t, bound);
|
||||||
break;
|
break;
|
||||||
case nlsat::atom::LT:
|
case nlsat::atom::LT:
|
||||||
inq = nla::ineq(l.sign() ? lp::lconstraint_kind::GE : lp::lconstraint_kind::LT, t, bound);
|
inq = nla::ineq(l.sign() ? lp::lconstraint_kind::GE : lp::lconstraint_kind::LT, t, bound);
|
||||||
break;
|
break;
|
||||||
case nlsat::atom::GT:
|
case nlsat::atom::GT:
|
||||||
inq = nla::ineq(l.sign() ? lp::lconstraint_kind::LE : lp::lconstraint_kind::GT, t, bound);
|
inq = nla::ineq(l.sign() ? lp::lconstraint_kind::LE : lp::lconstraint_kind::GT, t, bound);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
return l_undef;
|
result = l_undef;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (result == l_undef)
|
||||||
|
break;
|
||||||
|
if (m_nla_core.ineq_holds(inq)) {
|
||||||
|
result = l_undef;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
lemma |= inq;
|
||||||
}
|
}
|
||||||
if (m_nla_core.ineq_holds(inq))
|
if (result == l_false)
|
||||||
return l_undef;
|
this->m_nla_core.m_check_feasible = true;
|
||||||
lemma |= inq;
|
} // lemma_builder destructor runs here
|
||||||
}
|
if (result == l_undef)
|
||||||
this->m_nla_core.m_check_feasible = true;
|
m_nla_core.m_lemmas.pop_back(); // discard incomplete lemma
|
||||||
return l_false;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -60,6 +60,7 @@ def_module_params(module_name='smt',
|
||||||
('arith.solver', UINT, 6, 'arithmetic solver: 0 - no solver, 1 - bellman-ford based solver (diff. logic only), 2 - simplex based solver, 3 - floyd-warshall based solver (diff. logic only) and no theory combination 4 - utvpi, 5 - infinitary lra, 6 - lra solver'),
|
('arith.solver', UINT, 6, 'arithmetic solver: 0 - no solver, 1 - bellman-ford based solver (diff. logic only), 2 - simplex based solver, 3 - floyd-warshall based solver (diff. logic only) and no theory combination 4 - utvpi, 5 - infinitary lra, 6 - lra solver'),
|
||||||
('arith.nl', BOOL, True, '(incomplete) nonlinear arithmetic support based on Groebner basis and interval propagation, relevant only if smt.arith.solver=2'),
|
('arith.nl', BOOL, True, '(incomplete) nonlinear arithmetic support based on Groebner basis and interval propagation, relevant only if smt.arith.solver=2'),
|
||||||
('arith.nl.nra', BOOL, True, 'call nra_solver when incremental linearization does not produce a lemma, this option is ignored when arith.nl=false, relevant only if smt.arith.solver=6'),
|
('arith.nl.nra', BOOL, True, 'call nra_solver when incremental linearization does not produce a lemma, this option is ignored when arith.nl=false, relevant only if smt.arith.solver=6'),
|
||||||
|
('arith.nl.nra_check_assignment', BOOL, True, 'call check_assignment in nra_solver to verify current assignment against nlsat constraints'),
|
||||||
('arith.nl.branching', BOOL, True, 'branching on integer variables in non linear clusters'),
|
('arith.nl.branching', BOOL, True, 'branching on integer variables in non linear clusters'),
|
||||||
('arith.nl.expensive_patching', BOOL, False, 'use the expensive of monomials'),
|
('arith.nl.expensive_patching', BOOL, False, 'use the expensive of monomials'),
|
||||||
('arith.nl.rounds', UINT, 1024, 'threshold for number of (nested) final checks for non linear arithmetic, relevant only if smt.arith.solver=2'),
|
('arith.nl.rounds', UINT, 1024, 'threshold for number of (nested) final checks for non linear arithmetic, relevant only if smt.arith.solver=2'),
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue