3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-04-27 02:45:51 +00:00

fix quantifier elimination bugs reported by Berdine and Bornat

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
Nikolaj Bjorner 2014-07-14 15:38:22 +02:00
parent 4f7d872d59
commit e4dedbbefc
5 changed files with 137 additions and 60 deletions

View file

@ -1120,6 +1120,7 @@ namespace qe {
st->init(fml);
st->m_vars.append(m_vars.size(), m_vars.c_ptr());
SASSERT(invariant());
TRACE("qe", tout << mk_pp(m_fml, m) << " child: " << mk_pp(fml, m) << "\n";);
return st;
}
@ -1133,6 +1134,7 @@ namespace qe {
m_branch_index.insert(branch_id, index);
st->m_vars.append(m_vars.size(), m_vars.c_ptr());
SASSERT(invariant());
//TRACE("qe", tout << mk_pp(m_fml, m) << " child: " << mk_pp(st->fml(), m) << "\n";);
return st;
}
@ -1164,6 +1166,16 @@ namespace qe {
}
}
expr_ref abstract_variable(app* x, expr* fml) const {
expr_ref result(m);
expr* y = x;
expr_abstract(m, 0, 1, &y, fml, result);
symbol X(x->get_decl()->get_name());
sort* s = m.get_sort(x);
result = m.mk_exists(1, &s, &X, result);
return result;
}
void display_validate(std::ostream& out) const {
if (m_children.empty()) {
return;
@ -1171,25 +1183,53 @@ namespace qe {
expr_ref q(m);
expr* x = m_var;
if (x) {
expr_abstract(m, 0, 1, &x, m_fml, q);
ptr_vector<expr> fmls;
q = abstract_variable(m_var, m_fml);
expr_ref_vector fmls(m);
expr_ref fml(m);
for (unsigned i = 0; i < m_children.size(); ++i) {
expr* fml = m_children[i]->fml();
search_tree const& child = *m_children[i];
fml = child.fml();
if (fml) {
// abstract free variables in children.
ptr_vector<app> child_vars, new_vars;
child_vars.append(child.m_vars.size(), child.m_vars.c_ptr());
if (child.m_var) {
child_vars.push_back(child.m_var);
}
for (unsigned j = 0; j < child_vars.size(); ++j) {
if (!m_vars.contains(child_vars[j]) &&
!new_vars.contains(child_vars[j])) {
fml = abstract_variable(child_vars[j], fml);
new_vars.push_back(child_vars[j]);
}
}
fmls.push_back(fml);
}
}
symbol X(m_var->get_decl()->get_name());
sort* s = m.get_sort(x);
q = m.mk_exists(1, &s, &X, q);
expr_ref tmp(m);
bool_rewriter(m).mk_or(fmls.size(), fmls.c_ptr(), tmp);
expr_ref f(m.mk_not(m.mk_iff(q, tmp)), m);
bool_rewriter(m).mk_or(fmls.size(), fmls.c_ptr(), fml);
fml = m.mk_not(m.mk_iff(q, fml));
ast_smt_pp pp(m);
out << "(echo " << m_var->get_decl()->get_name() << ")\n";
out << "; eliminate " << mk_pp(m_var, m) << "\n";
out << "(push)\n";
pp.display_smt2(out, f);
pp.display_smt2(out, fml);
out << "(pop)\n\n";
DEBUG_CODE(
smt_params params;
params.m_simplify_bit2int = true;
params.m_arith_enum_const_mod = true;
params.m_bv_enable_int2bv2int = true;
params.m_relevancy_lvl = 0;
smt::kernel ctx(m, params);
ctx.assert_expr(fml);
lbool is_sat = ctx.check();
if (is_sat == l_true) {
std::cout << "; Validation failed:\n";
std::cout << mk_pp(fml, m) << "\n";
}
);
}
for (unsigned i = 0; i < m_children.size(); ++i) {
if (m_children[i]->fml()) {
@ -1410,13 +1450,9 @@ namespace qe {
m_solver.assert_expr(m_fml);
if (assumption) m_solver.assert_expr(assumption);
bool is_sat = false;
while (l_false != m_solver.check()) {
while (l_true == m_solver.check()) {
is_sat = true;
model_ref model;
m_solver.get_model(model);
TRACE("qe", model_v2_pp(tout, *model););
model_evaluator model_eval(*model);
final_check(model_eval);
final_check();
}
if (!is_sat) {
@ -1466,14 +1502,30 @@ namespace qe {
private:
void final_check(model_evaluator& model_eval) {
TRACE("qe", tout << "\n";);
while (can_propagate_assignment(model_eval)) {
propagate_assignment(model_eval);
}
VERIFY(CHOOSE_VAR == update_current(model_eval, true));
SASSERT(m_current->fml());
pop(model_eval);
void final_check() {
model_ref model;
m_solver.get_model(model);
scoped_ptr<model_evaluator> model_eval = alloc(model_evaluator, *model);
while (true) {
TRACE("qe", model_v2_pp(tout, *model););
while (can_propagate_assignment(*model_eval)) {
propagate_assignment(*model_eval);
}
VERIFY(CHOOSE_VAR == update_current(*model_eval, true));
SASSERT(m_current->fml());
if (l_true != m_solver.check()) {
return;
}
m_solver.get_model(model);
model_eval = alloc(model_evaluator, *model);
search_tree* st = m_current;
update_current(*model_eval, false);
if (st == m_current) {
break;
}
}
pop(*model_eval);
}
ast_manager& get_manager() { return m; }
@ -1633,6 +1685,7 @@ namespace qe {
nb = m_current->get_num_branches();
expr_ref fml(m_current->fml(), m);
if (!eval(model_eval, b, branch) || branch >= nb) {
TRACE("qe", tout << "evaluation failed: setting branch to 0\n";);
branch = rational::zero();
}
SASSERT(!branch.is_neg());
@ -1694,11 +1747,12 @@ namespace qe {
}
//
// The current state is satisfiable
// and the closed portion of the formula
// can be used as the quantifier-free portion.
// The closed portion of the formula
// can be used as the quantifier-free portion,
// unless the current state is unsatisfiable.
//
if (m.is_true(fml_mixed)) {
SASSERT(l_true == m_solver.check());
m_current = m_current->add_child(fml_closed);
for (unsigned i = 0; m_defs && i < m_current->num_free_vars(); ++i) {
expr_ref val(m);
@ -1708,6 +1762,7 @@ namespace qe {
if (val == x) {
model_ref model;
lbool is_sat = m_solver.check();
if (is_sat == l_undef) return;
m_solver.get_model(model);
SASSERT(is_sat == l_true);
model_evaluator model_eval2(*model);
@ -1890,7 +1945,7 @@ namespace qe {
vars.reset();
closed = closed && (r != l_undef);
}
TRACE("qe", tout << mk_ismt2_pp(fml, m) << "\n";);
TRACE("qe", tout << mk_pp(fml, m) << "\n";);
m_current->add_child(fml)->reset_free_vars();
block_assignment();
}
@ -1959,7 +2014,7 @@ namespace qe {
class quant_elim_new : public quant_elim {
ast_manager& m;
smt_params& m_fparams;
smt_params& m_fparams;
expr_ref m_assumption;
bool m_produce_models;
ptr_vector<quant_elim_plugin> m_plugins;