3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-04-24 01:25:31 +00:00

add recfun rewriting, remove quantifier based recfun

This commit is contained in:
Nikolaj Bjorner 2020-04-26 12:59:51 -07:00
parent 7f1b147cba
commit f9193809ea
13 changed files with 94 additions and 143 deletions

View file

@ -4507,32 +4507,6 @@ namespace smt {
void context::add_rec_funs_to_model() {
if (!m_model) return;
for (unsigned i = 0; !get_cancel_flag() && i < m_asserted_formulas.get_num_formulas(); ++i) {
expr* e = m_asserted_formulas.get_formula(i);
if (is_quantifier(e)) {
quantifier* q = to_quantifier(e);
if (!m.is_rec_fun_def(q)) continue;
TRACE("context", tout << mk_pp(e, m) << "\n";);
SASSERT(q->get_num_patterns() == 2);
expr* fn = to_app(q->get_pattern(0))->get_arg(0);
expr* body = to_app(q->get_pattern(1))->get_arg(0);
SASSERT(is_app(fn));
// reverse argument order so that variable 0 starts at the beginning.
expr_ref_vector subst(m);
unsigned idx = 0;
for (expr* arg : *to_app(fn)) {
subst.push_back(m.mk_var(idx++, m.get_sort(arg)));
}
expr_ref bodyr(m);
var_subst sub(m, true);
TRACE("context", tout << expr_ref(q, m) << " " << subst << "\n";);
bodyr = sub(body, subst.size(), subst.c_ptr());
func_decl* f = to_app(fn)->get_decl();
func_interp* fi = alloc(func_interp, m, f->get_arity());
fi->set_else(bodyr);
m_model->register_decl(f, fi);
}
}
recfun::util u(m);
func_decl_ref_vector recfuns = u.get_rec_funs();
for (func_decl* f : recfuns) {

View file

@ -367,9 +367,6 @@ namespace smt {
if (!is_ground(n)) {
continue;
}
if (is_quantifier(n) && m.is_rec_fun_def(to_quantifier(n))) {
continue;
}
switch (get_assignment(lit)) {
case l_undef:
break;

View file

@ -47,7 +47,6 @@ namespace smt {
m_model_finder(mf),
m_max_cexs(1),
m_iteration_idx(0),
m_has_rec_fun(false),
m_curr_model(nullptr),
m_fresh_exprs(m),
m_pinned_exprs(m) {
@ -380,36 +379,6 @@ namespace smt {
return false;
}
bool model_checker::check_rec_fun(quantifier* q, bool strict_rec_fun) {
TRACE("model_checker", tout << mk_pp(q, m) << "\n";);
SASSERT(q->get_num_patterns() == 2); // first pattern is the function, second is the body.
func_decl* f = m.get_rec_fun_decl(q);
expr_ref_vector args(m);
unsigned num_decls = q->get_num_decls();
args.resize(num_decls, nullptr);
var_subst sub(m);
expr_ref tmp(m), result(m);
for (enode* n : m_context->enodes_of(f)) {
if (m_context->is_relevant(n)) {
app* e = n->get_owner();
SASSERT(e->get_num_args() == num_decls);
for (unsigned i = 0; i < num_decls; ++i) {
args[i] = e->get_arg(i);
}
tmp = sub(q->get_expr(), num_decls, args.c_ptr());
TRACE("model_checker", tout << "curr_model:\n"; model_pp(tout, *m_curr_model););
m_curr_model->eval(tmp, result, true);
if (strict_rec_fun ? !m.is_true(result) : m.is_false(result)) {
add_instance(q, args, 0, nullptr);
return false;
}
TRACE("model_checker", tout << tmp << "\nevaluates to:\n" << result << "\n";);
}
}
return true;
}
void model_checker::init_aux_context() {
if (!m_fparams) {
m_fparams = alloc(smt_params, m_context->get_fparams());
@ -458,7 +427,7 @@ namespace smt {
bool found_relevant = false;
unsigned num_failures = 0;
check_quantifiers(false, found_relevant, num_failures);
check_quantifiers(found_relevant, num_failures);
if (found_relevant)
m_iteration_idx++;
@ -467,11 +436,11 @@ namespace smt {
TRACE("model_checker", tout << "model checker result: " << (num_failures == 0) << "\n";);
m_max_cexs += m_params.m_mbqi_max_cexs;
if (num_failures == 0 && (!m_context->validate_model() || has_rec_under_quantifiers())) {
if (num_failures == 0 && (!m_context->validate_model())) {
num_failures = 1;
// this time force expanding recursive function definitions
// that are not forced true in the current model.
check_quantifiers(true, found_relevant, num_failures);
check_quantifiers(found_relevant, num_failures);
}
if (num_failures == 0)
m_curr_model->cleanup();
@ -484,43 +453,6 @@ namespace smt {
return num_failures == 0;
}
struct has_rec_fun_proc {
obj_hashtable<func_decl>& m_rec_funs;
bool m_has_rec_fun;
bool has_rec_fun() const { return m_has_rec_fun; }
has_rec_fun_proc(obj_hashtable<func_decl>& rec_funs):
m_rec_funs(rec_funs),
m_has_rec_fun(false) {}
void operator()(app* fn) {
m_has_rec_fun |= m_rec_funs.contains(fn->get_decl());
}
void operator()(expr*) {}
};
bool model_checker::has_rec_under_quantifiers() {
if (!m_has_rec_fun) {
return false;
}
obj_hashtable<func_decl> rec_funs;
for (quantifier * q : *m_qm) {
if (m.is_rec_fun_def(q)) {
rec_funs.insert(m.get_rec_fun_decl(q));
}
}
expr_fast_mark1 visited;
has_rec_fun_proc proc(rec_funs);
for (quantifier * q : *m_qm) {
if (!m.is_rec_fun_def(q)) {
quick_for_each_expr(proc, visited, q);
if (proc.has_rec_fun()) return true;
}
}
return false;
}
//
// (repeated from defined_names.cpp)
// NB. The pattern for lambdas is incomplete.
@ -532,7 +464,7 @@ namespace smt {
// using multi-patterns.
//
void model_checker::check_quantifiers(bool strict_rec_fun, bool& found_relevant, unsigned& num_failures) {
void model_checker::check_quantifiers(bool& found_relevant, unsigned& num_failures) {
for (quantifier * q : *m_qm) {
if (!(m_qm->mbqi_enabled(q) &&
m_context->is_relevant(q) &&
@ -549,14 +481,7 @@ namespace smt {
verbose_stream() << "(smt.mbqi :checking " << q->get_qid() << ")\n";
}
found_relevant = true;
if (m.is_rec_fun_def(q)) {
m_has_rec_fun = true;
if (!check_rec_fun(q, strict_rec_fun)) {
TRACE("model_checker", tout << "checking recursive function failed\n";);
num_failures++;
}
}
else if (!check(q)) {
if (!check(q)) {
if (m_params.m_mbqi_trace || get_verbosity_level() >= 5) {
IF_VERBOSE(0, verbose_stream() << "(smt.mbqi :failed " << q->get_qid() << ")\n");
}

View file

@ -51,7 +51,6 @@ namespace smt {
scoped_ptr<context> m_aux_context; // Auxiliary context used for model checking quantifiers.
unsigned m_max_cexs;
unsigned m_iteration_idx;
bool m_has_rec_fun;
proto_model * m_curr_model;
obj_map<expr, expr *> m_value2expr;
expr_ref_vector m_fresh_exprs;
@ -67,9 +66,7 @@ namespace smt {
void assert_neg_q_m(quantifier * q, expr_ref_vector & sks);
bool add_blocking_clause(model * cex, expr_ref_vector & sks);
bool check(quantifier * q);
bool check_rec_fun(quantifier* q, bool strict_rec_fun);
bool has_rec_under_quantifiers();
void check_quantifiers(bool strict_rec_fun, bool& found_relevant, unsigned& num_failures);
void check_quantifiers(bool& found_relevant, unsigned& num_failures);
struct instance {
quantifier * m_q;

View file

@ -625,9 +625,6 @@ namespace smt {
if (!m_fparams->m_ematching) {
return;
}
if (false && m.is_rec_fun_def(q) && mbqi_enabled(q)) {
return;
}
bool has_unary_pattern = false;
unsigned num_patterns = q->get_num_patterns();
for (unsigned i = 0; i < num_patterns; i++) {
@ -644,11 +641,7 @@ namespace smt {
app * mp = to_app(q->get_pattern(i));
SASSERT(m.is_pattern(mp));
bool unary = (mp->get_num_args() == 1);
if (m.is_rec_fun_def(q) && i > 0) {
// add only the first pattern
TRACE("quantifier", tout << "skip recursive function body " << mk_ismt2_pp(mp, m) << "\n";);
}
else if (!unary && j >= num_eager_multi_patterns) {
if (!unary && j >= num_eager_multi_patterns) {
TRACE("quantifier", tout << "delaying (too many multipatterns):\n" << mk_ismt2_pp(mp, m) << "\n"
<< "j: " << j << " unary: " << unary << " m_params.m_qi_max_eager_multipatterns: " << m_fparams->m_qi_max_eager_multipatterns
<< " num_eager_multi_patterns: " << num_eager_multi_patterns << "\n";);