mirror of
https://github.com/Z3Prover/z3
synced 2025-04-29 11:55:51 +00:00
working on new solver core
This commit is contained in:
parent
f519c58ace
commit
523578e3f6
13 changed files with 224 additions and 81 deletions
|
@ -50,7 +50,7 @@ namespace q {
|
|||
for (expr* e : universe)
|
||||
eqs.push_back(m.mk_eq(sk, e));
|
||||
expr_ref fml = mk_or(eqs);
|
||||
std::cout << "restrict to universe " << fml << "\n";
|
||||
// std::cout << "restrict to universe " << fml << "\n";
|
||||
m_solver->assert_expr(fml);
|
||||
}
|
||||
|
||||
|
@ -82,14 +82,15 @@ namespace q {
|
|||
quantifier* q_flat = m_qs.flatten(q);
|
||||
init_solver();
|
||||
::solver::scoped_push _sp(*m_solver);
|
||||
std::cout << "quantifier\n" << mk_pp(q, m, 4) << "\n";
|
||||
std::cout << mk_pp(q, m, 4) << "\n";
|
||||
// std::cout << *m_model << "\n";
|
||||
auto* qb = specialize(q_flat);
|
||||
if (!qb)
|
||||
return l_undef;
|
||||
// return l_undef;
|
||||
if (m.is_false(qb->mbody))
|
||||
return l_true;
|
||||
std::cout << "body\n" << qb->mbody << "\n";
|
||||
// std::cout << "body\n" << qb->mbody << "\n";
|
||||
m_solver->assert_expr(qb->mbody);
|
||||
lbool r = m_solver->check_sat(0, nullptr);
|
||||
if (r == l_undef)
|
||||
|
@ -103,37 +104,29 @@ namespace q {
|
|||
if (is_exists(q))
|
||||
qlit.neg();
|
||||
unsigned i = 0;
|
||||
expr_ref_vector eqs(m);
|
||||
if (!qb->var_args.empty()) {
|
||||
::solver::scoped_push _sp(*m_solver);
|
||||
add_domain_eqs(*mdl0, *qb);
|
||||
std::cout << "check\n";
|
||||
for (; i < m_max_cex && l_true == m_solver->check_sat(0, nullptr); ++i) {
|
||||
m_solver->get_model(mdl1);
|
||||
proj = solver_project(*mdl1, *qb);
|
||||
proj = solver_project(*mdl1, *qb, eqs, true);
|
||||
if (!proj)
|
||||
break;
|
||||
TRACE("q", tout << "project: " << proj << "\n";);
|
||||
std::cout << "project\n" << proj << "\n";
|
||||
std::cout << *m_model << "\n";
|
||||
std::cout << "eqs: " << eqs << "\n";
|
||||
|
||||
static unsigned s_count = 0;
|
||||
++s_count;
|
||||
if (s_count == 3)
|
||||
exit(0);
|
||||
++m_stats.m_num_instantiations;
|
||||
m_qs.add_clause(~qlit, ~ctx.mk_literal(proj));
|
||||
m_solver->assert_expr(m.mk_not(proj));
|
||||
add_instantiation(qlit, proj);
|
||||
m_solver->assert_expr(m.mk_not(mk_and(eqs)));
|
||||
}
|
||||
}
|
||||
if (i == 0) {
|
||||
add_domain_bounds(*mdl0, *qb);
|
||||
proj = solver_project(*mdl0, *qb);
|
||||
proj = solver_project(*mdl0, *qb, eqs, false);
|
||||
if (!proj)
|
||||
return l_undef;
|
||||
std::cout << "project-base\n" << proj << "\n";
|
||||
TRACE("q", tout << "project-base: " << proj << "\n";);
|
||||
++m_stats.m_num_instantiations;
|
||||
m_qs.add_clause(~qlit, ~ctx.mk_literal(proj));
|
||||
add_instantiation(qlit, proj);
|
||||
}
|
||||
// TODO: add as top-level clause for relevancy
|
||||
return l_false;
|
||||
|
@ -142,30 +135,45 @@ namespace q {
|
|||
mbqi::q_body* mbqi::specialize(quantifier* q) {
|
||||
mbqi::q_body* result = nullptr;
|
||||
var_subst subst(m);
|
||||
unsigned sz = q->get_num_decls();
|
||||
if (!m_q2body.find(q, result)) {
|
||||
unsigned sz = q->get_num_decls();
|
||||
result = alloc(q_body, m);
|
||||
m_q2body.insert(q, result);
|
||||
ctx.push(new_obj_trail<euf::solver, q_body>(result));
|
||||
ctx.push(insert_obj_map<euf::solver, quantifier, q_body*>(m_q2body, q));
|
||||
obj_hashtable<expr> _vars;
|
||||
app_ref_vector& vars = result->vars;
|
||||
vars.resize(sz, nullptr);
|
||||
for (unsigned i = 0; i < sz; ++i) {
|
||||
sort* s = q->get_decl_sort(i);
|
||||
vars[i] = m.mk_fresh_const(q->get_decl_name(i), s, false);
|
||||
if (m_model->has_uninterpreted_sort(s))
|
||||
restrict_to_universe(vars.get(i), m_model->get_universe(s));
|
||||
_vars.insert(vars.get(i));
|
||||
}
|
||||
expr_ref fml = subst(q->get_expr(), vars);
|
||||
extract_var_args(q->get_expr(), *result);
|
||||
if (is_forall(q))
|
||||
fml = m.mk_not(fml);
|
||||
flatten_and(fml, result->vbody);
|
||||
for (expr* e : result->vbody) {
|
||||
expr* e1 = nullptr, *e2 = nullptr;
|
||||
if (m.is_not(e, e) && m.is_eq(e, e1, e2)) {
|
||||
if (_vars.contains(e1) && !_vars.contains(e2) && is_app(e2))
|
||||
result->var_diff.push_back(std::make_pair(to_app(e1), to_app(e2)->get_decl()));
|
||||
else if (_vars.contains(e2) && !_vars.contains(e1) && is_app(e1))
|
||||
result->var_diff.push_back(std::make_pair(to_app(e2), to_app(e1)->get_decl()));
|
||||
}
|
||||
}
|
||||
}
|
||||
expr_ref& mbody = result->mbody;
|
||||
if (!m_model->eval_expr(q->get_expr(), mbody, true))
|
||||
return nullptr;
|
||||
|
||||
for (unsigned i = 0; i < sz; ++i) {
|
||||
sort* s = q->get_decl_sort(i);
|
||||
if (m_model->has_uninterpreted_sort(s))
|
||||
restrict_to_universe(result->vars.get(i), m_model->get_universe(s));
|
||||
}
|
||||
|
||||
mbody = subst(mbody, result->vars);
|
||||
if (is_forall(q))
|
||||
mbody = mk_not(m, mbody);
|
||||
|
@ -173,7 +181,8 @@ namespace q {
|
|||
return result;
|
||||
}
|
||||
|
||||
expr_ref mbqi::solver_project(model& mdl, q_body& qb) {
|
||||
expr_ref mbqi::solver_project(model& mdl, q_body& qb, expr_ref_vector& eqs, bool use_inst) {
|
||||
eqs.reset();
|
||||
model::scoped_model_completion _sc(mdl, true);
|
||||
for (app* v : qb.vars)
|
||||
m_model->register_decl(v->get_decl(), mdl(v));
|
||||
|
@ -186,13 +195,14 @@ namespace q {
|
|||
tout << fmls << "\n";
|
||||
tout << "model of projection\n" << mdl << "\n";
|
||||
tout << "var args: " << qb.var_args.size() << "\n";
|
||||
tout << "domain eqs: " << qb.domain_eqs << "\n";
|
||||
for (expr* f : fmls)
|
||||
if (m_model->is_false(f))
|
||||
tout << mk_pp(f, m) << " := false\n";
|
||||
tout << "vars: " << vars << "\n";);
|
||||
|
||||
expr_safe_replace rep(m);
|
||||
for (unsigned i = 0; i < vars.size(); ++i) {
|
||||
for (unsigned i = 0; !use_inst && i < vars.size(); ++i) {
|
||||
app* v = vars.get(i);
|
||||
auto* p = get_plugin(v);
|
||||
if (p && !fmls_extracted) {
|
||||
|
@ -213,6 +223,7 @@ namespace q {
|
|||
rep.insert(v, term);
|
||||
if (val != term)
|
||||
rep.insert(val, term);
|
||||
eqs.push_back(m.mk_eq(v, val));
|
||||
}
|
||||
rep(fmls);
|
||||
return mk_and(fmls);
|
||||
|
@ -228,7 +239,59 @@ namespace q {
|
|||
void mbqi::add_domain_eqs(model& mdl, q_body& qb) {
|
||||
qb.domain_eqs.reset();
|
||||
var_subst subst(m);
|
||||
expr_mark diff_vars;
|
||||
for (auto vd : qb.var_diff) {
|
||||
app* v = vd.first;
|
||||
func_decl* f = vd.second;
|
||||
expr_ref_vector diff_set(m), vdiff_set(m);
|
||||
typedef std::tuple<euf::enode*, unsigned, unsigned> tup;
|
||||
svector<tup> todo;
|
||||
expr_mark visited;
|
||||
expr_ref val(m);
|
||||
for (euf::enode* n : ctx.get_egraph().enodes_of(f)) {
|
||||
euf::enode* r1 = n->get_root();
|
||||
expr* e1 = n->get_expr();
|
||||
todo.push_back(tup(r1, 2, 2));
|
||||
for (unsigned i = 0; i < todo.size(); ++i) {
|
||||
auto t = todo[i];
|
||||
euf::enode* r2 = std::get<0>(t)->get_root();
|
||||
expr* e2 = r2->get_expr();
|
||||
if (visited.is_marked(e2))
|
||||
continue;
|
||||
visited.mark(e2);
|
||||
std::cout << "try: " << mk_bounded_pp(e2, m) << " " << std::get<1>(t) << " " << std::get<2>(t) << "\n";
|
||||
if (r1 != r2 && m.get_sort(e1) == m.get_sort(e2) && m_model->eval_expr(e2, val, true) && !visited.is_marked(val)) {
|
||||
visited.mark(val);
|
||||
diff_set.push_back(m.mk_eq(v, val));
|
||||
vdiff_set.push_back(m.mk_eq(v, e2));
|
||||
}
|
||||
if (std::get<1>(t) > 0)
|
||||
for (euf::enode* p : euf::enode_parents(r2))
|
||||
todo.push_back(tup(p, std::get<1>(t)-1, std::get<2>(t)+1));
|
||||
if (std::get<2>(t) > 0)
|
||||
for (euf::enode* n : euf::enode_class(r2))
|
||||
for (euf::enode* arg : euf::enode_args(n))
|
||||
todo.push_back(tup(arg, 0, std::get<2>(t)-1));
|
||||
|
||||
}
|
||||
todo.reset();
|
||||
}
|
||||
if (!diff_set.empty()) {
|
||||
diff_vars.mark(v);
|
||||
expr_ref diff = mk_or(diff_set);
|
||||
expr_ref vdiff = mk_or(vdiff_set);
|
||||
std::cout << "diff: " << vdiff_set << "\n";
|
||||
m_solver->assert_expr(diff);
|
||||
qb.domain_eqs.push_back(vdiff);
|
||||
}
|
||||
std::cout << "var-diff: " << mk_pp(vd.first, m) << " " << mk_pp(vd.second, m) << "\n";
|
||||
}
|
||||
|
||||
for (auto p : qb.var_args) {
|
||||
expr_ref arg(p.first->get_arg(p.second), m);
|
||||
arg = subst(arg, qb.vars);
|
||||
if (diff_vars.is_marked(arg))
|
||||
continue;
|
||||
expr_ref bounds = m_model_fixer.restrict_arg(p.first, p.second);
|
||||
if (m.is_true(bounds))
|
||||
continue;
|
||||
|
@ -237,13 +300,15 @@ namespace q {
|
|||
if (!m_model->eval_expr(bounds, mbounds, true))
|
||||
return;
|
||||
mbounds = subst(mbounds, qb.vars);
|
||||
std::cout << "bounds: " << mk_pp(p.first, m) << " @ " << p.second << " - " << bounds << "\n";
|
||||
std::cout << "domain eqs " << mbounds << "\n";
|
||||
std::cout << "vbounds " << vbounds << "\n";
|
||||
std::cout << *m_model << "\n";
|
||||
m_solver->assert_expr(mbounds);
|
||||
qb.domain_eqs.push_back(vbounds);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Add bounds to sub-terms under uninterpreted functions for projection.
|
||||
*/
|
||||
|
@ -279,8 +344,13 @@ namespace q {
|
|||
expr_safe_replace rep(m);
|
||||
var_subst subst(m);
|
||||
expr_ref_vector eqs(m);
|
||||
expr_mark visited;
|
||||
for (auto p : qb.var_args) {
|
||||
expr_ref _term = subst(p.first, qb.vars);
|
||||
expr* e = p.first;
|
||||
if (visited.is_marked(e))
|
||||
continue;
|
||||
visited.mark(e);
|
||||
expr_ref _term = subst(e, qb.vars);
|
||||
app_ref term(to_app(_term), m);
|
||||
expr_ref value = (*m_model)(term);
|
||||
expr* s = m_model_fixer.invert_app(term, value);
|
||||
|
@ -313,6 +383,7 @@ namespace q {
|
|||
lbool mbqi::operator()() {
|
||||
lbool result = l_true;
|
||||
m_model = nullptr;
|
||||
m_instantiations.reset();
|
||||
for (sat::literal lit : m_qs.m_universal) {
|
||||
quantifier* q = to_quantifier(ctx.bool_var2expr(lit.var()));
|
||||
if (!ctx.is_relevant(q))
|
||||
|
@ -331,6 +402,9 @@ namespace q {
|
|||
}
|
||||
}
|
||||
m_max_cex += ctx.get_config().m_mbqi_max_cexs;
|
||||
for (auto p : m_instantiations)
|
||||
m_qs.add_clause(~p.first, ~ctx.mk_literal(p.second));
|
||||
m_instantiations.reset();
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue