3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-06-03 12:51:22 +00:00

hoist simplifier functionality out of context loop to allow plugging in other contextual simplification methods

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
Nikolaj Bjorner 2016-02-12 18:58:37 +00:00
parent e2dc7c6f64
commit 45999b254c
2 changed files with 157 additions and 90 deletions

View file

@ -18,11 +18,95 @@ Notes:
--*/ --*/
#include"ctx_simplify_tactic.h" #include"ctx_simplify_tactic.h"
#include"mk_simplified_app.h" #include"mk_simplified_app.h"
#include"goal_num_occurs.h"
#include"cooperate.h" #include"cooperate.h"
#include"ast_ll_pp.h" #include"ast_ll_pp.h"
#include"ast_pp.h" #include"ast_pp.h"
ctx_propagate_assertions::ctx_propagate_assertions(ast_manager& m): m(m), m_trail(m) {}
void ctx_propagate_assertions::assert_expr(expr * t, bool sign) {
expr * p = t;
while (m.is_not(t, t)) {
sign = !sign;
}
bool mk_scope = true;
if (shared(t) || shared(p)) {
push();
mk_scope = false;
assert_eq_core(t, sign ? m.mk_false() : m.mk_true());
}
expr * lhs, * rhs;
if (!sign && m.is_eq(t, lhs, rhs)) {
if (m.is_value(rhs))
assert_eq_val(lhs, to_app(rhs), mk_scope);
else if (m.is_value(lhs))
assert_eq_val(rhs, to_app(lhs), mk_scope);
}
}
void ctx_propagate_assertions::assert_eq_val(expr * t, app * val, bool mk_scope) {
if (shared(t)) {
if (mk_scope)
push();
assert_eq_core(t, val);
}
}
void ctx_propagate_assertions::assert_eq_core(expr * t, app * val) {
if (m_assertions.contains(t)) {
// This branch can only happen when m_max_depth was reached.
// It can happen when m_assertions contains an entry t->val',
// but (= t val) was not simplified to (= val' val)
// because the simplifier stopped at depth m_max_depth
return;
}
CTRACE("assert_eq_bug", m_assertions.contains(t),
tout << "t:\n" << mk_ismt2_pp(t, m) << "\nval:\n" << mk_ismt2_pp(val, m) << "\n";
expr * old_val = 0;
m_assertions.find(t, old_val);
tout << "old_val:\n" << mk_ismt2_pp(old_val, m) << "\n";);
m_assertions.insert(t, val);
m_trail.push_back(t);
}
bool ctx_propagate_assertions::simplify(expr* t, expr_ref& result) {
expr* r;
return m_assertions.find(t, r) && (result = r, true);
}
void ctx_propagate_assertions::push() {
m_scopes.push_back(m_trail.size());
}
void ctx_propagate_assertions::pop(unsigned num_scopes) {
unsigned scope_lvl = m_scopes.size();
unsigned old_trail_size = m_scopes[scope_lvl - num_scopes];
unsigned i = m_trail.size();
while (i > old_trail_size) {
--i;
expr * key = m_trail.back();
m_assertions.erase(key);
m_trail.pop_back();
}
SASSERT(m_trail.size() == old_trail_size);
m_scopes.shrink(scope_lvl - num_scopes);
}
bool ctx_simplify_tactic::simplifier::shared(expr * t) const {
SASSERT(m_occs);
return t->get_ref_count() > 1 && m_occs->get_num_occs(t) > 1;
}
ctx_simplify_tactic::simplifier * ctx_propagate_assertions::translate(ast_manager & m) {
return alloc(ctx_propagate_assertions, m);
}
struct ctx_simplify_tactic::imp { struct ctx_simplify_tactic::imp {
struct cached_result { struct cached_result {
expr * m_to; expr * m_to;
@ -42,13 +126,10 @@ struct ctx_simplify_tactic::imp {
}; };
ast_manager & m; ast_manager & m;
simplifier* m_simp;
small_object_allocator m_allocator; small_object_allocator m_allocator;
obj_map<expr, expr*> m_assertions;
ptr_vector<expr> m_trail;
svector<unsigned> m_scopes;
svector<cache_cell> m_cache; svector<cache_cell> m_cache;
vector<ptr_vector<expr> > m_cache_undo; vector<ptr_vector<expr> > m_cache_undo;
unsigned m_scope_lvl;
unsigned m_depth; unsigned m_depth;
unsigned m_num_steps; unsigned m_num_steps;
goal_num_occurs m_occs; goal_num_occurs m_occs;
@ -58,19 +139,20 @@ struct ctx_simplify_tactic::imp {
unsigned m_max_steps; unsigned m_max_steps;
bool m_bail_on_blowup; bool m_bail_on_blowup;
imp(ast_manager & _m, params_ref const & p): imp(ast_manager & _m, simplifier* simp, params_ref const & p):
m(_m), m(_m),
m_simp(simp),
m_allocator("context-simplifier"), m_allocator("context-simplifier"),
m_occs(true, true), m_occs(true, true),
m_mk_app(m, p) { m_mk_app(m, p) {
m_scope_lvl = 0;
updt_params(p); updt_params(p);
m_simp->set_occs(m_occs);
} }
~imp() { ~imp() {
pop(m_scope_lvl); pop(scope_level());
SASSERT(m_scope_lvl == 0); SASSERT(scope_level() == 0);
restore_cache(0); restore_cache(0);
DEBUG_CODE({ DEBUG_CODE({
for (unsigned i = 0; i < m_cache.size(); i++) { for (unsigned i = 0; i < m_cache.size(); i++) {
@ -128,17 +210,17 @@ struct ctx_simplify_tactic::imp {
if (cell.m_from == 0) { if (cell.m_from == 0) {
// new_entry // new_entry
cell.m_from = from; cell.m_from = from;
cell.m_result = new (mem) cached_result(to, m_scope_lvl, 0); cell.m_result = new (mem) cached_result(to, scope_level(), 0);
m.inc_ref(from); m.inc_ref(from);
m.inc_ref(to); m.inc_ref(to);
} }
else { else {
// update // update
cell.m_result = new (mem) cached_result(to, m_scope_lvl, cell.m_result); cell.m_result = new (mem) cached_result(to, scope_level(), cell.m_result);
m.inc_ref(to); m.inc_ref(to);
} }
m_cache_undo.reserve(m_scope_lvl+1); m_cache_undo.reserve(scope_level()+1);
m_cache_undo[m_scope_lvl].push_back(from); m_cache_undo[scope_level()].push_back(from);
} }
void cache(expr * from, expr * to) { void cache(expr * from, expr * to) {
@ -147,12 +229,11 @@ struct ctx_simplify_tactic::imp {
} }
unsigned scope_level() const { unsigned scope_level() const {
return m_scope_lvl; return m_simp->scope_level();
} }
void push() { void push() {
m_scope_lvl++; m_simp->push();
m_scopes.push_back(m_trail.size());
} }
void restore_cache(unsigned lvl) { void restore_cache(unsigned lvl) {
@ -188,74 +269,21 @@ struct ctx_simplify_tactic::imp {
void pop(unsigned num_scopes) { void pop(unsigned num_scopes) {
if (num_scopes == 0) if (num_scopes == 0)
return; return;
SASSERT(num_scopes <= m_scope_lvl); SASSERT(num_scopes <= scope_level());
SASSERT(m_scope_lvl == m_scopes.size());
// undo assertions m_simp->pop(num_scopes);
unsigned old_trail_size = m_scopes[m_scope_lvl - num_scopes];
unsigned i = m_trail.size();
while (i > old_trail_size) {
--i;
expr * key = m_trail.back();
m_assertions.erase(key);
m_trail.pop_back();
}
SASSERT(m_trail.size() == old_trail_size);
m_scopes.shrink(m_scope_lvl - num_scopes);
// restore cache // restore cache
unsigned lvl = scope_level();
for (unsigned i = 0; i < num_scopes; i++) { for (unsigned i = 0; i < num_scopes; i++) {
restore_cache(m_scope_lvl); restore_cache(lvl);
m_scope_lvl--; lvl--;
} }
CASSERT("ctx_simplify_tactic", check_cache()); CASSERT("ctx_simplify_tactic", check_cache());
} }
void assert_eq_core(expr * t, app * val) {
if (m_assertions.contains(t)) {
// This branch can only happen when m_max_depth was reached.
// It can happen when m_assertions contains an entry t->val',
// but (= t val) was not simplified to (= val' val)
// because the simplifier stopped at depth m_max_depth
return;
}
CTRACE("assert_eq_bug", m_assertions.contains(t), tout << "m_depth: " << m_depth << " m_max_depth: " << m_max_depth << "\n"
<< "t:\n" << mk_ismt2_pp(t, m) << "\nval:\n" << mk_ismt2_pp(val, m) << "\n";
expr * old_val = 0;
m_assertions.find(t, old_val);
tout << "old_val:\n" << mk_ismt2_pp(old_val, m) << "\n";);
m_assertions.insert(t, val);
m_trail.push_back(t);
}
void assert_eq_val(expr * t, app * val, bool mk_scope) {
if (shared(t)) {
if (mk_scope)
push();
assert_eq_core(t, val);
}
}
void assert_expr(expr * t, bool sign) { void assert_expr(expr * t, bool sign) {
expr * p = t; m_simp->assert_expr(t, sign);
if (m.is_not(t)) {
t = to_app(t)->get_arg(0);
sign = !sign;
}
bool mk_scope = true;
if (shared(t) || shared(p)) {
push();
mk_scope = false;
assert_eq_core(t, sign ? m.mk_false() : m.mk_true());
}
expr * lhs, * rhs;
if (!sign && m.is_eq(t, lhs, rhs)) {
if (m.is_value(rhs))
assert_eq_val(lhs, to_app(rhs), mk_scope);
else if (m.is_value(lhs))
assert_eq_val(rhs, to_app(lhs), mk_scope);
}
} }
bool is_cached(expr * t, expr_ref & r) { bool is_cached(expr * t, expr_ref & r) {
@ -281,9 +309,7 @@ struct ctx_simplify_tactic::imp {
} }
checkpoint(); checkpoint();
TRACE("ctx_simplify_tactic_detail", tout << "processing: " << mk_bounded_pp(t, m) << "\n";); TRACE("ctx_simplify_tactic_detail", tout << "processing: " << mk_bounded_pp(t, m) << "\n";);
expr * _r; if (m_simp->simplify(t, r)) {
if (m_assertions.find(t, _r)) {
r = _r;
SASSERT(r.get() != 0); SASSERT(r.get() != 0);
return; return;
} }
@ -465,10 +491,10 @@ struct ctx_simplify_tactic::imp {
void process(expr * s, expr_ref & r) { void process(expr * s, expr_ref & r) {
TRACE("ctx_simplify_tactic", tout << "simplifying:\n" << mk_ismt2_pp(s, m) << "\n";); TRACE("ctx_simplify_tactic", tout << "simplifying:\n" << mk_ismt2_pp(s, m) << "\n";);
SASSERT(m_scope_lvl == 0); SASSERT(scope_level() == 0);
m_depth = 0; m_depth = 0;
simplify(s, r); simplify(s, r);
SASSERT(m_scope_lvl == 0); SASSERT(scope_level() == 0);
SASSERT(m_depth == 0); SASSERT(m_depth == 0);
SASSERT(r.get() != 0); SASSERT(r.get() != 0);
TRACE("ctx_simplify_tactic", tout << "result\n" << mk_ismt2_pp(r, m) << " :num-steps " << m_num_steps << "\n"; TRACE("ctx_simplify_tactic", tout << "result\n" << mk_ismt2_pp(r, m) << " :num-steps " << m_num_steps << "\n";
@ -505,13 +531,15 @@ struct ctx_simplify_tactic::imp {
}; };
ctx_simplify_tactic::ctx_simplify_tactic(ast_manager & m, params_ref const & p): ctx_simplify_tactic::ctx_simplify_tactic(ast_manager & m, simplifier* simp, params_ref const & p):
m_imp(alloc(imp, m, p)), m_imp(alloc(imp, m, simp, p)),
m_params(p) { m_params(p),
m_simp(simp) {
} }
ctx_simplify_tactic::~ctx_simplify_tactic() { ctx_simplify_tactic::~ctx_simplify_tactic() {
dealloc(m_imp); dealloc(m_imp);
dealloc(m_simp);
} }
void ctx_simplify_tactic::updt_params(params_ref const & p) { void ctx_simplify_tactic::updt_params(params_ref const & p) {
@ -539,7 +567,7 @@ void ctx_simplify_tactic::operator()(goal_ref const & in,
void ctx_simplify_tactic::cleanup() { void ctx_simplify_tactic::cleanup() {
ast_manager & m = m_imp->m; ast_manager & m = m_imp->m;
imp * d = alloc(imp, m, m_params); imp * d = alloc(imp, m, m_simp->translate(m), m_params);
std::swap(d, m_imp); std::swap(d, m_imp);
dealloc(d); dealloc(d);
} }

View file

@ -20,16 +20,34 @@ Notes:
#define CTX_SIMPLIFY_TACTIC_H_ #define CTX_SIMPLIFY_TACTIC_H_
#include"tactical.h" #include"tactical.h"
#include"goal_num_occurs.h"
class ctx_simplify_tactic : public tactic { class ctx_simplify_tactic : public tactic {
struct imp;
imp * m_imp;
params_ref m_params;
public: public:
ctx_simplify_tactic(ast_manager & m, params_ref const & p = params_ref()); class simplifier {
goal_num_occurs* m_occs;
public:
virtual ~simplifier() {}
virtual void assert_expr(expr * t, bool sign) = 0;
virtual bool simplify(expr* t, expr_ref& result) = 0;
virtual void push() = 0;
virtual void pop(unsigned num_scopes) = 0;
virtual simplifier * translate(ast_manager & m) = 0;
virtual unsigned scope_level() const = 0;
void set_occs(goal_num_occurs& occs) { m_occs = &occs; };
bool shared(expr* t) const;
};
protected:
struct imp;
imp * m_imp;
params_ref m_params;
simplifier* m_simp;
public:
ctx_simplify_tactic(ast_manager & m, simplifier* simp, params_ref const & p = params_ref());
virtual tactic * translate(ast_manager & m) { virtual tactic * translate(ast_manager & m) {
return alloc(ctx_simplify_tactic, m, m_params); return alloc(ctx_simplify_tactic, m, m_simp->translate(m), m_params);
} }
virtual ~ctx_simplify_tactic(); virtual ~ctx_simplify_tactic();
@ -47,8 +65,29 @@ public:
virtual void cleanup(); virtual void cleanup();
}; };
class ctx_propagate_assertions : public ctx_simplify_tactic::simplifier {
ast_manager& m;
obj_map<expr, expr*> m_assertions;
expr_ref_vector m_trail;
unsigned_vector m_scopes;
void assert_eq_val(expr * t, app * val, bool mk_scope);
void assert_eq_core(expr * t, app * val);
public:
ctx_propagate_assertions(ast_manager& m);
virtual ~ctx_propagate_assertions() {}
virtual void assert_expr(expr * t, bool sign);
virtual bool simplify(expr* t, expr_ref& result);
virtual void push();
virtual void pop(unsigned num_scopes);
virtual unsigned scope_level() const { return m_scopes.size(); }
virtual simplifier * translate(ast_manager & m);
};
inline tactic * mk_ctx_simplify_tactic(ast_manager & m, params_ref const & p = params_ref()) { inline tactic * mk_ctx_simplify_tactic(ast_manager & m, params_ref const & p = params_ref()) {
return clean(alloc(ctx_simplify_tactic, m, p)); return clean(alloc(ctx_simplify_tactic, m, alloc(ctx_propagate_assertions, m), p));
} }
/* /*