3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-04-30 04:15:51 +00:00
#6319 - fix incompleteness in propagation of default to all array terms in the equivalence class.

Fix bug with q_mbi where domain restrictions are not using values because the current model does not evaluate certain bound variables to values. Set model completion when adding these bound variables to the model to ensure their values are not missed.

Add better propagation of diagnostics when tactics and the new solver return unknown. The reason for unknown can now be traced to what theory was culprit (currently no additional information)
This commit is contained in:
Nikolaj Bjorner 2022-09-23 22:22:34 -05:00
parent 6226875283
commit 1f150ecd52
16 changed files with 70 additions and 24 deletions

View file

@ -686,7 +686,6 @@ namespace arith {
if (m_nla)
m_nla->push();
th_euf_solver::push_core();
}
void solver::pop_core(unsigned num_scopes) {

View file

@ -122,7 +122,7 @@ namespace array {
ctx.push(push_back_vector(m_minmaxdiffs));
break;
case OP_ARRAY_DEFAULT:
add_parent_default(find(n->get_arg(0)), n);
add_parent_default(find(n->get_arg(0)));
break;
case OP_ARRAY_MAP:
case OP_SET_UNION:

View file

@ -69,14 +69,21 @@ namespace array {
values.set(n->get_expr_id(), n->get_expr());
return;
}
theory_var v = get_th_var(n);
euf::enode* d = get_default(v);
if (a.is_const(n->get_expr())) {
expr* val = values.get(d->get_root_id());
SASSERT(val);
values.set(n->get_expr_id(), a.mk_const_array(n->get_sort(), val));
return;
}
unsigned arity = get_array_arity(srt);
func_decl * f = mk_aux_decl_for_array_sort(m, srt);
func_interp * fi = alloc(func_interp, m, arity);
mdl.register_decl(f, fi);
theory_var v = get_th_var(n);
euf::enode* d = get_default(v);
if (d && !fi->get_else())
fi->set_else(values.get(d->get_root_id()));

View file

@ -172,6 +172,10 @@ namespace array {
add_parent_select(v1, select);
if (is_lambda(e1) || is_lambda(e2))
push_axiom(congruence_axiom(n1, n2));
if (d1.m_has_default && !d2.m_has_default)
add_parent_default(v2);
if (!d1.m_has_default && d2.m_has_default)
add_parent_default(v1);
}
void solver::add_parent_select(theory_var v_child, euf::enode* select) {
@ -206,9 +210,10 @@ namespace array {
propagate_select_axioms(d, lambda);
}
void solver::add_parent_default(theory_var v, euf::enode* def) {
SASSERT(a.is_default(def->get_expr()));
void solver::add_parent_default(theory_var v) {
auto& d = get_var_data(find(v));
ctx.push(value_trail(d.m_has_default));
d.m_has_default = true;
for (euf::enode* lambda : d.m_lambdas)
push_axiom(default_axiom(lambda));
if (should_prop_upward(d))

View file

@ -50,7 +50,8 @@ namespace array {
// void log_drat(array_justification const& c);
struct var_data {
bool m_prop_upward{ false };
bool m_prop_upward = false ;
bool m_has_default = false;
euf::enode_vector m_lambdas; // equivalent nodes that have beta reduction properties
euf::enode_vector m_parent_lambdas; // parents that have beta reduction properties
euf::enode_vector m_parent_selects; // parents that use array in select position
@ -202,7 +203,7 @@ namespace array {
// solving
void add_parent_select(theory_var v_child, euf::enode* select);
void add_parent_default(theory_var v_child, euf::enode* def);
void add_parent_default(theory_var v_child);
void add_lambda(theory_var v, euf::enode* lambda);
void add_parent_lambda(theory_var v_child, euf::enode* lambda);

View file

@ -296,7 +296,17 @@ namespace euf {
expr_ref sval(m);
th_rewriter rw(m);
rw(val, sval);
out << bpp(r) << " := " << sval << " " << mdl(r->get_root()->get_expr()) << "\n";
expr_ref mval = mdl(r->get_root()->get_expr());
if (mval != sval) {
out << bpp(r) << " :=\neval: " << sval << "\nmval: " << mval << "\n";
continue;
}
if (!m.is_bool(val))
continue;
auto bval = s().value(r->bool_var());
bool tt = l_true == bval;
if (tt != m.is_true(sval))
out << bpp(r) << " :=\neval: " << sval << "\nmval: " << bval << "\n";
}
for (euf::enode* r : nodes)
r->unmark1();

View file

@ -166,8 +166,9 @@ namespace euf {
IF_VERBOSE(0, verbose_stream() << mk_pp(f, m) << " not handled\n");
}
void solver::init_search() {
void solver::init_search() {
TRACE("before_search", s().display(tout););
m_reason_unknown.clear();
for (auto* s : m_solvers)
s->init_search();
}
@ -482,7 +483,7 @@ namespace euf {
auto apply_solver = [&](th_solver* e) {
switch (e->check()) {
case sat::check_result::CR_CONTINUE: cont = true; break;
case sat::check_result::CR_GIVEUP: give_up = true; break;
case sat::check_result::CR_GIVEUP: m_reason_unknown = "incomplete theory " + e->name().str(); TRACE("euf", tout << "give up " << e->name() << "\n"); give_up = true; break;
default: break;
}
};
@ -490,8 +491,10 @@ namespace euf {
cont = true;
for (unsigned i = 0; i < m_solvers.size(); ++i) {
auto* e = m_solvers[i];
if (!m.inc())
if (!m.inc()) {
m_reason_unknown = "canceled";
return sat::check_result::CR_GIVEUP;
}
if (e == m_qsolver)
continue;
apply_solver(e);

View file

@ -105,6 +105,7 @@ namespace euf {
user_solver::solver* m_user_propagator = nullptr;
th_solver* m_qsolver = nullptr;
unsigned m_generation = 0;
std::string m_reason_unknown;
mutable ptr_vector<expr> m_todo;
ptr_vector<expr> m_bool_var2expr;
@ -290,6 +291,7 @@ namespace euf {
bool should_research(sat::literal_vector const& core) override;
void add_assumptions(sat::literal_set& assumptions) override;
bool tracking_assumptions() override;
std::string reason_unknown() override { return m_reason_unknown; }
void propagate(literal lit, ext_justification_idx idx);
bool propagate(enode* a, enode* b, ext_justification_idx idx);

View file

@ -198,6 +198,7 @@ namespace q {
expr_ref_vector eqs(m);
add_domain_bounds(mdl, qb);
auto proj = solver_project(mdl, qb, eqs, false);
CTRACE("q", !proj, tout << "could not project " << qb.mbody << " " << eqs << "\n" << mdl);
if (!proj)
return false;
add_instantiation(q, proj);
@ -339,8 +340,10 @@ namespace q {
fmls.append(qb.domain_eqs);
eliminate_nested_vars(fmls, qb);
for (expr* e : fmls)
if (!m_model->is_true(e))
if (!m_model->is_true(e)) {
TRACE("q", tout << "not true: " << mk_pp(e, m) << " := " << (*m_model)(e) << "\n");
return expr_ref(nullptr, m);
}
mbp::project_plugin proj(m);
proj.extract_literals(*m_model, vars, fmls);
fmls_extracted = true;
@ -348,8 +351,9 @@ namespace q {
if (!p)
continue;
if (ctx.use_drat()) {
if (!p->project(*m_model, vars, fmls, m_defs))
return expr_ref(m);
if (!p->project(*m_model, vars, fmls, m_defs))
return expr_ref(m);
}
else if (!(*p)(*m_model, vars, fmls))
return expr_ref(m);
@ -430,8 +434,11 @@ namespace q {
void mbqi::add_domain_bounds(model& mdl, q_body& qb) {
qb.domain_eqs.reset();
m_model->reset_eval_cache();
for (app* v : qb.vars)
m_model->register_decl(v->get_decl(), mdl(v));
{
model::scoped_model_completion _sc(mdl, true);
for (app* v : qb.vars)
m_model->register_decl(v->get_decl(), mdl(v));
}
ctx.model_updated(m_model);
if (qb.var_args.empty())
return;
@ -440,7 +447,8 @@ namespace q {
expr_ref _term = subst(t, qb.vars);
app_ref term(to_app(_term), m);
expr_ref value = (*m_model)(term->get_arg(idx));
m_model_fixer.invert_arg(term, idx, value, qb.domain_eqs);
if (m.is_value(value))
m_model_fixer.invert_arg(term, idx, value, qb.domain_eqs);
}
}