mirror of
https://github.com/Z3Prover/z3
synced 2025-06-06 14:13:23 +00:00
updates to recfun_decl_plugin
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
parent
ccca063e54
commit
918a5b9e8c
2 changed files with 44 additions and 69 deletions
|
@ -33,26 +33,32 @@ namespace recfun {
|
||||||
family_id fid,
|
family_id fid,
|
||||||
def * d,
|
def * d,
|
||||||
std::string & name,
|
std::string & name,
|
||||||
|
unsigned case_index,
|
||||||
sort_ref_vector const & arg_sorts,
|
sort_ref_vector const & arg_sorts,
|
||||||
unsigned num_guards, expr ** guards, expr* rhs)
|
expr_ref_vector const& guards,
|
||||||
|
expr* rhs)
|
||||||
: m_pred(m),
|
: m_pred(m),
|
||||||
m_guards(m, num_guards, guards),
|
m_guards(guards),
|
||||||
m_rhs(expr_ref(rhs,m)),
|
m_rhs(expr_ref(rhs,m)),
|
||||||
m_def(d) {
|
m_def(d) {
|
||||||
func_decl_info info(fid, OP_FUN_CASE_PRED);
|
parameter p(case_index);
|
||||||
|
func_decl_info info(fid, OP_FUN_CASE_PRED, 1, &p);
|
||||||
m_pred = m.mk_func_decl(symbol(name.c_str()), arg_sorts.size(), arg_sorts.c_ptr(), m.mk_bool_sort(), info);
|
m_pred = m.mk_func_decl(symbol(name.c_str()), arg_sorts.size(), arg_sorts.c_ptr(), m.mk_bool_sort(), info);
|
||||||
}
|
}
|
||||||
|
|
||||||
def::def(ast_manager &m, family_id fid, symbol const & s,
|
def::def(ast_manager &m, family_id fid, symbol const & s,
|
||||||
unsigned arity, sort* const * domain, sort* range)
|
unsigned arity, sort* const * domain, sort* range)
|
||||||
: m(m), m_name(s),
|
: m(m), m_name(s),
|
||||||
m_domain(m, arity, domain), m_range(range, m), m_vars(m), m_cases(),
|
m_domain(m, arity, domain),
|
||||||
m_decl(m), m_fid(fid), m_macro(false)
|
m_range(range, m), m_vars(m), m_cases(),
|
||||||
|
m_decl(m),
|
||||||
|
m_fid(fid),
|
||||||
|
m_macro(false)
|
||||||
{
|
{
|
||||||
SASSERT(arity == get_arity());
|
SASSERT(arity == get_arity());
|
||||||
|
|
||||||
func_decl_info info(fid, OP_FUN_DEFINED);
|
func_decl_info info(fid, OP_FUN_DEFINED);
|
||||||
m_decl = m.mk_func_decl(m_name, arity, domain, range, info);
|
m_decl = m.mk_func_decl(s, arity, domain, range, info);
|
||||||
}
|
}
|
||||||
|
|
||||||
// does `e` contain any `ite` construct?
|
// does `e` contain any `ite` construct?
|
||||||
|
@ -101,6 +107,8 @@ namespace recfun {
|
||||||
ite_lst const * to_split; // `ite` terms to make a choice on
|
ite_lst const * to_split; // `ite` terms to make a choice on
|
||||||
unfold_lst const * to_unfold; // terms yet to unfold
|
unfold_lst const * to_unfold; // terms yet to unfold
|
||||||
|
|
||||||
|
branch(unfold_lst const * to_unfold):
|
||||||
|
path(nullptr), to_split(nullptr), to_unfold(to_unfold) {}
|
||||||
branch(choice_lst const * path, ite_lst const * to_split, unfold_lst const * to_unfold) :
|
branch(choice_lst const * path, ite_lst const * to_split, unfold_lst const * to_unfold) :
|
||||||
path(path), to_split(to_split), to_unfold(to_unfold) {}
|
path(path), to_split(to_split), to_unfold(to_unfold) {}
|
||||||
branch(branch const & from) :
|
branch(branch const & from) :
|
||||||
|
@ -110,14 +118,12 @@ namespace recfun {
|
||||||
// state for computing cases from the RHS of a functions' definition
|
// state for computing cases from the RHS of a functions' definition
|
||||||
class case_state {
|
class case_state {
|
||||||
region m_reg;
|
region m_reg;
|
||||||
ast_manager & m_manager;
|
|
||||||
vector<branch> m_branches;
|
vector<branch> m_branches;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
case_state(ast_manager & m) : m_reg(), m_manager(m), m_branches() {}
|
case_state() : m_reg(), m_branches() {}
|
||||||
|
|
||||||
bool empty() const { return m_branches.empty(); }
|
bool empty() const { return m_branches.empty(); }
|
||||||
ast_manager & m() const { return m_manager; }
|
|
||||||
region & reg() { return m_reg; }
|
region & reg() { return m_reg; }
|
||||||
|
|
||||||
branch pop_branch() {
|
branch pop_branch() {
|
||||||
|
@ -128,7 +134,6 @@ namespace recfun {
|
||||||
|
|
||||||
void push_branch(branch const & b) { m_branches.push_back(b); }
|
void push_branch(branch const & b) { m_branches.push_back(b); }
|
||||||
|
|
||||||
|
|
||||||
unfold_lst const * cons_unfold(expr * e, unfold_lst const * next) {
|
unfold_lst const * cons_unfold(expr * e, unfold_lst const * next) {
|
||||||
return new (reg()) unfold_lst{e, next};
|
return new (reg()) unfold_lst{e, next};
|
||||||
}
|
}
|
||||||
|
@ -149,7 +154,7 @@ namespace recfun {
|
||||||
};
|
};
|
||||||
|
|
||||||
//<! build a substitution and a list of conditions from a path
|
//<! build a substitution and a list of conditions from a path
|
||||||
void convert_path(ast_manager & m,
|
static void convert_path(ast_manager & m,
|
||||||
choice_lst const * choices,
|
choice_lst const * choices,
|
||||||
expr_ref_vector & conditions /* out */,
|
expr_ref_vector & conditions /* out */,
|
||||||
expr_substitution & subst /* out */)
|
expr_substitution & subst /* out */)
|
||||||
|
@ -168,7 +173,7 @@ namespace recfun {
|
||||||
}
|
}
|
||||||
|
|
||||||
// substitute `subst` in `e`
|
// substitute `subst` in `e`
|
||||||
expr_ref replace_subst(th_rewriter & th_rw, ast_manager & m,
|
static expr_ref replace_subst(th_rewriter & th_rw, ast_manager & m,
|
||||||
expr_substitution & subst, expr * e) {
|
expr_substitution & subst, expr * e) {
|
||||||
th_rw.reset();
|
th_rw.reset();
|
||||||
th_rw.set_substitution(&subst);
|
th_rw.set_substitution(&subst);
|
||||||
|
@ -177,60 +182,43 @@ namespace recfun {
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
void def::add_case(std::string & name, unsigned n_conditions,
|
void def::add_case(std::string & name, unsigned case_index, expr_ref_vector const& conditions, expr * rhs, bool is_imm) {
|
||||||
expr ** conditions, expr * rhs, bool is_imm) {
|
case_def c(m, m_fid, this, name, case_index, get_domain(), conditions, rhs);
|
||||||
case_def c(m, m_fid, this, name, get_domain(), n_conditions, conditions, rhs);
|
|
||||||
c.set_is_immediate(is_imm);
|
c.set_is_immediate(is_imm);
|
||||||
TRACEFN("add_case " << name << " " << mk_pp(rhs, m)
|
TRACEFN("add_case " << name << " " << mk_pp(rhs, m)
|
||||||
<< " :is_imm " << is_imm
|
<< " :is_imm " << is_imm
|
||||||
<< " :guards " << mk_pp_vec(n_conditions, (ast**)conditions, m));
|
<< " :guards " << conditions);
|
||||||
m_cases.push_back(c);
|
m_cases.push_back(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Compute a set of cases, given the RHS
|
// Compute a set of cases, given the RHS
|
||||||
void def::compute_cases(is_immediate_pred & is_i, th_rewriter & th_rw,
|
void def::compute_cases(is_immediate_pred & is_i, th_rewriter & th_rw,
|
||||||
unsigned n_vars, var *const * vars, expr* rhs0)
|
unsigned n_vars, var *const * vars, expr* rhs)
|
||||||
{
|
{
|
||||||
if (!m_cases.empty()) {
|
VERIFY(m_cases.empty() && "cases cannot already be computed");
|
||||||
TRACEFN("bug: " << m_name << " has cases already");
|
|
||||||
UNREACHABLE();
|
|
||||||
}
|
|
||||||
SASSERT(m_cases.empty());
|
|
||||||
SASSERT(n_vars == m_domain.size());
|
SASSERT(n_vars == m_domain.size());
|
||||||
|
|
||||||
TRACEFN("compute cases " << mk_pp(rhs0, m));
|
TRACEFN("compute cases " << mk_pp(rhs, m));
|
||||||
|
|
||||||
unsigned case_idx = 0;
|
unsigned case_idx = 0;
|
||||||
std::string name;
|
|
||||||
|
|
||||||
|
std::string name;
|
||||||
name.append("case_");
|
name.append("case_");
|
||||||
name.append(m_name.bare_str());
|
name.append(m_name.bare_str());
|
||||||
name.append("_");
|
name.append("_");
|
||||||
|
|
||||||
for (unsigned i = 0; i < n_vars; ++i)
|
m_vars.append(n_vars, vars);
|
||||||
m_vars.push_back(vars[i]);
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
// simplify `rhs`
|
|
||||||
expr_ref simplified_rhs(m);
|
|
||||||
expr* rhs;
|
|
||||||
th_rw.reset();
|
|
||||||
th_rw(rhs0, simplified_rhs);
|
|
||||||
rhs = simplified_rhs.get();
|
|
||||||
|
|
||||||
TRACEFN("simplified into " << mk_pp(rhs, m()));
|
|
||||||
#else
|
|
||||||
expr* rhs = rhs0;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// is the function a macro (unconditional body)?
|
// is the function a macro (unconditional body)?
|
||||||
m_macro = n_vars == 0 || !contains_ite(rhs);
|
m_macro = n_vars == 0 || !contains_ite(rhs);
|
||||||
|
|
||||||
|
expr_ref_vector conditions(m);
|
||||||
|
|
||||||
if (m_macro) {
|
if (m_macro) {
|
||||||
// constant function or trivial control flow, only one (dummy) case
|
// constant function or trivial control flow, only one (dummy) case
|
||||||
name.append("dummy");
|
name.append("dummy");
|
||||||
add_case(name, 0, nullptr, rhs);
|
add_case(name, 0, conditions, rhs);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -238,11 +226,9 @@ namespace recfun {
|
||||||
// rebuilding a `ite`-free RHS on the fly for each path in `rhs`.
|
// rebuilding a `ite`-free RHS on the fly for each path in `rhs`.
|
||||||
// Each such `ite`-free term is converted into a case_def and added to definition.
|
// Each such `ite`-free term is converted into a case_def and added to definition.
|
||||||
|
|
||||||
case_state st(m);
|
case_state st;
|
||||||
{
|
|
||||||
branch b(nullptr, nullptr, st.mk_unfold_lst(rhs));
|
st.push_branch(branch(st.mk_unfold_lst(rhs)));
|
||||||
st.push_branch(b);
|
|
||||||
}
|
|
||||||
|
|
||||||
while (! st.empty()) {
|
while (! st.empty()) {
|
||||||
TRACEFN("main loop iter");
|
TRACEFN("main loop iter");
|
||||||
|
@ -301,31 +287,19 @@ namespace recfun {
|
||||||
else {
|
else {
|
||||||
// leaf of the search tree
|
// leaf of the search tree
|
||||||
|
|
||||||
expr_ref_vector conditions_raw(m);
|
conditions.reset();
|
||||||
expr_substitution subst(m);
|
expr_substitution subst(m);
|
||||||
convert_path(m, b.path, conditions_raw, subst);
|
convert_path(m, b.path, conditions, subst);
|
||||||
|
|
||||||
// substitute, to get rid of `ite` terms
|
// substitute, to get rid of `ite` terms
|
||||||
expr_ref case_rhs = replace_subst(th_rw, m, subst, rhs);
|
expr_ref case_rhs = replace_subst(th_rw, m, subst, rhs);
|
||||||
expr_ref_vector conditions(m);
|
for (unsigned i = 0; i < conditions.size(); ++i) {
|
||||||
for (expr * g : conditions_raw) {
|
conditions[i] = replace_subst(th_rw, m, subst, conditions.get(i));
|
||||||
expr_ref g_subst(replace_subst(th_rw, m, subst, g), m);
|
|
||||||
conditions.push_back(g_subst);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
size_t old_name_len = name.size();
|
|
||||||
{ // TODO: optimize? this does many copies
|
|
||||||
std::ostringstream sout;
|
|
||||||
sout << ((unsigned long) case_idx);
|
|
||||||
name.append(sout.str());
|
|
||||||
}
|
|
||||||
case_idx ++;
|
|
||||||
|
|
||||||
// yield new case
|
// yield new case
|
||||||
bool is_imm = is_i(case_rhs);
|
bool is_imm = is_i(case_rhs);
|
||||||
add_case(name, conditions.size(), conditions.c_ptr(), case_rhs, is_imm);
|
add_case(name, case_idx++, conditions, case_rhs, is_imm);
|
||||||
name.resize(old_name_len);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -466,7 +440,8 @@ namespace recfun {
|
||||||
case OP_FUN_DEFINED:
|
case OP_FUN_DEFINED:
|
||||||
return mk_fun_defined_decl(k, num_parameters, parameters, arity, domain, range);
|
return mk_fun_defined_decl(k, num_parameters, parameters, arity, domain, range);
|
||||||
default:
|
default:
|
||||||
UNREACHABLE(); return 0;
|
UNREACHABLE();
|
||||||
|
return nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,9 +55,9 @@ namespace recfun {
|
||||||
family_id fid,
|
family_id fid,
|
||||||
def * d,
|
def * d,
|
||||||
std::string & name,
|
std::string & name,
|
||||||
|
unsigned case_index,
|
||||||
sort_ref_vector const & arg_sorts,
|
sort_ref_vector const & arg_sorts,
|
||||||
unsigned num_guards,
|
expr_ref_vector const& guards,
|
||||||
expr** guards,
|
|
||||||
expr* rhs);
|
expr* rhs);
|
||||||
|
|
||||||
void add_guard(expr_ref && e) { m_guards.push_back(e); }
|
void add_guard(expr_ref && e) { m_guards.push_back(e); }
|
||||||
|
@ -104,7 +104,7 @@ namespace recfun {
|
||||||
// compute cases for a function, given its RHS (possibly containing `ite`).
|
// compute cases for a function, given its RHS (possibly containing `ite`).
|
||||||
void compute_cases(is_immediate_pred &, th_rewriter & th_rw,
|
void compute_cases(is_immediate_pred &, th_rewriter & th_rw,
|
||||||
unsigned n_vars, var *const * vars, expr* rhs);
|
unsigned n_vars, var *const * vars, expr* rhs);
|
||||||
void add_case(std::string & name, unsigned n_conds, expr ** conditions, expr* rhs, bool is_imm = false);
|
void add_case(std::string & name, unsigned case_index, expr_ref_vector const& conditions, expr* rhs, bool is_imm = false);
|
||||||
bool contains_ite(expr* e); // expression contains a test?
|
bool contains_ite(expr* e); // expression contains a test?
|
||||||
public:
|
public:
|
||||||
symbol const & get_name() const { return m_name; }
|
symbol const & get_name() const { return m_name; }
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue