3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-04-24 01:25:31 +00:00
get_antecedent has to be well-founded. It got broken when using eval during propagation and egraph explain during conflict resolution.
This commit is contained in:
Nikolaj Bjorner 2022-01-15 09:35:25 -08:00
parent d09abdf58e
commit 74824ac901
10 changed files with 53 additions and 4547 deletions

View file

@ -243,11 +243,11 @@ namespace euf {
m_egraph.explain_eq<size_t>(m_explain, a, b);
}
void solver::add_diseq_antecedent(enode* a, enode* b) {
sat::bool_var v = get_egraph().explain_diseq(m_explain, 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);
SASSERT(v == sat::null_bool_var || s().value(v) == l_false);
if (v != sat::null_bool_var)
m_explain.push_back(to_ptr(sat::literal(v, true)));
ex.push_back(to_ptr(sat::literal(v, true)));
}
bool solver::propagate(enode* a, enode* b, ext_justification_idx idx) {

View file

@ -305,7 +305,9 @@ namespace euf {
void get_antecedents(literal l, ext_justification_idx idx, literal_vector& r, bool probing) override;
void get_antecedents(literal l, th_explain& jst, literal_vector& r, bool probing);
void add_antecedent(enode* a, enode* b);
void add_diseq_antecedent(enode* a, enode* b);
void add_diseq_antecedent(ptr_vector<size_t>& ex, enode* a, enode* b);
void add_explain(size_t* p) { m_explain.push_back(p); }
void reset_explain() { m_explain.reset(); }
void set_eliminated(bool_var v) override;
void asserted(literal l) override;
sat::check_result check() override;

View file

@ -122,18 +122,17 @@ namespace q {
return out << "]";
}
struct justification {
expr* m_lhs, *m_rhs;
expr* m_lhs, * m_rhs;
bool m_sign;
unsigned m_num_ev;
euf::enode_pair* m_evidence;
clause& m_clause;
unsigned m_num_ex;
size_t** m_explain;
clause& m_clause;
euf::enode* const* m_binding;
justification(lit const& l, clause& c, euf::enode* const* b, unsigned n, euf::enode_pair* ev):
m_lhs(l.lhs), m_rhs(l.rhs), m_sign(l.sign), m_num_ev(n), m_evidence(ev), m_clause(c), m_binding(b) {}
sat::ext_constraint_idx to_index() const {
return sat::constraint_base::mem2base(this);
justification(lit const& l, clause& c, euf::enode* const* b, unsigned n, size_t** ev) :
m_lhs(l.lhs), m_rhs(l.rhs), m_sign(l.sign), m_num_ex(n), m_explain(ev), m_clause(c), m_binding(b) {}
sat::ext_constraint_idx to_index() const {
return sat::constraint_base::mem2base(this);
}
static justification& from_index(size_t idx) {
return *reinterpret_cast<justification*>(sat::constraint_base::from_index(idx)->mem());

View file

@ -97,23 +97,46 @@ namespace q {
}
}
/**
* Create a justification for binding b.
* The justification involves equalities in the E-graph that have
* explanations. Retrieve the explanations while the justification
* is created to ensure the justification trail is well-founded
* during conflict resolution.
*/
sat::ext_justification_idx ematch::mk_justification(unsigned idx, clause& c, euf::enode* const* b) {
void* mem = ctx.get_region().allocate(justification::get_obj_size());
sat::constraint_base::initialize(mem, &m_qs);
bool sign = false;
expr* l = nullptr, *r = nullptr;
lit lit(expr_ref(l, m), expr_ref(r, m), sign);
expr* l = nullptr, * r = nullptr;
lit lit(expr_ref(l, m), expr_ref(r, m), sign);
if (idx != UINT_MAX)
lit = c[idx];
auto* ev = static_cast<euf::enode_pair*>(ctx.get_region().allocate(sizeof(euf::enode_pair) * m_evidence.size()));
for (unsigned i = m_evidence.size(); i-- > 0; )
ev[i] = m_evidence[i];
auto* constraint = new (sat::constraint_base::ptr2mem(mem)) justification(lit, c, b, m_evidence.size(), ev);
m_explain.reset();
ctx.get_egraph().begin_explain();
ctx.reset_explain();
for (auto const& [a, b] : m_evidence) {
SASSERT(a->get_root() == b->get_root() || ctx.get_egraph().are_diseq(a, b));
if (a->get_root() == b->get_root())
ctx.get_egraph().explain_eq<size_t>(m_explain, a, b);
else
ctx.add_diseq_antecedent(m_explain, a, b);
}
ctx.get_egraph().end_explain();
std::cout << "exp size " << m_explain.size() << "\n";
size_t** ev = static_cast<size_t**>(ctx.get_region().allocate(sizeof(size_t*) * m_explain.size()));
for (unsigned i = m_explain.size(); i-- > 0; )
ev[i] = m_explain[i];
auto* constraint = new (sat::constraint_base::ptr2mem(mem)) justification(lit, c, b, m_explain.size(), ev);
return constraint->to_index();
}
void ematch::get_antecedents(sat::literal l, sat::ext_justification_idx idx, sat::literal_vector& r, bool probing) {
m_eval.explain(l, justification::from_index(idx), r, probing);
justification& j = justification::from_index(idx);
for (unsigned i = 0; i < j.m_num_ex; ++i)
ctx.add_explain(j.m_explain[i]);
r.push_back(j.m_clause.m_literal);
}
quantifier_ref ematch::nnf_skolem(quantifier* q) {

View file

@ -94,7 +94,8 @@ namespace q {
euf::enode* const* copy_nodes(clause& c, euf::enode* const* _binding);
binding* tmp_binding(clause& c, app* pat, euf::enode* const* _binding);
binding* alloc_binding(clause& c, app* pat, euf::enode* const* _binding, unsigned max_generation, unsigned min_top, unsigned max_top);
ptr_vector<size_t> m_explain;
sat::ext_justification_idx mk_justification(unsigned idx, clause& c, euf::enode* const* b);
void ensure_ground_enodes(expr* e);

View file

@ -246,20 +246,5 @@ namespace q {
}
return m_eval[e->get_id()];
}
void eval::explain(sat::literal l, justification& j, sat::literal_vector& r, bool probing) {
clause& c = j.m_clause;
for (unsigned i = 0; i < j.m_num_ev; ++i) {
auto [a, b] = j.m_evidence[i];
SASSERT(a->get_root() == b->get_root() || ctx.get_egraph().are_diseq(a, b));
if (a->get_root() == b->get_root())
ctx.add_antecedent(a, b);
else
ctx.add_diseq_antecedent(a, b);
}
r.push_back(c.m_literal);
(void)probing; // ignored
}
}

View file

@ -43,7 +43,6 @@ namespace q {
public:
eval(euf::solver& ctx);
void explain(sat::literal l, justification& j, sat::literal_vector& r, bool probing);
lbool operator()(euf::enode* const* binding, clause& c, euf::enode_pair_vector& evidence);
lbool operator()(euf::enode* const* binding, clause& c, unsigned& idx, euf::enode_pair_vector& evidence);

View file

@ -553,8 +553,8 @@ namespace q {
void unmark(unsigned head) {
for (unsigned i = m_candidates.size(); i-- > head; ) {
enode* app = m_candidates[i];
if (app->is_marked1())
app->unmark1();
if (app->is_marked2())
app->unmark2();
}
}
@ -946,9 +946,9 @@ namespace q {
void linearise_core() {
m_aux.reset();
app * first_app = nullptr;
unsigned first_app_reg;
unsigned first_app_sz;
unsigned first_app_num_unbound_vars;
unsigned first_app_reg = 0;
unsigned first_app_sz = 0;
unsigned first_app_num_unbound_vars = 0;
// generate first the non-BIND operations
for (unsigned reg : m_todo) {
expr * p = m_registers[reg];
@ -2022,9 +2022,9 @@ namespace q {
code_tree::scoped_unmark _unmark(t);
while ((app = t->next_candidate()) && !ctx.resource_limits_exceeded()) {
TRACE("trigger_bug", tout << "candidate\n" << ctx.bpp(app) << "\n";);
if (!app->is_marked1() && app->is_cgr()) {
if (!app->is_marked2() && app->is_cgr()) {
execute_core(t, app);
app->mark1();
app->mark2();
}
}
}