mirror of
https://github.com/Z3Prover/z3
synced 2025-04-24 01:25:31 +00:00
fix bug reported in issue #193: MBQI needs to avoid instantiating data-types that contain model values in nested positions
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
parent
702af71a2d
commit
cd838e5cf4
7 changed files with 100 additions and 40 deletions
|
@ -171,7 +171,7 @@ namespace smt {
|
|||
sk_value = sk_term;
|
||||
}
|
||||
}
|
||||
if (m_manager.is_model_value(sk_value))
|
||||
if (contains_model_value(sk_value))
|
||||
return false;
|
||||
bindings.set(num_decls - i - 1, sk_value);
|
||||
}
|
||||
|
@ -190,6 +190,30 @@ namespace smt {
|
|||
return true;
|
||||
}
|
||||
|
||||
void model_checker::operator()(expr *n) {
|
||||
if (m_manager.is_model_value(n)) {
|
||||
throw is_model_value();
|
||||
}
|
||||
}
|
||||
|
||||
bool model_checker::contains_model_value(expr* n) {
|
||||
if (m_manager.is_model_value(n)) {
|
||||
return true;
|
||||
}
|
||||
if (is_app(n) && to_app(n)->get_num_args() == 0) {
|
||||
return false;
|
||||
}
|
||||
m_visited.reset();
|
||||
try {
|
||||
for_each_expr(*this, m_visited, n);
|
||||
}
|
||||
catch (is_model_value) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool model_checker::add_blocking_clause(model * cex, expr_ref_vector & sks) {
|
||||
SASSERT(cex != 0);
|
||||
unsigned num_sks = sks.size();
|
||||
|
|
|
@ -80,6 +80,10 @@ namespace smt {
|
|||
|
||||
quantifier * get_flat_quantifier(quantifier * q);
|
||||
|
||||
struct is_model_value {};
|
||||
expr_mark m_visited;
|
||||
bool contains_model_value(expr* e);
|
||||
|
||||
public:
|
||||
model_checker(ast_manager & m, qi_params const & p, model_finder & mf);
|
||||
~model_checker();
|
||||
|
@ -95,6 +99,9 @@ namespace smt {
|
|||
void reset();
|
||||
|
||||
void set_cancel(bool f) { m_cancel = f; }
|
||||
|
||||
void operator()(expr* e);
|
||||
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
@ -83,6 +83,7 @@ namespace smt {
|
|||
ast_manager & m_manager;
|
||||
obj_map<expr, unsigned> m_elems; // and the associated generation
|
||||
obj_map<expr, expr *> m_inv;
|
||||
expr_mark m_visited;
|
||||
public:
|
||||
instantiation_set(ast_manager & m):m_manager(m) {}
|
||||
|
||||
|
@ -98,11 +99,11 @@ namespace smt {
|
|||
obj_map<expr, unsigned> const & get_elems() const { return m_elems; }
|
||||
|
||||
void insert(expr * n, unsigned generation) {
|
||||
if (m_elems.contains(n))
|
||||
if (m_elems.contains(n) || contains_model_value(n))
|
||||
return;
|
||||
TRACE("model_finder", tout << mk_pp(n, m_manager) << "\n";);
|
||||
m_manager.inc_ref(n);
|
||||
m_elems.insert(n, generation);
|
||||
CTRACE("model_finder", m_manager.is_model_value(n), tout << mk_pp(n, m_manager) << "\n";);
|
||||
SASSERT(!m_manager.is_model_value(n));
|
||||
}
|
||||
|
||||
|
@ -145,9 +146,10 @@ namespace smt {
|
|||
obj_map<expr, unsigned>::iterator end = m_elems.end();
|
||||
for (; it != end; ++it) {
|
||||
expr * t = (*it).m_key;
|
||||
SASSERT(!m_manager.is_model_value(t));
|
||||
SASSERT(!contains_model_value(t));
|
||||
unsigned gen = (*it).m_value;
|
||||
expr * t_val = ev.eval(t, true);
|
||||
TRACE("model_finder", tout << mk_pp(t, m_manager) << "\n";);
|
||||
|
||||
expr * old_t = 0;
|
||||
if (m_inv.find(t_val, old_t)) {
|
||||
|
@ -167,6 +169,30 @@ namespace smt {
|
|||
obj_map<expr, expr *> const & get_inv_map() const {
|
||||
return m_inv;
|
||||
}
|
||||
|
||||
struct is_model_value {};
|
||||
void operator()(expr *n) {
|
||||
if (m_manager.is_model_value(n)) {
|
||||
throw is_model_value();
|
||||
}
|
||||
}
|
||||
|
||||
bool contains_model_value(expr* n) {
|
||||
if (m_manager.is_model_value(n)) {
|
||||
return true;
|
||||
}
|
||||
if (is_app(n) && to_app(n)->get_num_args() == 0) {
|
||||
return false;
|
||||
}
|
||||
m_visited.reset();
|
||||
try {
|
||||
for_each_expr(*this, m_visited, n);
|
||||
}
|
||||
catch (is_model_value) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -286,7 +312,7 @@ namespace smt {
|
|||
return get_root()->m_signed_proj;
|
||||
}
|
||||
|
||||
void mk_instatiation_set(ast_manager & m) {
|
||||
void mk_instantiation_set(ast_manager & m) {
|
||||
SASSERT(is_root());
|
||||
m_set = alloc(instantiation_set, m);
|
||||
}
|
||||
|
@ -527,13 +553,13 @@ namespace smt {
|
|||
return 0;
|
||||
}
|
||||
|
||||
void mk_instatiation_sets() {
|
||||
void mk_instantiation_sets() {
|
||||
ptr_vector<node>::const_iterator it = m_nodes.begin();
|
||||
ptr_vector<node>::const_iterator end = m_nodes.end();
|
||||
for (; it != end; ++it) {
|
||||
node * curr = *it;
|
||||
if (curr->is_root()) {
|
||||
curr->mk_instatiation_set(m_manager);
|
||||
curr->mk_instantiation_set(m_manager);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -695,6 +721,7 @@ namespace smt {
|
|||
return 0;
|
||||
m_model->register_decl(k_decl, r);
|
||||
SASSERT(m_model->get_const_interp(k_decl) == r);
|
||||
TRACE("model_finder", tout << mk_pp(r, m_manager) << "\n";);
|
||||
return r;
|
||||
}
|
||||
|
||||
|
@ -1204,7 +1231,7 @@ namespace smt {
|
|||
// a necessary instantiation.
|
||||
enode * e_arg = n->get_arg(m_arg_i);
|
||||
expr * arg = e_arg->get_owner();
|
||||
A_f_i->insert(arg, e_arg->get_generation());
|
||||
A_f_i->insert(arg, e_arg->get_generation());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1225,7 +1252,7 @@ namespace smt {
|
|||
if (ctx->is_relevant(n)) {
|
||||
enode * e_arg = n->get_arg(m_arg_i);
|
||||
expr * arg = e_arg->get_owner();
|
||||
s->insert(arg, e_arg->get_generation());
|
||||
s->insert(arg, e_arg->get_generation());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3378,7 +3405,7 @@ namespace smt {
|
|||
quantifier_info * qi = get_quantifier_info(q);
|
||||
qi->process_auf(*(m_auf_solver.get()), m_context);
|
||||
}
|
||||
m_auf_solver->mk_instatiation_sets();
|
||||
m_auf_solver->mk_instantiation_sets();
|
||||
it = qs.begin();
|
||||
for (; it != end; ++it) {
|
||||
quantifier * q = *it;
|
||||
|
|
|
@ -68,17 +68,10 @@ namespace smt {
|
|||
|
||||
|
||||
bool theory_opt::is_numeral(arith_util& a, expr* term) {
|
||||
while (true) {
|
||||
if (a.is_uminus(term) || a.is_to_real(term) || a.is_to_int(term)) {
|
||||
term = to_app(term)->get_arg(0);
|
||||
}
|
||||
else if (a.is_numeral(term)) {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
while (a.is_uminus(term) || a.is_to_real(term) || a.is_to_int(term)) {
|
||||
term = to_app(term)->get_arg(0);
|
||||
}
|
||||
return a.is_numeral(term);
|
||||
}
|
||||
|
||||
};
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue