mirror of
https://github.com/Z3Prover/z3
synced 2025-04-28 19:35:50 +00:00
model refactor (#4723)
* refactor model fixing Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * missing cond macro Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * file Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * file Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * add macros dependency Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * deps and debug Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * add dependency to normal forms Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * na Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * build issues Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * compile Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * fix leal regression * complete model fixer Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * fold back private functionality to model_finder Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * avoid duplicate fixed callbacks Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
parent
6cc52e04c3
commit
fa58a36b9f
42 changed files with 2060 additions and 1494 deletions
198
src/sat/smt/q_model_fixer.cpp
Normal file
198
src/sat/smt/q_model_fixer.cpp
Normal file
|
@ -0,0 +1,198 @@
|
|||
/*++
|
||||
Copyright (c) 2020 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
q_model_fixer.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
Model-based quantifier instantiation model-finder plugin
|
||||
|
||||
Author:
|
||||
|
||||
Nikolaj Bjorner (nbjorner) 2020-10-02
|
||||
|
||||
Notes:
|
||||
|
||||
Derives from smt/smt_model_finder.cpp
|
||||
|
||||
--*/
|
||||
|
||||
|
||||
#include "ast/for_each_expr.h"
|
||||
#include "ast/arith_decl_plugin.h"
|
||||
#include "ast/bv_decl_plugin.h"
|
||||
#include "model/model_macro_solver.h"
|
||||
#include "sat/smt/q_model_fixer.h"
|
||||
#include "sat/smt/q_solver.h"
|
||||
#include "sat/smt/euf_solver.h"
|
||||
|
||||
|
||||
namespace q {
|
||||
|
||||
template<typename U>
|
||||
static bool lt(U const& u, expr* x, expr* y) {
|
||||
rational v1, v2;
|
||||
if (u.is_numeral(x, v1) && u.is_numeral(y, v2))
|
||||
return v1 < v2;
|
||||
else
|
||||
return x->get_id() < y->get_id();
|
||||
}
|
||||
|
||||
class arith_projection : public projection_function {
|
||||
ast_manager& m;
|
||||
arith_util a;
|
||||
public:
|
||||
bool operator()(expr* e1, expr* e2) const { return lt(a, e1, e2); }
|
||||
arith_projection(ast_manager& m): m(m), a(m) {}
|
||||
~arith_projection() override {}
|
||||
void sort(ptr_buffer<expr>& values) override { std::sort(values.begin(), values.end(), *this); }
|
||||
expr* mk_lt(expr* x, expr* y) override { return a.mk_lt(x, y); }
|
||||
};
|
||||
|
||||
class ubv_projection : public projection_function {
|
||||
ast_manager& m;
|
||||
bv_util bvu;
|
||||
public:
|
||||
bool operator()(expr* e1, expr* e2) const { return lt(bvu, e1, e2); }
|
||||
ubv_projection(ast_manager& m): m(m), bvu(m) {}
|
||||
~ubv_projection() override {}
|
||||
void sort(ptr_buffer<expr>& values) override { std::sort(values.begin(), values.end(), *this); }
|
||||
expr* mk_lt(expr* x, expr* y) override { return m.mk_not(bvu.mk_ule(y, x)); }
|
||||
};
|
||||
|
||||
model_fixer::model_fixer(euf::solver& ctx, q::solver& qs) :
|
||||
ctx(ctx), m_qs(qs), m(ctx.get_manager()), m_dependencies(m) {}
|
||||
|
||||
void model_fixer::operator()(model& mdl) {
|
||||
ptr_vector<quantifier> univ;
|
||||
for (sat::literal lit : m_qs.universal()) {
|
||||
quantifier* q = to_quantifier(ctx.bool_var2expr(lit.var()));
|
||||
if (ctx.is_relevant(q))
|
||||
univ.push_back(q);
|
||||
}
|
||||
if (univ.empty())
|
||||
return;
|
||||
|
||||
m_dependencies.reset();
|
||||
ptr_vector<quantifier> residue;
|
||||
|
||||
simple_macro_solver sms(m, *this);
|
||||
sms(mdl, univ, residue);
|
||||
|
||||
hint_macro_solver hms(m, *this);
|
||||
hms(mdl, univ, residue);
|
||||
|
||||
non_auf_macro_solver nas(m, *this, m_dependencies);
|
||||
nas.set_mbqi_force_template(ctx.get_config().m_mbqi_force_template);
|
||||
nas(mdl, univ, residue);
|
||||
|
||||
univ.append(residue);
|
||||
add_projection_functions(mdl, univ);
|
||||
}
|
||||
|
||||
quantifier_macro_info* model_fixer::operator()(quantifier* q) {
|
||||
quantifier_macro_info* info = nullptr;
|
||||
if (!m_q2info.find(q, info)) {
|
||||
info = alloc(quantifier_macro_info, m, m_qs.flatten(q));
|
||||
m_q2info.insert(q, info);
|
||||
ctx.push(new_obj_trail<euf::solver, quantifier_macro_info>(info));
|
||||
ctx.push(insert_obj_map<euf::solver, quantifier, quantifier_macro_info*>(m_q2info, q));
|
||||
}
|
||||
return info;
|
||||
}
|
||||
|
||||
void model_fixer::add_projection_functions(model& mdl, ptr_vector<quantifier> const& qs) {
|
||||
func_decl_set fns;
|
||||
collect_partial_functions(qs, fns);
|
||||
for (func_decl* f : fns)
|
||||
add_projection_functions(mdl, f);
|
||||
}
|
||||
|
||||
void model_fixer::add_projection_functions(model& mdl, func_decl* f) {
|
||||
// update interpretation of f so that the graph of f is fully determined by the
|
||||
// ground values of its arguments.
|
||||
func_interp* fi = mdl.get_func_interp(f);
|
||||
if (!fi)
|
||||
return;
|
||||
if (fi->is_constant())
|
||||
return;
|
||||
expr_ref_vector args(m);
|
||||
for (unsigned i = 0; i < f->get_arity(); ++i)
|
||||
args.push_back(add_projection_function(mdl, f, i));
|
||||
if (!fi->get_else() && fi->num_entries() > 0)
|
||||
fi->set_else(fi->get_entry(ctx.s().rand()(fi->num_entries()))->get_result());
|
||||
bool has_projection = false;
|
||||
for (expr* arg : args)
|
||||
has_projection |= !is_var(arg);
|
||||
if (!has_projection)
|
||||
return;
|
||||
func_interp* new_fi = alloc(func_interp, m, f->get_arity());
|
||||
func_decl* f_new = m.mk_fresh_func_decl(f->get_name(), symbol("aux"), f->get_arity(), f->get_domain(), f->get_range());
|
||||
new_fi->set_else(m.mk_app(f_new, args));
|
||||
mdl.update_func_interp(f, new_fi);
|
||||
mdl.register_decl(f_new, fi);
|
||||
}
|
||||
|
||||
expr_ref model_fixer::add_projection_function(model& mdl, func_decl* f, unsigned idx) {
|
||||
sort* srt = f->get_domain(idx);
|
||||
projection_function* proj = get_projection(srt);
|
||||
if (!proj)
|
||||
return expr_ref(m.mk_var(idx, srt), m);
|
||||
ptr_buffer<expr> values;
|
||||
for (euf::enode* n : ctx.get_egraph().enodes_of(f))
|
||||
values.push_back(mdl(n->get_arg(idx)->get_expr()));
|
||||
if (values.empty())
|
||||
return expr_ref(m.mk_var(idx, srt), m);
|
||||
proj->sort(values);
|
||||
unsigned j = 0;
|
||||
for (unsigned i = 0; i < values.size(); ++i)
|
||||
if (i == 0 || values[i-1] != values[i])
|
||||
values[j++] = values[i];
|
||||
values.shrink(j);
|
||||
|
||||
unsigned sz = values.size();
|
||||
expr_ref var(m.mk_var(0, srt), m);
|
||||
expr_ref pi(values.get(sz-1), m);
|
||||
for (unsigned i = sz - 1; i >= 1; i--) {
|
||||
expr* c = proj->mk_lt(var, values[i]);
|
||||
pi = m.mk_ite(c, values[i - 1], pi);
|
||||
}
|
||||
func_interp* rpi = alloc(func_interp, m, 1);
|
||||
rpi->set_else(pi);
|
||||
func_decl * p = m.mk_fresh_func_decl(1, &srt, srt);
|
||||
mdl.register_decl(p, rpi);
|
||||
return expr_ref(m.mk_app(p, m.mk_var(idx, srt)), m);
|
||||
}
|
||||
|
||||
projection_function* model_fixer::get_projection(sort* srt) {
|
||||
projection_function* proj = nullptr;
|
||||
if (m_projections.find(srt, proj))
|
||||
return proj;
|
||||
arith_util autil(m);
|
||||
bv_util butil(m);
|
||||
if (autil.is_real(srt) || autil.is_int(srt))
|
||||
proj = alloc(arith_projection, m);
|
||||
else if (butil.is_bv_sort(srt))
|
||||
proj = alloc(ubv_projection, m);
|
||||
// TBD: sbv_projection? FP, ADT projection?
|
||||
if (!proj)
|
||||
return nullptr;
|
||||
m_projections.insert(srt, proj);
|
||||
ctx.push(new_obj_trail<euf::solver, projection_function>(proj));
|
||||
ctx.push(insert_obj_map<euf::solver, sort, projection_function*>(m_projections, srt));
|
||||
return proj;
|
||||
}
|
||||
|
||||
void model_fixer::collect_partial_functions(ptr_vector<quantifier> const& qs, func_decl_set& fns) {
|
||||
for (quantifier* q : qs) {
|
||||
auto* info = (*this)(q);
|
||||
quantifier* flat_q = info->get_flat_q();
|
||||
expr_ref body(flat_q->get_expr(), m);
|
||||
for (expr* t : subterms(body))
|
||||
if (is_uninterp(t) && !to_app(t)->is_ground())
|
||||
fns.insert(to_app(t)->get_decl());
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue