3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-04-29 11:55:51 +00:00

Add EUF (congruence closure) proof hints and checker to the new core

EUF proofs are checked modulo union-find.
Equalities are added to to union-find if they are assumptions or if they can be derived using congruence closure. The congruence closure assumptions are added as proof-hints.
Note that this proof format does not track equality inferences, symmetry and transitivity. Instead they are handled by assuming a union-find based checker.
This commit is contained in:
Nikolaj Bjorner 2022-09-25 14:26:20 -07:00
parent 6f2fde87d1
commit 9be8fc7857
11 changed files with 315 additions and 57 deletions

View file

@ -202,6 +202,8 @@ namespace euf {
void solver::get_antecedents(literal l, ext_justification_idx idx, literal_vector& r, bool probing) {
m_egraph.begin_explain();
m_explain.reset();
if (use_drat() && !probing)
push(restore_size_trail(m_explain_cc, m_explain_cc.size()));
auto* ext = sat::constraint_base::to_extension(idx);
if (ext == this)
get_antecedents(l, constraint::from_idx(idx), r, probing);
@ -220,33 +222,35 @@ namespace euf {
}
}
m_egraph.end_explain();
eq_proof_hint* hint = (use_drat() && !probing) ? mk_hint(l, r) : nullptr;
unsigned j = 0;
for (sat::literal lit : r)
if (s().lvl(lit) > 0) r[j++] = lit;
r.shrink(j);
TRACE("euf", tout << "explain " << l << " <- " << r << " " << probing << "\n";);
CTRACE("euf", probing, tout << "explain " << l << " <- " << r << "\n");
DEBUG_CODE(for (auto lit : r) SASSERT(s().value(lit) == l_true););
if (!probing)
log_antecedents(l, r);
log_antecedents(l, r, hint);
}
void solver::get_antecedents(literal l, th_explain& jst, literal_vector& r, bool probing) {
for (auto lit : euf::th_explain::lits(jst))
r.push_back(lit);
for (auto eq : euf::th_explain::eqs(jst))
add_antecedent(eq.first, eq.second);
add_antecedent(probing, eq.first, eq.second);
if (!probing && use_drat())
log_justification(l, jst);
}
void solver::add_antecedent(enode* a, enode* b) {
m_egraph.explain_eq<size_t>(m_explain, a, b);
void solver::add_antecedent(bool probing, enode* a, enode* b) {
cc_justification* cc = (!probing && use_drat()) ? &m_explain_cc : nullptr;
m_egraph.explain_eq<size_t>(m_explain, cc, a, b);
}
void solver::add_diseq_antecedent(ptr_vector<size_t>& ex, enode* a, enode* b) {
sat::bool_var v = get_egraph().explain_diseq(ex, a, b);
void solver::add_diseq_antecedent(ptr_vector<size_t>& ex, cc_justification* cc, enode* a, enode* b) {
sat::bool_var v = get_egraph().explain_diseq(ex, cc, a, b);
SASSERT(v == sat::null_bool_var || s().value(v) == l_false);
if (v != sat::null_bool_var)
ex.push_back(to_ptr(sat::literal(v, true)));
@ -262,14 +266,17 @@ namespace euf {
void solver::get_antecedents(literal l, constraint& j, literal_vector& r, bool probing) {
expr* e = nullptr;
euf::enode* n = nullptr;
cc_justification* cc = nullptr;
if (!probing && !m_drating)
init_ackerman();
if (!probing && use_drat())
cc = &m_explain_cc;
switch (j.kind()) {
case constraint::kind_t::conflict:
SASSERT(m_egraph.inconsistent());
m_egraph.explain<size_t>(m_explain);
m_egraph.explain<size_t>(m_explain, cc);
break;
case constraint::kind_t::eq:
e = m_bool_var2expr[l.var()];
@ -277,14 +284,14 @@ namespace euf {
SASSERT(n);
SASSERT(n->is_equality());
SASSERT(!l.sign());
m_egraph.explain_eq<size_t>(m_explain, n->get_arg(0), n->get_arg(1));
m_egraph.explain_eq<size_t>(m_explain, cc, n->get_arg(0), n->get_arg(1));
break;
case constraint::kind_t::lit:
e = m_bool_var2expr[l.var()];
n = m_egraph.find(e);
SASSERT(n);
SASSERT(m.is_bool(n->get_expr()));
m_egraph.explain_eq<size_t>(m_explain, n, (l.sign() ? mk_false() : mk_true()));
m_egraph.explain_eq<size_t>(m_explain, cc, n, (l.sign() ? mk_false() : mk_true()));
break;
default:
IF_VERBOSE(0, verbose_stream() << (unsigned)j.kind() << "\n");
@ -423,7 +430,7 @@ namespace euf {
m_egraph.begin_explain();
m_explain.reset();
m_egraph.explain_eq<size_t>(m_explain, e.child(), e.root());
m_egraph.explain_eq<size_t>(m_explain, nullptr, e.child(), e.root());
m_egraph.end_explain();
if (m_egraph.uses_congruence())
return false;