3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-05-10 01:05:47 +00:00

set up model reconstruction trail

This commit is contained in:
Nikolaj Bjorner 2022-11-04 11:25:05 -07:00
parent 84af521514
commit 28668c6efc
8 changed files with 130 additions and 44 deletions

View file

@ -68,6 +68,10 @@ public:
m_fml = nullptr;
m_dep = nullptr;
}
ast_manager& get_manager() const { return m; }
expr* fml() const { return m_fml; }
std::tuple<expr*, expr_dependency*> operator()() const {
return { m_fml, m_dep };

View file

@ -21,24 +21,86 @@ void model_reconstruction_trail::replay(dependent_expr const& d, vector<dependen
// accumulate a set of dependent exprs, updating m_trail to exclude loose
// substitutions that use variables from the dependent expressions.
ast_mark free_vars;
auto [f, dep] = d();
for (expr* t : subterms::all(expr_ref(f, m)))
free_vars.mark(t, true);
NOT_IMPLEMENTED_YET();
add_vars(d, free_vars);
added.push_back(d);
for (auto& t : m_trail) {
if (!t->m_active)
continue;
// updates that have no intersections with current variables are skipped
if (!t->intersects(free_vars))
continue;
// loose entries that intersect with free vars are deleted from the trail
// and their removed formulas are added to the resulting constraints.
if (t->is_loose()) {
added.append(t->m_removed);
for (auto r : t->m_removed)
add_vars(r, free_vars);
m_trail_stack.push(value_trail(t->m_active));
t->m_active = false;
continue;
}
// rigid entries:
// apply substitution to added in case of rigid model convertions
for (auto& d : added) {
auto [f, dep1] = d();
expr_ref g(m);
expr_dependency_ref dep2(m);
(*t->m_replace)(f, g, dep2);
d = dependent_expr(m, g, m.mk_join(dep1, dep2));
}
}
}
/**
* retrieve the current model converter corresponding to chaining substitutions from the trail.
*/
model_converter_ref model_reconstruction_trail::get_model_converter() {
model_converter_ref mc = alloc(generic_model_converter, m, "dependent-expr-model");
//
// walk the trail from the back
// add substitutions from the back to the generic model converter
// after they have been normalized using a global replace that replaces
// substituted variables by their terms.
NOT_IMPLEMENTED_YET();
return mc;
//
scoped_ptr<expr_replacer> rp = mk_default_expr_replacer(m, true);
scoped_ptr<expr_substitution> subst = alloc(expr_substitution, m, true, false);
rp->set_substitution(subst.get());
generic_model_converter_ref mc = alloc(generic_model_converter, m, "dependent-expr-model");
bool first = true;
for (unsigned i = m_trail.size(); i-- > 0; ) {
auto* t = m_trail[i];
if (!t->m_active)
continue;
if (first) {
first = false;
for (auto const& [v, def] : t->m_subst->sub()) {
expr_dependency* dep = t->m_subst->dep(v);
subst->insert(v, def, dep);
mc->add(v, def);
}
continue;
}
expr_dependency_ref new_dep(m);
expr_ref new_def(m);
for (auto const& [v, def] : t->m_subst->sub()) {
rp->operator()(def, new_def, new_dep);
expr_dependency* dep = t->m_subst->dep(v);
new_dep = m.mk_join(dep, new_dep);
subst->insert(v, new_def, new_dep);
mc->add(v, new_def);
}
}
return model_converter_ref(mc.get());
}

View file

@ -24,33 +24,62 @@ Author:
#pragma once
#include "util/scoped_ptr_vector.h"
#include "util/trail.h"
#include "ast/for_each_expr.h"
#include "ast/rewriter/expr_replacer.h"
#include "ast/simplifiers/dependent_expr.h"
#include "ast/converters/model_converter.h"
class model_reconstruction_trail {
ast_manager& m;
struct entry {
scoped_ptr<expr_replacer> m_replace;
scoped_ptr<expr_substitution> m_subst;
vector<dependent_expr> m_removed;
bool m_active = true;
entry(expr_replacer* r, expr_substitution* s, vector<dependent_expr> const& rem) :
m_replace(r), m_subst(s), m_removed(rem) {}
bool is_loose() const { return !m_removed.empty(); }
bool intersects(ast_mark const& free_vars) const {
return std::any_of(m_subst->sub().begin(), m_subst->sub().end(), [&](auto const& kv) { return free_vars.is_marked(kv.m_key); });
}
struct model_reconstruction_trail_entry {
scoped_ptr<expr_replacer> m_replace;
vector<dependent_expr> m_removed;
model_reconstruction_trail_entry(expr_replacer* r, vector<dependent_expr> const& rem) :
m_replace(r), m_removed(rem) {}
};
scoped_ptr_vector<model_reconstruction_trail_entry> m_trail;
unsigned_vector m_limit;
ast_manager& m;
trail_stack& m_trail_stack;
scoped_ptr_vector<entry> m_trail;
void add_vars(dependent_expr const& d, ast_mark& free_vars) {
for (expr* t : subterms::all(expr_ref(d.fml(), d.get_manager())))
free_vars.mark(t, true);
}
bool intersects(ast_mark const& free_vars, dependent_expr const& d) {
expr_ref term(d.fml(), d.get_manager());
auto iter = subterms::all(term);
return std::any_of(iter.begin(), iter.end(), [&](expr* t) { return free_vars.is_marked(t); });
}
bool intersects(ast_mark const& free_vars, vector<dependent_expr> const& added) {
return std::any_of(added.begin(), added.end(), [&](dependent_expr const& d) { return intersects(free_vars, d); });
}
public:
model_reconstruction_trail(ast_manager& m) : m(m) {}
model_reconstruction_trail(ast_manager& m, trail_stack& tr):
m(m), m_trail_stack(tr) {}
/**
* add a new substitution to the stack
*/
void push(expr_replacer* r, vector<dependent_expr> const& removed) {
m_trail.push_back(alloc(model_reconstruction_trail_entry, r, removed));
m_trail.push_back(alloc(entry, r, nullptr, removed));
m_trail_stack.push(push_back_vector(m_trail));
}
/**
@ -63,18 +92,5 @@ public:
* retrieve the current model converter corresponding to chaining substitutions from the trail.
*/
model_converter_ref get_model_converter();
/**
* push a context. Portions of the trail added within a context are removed after a context pop.
*/
void push() {
m_limit.push_back(m_trail.size());
}
void pop(unsigned n) {
unsigned old_sz = m_limit[m_limit.size() - n];
m_trail.resize(old_sz);
m_limit.shrink(m_limit.size() - n);
}
};

View file

@ -60,7 +60,7 @@ namespace euf {
m_id2level.reset();
m_id2level.resize(m_id2var.size(), UINT_MAX);
m_subst_ids.reset();
m_subst = alloc(expr_substitution, m, false, false);
m_subst = alloc(expr_substitution, m, true, false);
auto is_explored = [&](unsigned id) {
return m_id2level[id] != UINT_MAX;
@ -120,16 +120,15 @@ namespace euf {
expr_dependency_ref new_dep(m);
expr_ref new_def(m);
proof_ref new_pr(m);
for (unsigned id : m_subst_ids) {
if (!m.inc())
break;
auto const& [v, def, dep] = m_next[id][0];
rp->operator()(def, new_def, new_pr, new_dep);
rp->operator()(def, new_def, new_dep);
m_stats.m_num_steps += rp->get_num_steps() + 1;
new_dep = m.mk_join(dep, new_dep);
m_subst->insert(v, new_def, new_pr, new_dep);
m_subst->insert(v, new_def, nullptr, new_dep);
// we updated the substitution, but we don't need to reset rp
// because all cached values there do not depend on v.
}
@ -149,11 +148,10 @@ namespace euf {
scoped_ptr<expr_replacer> rp = mk_default_expr_replacer(m, true);
rp->set_substitution(m_subst.get());
expr_ref new_f(m);
proof_ref new_pr(m);
expr_dependency_ref new_dep(m);
for (unsigned i = m_qhead; i < m_fmls.size() && !m_fmls.inconsistent(); ++i) {
auto [f, d] = m_fmls[i]();
rp->operator()(f, new_f, new_pr, new_dep);
rp->operator()(f, new_f, new_dep);
if (new_f == f)
continue;
new_dep = m.mk_join(d, new_dep);