3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-04-07 18:05:21 +00:00

working on relevant

This commit is contained in:
Nikolaj Bjorner 2021-12-28 11:00:02 -08:00
parent 9527471967
commit 28bce8f09c
11 changed files with 121 additions and 98 deletions

View file

@ -446,8 +446,8 @@ namespace euf {
r2->inc_class_size(r1->class_size());
merge_th_eq(r1, r2);
reinsert_parents(r1, r2);
if (m_on_merge)
m_on_merge(r2, r1);
for (auto& cb : m_on_merge)
cb(r2, r1);
}
void egraph::remove_parents(enode* r1, enode* r2) {

View file

@ -32,6 +32,7 @@ Notes:
#include "ast/euf/euf_enode.h"
#include "ast/euf/euf_etable.h"
#include "ast/ast_ll_pp.h"
#include <vector>
namespace euf {
@ -181,7 +182,7 @@ namespace euf {
enode_vector m_todo;
stats m_stats;
bool m_uses_congruence = false;
std::function<void(enode*,enode*)> m_on_merge;
std::vector<std::function<void(enode*,enode*)>> m_on_merge;
std::function<void(enode*)> m_on_make;
std::function<void(expr*,expr*,expr*)> m_used_eq;
std::function<void(app*,app*)> m_used_cc;
@ -293,7 +294,7 @@ namespace euf {
void set_value(enode* n, lbool value);
void set_bool_var(enode* n, unsigned v) { n->set_bool_var(v); }
void set_on_merge(std::function<void(enode* root,enode* other)>& on_merge) { m_on_merge = on_merge; }
void set_on_merge(std::function<void(enode* root,enode* other)>& on_merge) { m_on_merge.push_back(on_merge); }
void set_on_make(std::function<void(enode* n)>& on_make) { m_on_make = on_make; }
void set_used_eq(std::function<void(expr*,expr*,expr*)>& used_eq) { m_used_eq = used_eq; }
void set_used_cc(std::function<void(app*,app*)>& used_cc) { m_used_cc = used_cc; }

View file

@ -23,10 +23,10 @@ Author:
namespace euf {
void solver::add_auto_relevant(sat::literal lit) {
#if NEW_RELEVANCY
m_relevancy.mark_relevant(lit);
return;
#endif
if (m_relevancy.enabled()) {
m_relevancy.mark_relevant(lit);
return;
}
if (!relevancy_enabled())
return;
for (; m_auto_relevant_scopes > 0; --m_auto_relevant_scopes)
@ -37,10 +37,10 @@ namespace euf {
}
void solver::pop_relevant(unsigned n) {
#if NEW_RELEVANCY
m_relevancy.pop(n);
return;
#endif
if (m_relevancy.enabled()) {
m_relevancy.pop(n);
return;
}
if (m_auto_relevant_scopes >= n) {
m_auto_relevant_scopes -= n;
return;
@ -54,31 +54,28 @@ namespace euf {
}
void solver::push_relevant() {
#if NEW_RELEVANCY
m_relevancy.push();
return;
#endif
if (m_relevancy.enabled()) {
m_relevancy.push();
return;
}
++m_auto_relevant_scopes;
}
bool solver::is_relevant(expr* e) const {
#if NEW_RELEVANCY
return m_relevancy.is_relevant(e);
#endif
if (m_relevancy.enabled())
return m_relevancy.is_relevant(e);
return m_relevant_expr_ids.get(e->get_id(), true);
}
bool solver::is_relevant(enode* n) const {
#if NEW_RELEVANCY
return m_relevancy.is_relevant(n);
#endif
if (m_relevancy.enabled())
return m_relevancy.is_relevant(n);
return m_relevant_expr_ids.get(n->get_expr_id(), true);
}
void solver::ensure_dual_solver() {
#if NEW_RELEVANCY
return;
#endif
if (m_relevancy.enabled())
return;
if (m_dual_solver)
return;
m_dual_solver = alloc(sat::dual_solver, s(), s().rlimit());
@ -93,10 +90,10 @@ namespace euf {
* not tracked.
*/
void solver::add_root(unsigned n, sat::literal const* lits) {
#if NEW_RELEVANCY
m_relevancy.add_root(n, lits);
return;
#endif
if (m_relevancy.enabled()) {
m_relevancy.add_root(n, lits);
return;
}
if (!relevancy_enabled())
return;
ensure_dual_solver();
@ -104,10 +101,10 @@ namespace euf {
}
void solver::add_aux(unsigned n, sat::literal const* lits) {
#if NEW_RELEVANCY
m_relevancy.add_def(n, lits);
return;
#endif
if (m_relevancy.enabled()) {
m_relevancy.add_def(n, lits);
return;
}
if (!relevancy_enabled())
return;
ensure_dual_solver();
@ -115,17 +112,15 @@ namespace euf {
}
void solver::track_relevancy(sat::bool_var v) {
#if NEW_RELEVANCY
return;
#endif
if (m_relevancy.enabled())
return;
ensure_dual_solver();
m_dual_solver->track_relevancy(v);
}
bool solver::init_relevancy() {
#if NEW_RELEVANCY
return true;
#endif
if (m_relevancy.enabled())
return true;
m_relevant_expr_ids.reset();
if (!relevancy_enabled())
return true;
@ -144,19 +139,19 @@ namespace euf {
}
void solver::push_relevant(sat::bool_var v) {
SASSERT(!NEW_RELEVANCY);
SASSERT(!m_relevancy.enabled());
expr* e = m_bool_var2expr.get(v, nullptr);
if (e)
m_relevant_todo.push_back(e);
}
bool solver::is_propagated(sat::literal lit) {
SASSERT(!NEW_RELEVANCY);
SASSERT(!m_relevancy.enabled());
return s().value(lit) == l_true && !s().get_justification(lit.var()).is_none();
}
void solver::init_relevant_expr_ids() {
SASSERT(!NEW_RELEVANCY);
SASSERT(!m_relevancy.enabled());
unsigned max_id = 0;
for (enode* n : m_egraph.nodes())
max_id = std::max(max_id, n->get_expr_id());
@ -166,7 +161,7 @@ namespace euf {
}
void solver::relevant_subterms() {
SASSERT(!NEW_RELEVANCY);
SASSERT(!m_relevancy.enabled());
ptr_vector<expr>& todo = m_relevant_todo;
bool_vector& visited = m_relevant_visited;
for (unsigned i = 0; i < todo.size(); ++i) {

View file

@ -58,6 +58,14 @@ namespace euf {
display_justification_ptr(out, reinterpret_cast<size_t*>(j));
};
m_egraph.set_display_justification(disp);
if (m_relevancy.enabled()) {
std::function<void(euf::enode* root, euf::enode* other)> on_merge =
[&](enode* root, enode* other) {
m_relevancy.merge(root, other);
};
m_egraph.set_on_merge(on_merge);
}
}
void solver::updt_params(params_ref const& p) {
@ -244,17 +252,10 @@ namespace euf {
bool solver::propagate(enode* a, enode* b, ext_justification_idx idx) {
if (a->get_root() == b->get_root())
return false;
merge(a, b, to_ptr(idx));
m_egraph.merge(a, b, to_ptr(idx));
return true;
}
void solver::merge(enode* a, enode* b, void* r) {
#if NEW_RELEVANCY
m_relevancy.merge(a, b);
#endif
m_egraph.merge(a, b, r);
}
void solver::get_antecedents(literal l, constraint& j, literal_vector& r, bool probing) {
expr* e = nullptr;
euf::enode* n = nullptr;
@ -294,12 +295,11 @@ namespace euf {
}
void solver::asserted(literal l) {
#if NEW_RELEVANCY
if (!m_relevancy.is_relevant(l)) {
if (m_relevancy.enabled() && !m_relevancy.is_relevant(l)) {
m_relevancy.asserted(l);
return;
}
#endif
expr* e = m_bool_var2expr.get(l.var(), nullptr);
TRACE("euf", tout << "asserted: " << l << "@" << s().scope_lvl() << " := " << mk_bounded_pp(e, m) << "\n";);
if (!e)
@ -320,14 +320,14 @@ namespace euf {
euf::enode* r = n->get_root();
euf::enode* rb = sign ? mk_true() : mk_false();
sat::literal rl(r->bool_var(), r->value() == l_false);
merge(n, nb, c);
merge(r, rb, to_ptr(rl));
m_egraph.merge(n, nb, c);
m_egraph.merge(r, rb, to_ptr(rl));
SASSERT(m_egraph.inconsistent());
return;
}
if (n->merge_tf()) {
euf::enode* nb = sign ? mk_false() : mk_true();
merge(n, nb, c);
m_egraph.merge(n, nb, c);
}
if (n->is_equality()) {
SASSERT(!m.is_iff(e));
@ -335,7 +335,7 @@ namespace euf {
if (sign)
m_egraph.new_diseq(n);
else
merge(n->get_arg(0), n->get_arg(1), c);
m_egraph.merge(n->get_arg(0), n->get_arg(1), c);
}
}
@ -343,9 +343,8 @@ namespace euf {
bool solver::unit_propagate() {
bool propagated = false;
while (!s().inconsistent()) {
#if NEW_RELEVANCY
m_relevancy.propagate();
#endif
if (m_relevancy.enabled())
m_relevancy.propagate();
if (m_egraph.inconsistent()) {
unsigned lvl = s().scope_lvl();
s().set_conflict(sat::justification::mk_ext_justification(lvl, conflict_constraint().to_index()));
@ -362,9 +361,13 @@ namespace euf {
if (m_solvers[i]->unit_propagate())
propagated1 = true;
if (!propagated1)
break;
propagated = true;
if (propagated1) {
propagated = true;
continue;
}
if (m_relevancy.enabled() && m_relevancy.can_propagate())
continue;
break;
}
DEBUG_CODE(if (!propagated && !s().inconsistent()) check_missing_eq_propagation(););
return propagated;
@ -439,12 +442,10 @@ namespace euf {
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()) {
if (!is_self_propagated(eq))
m_id2solver[eq.id()]->new_eq_eh(eq);
}
else
if (!eq.is_eq())
m_id2solver[eq.id()]->new_diseq_eh(eq);
else if (!is_self_propagated(eq))
m_id2solver[eq.id()]->new_eq_eh(eq);
}
}

View file

@ -31,7 +31,6 @@ Author:
#include "sat/smt/smt_relevant.h"
#include "smt/params/smt_params.h"
#define NEW_RELEVANCY 0
namespace euf {
typedef sat::literal literal;
@ -257,6 +256,10 @@ namespace euf {
sat::sat_internalizer& get_si() { return si; }
ast_manager& get_manager() { return m; }
enode* get_enode(expr* e) const { return m_egraph.find(e); }
enode* bool_var2enode(sat::bool_var b) const {
expr* e = m_bool_var2expr.get(b);
return e ? get_enode(e) : nullptr;
}
sat::literal expr2literal(expr* e) const { return enode2literal(get_enode(e)); }
sat::literal enode2literal(enode* n) const { return sat::literal(n->bool_var(), false); }
lbool value(enode* n) const { return s().value(enode2literal(n)); }
@ -293,7 +296,6 @@ namespace euf {
void propagate(literal lit, ext_justification_idx idx);
bool propagate(enode* a, enode* b, ext_justification_idx idx);
void merge(enode* a, enode* b, void* r);
void set_conflict(ext_justification_idx idx);
void propagate(literal lit, th_explain* p) { propagate(lit, p->to_index()); }
@ -395,7 +397,7 @@ namespace euf {
void add_auto_relevant(sat::literal lit);
void pop_relevant(unsigned n);
void push_relevant();
smt::relevancy& relevancy() { return m_relevancy; }
// model construction
void update_model(model_ref& mdl);

View file

@ -66,13 +66,21 @@ namespace q {
};
std::function<void(euf::enode*)> _on_make =
[&](euf::enode* n) {
m_mam->add_node(n, false);
relevant_eh(n);
};
ctx.get_egraph().set_on_merge(_on_merge);
ctx.get_egraph().set_on_make(_on_make);
if (ctx.relevancy().enabled())
ctx.get_egraph().set_on_make(_on_make);
else
ctx.relevancy().add_relevant(&s);
m_mam = mam::mk(ctx, *this);
}
void ematch::relevant_eh(euf::enode* n) {
m_mam->add_node(n, false);
}
void ematch::ensure_ground_enodes(expr* e) {
mam::ground_subterms(e, m_ground);
for (expr* g : m_ground)

View file

@ -135,9 +135,10 @@ namespace q {
bool unit_propagate();
void add(quantifier* q);
void relevant_eh(euf::enode* n);
void collect_statistics(statistics& st) const;
void get_antecedents(sat::literal l, sat::ext_justification_idx idx, sat::literal_vector& r, bool probing);

View file

@ -83,6 +83,7 @@ namespace q {
void init_search() override;
void finalize_model(model& mdl) override;
bool is_shared(euf::theory_var v) const override { return true; }
void relevant_eh(euf::enode* n) override { m_ematch.relevant_eh(n); }
ast_manager& get_manager() { return m; }
sat::literal_vector const& universal() const { return m_universal; }

View file

@ -111,6 +111,8 @@ namespace euf {
virtual void new_diseq_eh(euf::th_eq const& eq) {}
virtual void relevant_eh(euf::enode* n) {}
/**
\brief Parametric theories (e.g. Arrays) should implement this method.
*/

View file

@ -3,7 +3,7 @@ Copyright (c) 2020 Microsoft Corporation
Module Name:
relevancy.cpp
smt_relevant.cpp
Abstract:
@ -22,11 +22,13 @@ Author:
namespace smt {
relevancy::relevancy(euf::solver& ctx): ctx(ctx) {
m_enabled = ctx.relevancy_enabled();
m_enabled = ctx.get_config().m_relevancy_lvl > 2;
}
void relevancy::relevant_eh(euf::enode* n) {
// nothing
SASSERT(is_relevant(n));
for (auto* th : m_relevant_eh)
th->relevant_eh(n);
}
void relevancy::relevant_eh(sat::literal lit) {
@ -102,8 +104,10 @@ namespace smt {
m_clauses.push_back(cl);
m_roots.push_back(true);
m_trail.push_back(std::make_pair(update::add_clause, 0));
for (sat::literal lit : *cl)
for (sat::literal lit : *cl) {
ctx.s().set_external(lit.var());
occurs(lit).push_back(sz);
}
}
void relevancy::add_def(unsigned n, sat::literal const* lits) {
@ -121,15 +125,17 @@ namespace smt {
m_clauses.push_back(cl);
m_roots.push_back(false);
m_trail.push_back(std::make_pair(update::add_clause, 0));
for (sat::literal lit : *cl)
occurs(lit).push_back(sz);
for (sat::literal lit : *cl) {
ctx.s().set_external(lit.var());
occurs(lit).push_back(sz);
}
}
void relevancy::asserted(sat::literal lit) {
if (!m_enabled)
return;
flush();
if (ctx.s().lvl(lit) == 0) {
if (ctx.s().lvl(lit) <= ctx.s().search_lvl()) {
mark_relevant(lit);
return;
}
@ -164,11 +170,11 @@ namespace smt {
}
}
void relevancy::merge(euf::enode* n1, euf::enode* n2) {
if (is_relevant(n1))
mark_relevant(n2);
else if (is_relevant(n2))
mark_relevant(n1);
void relevancy::merge(euf::enode* root, euf::enode* other) {
if (is_relevant(root))
mark_relevant(other);
else if (is_relevant(other))
mark_relevant(root);
}
void relevancy::mark_relevant(euf::enode* n) {
@ -177,6 +183,8 @@ namespace smt {
flush();
if (is_relevant(n))
return;
if (ctx.get_si().is_bool_op(n->get_expr()))
return;
for (euf::enode* sib : euf::enode_class(n))
set_relevant(sib);
}
@ -195,12 +203,12 @@ namespace smt {
flush();
if (is_relevant(lit))
return;
euf::enode* n = ctx.bool_var2enode(lit.var());
if (n)
mark_relevant(n);
m_relevant_var_ids.setx(lit.var(), true, false);
m_trail.push_back(std::make_pair(update::relevant_var, lit.var()));
m_queue.push_back(std::make_pair(lit, nullptr));
euf::enode* n = nullptr;
if (n)
mark_relevant(n);
}
void relevancy::propagate_relevant(sat::literal lit) {
@ -208,9 +216,9 @@ namespace smt {
for (auto idx : occurs(~lit)) {
if (m_roots[idx])
continue;
sat::clause& cl = *m_clauses[idx];
sat::clause* cl = m_clauses[idx];
sat::literal true_lit = sat::null_literal;
for (sat::literal lit2 : cl) {
for (sat::literal lit2 : *cl) {
if (ctx.s().value(lit2) == l_true) {
if (is_relevant(lit2))
goto next;
@ -231,7 +239,6 @@ namespace smt {
void relevancy::propagate_relevant(euf::enode* n) {
relevant_eh(n);
// if is_bool_op n, return;
for (euf::enode* arg : euf::enode_args(n))
mark_relevant(arg);
}

View file

@ -3,7 +3,7 @@ Copyright (c) 2020 Microsoft Corporation
Module Name:
relevancy.h
smt_relevant.h
Abstract:
@ -26,7 +26,7 @@ The state transitions are:
->
lit is set relevant
lit is justified at level 0
lit is justified at search level
->
lit is set relevant
@ -39,7 +39,7 @@ The state transitions are:
->
all clauses C in Defs where lit appears negatively are added to Roots
- When a clause R is added to Roots:
- When a clause R is added to Roots:
R contains a positive literal lit that is relevant
->
skip adding R to Roots
@ -72,7 +72,7 @@ Can a literal that is not in a root be set relevant?
- yes, if we propagate over expressions
Do we need full watch lists instead of 2-watch lists?
- probably, but unclear. The dual SAT solver only uses 2-watch lists, but has uses a large clause for tracking
- probably, but unclear. The dual SAT solver only uses 2-watch lists, but uses a large clause for tracking
roots.
@ -105,6 +105,7 @@ namespace smt {
vector<unsigned_vector> m_occurs; // where do literals occur
unsigned m_qhead = 0; // queue head for relevancy
svector<std::pair<sat::literal, euf::enode*>> m_queue; // propagation queue for relevancy
ptr_vector<euf::th_solver> m_relevant_eh;
// callbacks during propagation
void relevant_eh(euf::enode* n);
@ -131,6 +132,7 @@ namespace smt {
void add_def(unsigned n, sat::literal const* lits);
void asserted(sat::literal lit);
void propagate();
bool can_propagate() const { return m_qhead < m_queue.size(); }
void mark_relevant(euf::enode* n);
void mark_relevant(sat::literal lit);
@ -139,6 +141,9 @@ namespace smt {
bool is_relevant(sat::literal lit) const { return !m_enabled || m_relevant_var_ids.get(lit.var(), false); }
bool is_relevant(euf::enode* n) const { return !m_enabled || m_relevant_expr_ids.get(n->get_expr_id(), false); }
bool is_relevant(expr* e) const { return !m_enabled || m_relevant_expr_ids.get(e->get_id(), false); }
bool enabled() const { return m_enabled; }
void add_relevant(euf::th_solver* th) { m_relevant_eh.push_back(th); }
};
}