mirror of
https://github.com/Z3Prover/z3
synced 2025-06-13 01:16:15 +00:00
add recfuns to model
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
parent
51a0022450
commit
80acf8ed79
9 changed files with 45 additions and 15 deletions
|
@ -1360,7 +1360,8 @@ ast_manager::ast_manager(ast_manager const & src, bool disable_proofs):
|
||||||
m_proof_mode(disable_proofs ? PGM_DISABLED : src.m_proof_mode),
|
m_proof_mode(disable_proofs ? PGM_DISABLED : src.m_proof_mode),
|
||||||
m_trace_stream(src.m_trace_stream),
|
m_trace_stream(src.m_trace_stream),
|
||||||
m_trace_stream_owner(false),
|
m_trace_stream_owner(false),
|
||||||
m_rec_fun(":rec-fun") {
|
m_rec_fun(":rec-fun"),
|
||||||
|
m_lambda_def(":lambda-def") {
|
||||||
SASSERT(!src.is_format_manager());
|
SASSERT(!src.is_format_manager());
|
||||||
m_format_manager = alloc(ast_manager, PGM_DISABLED, m_trace_stream, true);
|
m_format_manager = alloc(ast_manager, PGM_DISABLED, m_trace_stream, true);
|
||||||
init();
|
init();
|
||||||
|
|
|
@ -1636,7 +1636,7 @@ public:
|
||||||
bool are_distinct(expr * a, expr * b) const;
|
bool are_distinct(expr * a, expr * b) const;
|
||||||
|
|
||||||
bool contains(ast * a) const { return m_ast_table.contains(a); }
|
bool contains(ast * a) const { return m_ast_table.contains(a); }
|
||||||
|
|
||||||
bool is_rec_fun_def(quantifier* q) const { return q->get_qid() == m_rec_fun; }
|
bool is_rec_fun_def(quantifier* q) const { return q->get_qid() == m_rec_fun; }
|
||||||
bool is_lambda_def(quantifier* q) const { return q->get_qid() == m_lambda_def; }
|
bool is_lambda_def(quantifier* q) const { return q->get_qid() == m_lambda_def; }
|
||||||
func_decl* get_rec_fun_decl(quantifier* q) const;
|
func_decl* get_rec_fun_decl(quantifier* q) const;
|
||||||
|
|
|
@ -56,6 +56,7 @@ namespace recfun {
|
||||||
m_domain(m, arity, domain),
|
m_domain(m, arity, domain),
|
||||||
m_range(range, m), m_vars(m), m_cases(),
|
m_range(range, m), m_vars(m), m_cases(),
|
||||||
m_decl(m),
|
m_decl(m),
|
||||||
|
m_rhs(m),
|
||||||
m_fid(fid)
|
m_fid(fid)
|
||||||
{
|
{
|
||||||
SASSERT(arity == get_arity());
|
SASSERT(arity == get_arity());
|
||||||
|
@ -211,7 +212,7 @@ namespace recfun {
|
||||||
name.append(m_name.bare_str());
|
name.append(m_name.bare_str());
|
||||||
|
|
||||||
m_vars.append(n_vars, vars);
|
m_vars.append(n_vars, vars);
|
||||||
|
m_rhs = rhs;
|
||||||
|
|
||||||
expr_ref_vector conditions(m);
|
expr_ref_vector conditions(m);
|
||||||
|
|
||||||
|
|
|
@ -99,6 +99,7 @@ namespace recfun {
|
||||||
vars m_vars; //<! variables of the function
|
vars m_vars; //<! variables of the function
|
||||||
cases m_cases; //!< possible cases
|
cases m_cases; //!< possible cases
|
||||||
func_decl_ref m_decl; //!< generic declaration
|
func_decl_ref m_decl; //!< generic declaration
|
||||||
|
expr_ref m_rhs; //!< definition
|
||||||
family_id m_fid;
|
family_id m_fid;
|
||||||
|
|
||||||
def(ast_manager &m, family_id fid, symbol const & s, unsigned arity, sort *const * domain, sort* range);
|
def(ast_manager &m, family_id fid, symbol const & s, unsigned arity, sort *const * domain, sort* range);
|
||||||
|
@ -116,13 +117,11 @@ namespace recfun {
|
||||||
sort_ref_vector const & get_domain() const { return m_domain; }
|
sort_ref_vector const & get_domain() const { return m_domain; }
|
||||||
sort_ref const & get_range() const { return m_range; }
|
sort_ref const & get_range() const { return m_range; }
|
||||||
func_decl * get_decl() const { return m_decl.get(); }
|
func_decl * get_decl() const { return m_decl.get(); }
|
||||||
|
expr * get_rhs() const { return m_rhs; }
|
||||||
|
|
||||||
bool is_fun_macro() const { return m_cases.size() == 1; }
|
bool is_fun_macro() const { return m_cases.size() == 1; }
|
||||||
bool is_fun_defined() const { return !is_fun_macro(); }
|
bool is_fun_defined() const { return !is_fun_macro(); }
|
||||||
|
|
||||||
expr * get_macro_rhs() const {
|
|
||||||
return m_cases[0].get_rhs();
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// definition to be complete (missing RHS)
|
// definition to be complete (missing RHS)
|
||||||
|
@ -180,7 +179,12 @@ namespace recfun {
|
||||||
def& get_def(func_decl* f) { return *(m_defs[f]); }
|
def& get_def(func_decl* f) { return *(m_defs[f]); }
|
||||||
bool has_case_def(func_decl* f) const { return m_case_defs.contains(f); }
|
bool has_case_def(func_decl* f) const { return m_case_defs.contains(f); }
|
||||||
case_def& get_case_def(func_decl* f) { SASSERT(has_case_def(f)); return *(m_case_defs[f]); }
|
case_def& get_case_def(func_decl* f) { SASSERT(has_case_def(f)); return *(m_case_defs[f]); }
|
||||||
//bool is_declared(symbol const& s) const { return m_defs.contains(s); }
|
|
||||||
|
func_decl_ref_vector get_rec_funs() {
|
||||||
|
func_decl_ref_vector result(m());
|
||||||
|
for (auto& kv : m_defs) result.push_back(kv.m_key);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -232,6 +236,10 @@ namespace recfun {
|
||||||
return mk_fun_defined(d, args.size(), args.c_ptr());
|
return mk_fun_defined(d, args.size(), args.c_ptr());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func_decl_ref_vector get_rec_funs() {
|
||||||
|
return m_plugin->get_rec_funs();
|
||||||
|
}
|
||||||
|
|
||||||
app_ref mk_depth_limit_pred(unsigned d);
|
app_ref mk_depth_limit_pred(unsigned d);
|
||||||
|
|
||||||
decl::plugin& get_plugin() { return *m_plugin; }
|
decl::plugin& get_plugin() { return *m_plugin; }
|
||||||
|
|
|
@ -279,8 +279,9 @@ protected:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool get_macro(func_decl * f, expr * & def, quantifier * & q, proof * & def_pr) {
|
bool get_macro(func_decl * f, expr * & def, proof * & def_pr) {
|
||||||
return m_cfg.get_macro(f, def, q, def_pr);
|
quantifier* q = nullptr;
|
||||||
|
return m_cfg.get_macro(f, def, q, def_pr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void push_frame(expr * t, bool mcache, unsigned max_depth) {
|
void push_frame(expr * t, bool mcache, unsigned max_depth) {
|
||||||
|
|
|
@ -212,6 +212,7 @@ bool rewriter_tpl<Config>::constant_fold(app * t, frame & fr) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
template<typename Config>
|
template<typename Config>
|
||||||
template<bool ProofGen>
|
template<bool ProofGen>
|
||||||
void rewriter_tpl<Config>::process_app(app * t, frame & fr) {
|
void rewriter_tpl<Config>::process_app(app * t, frame & fr) {
|
||||||
|
@ -338,15 +339,12 @@ void rewriter_tpl<Config>::process_app(app * t, frame & fr) {
|
||||||
// TODO: add rewrite rules support
|
// TODO: add rewrite rules support
|
||||||
expr * def = nullptr;
|
expr * def = nullptr;
|
||||||
proof * def_pr = nullptr;
|
proof * def_pr = nullptr;
|
||||||
quantifier * def_q = nullptr;
|
|
||||||
// When get_macro succeeds, then
|
// When get_macro succeeds, then
|
||||||
// we know that:
|
// we know that:
|
||||||
// forall X. f(X) = def[X]
|
// forall X. f(X) = def[X]
|
||||||
// and def_pr is a proof for this quantifier.
|
// and def_pr is a proof for this quantifier.
|
||||||
//
|
//
|
||||||
// Remark: def_q is only used for proof generation.
|
if (get_macro(f, def, def_pr)) {
|
||||||
// It is the quantifier forall X. f(X) = def[X]
|
|
||||||
if (get_macro(f, def, def_q, def_pr)) {
|
|
||||||
SASSERT(!f->is_associative() || !flat_assoc(f));
|
SASSERT(!f->is_associative() || !flat_assoc(f));
|
||||||
SASSERT(new_num_args == t->get_num_args());
|
SASSERT(new_num_args == t->get_num_args());
|
||||||
SASSERT(m().get_sort(def) == m().get_sort(t));
|
SASSERT(m().get_sort(def) == m().get_sort(t));
|
||||||
|
|
|
@ -96,6 +96,6 @@ def_module_params(module_name='smt',
|
||||||
('core.extend_nonlocal_patterns', BOOL, False, 'extend unsat cores with literals that have quantifiers with patterns that contain symbols which are not in the quantifier\'s body'),
|
('core.extend_nonlocal_patterns', BOOL, False, 'extend unsat cores with literals that have quantifiers with patterns that contain symbols which are not in the quantifier\'s body'),
|
||||||
('lemma_gc_strategy', UINT, 0, 'lemma garbage collection strategy: 0 - fixed, 1 - geometric, 2 - at restart, 3 - none'),
|
('lemma_gc_strategy', UINT, 0, 'lemma garbage collection strategy: 0 - fixed, 1 - geometric, 2 - at restart, 3 - none'),
|
||||||
('dt_lazy_splits', UINT, 1, 'How lazy datatype splits are performed: 0- eager, 1- lazy for infinite types, 2- lazy'),
|
('dt_lazy_splits', UINT, 1, 'How lazy datatype splits are performed: 0- eager, 1- lazy for infinite types, 2- lazy'),
|
||||||
('recfun.native', BOOL, False, 'use native rec-fun solver'),
|
('recfun.native', BOOL, True, 'use native rec-fun solver'),
|
||||||
('recfun.depth', UINT, 2, 'initial depth for maxrec expansion')
|
('recfun.depth', UINT, 2, 'initial depth for maxrec expansion')
|
||||||
))
|
))
|
||||||
|
|
|
@ -37,6 +37,7 @@ Revision History:
|
||||||
#include "model/model_pp.h"
|
#include "model/model_pp.h"
|
||||||
#include "ast/ast_smt2_pp.h"
|
#include "ast/ast_smt2_pp.h"
|
||||||
#include "ast/ast_translation.h"
|
#include "ast/ast_translation.h"
|
||||||
|
#include "ast/recfun_decl_plugin.h"
|
||||||
|
|
||||||
namespace smt {
|
namespace smt {
|
||||||
|
|
||||||
|
@ -4453,6 +4454,26 @@ namespace smt {
|
||||||
m_model->register_decl(f, fi);
|
m_model->register_decl(f, fi);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
recfun::util u(m);
|
||||||
|
recfun::decl::plugin& p = u.get_plugin();
|
||||||
|
func_decl_ref_vector recfuns = u.get_rec_funs();
|
||||||
|
for (func_decl* f : recfuns) {
|
||||||
|
auto& def = u.get_def(f);
|
||||||
|
expr* rhs = def.get_rhs();
|
||||||
|
if (!rhs) continue;
|
||||||
|
func_interp* fi = alloc(func_interp, m, f->get_arity());
|
||||||
|
// reverse argument order so that variable 0 starts at the beginning.
|
||||||
|
expr_ref_vector subst(m);
|
||||||
|
unsigned idx = 0;
|
||||||
|
for (unsigned i = 0; i < f->get_arity(); ++i) {
|
||||||
|
subst.push_back(m.mk_var(i, f->get_domain(i)));
|
||||||
|
}
|
||||||
|
var_subst sub(m, true);
|
||||||
|
expr_ref bodyr = sub(rhs, subst.size(), subst.c_ptr());
|
||||||
|
|
||||||
|
fi->set_else(bodyr);
|
||||||
|
m_model->register_decl(f, fi);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -306,7 +306,7 @@ namespace smt {
|
||||||
auto & vars = e.m_def->get_vars();
|
auto & vars = e.m_def->get_vars();
|
||||||
expr_ref lhs(e.m_lhs, m);
|
expr_ref lhs(e.m_lhs, m);
|
||||||
unsigned depth = get_depth(e.m_lhs);
|
unsigned depth = get_depth(e.m_lhs);
|
||||||
expr_ref rhs(apply_args(depth, vars, e.m_args, e.m_def->get_macro_rhs()), m);
|
expr_ref rhs(apply_args(depth, vars, e.m_args, e.m_def->get_rhs()), m);
|
||||||
literal lit = mk_eq_lit(lhs, rhs);
|
literal lit = mk_eq_lit(lhs, rhs);
|
||||||
ctx().mk_th_axiom(get_id(), 1, &lit);
|
ctx().mk_th_axiom(get_id(), 1, &lit);
|
||||||
TRACEFN("macro expansion yields " << mk_pp(rhs, m) << "\n" <<
|
TRACEFN("macro expansion yields " << mk_pp(rhs, m) << "\n" <<
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue