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

@ -46,7 +46,7 @@ namespace euf {
* so it isn't necessarily an axiom over EUF,
* We will here leave it to the EUF checker to perform resolution steps.
*/
void solver::log_antecedents(literal l, literal_vector const& r) {
void solver::log_antecedents(literal l, literal_vector const& r, eq_proof_hint* hint) {
TRACE("euf", log_antecedents(tout, l, r););
if (!use_drat())
return;
@ -55,7 +55,7 @@ namespace euf {
lits.push_back(~lit);
if (l != sat::null_literal)
lits.push_back(l);
get_drat().add(lits, sat::status::th(true, get_id()));
get_drat().add(lits, sat::status::th(true, get_id(), hint));
}
void solver::log_antecedents(std::ostream& out, literal l, literal_vector const& r) {
@ -74,6 +74,55 @@ namespace euf {
}
}
eq_proof_hint* solver::mk_hint(literal lit, literal_vector const& r) {
if (!use_drat())
return nullptr;
push(value_trail(m_lit_tail));
push(value_trail(m_cc_tail));
push(restore_size_trail(m_eq_proof_literals));
if (lit != sat::null_literal)
m_eq_proof_literals.push_back(~lit);
m_eq_proof_literals.append(r);
m_lit_head = m_lit_tail;
m_cc_head = m_cc_tail;
m_lit_tail = m_eq_proof_literals.size();
m_cc_tail = m_explain_cc.size();
return new (get_region()) eq_proof_hint(m_lit_head, m_lit_tail, m_cc_head, m_cc_tail);
}
expr* eq_proof_hint::get_hint(euf::solver& s) const {
ast_manager& m = s.get_manager();
func_decl_ref cc(m);
sort* proof = m.mk_proof_sort();
ptr_buffer<sort> sorts;
expr_ref_vector args(m);
if (m_cc_head < m_cc_tail) {
sort* sorts[2] = { m.mk_bool_sort(), m.mk_bool_sort() };
cc = m.mk_func_decl(symbol("cc"), 2, sorts, proof);
}
auto cc_proof = [&](bool comm, expr* eq) {
return m.mk_app(cc, m.mk_bool_val(comm), eq);
};
auto compare_ts = [](cc_justification_record const& a,
cc_justification_record const& b) {
auto const& [_1, _2, ta, _3] = a;
auto const& [_4, _5, tb, _6] = b;
return ta < tb;
};
for (unsigned i = m_lit_head; i < m_lit_tail; ++i)
args.push_back(s.literal2expr(s.m_eq_proof_literals[i]));
std::sort(s.m_explain_cc.data() + m_cc_head, s.m_explain_cc.data() + m_cc_tail, compare_ts);
for (unsigned i = m_cc_head; i < m_cc_tail; ++i) {
auto const& [a, b, ts, comm] = s.m_explain_cc[i];
args.push_back(cc_proof(comm, m.mk_eq(a->get_expr(), b->get_expr())));
}
for (auto * arg : args)
sorts.push_back(arg->get_sort());
func_decl* f = m.mk_func_decl(symbol("euf"), sorts.size(), sorts.data(), proof);
return m.mk_app(f, args);
}
void solver::set_tmp_bool_var(bool_var b, expr* e) {
m_bool_var2expr.setx(b, e, nullptr);
}