mirror of
https://github.com/Z3Prover/z3
synced 2025-04-23 09:05:31 +00:00
Propagator (#5845)
* user propagator without ids Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * user propagator without ids Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * fix signature Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * references #5818 Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * fix c++ build Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * switch to vs 2022 Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * switch 2022 Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * Update propagator example (I) (#5835) * fix #5829 * na Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * switch to vs 2022 Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * Adapted the example to the changes in the propagator Co-authored-by: Nikolaj Bjorner <nbjorner@microsoft.com> * context goes out of scope in stack allocation, so can't used scoped context when passing objects around * parameter check Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * add rewriter Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * Fixed bug in user-propagator "created" (#5843) Co-authored-by: Clemens Eisenhofer <56730610+CEisenhofer@users.noreply.github.com>
This commit is contained in:
parent
2e15e2aa4d
commit
2e00f2f32d
22 changed files with 261 additions and 328 deletions
|
@ -1726,10 +1726,10 @@ namespace smt {
|
|||
m_user_propagator->register_diseq(diseq_eh);
|
||||
}
|
||||
|
||||
unsigned user_propagate_register_expr(expr* e) {
|
||||
void user_propagate_register_expr(expr* e) {
|
||||
if (!m_user_propagator)
|
||||
throw default_exception("user propagator must be initialized");
|
||||
return m_user_propagator->add_expr(e);
|
||||
m_user_propagator->add_expr(e);
|
||||
}
|
||||
|
||||
void user_propagate_register_created(user_propagator::created_eh_t& r) {
|
||||
|
|
|
@ -276,8 +276,8 @@ namespace smt {
|
|||
m_imp->m_kernel.user_propagate_register_diseq(diseq_eh);
|
||||
}
|
||||
|
||||
unsigned kernel::user_propagate_register_expr(expr* e) {
|
||||
return m_imp->m_kernel.user_propagate_register_expr(e);
|
||||
void kernel::user_propagate_register_expr(expr* e) {
|
||||
m_imp->m_kernel.user_propagate_register_expr(e);
|
||||
}
|
||||
|
||||
void kernel::user_propagate_register_created(user_propagator::created_eh_t& r) {
|
||||
|
|
|
@ -307,7 +307,7 @@ namespace smt {
|
|||
|
||||
void user_propagate_register_diseq(user_propagator::eq_eh_t& diseq_eh);
|
||||
|
||||
unsigned user_propagate_register_expr(expr* e);
|
||||
void user_propagate_register_expr(expr* e);
|
||||
|
||||
void user_propagate_register_created(user_propagator::created_eh_t& r);
|
||||
|
||||
|
|
|
@ -236,8 +236,8 @@ namespace {
|
|||
m_context.user_propagate_register_diseq(diseq_eh);
|
||||
}
|
||||
|
||||
unsigned user_propagate_register_expr(expr* e) override {
|
||||
return m_context.user_propagate_register_expr(e);
|
||||
void user_propagate_register_expr(expr* e) override {
|
||||
m_context.user_propagate_register_expr(e);
|
||||
}
|
||||
|
||||
void user_propagate_register_created(user_propagator::created_eh_t& c) override {
|
||||
|
|
|
@ -40,6 +40,7 @@ class smt_tactic : public tactic {
|
|||
ast_manager& m;
|
||||
smt_params m_params;
|
||||
params_ref m_params_ref;
|
||||
expr_ref_vector m_vars;
|
||||
statistics m_stats;
|
||||
smt::kernel* m_ctx = nullptr;
|
||||
symbol m_logic;
|
||||
|
@ -321,141 +322,20 @@ public:
|
|||
user_propagator::eq_eh_t m_eq_eh;
|
||||
user_propagator::eq_eh_t m_diseq_eh;
|
||||
user_propagator::created_eh_t m_created_eh;
|
||||
|
||||
expr_ref_vector m_vars;
|
||||
unsigned_vector m_var2internal;
|
||||
unsigned_vector m_internal2var;
|
||||
unsigned_vector m_limit;
|
||||
|
||||
|
||||
user_propagator::push_eh_t i_push_eh;
|
||||
user_propagator::pop_eh_t i_pop_eh;
|
||||
user_propagator::fixed_eh_t i_fixed_eh;
|
||||
user_propagator::final_eh_t i_final_eh;
|
||||
user_propagator::eq_eh_t i_eq_eh;
|
||||
user_propagator::eq_eh_t i_diseq_eh;
|
||||
user_propagator::created_eh_t i_created_eh;
|
||||
|
||||
|
||||
struct callback : public user_propagator::callback {
|
||||
smt_tactic* t = nullptr;
|
||||
user_propagator::callback* cb = nullptr;
|
||||
unsigned_vector fixed, lhs, rhs;
|
||||
void propagate_cb(unsigned num_fixed, unsigned const* fixed_ids, unsigned num_eqs, unsigned const* eq_lhs, unsigned const* eq_rhs, expr* conseq) override {
|
||||
fixed.reset();
|
||||
lhs.reset();
|
||||
rhs.reset();
|
||||
for (unsigned i = 0; i < num_fixed; ++i)
|
||||
fixed.push_back(t->m_var2internal[fixed_ids[i]]);
|
||||
for (unsigned i = 0; i < num_eqs; ++i) {
|
||||
lhs.push_back(t->m_var2internal[eq_lhs[i]]);
|
||||
rhs.push_back(t->m_var2internal[eq_rhs[i]]);
|
||||
}
|
||||
cb->propagate_cb(num_fixed, fixed.data(), num_eqs, lhs.data(), rhs.data(), conseq);
|
||||
}
|
||||
|
||||
unsigned register_cb(expr* e) override {
|
||||
unsigned j = t->m_vars.size();
|
||||
t->m_vars.push_back(e);
|
||||
unsigned i = cb->register_cb(e);
|
||||
t->m_var2internal.setx(j, i, 0);
|
||||
t->m_internal2var.setx(i, j, 0);
|
||||
return j;
|
||||
}
|
||||
};
|
||||
|
||||
callback i_cb;
|
||||
|
||||
void init_i_fixed_eh() {
|
||||
if (!m_fixed_eh)
|
||||
return;
|
||||
i_fixed_eh = [this](void* ctx, user_propagator::callback* cb, unsigned id, expr* value) {
|
||||
i_cb.t = this;
|
||||
i_cb.cb = cb;
|
||||
m_fixed_eh(ctx, &i_cb, m_internal2var[id], value);
|
||||
};
|
||||
m_ctx->user_propagate_register_fixed(i_fixed_eh);
|
||||
}
|
||||
|
||||
void init_i_final_eh() {
|
||||
if (!m_final_eh)
|
||||
return;
|
||||
i_final_eh = [this](void* ctx, user_propagator::callback* cb) {
|
||||
i_cb.t = this;
|
||||
i_cb.cb = cb;
|
||||
m_final_eh(ctx, &i_cb);
|
||||
};
|
||||
m_ctx->user_propagate_register_final(i_final_eh);
|
||||
}
|
||||
|
||||
void init_i_eq_eh() {
|
||||
if (!m_eq_eh)
|
||||
return;
|
||||
i_eq_eh = [this](void* ctx, user_propagator::callback* cb, unsigned u, unsigned v) {
|
||||
i_cb.t = this;
|
||||
i_cb.cb = cb;
|
||||
m_eq_eh(ctx, &i_cb, m_internal2var[u], m_internal2var[v]);
|
||||
};
|
||||
m_ctx->user_propagate_register_eq(i_eq_eh);
|
||||
}
|
||||
|
||||
void init_i_diseq_eh() {
|
||||
if (!m_diseq_eh)
|
||||
return;
|
||||
i_diseq_eh = [this](void* ctx, user_propagator::callback* cb, unsigned u, unsigned v) {
|
||||
i_cb.t = this;
|
||||
i_cb.cb = cb;
|
||||
m_diseq_eh(ctx, &i_cb, m_internal2var[u], m_internal2var[v]);
|
||||
};
|
||||
m_ctx->user_propagate_register_diseq(i_diseq_eh);
|
||||
}
|
||||
|
||||
void init_i_created_eh() {
|
||||
if (!m_created_eh)
|
||||
return;
|
||||
i_created_eh = [this](void* ctx, user_propagator::callback* cb, expr* e, unsigned i) {
|
||||
unsigned j = m_vars.size();
|
||||
m_vars.push_back(e);
|
||||
m_internal2var.setx(i, j, 0);
|
||||
m_var2internal.setx(j, i, 0);
|
||||
m_created_eh(ctx, cb, e, j);
|
||||
};
|
||||
m_ctx->user_propagate_register_created(i_created_eh);
|
||||
}
|
||||
|
||||
void init_i_push_pop() {
|
||||
i_push_eh = [this](void* ctx) {
|
||||
m_limit.push_back(m_vars.size());
|
||||
m_push_eh(ctx);
|
||||
};
|
||||
i_pop_eh = [this](void* ctx, unsigned n) {
|
||||
unsigned old_sz = m_limit.size() - n;
|
||||
unsigned num_vars = m_limit[old_sz];
|
||||
m_vars.shrink(num_vars);
|
||||
m_limit.shrink(old_sz);
|
||||
m_pop_eh(ctx, n);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
void user_propagate_delay_init() {
|
||||
if (!m_user_ctx)
|
||||
return;
|
||||
init_i_push_pop();
|
||||
m_ctx->user_propagate_init(m_user_ctx, i_push_eh, i_pop_eh, m_fresh_eh);
|
||||
init_i_fixed_eh();
|
||||
init_i_final_eh();
|
||||
init_i_eq_eh();
|
||||
init_i_diseq_eh();
|
||||
init_i_created_eh();
|
||||
m_ctx->user_propagate_init(m_user_ctx, m_push_eh, m_pop_eh, m_fresh_eh);
|
||||
if (m_fixed_eh) m_ctx->user_propagate_register_fixed(m_fixed_eh);
|
||||
if (m_final_eh) m_ctx->user_propagate_register_final(m_final_eh);
|
||||
if (m_eq_eh) m_ctx->user_propagate_register_eq(m_eq_eh);
|
||||
if (m_diseq_eh) m_ctx->user_propagate_register_diseq(m_diseq_eh);
|
||||
if (m_created_eh) m_ctx->user_propagate_register_created(m_created_eh);
|
||||
|
||||
unsigned i = 0;
|
||||
for (expr* v : m_vars) {
|
||||
unsigned j = m_ctx->user_propagate_register_expr(v);
|
||||
m_var2internal.setx(i, j, 0);
|
||||
m_internal2var.setx(j, i, 0);
|
||||
++i;
|
||||
}
|
||||
for (expr* v : m_vars)
|
||||
m_ctx->user_propagate_register_expr(v);
|
||||
}
|
||||
|
||||
void user_propagate_clear() override {
|
||||
|
@ -496,9 +376,8 @@ public:
|
|||
m_diseq_eh = diseq_eh;
|
||||
}
|
||||
|
||||
unsigned user_propagate_register_expr(expr* e) override {
|
||||
void user_propagate_register_expr(expr* e) override {
|
||||
m_vars.push_back(e);
|
||||
return m_vars.size() - 1;
|
||||
}
|
||||
|
||||
void user_propagate_register_created(user_propagator::created_eh_t& created_eh) override {
|
||||
|
|
|
@ -23,7 +23,8 @@ Author:
|
|||
using namespace smt;
|
||||
|
||||
theory_user_propagator::theory_user_propagator(context& ctx):
|
||||
theory(ctx, ctx.get_manager().mk_family_id(user_propagator::plugin::name()))
|
||||
theory(ctx, ctx.get_manager().mk_family_id(user_propagator::plugin::name())),
|
||||
m_var2expr(ctx.get_manager())
|
||||
{}
|
||||
|
||||
theory_user_propagator::~theory_user_propagator() {
|
||||
|
@ -38,9 +39,10 @@ void theory_user_propagator::force_push() {
|
|||
}
|
||||
}
|
||||
|
||||
unsigned theory_user_propagator::add_expr(expr* e) {
|
||||
void theory_user_propagator::add_expr(expr* term) {
|
||||
force_push();
|
||||
expr_ref r(m);
|
||||
expr* e = term;
|
||||
ctx.get_rewriter()(e, r);
|
||||
if (r != e) {
|
||||
r = m.mk_fresh_const("aux-expr", e->get_sort());
|
||||
|
@ -52,8 +54,14 @@ unsigned theory_user_propagator::add_expr(expr* e) {
|
|||
}
|
||||
enode* n = ensure_enode(e);
|
||||
if (is_attached_to_var(n))
|
||||
return n->get_th_var(get_id());
|
||||
return;
|
||||
|
||||
|
||||
theory_var v = mk_var(n);
|
||||
m_var2expr.reserve(v + 1);
|
||||
m_var2expr[v] = term;
|
||||
m_expr2var.setx(term->get_id(), v, null_theory_var);
|
||||
|
||||
if (m.is_bool(e) && !ctx.b_internalized(e)) {
|
||||
bool_var bv = ctx.mk_bool_var(e);
|
||||
ctx.set_var_theory(bv, get_id());
|
||||
|
@ -65,22 +73,24 @@ unsigned theory_user_propagator::add_expr(expr* e) {
|
|||
literal_vector explain;
|
||||
if (ctx.is_fixed(n, r, explain))
|
||||
m_prop.push_back(prop_info(explain, v, r));
|
||||
return v;
|
||||
|
||||
}
|
||||
|
||||
void theory_user_propagator::propagate_cb(
|
||||
unsigned num_fixed, unsigned const* fixed_ids,
|
||||
unsigned num_eqs, unsigned const* eq_lhs, unsigned const* eq_rhs,
|
||||
unsigned num_fixed, expr* const* fixed_ids,
|
||||
unsigned num_eqs, expr* const* eq_lhs, expr* const* eq_rhs,
|
||||
expr* conseq) {
|
||||
CTRACE("user_propagate", ctx.lit_internalized(conseq) && ctx.get_assignment(ctx.get_literal(conseq)) == l_true,
|
||||
ctx.display(tout << "redundant consequence: " << mk_pp(conseq, m) << "\n"));
|
||||
if (ctx.lit_internalized(conseq) && ctx.get_assignment(ctx.get_literal(conseq)) == l_true)
|
||||
expr_ref _conseq(conseq, m);
|
||||
ctx.get_rewriter()(conseq, _conseq);
|
||||
if (ctx.lit_internalized(_conseq) && ctx.get_assignment(ctx.get_literal(_conseq)) == l_true)
|
||||
return;
|
||||
m_prop.push_back(prop_info(num_fixed, fixed_ids, num_eqs, eq_lhs, eq_rhs, expr_ref(conseq, m)));
|
||||
m_prop.push_back(prop_info(num_fixed, fixed_ids, num_eqs, eq_lhs, eq_rhs, _conseq));
|
||||
}
|
||||
|
||||
unsigned theory_user_propagator::register_cb(expr* e) {
|
||||
return add_expr(e);
|
||||
void theory_user_propagator::register_cb(expr* e) {
|
||||
add_expr(e);
|
||||
}
|
||||
|
||||
theory * theory_user_propagator::mk_fresh(context * new_ctx) {
|
||||
|
@ -91,6 +101,7 @@ theory * theory_user_propagator::mk_fresh(context * new_ctx) {
|
|||
if ((bool)m_final_eh) th->register_final(m_final_eh);
|
||||
if ((bool)m_eq_eh) th->register_eq(m_eq_eh);
|
||||
if ((bool)m_diseq_eh) th->register_diseq(m_diseq_eh);
|
||||
if ((bool)m_created_eh) th->register_created(m_created_eh);
|
||||
return th;
|
||||
}
|
||||
|
||||
|
@ -114,7 +125,7 @@ void theory_user_propagator::new_fixed_eh(theory_var v, expr* value, unsigned nu
|
|||
m_fixed.insert(v);
|
||||
ctx.push_trail(insert_map<uint_set, unsigned>(m_fixed, v));
|
||||
m_id2justification.setx(v, literal_vector(num_lits, jlits), literal_vector());
|
||||
m_fixed_eh(m_user_context, this, v, value);
|
||||
m_fixed_eh(m_user_context, this, var2expr(v), value);
|
||||
}
|
||||
|
||||
void theory_user_propagator::push_scope_eh() {
|
||||
|
@ -142,12 +153,12 @@ void theory_user_propagator::propagate_consequence(prop_info const& prop) {
|
|||
justification* js;
|
||||
m_lits.reset();
|
||||
m_eqs.reset();
|
||||
for (unsigned id : prop.m_ids)
|
||||
m_lits.append(m_id2justification[id]);
|
||||
for (expr* id : prop.m_ids)
|
||||
m_lits.append(m_id2justification[expr2var(id)]);
|
||||
for (auto const& p : prop.m_eqs)
|
||||
m_eqs.push_back(enode_pair(get_enode(p.first), get_enode(p.second)));
|
||||
m_eqs.push_back(enode_pair(get_enode(expr2var(p.first)), get_enode(expr2var(p.second))));
|
||||
DEBUG_CODE(for (auto const& p : m_eqs) VERIFY(p.first->get_root() == p.second->get_root()););
|
||||
DEBUG_CODE(for (unsigned id : prop.m_ids) VERIFY(m_fixed.contains(id)););
|
||||
DEBUG_CODE(for (expr* e : prop.m_ids) VERIFY(m_fixed.contains(expr2var(e))););
|
||||
DEBUG_CODE(for (literal lit : m_lits) VERIFY(ctx.get_assignment(lit) == l_true););
|
||||
|
||||
TRACE("user_propagate", tout << "propagating #" << prop.m_conseq->get_id() << ": " << prop.m_conseq << "\n");
|
||||
|
@ -216,12 +227,12 @@ bool theory_user_propagator::internalize_term(app* term) {
|
|||
if (term->get_family_id() == get_id() && !ctx.e_internalized(term))
|
||||
ctx.mk_enode(term, true, false, true);
|
||||
|
||||
unsigned v = add_expr(term);
|
||||
add_expr(term);
|
||||
|
||||
if (!m_created_eh && (m_fixed_eh || m_eq_eh || m_diseq_eh))
|
||||
throw default_exception("You have to register a created event handler for new terms if you track them");
|
||||
if (!m_created_eh && (m_fixed_eh || m_eq_eh || m_diseq_eh))
|
||||
return true;
|
||||
if (m_created_eh)
|
||||
m_created_eh(m_user_context, this, term, v);
|
||||
m_created_eh(m_user_context, this, term);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -30,13 +30,13 @@ namespace smt {
|
|||
class theory_user_propagator : public theory, public user_propagator::callback {
|
||||
|
||||
struct prop_info {
|
||||
unsigned_vector m_ids;
|
||||
ptr_vector<expr> m_ids;
|
||||
expr_ref m_conseq;
|
||||
svector<std::pair<unsigned, unsigned>> m_eqs;
|
||||
svector<std::pair<expr*, expr*>> m_eqs;
|
||||
literal_vector m_lits;
|
||||
theory_var m_var = null_theory_var;
|
||||
prop_info(unsigned num_fixed, unsigned const* fixed_ids,
|
||||
unsigned num_eqs, unsigned const* eq_lhs, unsigned const* eq_rhs, expr_ref const& c):
|
||||
theory_var m_var = null_theory_var;
|
||||
prop_info(unsigned num_fixed, expr* const* fixed_ids,
|
||||
unsigned num_eqs, expr* const* eq_lhs, expr* const* eq_rhs, expr_ref const& c):
|
||||
m_ids(num_fixed, fixed_ids),
|
||||
m_conseq(c) {
|
||||
for (unsigned i = 0; i < num_eqs; ++i)
|
||||
|
@ -64,7 +64,7 @@ namespace smt {
|
|||
user_propagator::fixed_eh_t m_fixed_eh;
|
||||
user_propagator::eq_eh_t m_eq_eh;
|
||||
user_propagator::eq_eh_t m_diseq_eh;
|
||||
user_propagator::created_eh_t m_created_eh;
|
||||
user_propagator::created_eh_t m_created_eh;
|
||||
|
||||
user_propagator::context_obj* m_api_context = nullptr;
|
||||
unsigned m_qhead = 0;
|
||||
|
@ -76,6 +76,15 @@ namespace smt {
|
|||
literal_vector m_lits;
|
||||
enode_pair_vector m_eqs;
|
||||
stats m_stats;
|
||||
expr_ref_vector m_var2expr;
|
||||
unsigned_vector m_expr2var;
|
||||
|
||||
expr* var2expr(theory_var v) { return m_var2expr.get(v); }
|
||||
theory_var expr2var(expr* e) { check_defined(e); return m_expr2var[e->get_id()]; }
|
||||
void check_defined(expr* e) {
|
||||
if (e->get_id() >= m_expr2var.size() || get_num_vars() <= m_expr2var[e->get_id()])
|
||||
throw default_exception("expression is not registered");
|
||||
}
|
||||
|
||||
void force_push();
|
||||
|
||||
|
@ -101,7 +110,7 @@ namespace smt {
|
|||
m_fresh_eh = fresh_eh;
|
||||
}
|
||||
|
||||
unsigned add_expr(expr* e);
|
||||
void add_expr(expr* e);
|
||||
|
||||
void register_final(user_propagator::final_eh_t& final_eh) { m_final_eh = final_eh; }
|
||||
void register_fixed(user_propagator::fixed_eh_t& fixed_eh) { m_fixed_eh = fixed_eh; }
|
||||
|
@ -110,17 +119,17 @@ namespace smt {
|
|||
void register_created(user_propagator::created_eh_t& created_eh) { m_created_eh = created_eh; }
|
||||
|
||||
bool has_fixed() const { return (bool)m_fixed_eh; }
|
||||
|
||||
void propagate_cb(unsigned num_fixed, unsigned const* fixed_ids, unsigned num_eqs, unsigned const* lhs, unsigned const* rhs, expr* conseq) override;
|
||||
unsigned register_cb(expr* e) override;
|
||||
|
||||
void propagate_cb(unsigned num_fixed, expr* const* fixed_ids, unsigned num_eqs, expr* const* lhs, expr* const* rhs, expr* conseq) override;
|
||||
void register_cb(expr* e) override;
|
||||
|
||||
void new_fixed_eh(theory_var v, expr* value, unsigned num_lits, literal const* jlits);
|
||||
|
||||
theory * mk_fresh(context * new_ctx) override;
|
||||
bool internalize_atom(app* atom, bool gate_ctx) override;
|
||||
bool internalize_term(app* term) override;
|
||||
void new_eq_eh(theory_var v1, theory_var v2) override { if (m_eq_eh) m_eq_eh(m_user_context, this, v1, v2); }
|
||||
void new_diseq_eh(theory_var v1, theory_var v2) override { if (m_diseq_eh) m_diseq_eh(m_user_context, this, v1, v2); }
|
||||
void new_eq_eh(theory_var v1, theory_var v2) override { if (m_eq_eh) m_eq_eh(m_user_context, this, var2expr(v1), var2expr(v2)); }
|
||||
void new_diseq_eh(theory_var v1, theory_var v2) override { if (m_diseq_eh) m_diseq_eh(m_user_context, this, var2expr(v1), var2expr(v2)); }
|
||||
bool use_diseqs() const override { return ((bool)m_diseq_eh); }
|
||||
bool build_models() const override { return false; }
|
||||
final_check_status final_check_eh() override;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue