mirror of
https://github.com/Z3Prover/z3
synced 2025-08-03 01:40:22 +00:00
add recfun rewriting, remove quantifier based recfun
This commit is contained in:
parent
7f1b147cba
commit
f9193809ea
13 changed files with 94 additions and 143 deletions
|
@ -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");
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue