3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-08-23 11:37:54 +00:00

debug arith/mbi

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
Nikolaj Bjorner 2020-11-02 12:13:19 -08:00
parent fb6e7e146b
commit ab199dedf9
22 changed files with 96 additions and 25 deletions

View file

@ -424,6 +424,7 @@ namespace sat {
}
}
switch (num_lits) {
case 0:
set_conflict();

View file

@ -296,15 +296,34 @@ namespace arith {
return lp::EQ;
}
void solver::mk_eq_axiom(bool is_eq, theory_var v1, theory_var v2) {
void solver::mk_eq_axiom(bool is_eq, euf::th_eq const& e) {
theory_var v1 = e.v1();
theory_var v2 = e.v2();
if (is_bool(v1))
return;
force_push();
expr* e1 = var2expr(v1);
expr* e2 = var2expr(v2);
if (e1->get_id() > e2->get_id())
std::swap(e1, e2);
if (is_eq && m.are_equal(e1, e2))
return;
if (!is_eq && m.are_distinct(e1, e2))
return;
if (is_eq) {
++m_stats.m_assert_eq;
euf::enode* n1 = var2enode(v1);
euf::enode* n2 = var2enode(v2);
lpvar w1 = register_theory_var_in_lar_solver(v1);
lpvar w2 = register_theory_var_in_lar_solver(v2);
auto cs = lp().add_equality(w1, w2);
add_eq_constraint(cs.first, n1, n2);
add_eq_constraint(cs.second, n1, n2);
m_new_eq = true;
return;
}
literal le, ge;
if (a.is_numeral(e1))
std::swap(e1, e2);
@ -332,6 +351,7 @@ namespace arith {
le = mk_literal(a.mk_le(diff, zero));
ge = mk_literal(a.mk_ge(diff, zero));
}
++m_stats.m_assert_diseq;
add_clause(~eq, le);
add_clause(~eq, ge);
add_clause(~le, ~ge, eq);

View file

@ -86,9 +86,10 @@ namespace arith {
}
bool solver::unit_propagate() {
if (m_new_bounds.empty() && m_asserted_qhead == m_asserted.size())
if (!m_new_eq && m_new_bounds.empty() && m_asserted_qhead == m_asserted.size())
return false;
m_new_eq = false;
flush_bound_axioms();
unsigned qhead = m_asserted_qhead;
@ -911,6 +912,8 @@ namespace arith {
theory_var v = (i + start) % sz;
if (is_bool(v))
continue;
if (!ctx.is_shared(var2enode(v)))
continue;
ensure_column(v);
if (!can_get_ivalue(v))
continue;
@ -945,7 +948,7 @@ namespace arith {
continue;
if (n1->get_root() == n2->get_root())
continue;
literal eq = eq_internalize(n1->get_expr(), n2->get_expr());
literal eq = eq_internalize(n1, n2);
if (s().value(eq) != l_true)
return true;
}
@ -1040,7 +1043,6 @@ namespace arith {
SASSERT(m_nla->use_nra_model());
auto t = get_tv(v);
if (t.is_term()) {
m_todo_terms.push_back(std::make_pair(t, rational::one()));
TRACE("nl_value", tout << "v" << v << " " << t.to_string() << "\n";);
TRACE("nl_value", tout << "v" << v << " := w" << t.to_string() << "\n";
@ -1193,8 +1195,13 @@ namespace arith {
TRACE("arith", display(tout << "is-conflict: " << is_conflict << "\n"););
for (auto const& ev : m_explanation)
set_evidence(ev.ci(), m_core, m_eqs);
DEBUG_CODE(
if (is_conflict) {
for (literal c : m_core) VERIFY(s().value(c) == l_false);
for (auto p : m_eqs) VERIFY(p.first->get_root() == p.second->get_root());
});
for (auto const& eq : m_eqs)
m_core.push_back(eq_internalize(eq.first->get_expr(), eq.second->get_expr()));
m_core.push_back(eq_internalize(eq.first, eq.second));
for (literal& c : m_core)
c.neg();
add_clause(m_core);

View file

@ -16,8 +16,8 @@ Author:
--*/
#pragma once
#include "util/obj_pair_set.h"
#include "ast/ast_trail.h"
#include "sat/smt/sat_th.h"
#include "ast/arith_decl_plugin.h"
#include "math/lp/lp_solver.h"
#include "math/lp/lp_primal_simplex.h"
@ -29,6 +29,7 @@ Author:
#include "math/lp/lp_api.h"
#include "math/polynomial/algebraic_numbers.h"
#include "math/polynomial/polynomial.h"
#include "sat/smt/sat_th.h"
namespace euf {
class solver;
@ -90,7 +91,7 @@ namespace arith {
};
int_hashtable<var_value_hash, var_value_eq> m_model_eqs;
bool m_new_eq { false };
// temporary values kept during internalization
@ -303,7 +304,7 @@ namespace arith {
void refine_bound(theory_var v, const lp::implied_bound& be);
literal is_bound_implied(lp::lconstraint_kind k, rational const& value, api_bound const& b) const;
void assert_bound(bool is_true, api_bound& b);
void mk_eq_axiom(bool is_eq, theory_var v1, theory_var v2);
void mk_eq_axiom(bool is_eq, euf::th_eq const& eq);
void assert_idiv_mod_axioms(theory_var u, theory_var v, theory_var w, rational const& r);
api_bound* mk_var_bound(sat::literal lit, theory_var v, lp_api::bound_kind bk, rational const& bound);
lp::lconstraint_kind bound2constraint_kind(bool is_int, lp_api::bound_kind bk, bool is_true);
@ -424,8 +425,8 @@ namespace arith {
void collect_statistics(statistics& st) const override;
euf::th_solver* clone(euf::solver& ctx) override;
bool use_diseqs() const override { return true; }
void new_eq_eh(euf::th_eq const& eq) override { mk_eq_axiom(true, eq.v1(), eq.v2()); }
void new_diseq_eh(euf::th_eq const& de) override { mk_eq_axiom(false, de.v1(), de.v2()); }
void new_eq_eh(euf::th_eq const& eq) override { mk_eq_axiom(true, eq); }
void new_diseq_eh(euf::th_eq const& de) override { mk_eq_axiom(false, de); }
bool unit_propagate() override;
void init_model() override { init_variable_values(); }
void finalize_model(model& mdl) override { DEBUG_CODE(dbg_finalize_model(mdl);); }

View file

@ -83,6 +83,7 @@ namespace euf {
if (ext)
return ext;
ext = alloc(q::solver, *this, fid);
m_qsolver = ext;
add_solver(ext);
return ext;
}
@ -364,11 +365,33 @@ namespace euf {
}
}
bool solver::is_self_propagated(th_eq const& e) {
if (!e.is_eq())
return false;
m_egraph.begin_explain();
m_explain.reset();
m_egraph.explain_eq<size_t>(m_explain, e.child(), e.root());
m_egraph.end_explain();
for (auto p : m_explain) {
if (is_literal(p))
return false;
size_t idx = get_justification(p);
auto* ext = sat::constraint_base::to_extension(idx);
if (ext->get_id() != e.id())
return false;
}
return true;
}
void solver::propagate_th_eqs() {
for (; m_egraph.has_th_eq() && !s().inconsistent() && !m_egraph.inconsistent(); m_egraph.next_th_eq()) {
th_eq eq = m_egraph.get_th_eq();
if (eq.is_eq())
m_id2solver[eq.id()]->new_eq_eh(eq);
if (eq.is_eq()) {
if (!is_self_propagated(eq))
m_id2solver[eq.id()]->new_eq_eh(eq);
}
else
m_id2solver[eq.id()]->new_diseq_eh(eq);
}
@ -404,16 +427,22 @@ namespace euf {
for (auto* e : m_solvers) {
if (!m.inc())
return sat::check_result::CR_GIVEUP;
if (e == m_qsolver)
continue;
switch (e->check()) {
case sat::check_result::CR_CONTINUE: cont = true; break;
case sat::check_result::CR_GIVEUP: give_up = true; break;
default: break;
}
if (s().inconsistent())
return sat::check_result::CR_CONTINUE;
}
if (cont)
return sat::check_result::CR_CONTINUE;
if (give_up)
return sat::check_result::CR_GIVEUP;
if (m_qsolver)
return m_qsolver->check();
TRACE("after_search", s().display(tout););
return sat::check_result::CR_DONE;
}

View file

@ -93,6 +93,7 @@ namespace euf {
scoped_ptr<euf::ackerman> m_ackerman;
scoped_ptr<sat::dual_solver> m_dual_solver;
user::solver* m_user_propagator{ nullptr };
th_solver* m_qsolver { nullptr };
ptr_vector<expr> m_bool_var2expr;
ptr_vector<size_t> m_explain;
@ -147,6 +148,7 @@ namespace euf {
// solving
void propagate_literals();
void propagate_th_eqs();
bool is_self_propagated(th_eq const& e);
void get_antecedents(literal l, constraint& j, literal_vector& r, bool probing);
void new_diseq(enode* a, enode* b, literal lit);

View file

@ -387,4 +387,9 @@ namespace q {
m_plugins.set(fid, p);
}
void mbqi::collect_statistics(statistics& st) const {
if (m_solver)
m_solver->collect_statistics(st);
}
}

View file

@ -79,6 +79,8 @@ namespace q {
void init_search();
void finalize_model(model& mdl);
void collect_statistics(statistics& st) const;
};
}

View file

@ -60,6 +60,7 @@ namespace q {
void solver::collect_statistics(statistics& st) const {
st.update("quantifier asserts", m_stats.m_num_quantifier_asserts);
m_mbqi.collect_statistics(st);
}
euf::th_solver* solver::clone(euf::solver& ctx) {

View file

@ -150,6 +150,7 @@ namespace euf {
bool is_true(sat::literal a, sat::literal b, sat::literal c, sat::literal d) { return is_true(a) || is_true(b, c, c); }
sat::literal eq_internalize(expr* a, expr* b);
sat::literal eq_internalize(enode* a, enode* b) { return eq_internalize(a->get_expr(), b->get_expr()); }
euf::enode* e_internalize(expr* e);
euf::enode* mk_enode(expr* e, bool suppress_args = false);

View file

@ -208,6 +208,7 @@ public:
}
catch (z3_exception& ex) {
(void)ex;
proc.m_solver->collect_statistics(m_stats);
TRACE("sat", tout << ex.msg() << "\n";);
throw;
}