mirror of
https://github.com/Z3Prover/z3
synced 2025-04-12 12:08:18 +00:00
#5417 - revise q_eval based on bug based on non-chronological dependencies with post-hoc explain function
This commit is contained in:
parent
e8bc9f3469
commit
7d915eb295
|
@ -156,26 +156,26 @@ namespace euf {
|
||||||
svector<update_record> m_updates;
|
svector<update_record> m_updates;
|
||||||
unsigned_vector m_scopes;
|
unsigned_vector m_scopes;
|
||||||
enode_vector m_expr2enode;
|
enode_vector m_expr2enode;
|
||||||
enode* m_tmp_eq { nullptr };
|
enode* m_tmp_eq = nullptr;
|
||||||
enode* m_tmp_node { nullptr };
|
enode* m_tmp_node = nullptr;
|
||||||
unsigned m_tmp_node_capacity { 0 };
|
unsigned m_tmp_node_capacity = 0;
|
||||||
enode_vector m_nodes;
|
enode_vector m_nodes;
|
||||||
expr_ref_vector m_exprs;
|
expr_ref_vector m_exprs;
|
||||||
vector<enode_vector> m_decl2enodes;
|
vector<enode_vector> m_decl2enodes;
|
||||||
enode_vector m_empty_enodes;
|
enode_vector m_empty_enodes;
|
||||||
unsigned m_num_scopes { 0 };
|
unsigned m_num_scopes = 0;
|
||||||
bool m_inconsistent { false };
|
bool m_inconsistent = false;
|
||||||
enode *m_n1 { nullptr };
|
enode *m_n1 = nullptr;
|
||||||
enode *m_n2 { nullptr };
|
enode *m_n2 = nullptr;
|
||||||
justification m_justification;
|
justification m_justification;
|
||||||
unsigned m_new_lits_qhead { 0 };
|
unsigned m_new_lits_qhead = 0;
|
||||||
unsigned m_new_th_eqs_qhead { 0 };
|
unsigned m_new_th_eqs_qhead = 0;
|
||||||
svector<enode_bool_pair> m_new_lits;
|
svector<enode_bool_pair> m_new_lits;
|
||||||
svector<th_eq> m_new_th_eqs;
|
svector<th_eq> m_new_th_eqs;
|
||||||
bool_vector m_th_propagates_diseqs;
|
bool_vector m_th_propagates_diseqs;
|
||||||
enode_vector m_todo;
|
enode_vector m_todo;
|
||||||
stats m_stats;
|
stats m_stats;
|
||||||
bool m_uses_congruence { false };
|
bool m_uses_congruence = false;
|
||||||
std::function<void(enode*,enode*)> m_on_merge;
|
std::function<void(enode*,enode*)> m_on_merge;
|
||||||
std::function<void(enode*)> m_on_make;
|
std::function<void(enode*)> m_on_make;
|
||||||
std::function<void(expr*,expr*,expr*)> m_used_eq;
|
std::function<void(expr*,expr*,expr*)> m_used_eq;
|
||||||
|
|
|
@ -125,7 +125,7 @@ namespace euf {
|
||||||
|
|
||||||
|
|
||||||
ast_manager & m_manager;
|
ast_manager & m_manager;
|
||||||
bool m_commutativity{ false }; //!< true if the last found congruence used commutativity
|
bool m_commutativity = false; //!< true if the last found congruence used commutativity
|
||||||
ptr_vector<void> m_tables;
|
ptr_vector<void> m_tables;
|
||||||
map<decl_info, unsigned, decl_hash, decl_eq> m_func_decl2id;
|
map<decl_info, unsigned, decl_hash, decl_eq> m_func_decl2id;
|
||||||
|
|
||||||
|
|
|
@ -57,7 +57,7 @@ namespace q {
|
||||||
unsigned m_index;
|
unsigned m_index;
|
||||||
vector<lit> m_lits;
|
vector<lit> m_lits;
|
||||||
quantifier_ref m_q;
|
quantifier_ref m_q;
|
||||||
sat::literal m_literal;
|
sat::literal m_literal = sat::null_literal;
|
||||||
q::quantifier_stat* m_stat = nullptr;
|
q::quantifier_stat* m_stat = nullptr;
|
||||||
binding* m_bindings = nullptr;
|
binding* m_bindings = nullptr;
|
||||||
|
|
||||||
|
@ -75,10 +75,12 @@ namespace q {
|
||||||
struct justification {
|
struct justification {
|
||||||
expr* m_lhs, *m_rhs;
|
expr* m_lhs, *m_rhs;
|
||||||
bool m_sign;
|
bool m_sign;
|
||||||
|
unsigned m_num_ev;
|
||||||
|
euf::enode_pair* m_evidence;
|
||||||
clause& m_clause;
|
clause& m_clause;
|
||||||
euf::enode* const* m_binding;
|
euf::enode* const* m_binding;
|
||||||
justification(lit const& l, clause& c, euf::enode* const* b):
|
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_clause(c), m_binding(b) {}
|
m_lhs(l.lhs), m_rhs(l.rhs), m_sign(l.sign), m_clause(c), m_binding(b), m_num_ev(n), m_evidence(ev) {}
|
||||||
sat::ext_constraint_idx to_index() const {
|
sat::ext_constraint_idx to_index() const {
|
||||||
return sat::constraint_base::mem2base(this);
|
return sat::constraint_base::mem2base(this);
|
||||||
}
|
}
|
||||||
|
|
|
@ -94,7 +94,10 @@ namespace q {
|
||||||
lit lit(expr_ref(l, m), expr_ref(r, m), sign);
|
lit lit(expr_ref(l, m), expr_ref(r, m), sign);
|
||||||
if (idx != UINT_MAX)
|
if (idx != UINT_MAX)
|
||||||
lit = c[idx];
|
lit = c[idx];
|
||||||
auto* constraint = new (sat::constraint_base::ptr2mem(mem)) justification(lit, c, b);
|
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);
|
||||||
return constraint->to_index();
|
return constraint->to_index();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -251,7 +254,8 @@ namespace q {
|
||||||
bool ematch::propagate(bool is_owned, euf::enode* const* binding, unsigned max_generation, clause& c, bool& propagated) {
|
bool ematch::propagate(bool is_owned, euf::enode* const* binding, unsigned max_generation, clause& c, bool& propagated) {
|
||||||
TRACE("q", c.display(ctx, tout) << "\n";);
|
TRACE("q", c.display(ctx, tout) << "\n";);
|
||||||
unsigned idx = UINT_MAX;
|
unsigned idx = UINT_MAX;
|
||||||
lbool ev = m_eval(binding, c, idx);
|
m_evidence.reset();
|
||||||
|
lbool ev = m_eval(binding, c, idx, m_evidence);
|
||||||
if (ev == l_true) {
|
if (ev == l_true) {
|
||||||
++m_stats.m_num_redundant;
|
++m_stats.m_num_redundant;
|
||||||
return true;
|
return true;
|
||||||
|
@ -267,15 +271,18 @@ namespace q {
|
||||||
if (ev == l_undef && max_generation > m_generation_propagation_threshold)
|
if (ev == l_undef && max_generation > m_generation_propagation_threshold)
|
||||||
return false;
|
return false;
|
||||||
if (!is_owned)
|
if (!is_owned)
|
||||||
binding = alloc_binding(c, binding);
|
binding = alloc_binding(c, binding);
|
||||||
auto j_idx = mk_justification(idx, c, binding);
|
|
||||||
|
auto j_idx = mk_justification(idx, c, binding);
|
||||||
|
|
||||||
if (ev == l_false) {
|
if (ev == l_false) {
|
||||||
++m_stats.m_num_conflicts;
|
++m_stats.m_num_conflicts;
|
||||||
ctx.set_conflict(j_idx);
|
ctx.set_conflict(j_idx);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
++m_stats.m_num_propagations;
|
++m_stats.m_num_propagations;
|
||||||
ctx.propagate(instantiate(c, binding, c[idx]), j_idx);
|
auto lit = instantiate(c, binding, c[idx]);
|
||||||
|
ctx.propagate(lit, j_idx);
|
||||||
}
|
}
|
||||||
propagated = true;
|
propagated = true;
|
||||||
return true;
|
return true;
|
||||||
|
@ -295,6 +302,7 @@ namespace q {
|
||||||
}
|
}
|
||||||
|
|
||||||
void ematch::add_instantiation(clause& c, binding& b, sat::literal lit) {
|
void ematch::add_instantiation(clause& c, binding& b, sat::literal lit) {
|
||||||
|
m_evidence.reset();
|
||||||
ctx.propagate(lit, mk_justification(UINT_MAX, c, b.nodes()));
|
ctx.propagate(lit, mk_justification(UINT_MAX, c, b.nodes()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -63,7 +63,7 @@ namespace q {
|
||||||
quantifier_stat_gen m_qstat_gen;
|
quantifier_stat_gen m_qstat_gen;
|
||||||
fingerprints m_fingerprints;
|
fingerprints m_fingerprints;
|
||||||
scoped_ptr<binding> m_tmp_binding;
|
scoped_ptr<binding> m_tmp_binding;
|
||||||
unsigned m_tmp_binding_capacity { 0 };
|
unsigned m_tmp_binding_capacity = 0;
|
||||||
queue m_inst_queue;
|
queue m_inst_queue;
|
||||||
pattern_inference_rw m_infer_patterns;
|
pattern_inference_rw m_infer_patterns;
|
||||||
scoped_ptr<q::mam> m_mam, m_lazy_mam;
|
scoped_ptr<q::mam> m_mam, m_lazy_mam;
|
||||||
|
@ -72,13 +72,14 @@ namespace q {
|
||||||
vector<unsigned_vector> m_watch; // expr_id -> clause-index*
|
vector<unsigned_vector> m_watch; // expr_id -> clause-index*
|
||||||
stats m_stats;
|
stats m_stats;
|
||||||
expr_fast_mark1 m_mark;
|
expr_fast_mark1 m_mark;
|
||||||
unsigned m_generation_propagation_threshold{ 3 };
|
unsigned m_generation_propagation_threshold = 3;
|
||||||
ptr_vector<app> m_ground;
|
ptr_vector<app> m_ground;
|
||||||
bool m_in_queue_set{ false };
|
bool m_in_queue_set = false;
|
||||||
nat_set m_node_in_queue;
|
nat_set m_node_in_queue;
|
||||||
nat_set m_clause_in_queue;
|
nat_set m_clause_in_queue;
|
||||||
unsigned m_qhead { 0 };
|
unsigned m_qhead = 0;
|
||||||
unsigned_vector m_clause_queue;
|
unsigned_vector m_clause_queue;
|
||||||
|
euf::enode_pair_vector m_evidence;
|
||||||
|
|
||||||
binding* alloc_binding(unsigned n, app* pat, unsigned max_generation, unsigned min_top, unsigned max_top);
|
binding* alloc_binding(unsigned n, app* pat, unsigned max_generation, unsigned min_top, unsigned max_top);
|
||||||
euf::enode* const* alloc_binding(clause& c, euf::enode* const* _binding);
|
euf::enode* const* alloc_binding(clause& c, euf::enode* const* _binding);
|
||||||
|
@ -115,7 +116,7 @@ namespace q {
|
||||||
|
|
||||||
bool propagate(bool flush);
|
bool propagate(bool flush);
|
||||||
|
|
||||||
void init_search();
|
// void init_search();
|
||||||
|
|
||||||
void add(quantifier* q);
|
void add(quantifier* q);
|
||||||
|
|
||||||
|
@ -127,7 +128,7 @@ namespace q {
|
||||||
void on_binding(quantifier* q, app* pat, euf::enode* const* binding, unsigned max_generation, unsigned min_gen, unsigned max_gen);
|
void on_binding(quantifier* q, app* pat, euf::enode* const* binding, unsigned max_generation, unsigned min_gen, unsigned max_gen);
|
||||||
|
|
||||||
// callbacks from queue
|
// callbacks from queue
|
||||||
lbool evaluate(euf::enode* const* binding, clause& c) { return m_eval(binding, c); }
|
lbool evaluate(euf::enode* const* binding, clause& c) { m_evidence.reset(); return m_eval(binding, c, m_evidence); }
|
||||||
|
|
||||||
void add_instantiation(clause& c, binding& b, sat::literal lit);
|
void add_instantiation(clause& c, binding& b, sat::literal lit);
|
||||||
|
|
||||||
|
|
|
@ -32,7 +32,7 @@ namespace q {
|
||||||
m(ctx.get_manager())
|
m(ctx.get_manager())
|
||||||
{}
|
{}
|
||||||
|
|
||||||
lbool eval::operator()(euf::enode* const* binding, clause& c, unsigned& idx) {
|
lbool eval::operator()(euf::enode* const* binding, clause& c, unsigned& idx, euf::enode_pair_vector& evidence) {
|
||||||
scoped_mark_reset _sr(*this);
|
scoped_mark_reset _sr(*this);
|
||||||
idx = UINT_MAX;
|
idx = UINT_MAX;
|
||||||
unsigned sz = c.m_lits.size();
|
unsigned sz = c.m_lits.size();
|
||||||
|
@ -41,7 +41,7 @@ namespace q {
|
||||||
for (unsigned i = 0; i < sz; ++i) {
|
for (unsigned i = 0; i < sz; ++i) {
|
||||||
unsigned lim = m_indirect_nodes.size();
|
unsigned lim = m_indirect_nodes.size();
|
||||||
lit l = c[i];
|
lit l = c[i];
|
||||||
lbool cmp = compare(n, binding, l.lhs, l.rhs);
|
lbool cmp = compare(n, binding, l.lhs, l.rhs, evidence);
|
||||||
switch (cmp) {
|
switch (cmp) {
|
||||||
case l_false:
|
case l_false:
|
||||||
m_indirect_nodes.shrink(lim);
|
m_indirect_nodes.shrink(lim);
|
||||||
|
@ -75,46 +75,55 @@ namespace q {
|
||||||
return l_undef;
|
return l_undef;
|
||||||
}
|
}
|
||||||
|
|
||||||
lbool eval::operator()(euf::enode* const* binding, clause& c) {
|
lbool eval::operator()(euf::enode* const* binding, clause& c, euf::enode_pair_vector& evidence) {
|
||||||
unsigned idx = 0;
|
unsigned idx = 0;
|
||||||
return (*this)(binding, c, idx);
|
return (*this)(binding, c, idx, evidence);
|
||||||
}
|
}
|
||||||
|
|
||||||
lbool eval::compare(unsigned n, euf::enode* const* binding, expr* s, expr* t) {
|
lbool eval::compare(unsigned n, euf::enode* const* binding, expr* s, expr* t, euf::enode_pair_vector& evidence) {
|
||||||
if (s == t)
|
if (s == t)
|
||||||
return l_true;
|
return l_true;
|
||||||
if (m.are_distinct(s, t))
|
if (m.are_distinct(s, t))
|
||||||
return l_false;
|
return l_false;
|
||||||
|
|
||||||
euf::enode* sn = (*this)(n, binding, s);
|
euf::enode* sn = (*this)(n, binding, s, evidence);
|
||||||
euf::enode* tn = (*this)(n, binding, t);
|
euf::enode* tn = (*this)(n, binding, t, evidence);
|
||||||
if (sn) sn = sn->get_root();
|
euf::enode* sr = sn ? sn->get_root() : sn;
|
||||||
if (tn) tn = tn->get_root();
|
euf::enode* tr = tn ? tn->get_root() : tn;
|
||||||
|
if (sn != sr) evidence.push_back(euf::enode_pair(sn, sr)), sn = sr;
|
||||||
|
if (tn != tr) evidence.push_back(euf::enode_pair(tn, tr)), tn = tr;
|
||||||
TRACE("q", tout << mk_pp(s, m) << " ~~ " << mk_pp(t, m) << "\n";
|
TRACE("q", tout << mk_pp(s, m) << " ~~ " << mk_pp(t, m) << "\n";
|
||||||
tout << ctx.bpp(sn) << " " << ctx.bpp(tn) << "\n";);
|
tout << ctx.bpp(sn) << " " << ctx.bpp(tn) << "\n";);
|
||||||
|
|
||||||
lbool c;
|
lbool c;
|
||||||
if (sn && sn == tn)
|
if (sn && sn == tn)
|
||||||
return l_true;
|
return l_true;
|
||||||
if (sn && tn && ctx.get_egraph().are_diseq(sn, tn))
|
if (sn && tn && ctx.get_egraph().are_diseq(sn, tn)) {
|
||||||
|
evidence.push_back(euf::enode_pair(sn, tn));
|
||||||
return l_false;
|
return l_false;
|
||||||
|
}
|
||||||
if (sn && tn)
|
if (sn && tn)
|
||||||
return l_undef;
|
return l_undef;
|
||||||
if (!sn && !tn)
|
if (!sn && !tn)
|
||||||
return compare_rec(n, binding, s, t);
|
return compare_rec(n, binding, s, t, evidence);
|
||||||
if (!tn && sn) {
|
if (!tn && sn) {
|
||||||
std::swap(tn, sn);
|
std::swap(tn, sn);
|
||||||
std::swap(t, s);
|
std::swap(t, s);
|
||||||
}
|
}
|
||||||
for (euf::enode* t1 : euf::enode_class(tn))
|
unsigned sz = evidence.size();
|
||||||
if (c = compare_rec(n, binding, s, t1->get_expr()), c != l_undef)
|
for (euf::enode* t1 : euf::enode_class(tn)) {
|
||||||
|
if (c = compare_rec(n, binding, s, t1->get_expr(), evidence), c != l_undef) {
|
||||||
|
evidence.push_back(euf::enode_pair(t1, tn));
|
||||||
return c;
|
return c;
|
||||||
|
}
|
||||||
|
evidence.shrink(sz);
|
||||||
|
}
|
||||||
return l_undef;
|
return l_undef;
|
||||||
}
|
}
|
||||||
|
|
||||||
// f(p1) = f(p2) if p1 = p2
|
// f(p1) = f(p2) if p1 = p2
|
||||||
// f(p1) != f(p2) if p1 != p2 and f is injective
|
// f(p1) != f(p2) if p1 != p2 and f is injective
|
||||||
lbool eval::compare_rec(unsigned n, euf::enode* const* binding, expr* s, expr* t) {
|
lbool eval::compare_rec(unsigned n, euf::enode* const* binding, expr* s, expr* t, euf::enode_pair_vector& evidence) {
|
||||||
if (m.are_equal(s, t))
|
if (m.are_equal(s, t))
|
||||||
return l_true;
|
return l_true;
|
||||||
if (m.are_distinct(s, t))
|
if (m.are_distinct(s, t))
|
||||||
|
@ -127,14 +136,20 @@ namespace q {
|
||||||
return l_undef;
|
return l_undef;
|
||||||
bool is_injective = to_app(s)->get_decl()->is_injective();
|
bool is_injective = to_app(s)->get_decl()->is_injective();
|
||||||
bool has_undef = false;
|
bool has_undef = false;
|
||||||
|
unsigned sz = evidence.size();
|
||||||
for (unsigned i = to_app(s)->get_num_args(); i-- > 0; ) {
|
for (unsigned i = to_app(s)->get_num_args(); i-- > 0; ) {
|
||||||
switch (compare(n, binding, to_app(s)->get_arg(i), to_app(t)->get_arg(i))) {
|
unsigned sz1 = evidence.size(), sz2;
|
||||||
|
switch (compare(n, binding, to_app(s)->get_arg(i), to_app(t)->get_arg(i), evidence)) {
|
||||||
case l_true:
|
case l_true:
|
||||||
break;
|
break;
|
||||||
case l_false:
|
case l_false:
|
||||||
if (is_injective)
|
if (!is_injective)
|
||||||
return l_false;
|
return l_undef;
|
||||||
return l_undef;
|
sz2 = evidence.size();
|
||||||
|
for (unsigned i = 0; i < sz2 - sz1; ++i)
|
||||||
|
evidence[sz + i] = evidence[sz1 + i];
|
||||||
|
evidence.shrink(sz + sz2 - sz1);
|
||||||
|
return l_false;
|
||||||
case l_undef:
|
case l_undef:
|
||||||
if (!is_injective)
|
if (!is_injective)
|
||||||
return l_undef;
|
return l_undef;
|
||||||
|
@ -142,10 +157,15 @@ namespace q {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return has_undef ? l_undef : l_true;
|
|
||||||
|
if (!has_undef)
|
||||||
|
return l_true;
|
||||||
|
|
||||||
|
evidence.shrink(sz);
|
||||||
|
return l_undef;
|
||||||
}
|
}
|
||||||
|
|
||||||
euf::enode* eval::operator()(unsigned n, euf::enode* const* binding, expr* e) {
|
euf::enode* eval::operator()(unsigned n, euf::enode* const* binding, expr* e, euf::enode_pair_vector& evidence) {
|
||||||
if (is_ground(e))
|
if (is_ground(e))
|
||||||
return ctx.get_egraph().find(e);
|
return ctx.get_egraph().find(e);
|
||||||
if (m_mark.is_marked(e))
|
if (m_mark.is_marked(e))
|
||||||
|
@ -186,6 +206,15 @@ namespace q {
|
||||||
euf::enode* n = ctx.get_egraph().find(t, args.size(), args.data());
|
euf::enode* n = ctx.get_egraph().find(t, args.size(), args.data());
|
||||||
if (!n)
|
if (!n)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
for (unsigned i = args.size(); i-- > 0; ) {
|
||||||
|
if (args[i] != n->get_arg(i)) {
|
||||||
|
// roots could be different when using commutativity
|
||||||
|
// instead of compensating for this, we just bail out
|
||||||
|
if (args[i]->get_root() != n->get_arg(i)->get_root())
|
||||||
|
return nullptr;
|
||||||
|
evidence.push_back(euf::enode_pair(args[i], n->get_arg(i)));
|
||||||
|
}
|
||||||
|
}
|
||||||
m_indirect_nodes.push_back(n);
|
m_indirect_nodes.push_back(n);
|
||||||
m_eval.setx(t->get_id(), n, nullptr);
|
m_eval.setx(t->get_id(), n, nullptr);
|
||||||
m_mark.mark(t);
|
m_mark.mark(t);
|
||||||
|
@ -195,99 +224,18 @@ namespace q {
|
||||||
return m_eval[e->get_id()];
|
return m_eval[e->get_id()];
|
||||||
}
|
}
|
||||||
|
|
||||||
void eval::explain(clause& c, unsigned literal_idx, euf::enode* const* b) {
|
|
||||||
unsigned n = c.num_decls();
|
|
||||||
for (unsigned i = c.size(); i-- > 0; ) {
|
|
||||||
if (i == literal_idx)
|
|
||||||
continue;
|
|
||||||
auto const& lit = c[i];
|
|
||||||
if (lit.sign)
|
|
||||||
explain_eq(n, b, lit.lhs, lit.rhs);
|
|
||||||
else
|
|
||||||
explain_diseq(n, b, lit.lhs, lit.rhs);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void eval::explain_eq(unsigned n, euf::enode* const* binding, expr* s, expr* t) {
|
|
||||||
SASSERT(l_true == compare(n, binding, s, t));
|
|
||||||
if (s == t)
|
|
||||||
return;
|
|
||||||
euf::enode* sn = (*this)(n, binding, s);
|
|
||||||
euf::enode* tn = (*this)(n, binding, t);
|
|
||||||
if (sn && tn) {
|
|
||||||
SASSERT(sn->get_root() == tn->get_root());
|
|
||||||
ctx.add_antecedent(sn, tn);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!sn && tn) {
|
|
||||||
std::swap(sn, tn);
|
|
||||||
std::swap(s, t);
|
|
||||||
}
|
|
||||||
if (sn && !tn) {
|
|
||||||
for (euf::enode* s1 : euf::enode_class(sn)) {
|
|
||||||
if (l_true == compare_rec(n, binding, t, s1->get_expr())) {
|
|
||||||
ctx.add_antecedent(sn, s1);
|
|
||||||
explain_eq(n, binding, t, s1->get_expr());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
UNREACHABLE();
|
|
||||||
}
|
|
||||||
SASSERT(is_app(s) && is_app(t));
|
|
||||||
SASSERT(to_app(s)->get_decl() == to_app(t)->get_decl());
|
|
||||||
for (unsigned i = to_app(s)->get_num_args(); i-- > 0; )
|
|
||||||
explain_eq(n, binding, to_app(s)->get_arg(i), to_app(t)->get_arg(i));
|
|
||||||
}
|
|
||||||
|
|
||||||
void eval::explain_diseq(unsigned n, euf::enode* const* binding, expr* s, expr* t) {
|
|
||||||
SASSERT(l_false == compare(n, binding, s, t));
|
|
||||||
if (m.are_distinct(s, t))
|
|
||||||
return;
|
|
||||||
euf::enode* sn = (*this)(n, binding, s);
|
|
||||||
euf::enode* tn = (*this)(n, binding, t);
|
|
||||||
if (sn && tn && ctx.get_egraph().are_diseq(sn, tn)) {
|
|
||||||
ctx.add_diseq_antecedent(sn, tn);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!sn && tn) {
|
|
||||||
std::swap(sn, tn);
|
|
||||||
std::swap(s, t);
|
|
||||||
}
|
|
||||||
if (sn && !tn) {
|
|
||||||
for (euf::enode* s1 : euf::enode_class(sn)) {
|
|
||||||
if (l_false == compare_rec(n, binding, t, s1->get_expr())) {
|
|
||||||
ctx.add_antecedent(sn, s1);
|
|
||||||
explain_diseq(n, binding, t, s1->get_expr());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
UNREACHABLE();
|
|
||||||
}
|
|
||||||
SASSERT(is_app(s) && is_app(t));
|
|
||||||
app* at = to_app(t);
|
|
||||||
app* as = to_app(s);
|
|
||||||
SASSERT(as->get_decl() == at->get_decl());
|
|
||||||
for (unsigned i = as->get_num_args(); i-- > 0; ) {
|
|
||||||
if (l_false == compare_rec(n, binding, as->get_arg(i), at->get_arg(i))) {
|
|
||||||
explain_eq(n, binding, as->get_arg(i), at->get_arg(i));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
UNREACHABLE();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void eval::explain(sat::literal l, justification& j, sat::literal_vector& r, bool probing) {
|
void eval::explain(sat::literal l, justification& j, sat::literal_vector& r, bool probing) {
|
||||||
scoped_mark_reset _sr(*this);
|
|
||||||
unsigned l_idx = 0;
|
|
||||||
clause& c = j.m_clause;
|
clause& c = j.m_clause;
|
||||||
for (; l_idx < c.size(); ++l_idx) {
|
for (unsigned i = 0; i < j.m_num_ev; ++i) {
|
||||||
if (c[l_idx].lhs == j.m_lhs && c[l_idx].rhs == j.m_rhs && c[l_idx].sign == j.m_sign)
|
auto [a, b] = j.m_evidence[i];
|
||||||
break;
|
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);
|
||||||
}
|
}
|
||||||
explain(c, l_idx, j.m_binding);
|
|
||||||
r.push_back(c.m_literal);
|
r.push_back(c.m_literal);
|
||||||
(void)probing; // ignored
|
(void)probing; // ignored
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -30,25 +30,20 @@ namespace q {
|
||||||
expr_fast_mark1 m_mark;
|
expr_fast_mark1 m_mark;
|
||||||
euf::enode_vector m_eval;
|
euf::enode_vector m_eval;
|
||||||
euf::enode_vector m_indirect_nodes;
|
euf::enode_vector m_indirect_nodes;
|
||||||
ptr_vector<size_t> m_explain;
|
|
||||||
|
|
||||||
struct scoped_mark_reset;
|
struct scoped_mark_reset;
|
||||||
|
|
||||||
void explain(clause& c, unsigned literal_idx, euf::enode* const* binding);
|
|
||||||
void explain_eq(unsigned n, euf::enode* const* binding, expr* s, expr* t);
|
|
||||||
void explain_diseq(unsigned n, euf::enode* const* binding, expr* s, expr* t);
|
|
||||||
|
|
||||||
// compare s, t modulo binding
|
// compare s, t modulo binding
|
||||||
lbool compare(unsigned n, euf::enode* const* binding, expr* s, expr* t);
|
lbool compare(unsigned n, euf::enode* const* binding, expr* s, expr* t, euf::enode_pair_vector& evidence);
|
||||||
lbool compare_rec(unsigned n, euf::enode* const* binding, expr* s, expr* t);
|
lbool compare_rec(unsigned n, euf::enode* const* binding, expr* s, expr* t, euf::enode_pair_vector& evidence);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
eval(euf::solver& ctx);
|
eval(euf::solver& ctx);
|
||||||
void explain(sat::literal l, justification& j, sat::literal_vector& r, bool probing);
|
void explain(sat::literal l, justification& j, sat::literal_vector& r, bool probing);
|
||||||
|
|
||||||
lbool operator()(euf::enode* const* binding, clause& c);
|
lbool operator()(euf::enode* const* binding, clause& c, euf::enode_pair_vector& evidence);
|
||||||
lbool operator()(euf::enode* const* binding, clause& c, unsigned& idx);
|
lbool operator()(euf::enode* const* binding, clause& c, unsigned& idx, euf::enode_pair_vector& evidence);
|
||||||
euf::enode* operator()(unsigned n, euf::enode* const* binding, expr* e);
|
euf::enode* operator()(unsigned n, euf::enode* const* binding, expr* e, euf::enode_pair_vector& evidence);
|
||||||
|
|
||||||
euf::enode_vector const& get_watch() { return m_indirect_nodes; }
|
euf::enode_vector const& get_watch() { return m_indirect_nodes; }
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in a new issue