mirror of
https://github.com/Z3Prover/z3
synced 2025-04-27 19:05:51 +00:00
integrate lambda expressions
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
parent
bf4edef761
commit
520ce9a5ee
139 changed files with 2243 additions and 1506 deletions
|
@ -15,11 +15,12 @@ Author:
|
|||
Revision History:
|
||||
|
||||
--*/
|
||||
#include "model/func_interp.h"
|
||||
#include "ast/rewriter/var_subst.h"
|
||||
#include "util/obj_hashtable.h"
|
||||
#include "ast/rewriter/var_subst.h"
|
||||
#include "ast/ast_pp.h"
|
||||
#include "ast/ast_smt2_pp.h"
|
||||
#include "ast/ast_util.h"
|
||||
#include "model/func_interp.h"
|
||||
|
||||
func_entry::func_entry(ast_manager & m, unsigned arity, expr * const * args, expr * result):
|
||||
m_args_are_values(true),
|
||||
|
@ -77,10 +78,7 @@ func_interp::func_interp(ast_manager & m, unsigned arity):
|
|||
}
|
||||
|
||||
func_interp::~func_interp() {
|
||||
ptr_vector<func_entry>::iterator it = m_entries.begin();
|
||||
ptr_vector<func_entry>::iterator end = m_entries.end();
|
||||
for (; it != end; ++it) {
|
||||
func_entry * curr = *it;
|
||||
for (func_entry* curr : m_entries) {
|
||||
curr->deallocate(m_manager, m_arity);
|
||||
}
|
||||
m_manager.dec_ref(m_else);
|
||||
|
@ -90,10 +88,7 @@ func_interp::~func_interp() {
|
|||
func_interp * func_interp::copy() const {
|
||||
func_interp * new_fi = alloc(func_interp, m_manager, m_arity);
|
||||
|
||||
ptr_vector<func_entry>::const_iterator it = m_entries.begin();
|
||||
ptr_vector<func_entry>::const_iterator end = m_entries.end();
|
||||
for (; it != end; ++it) {
|
||||
func_entry * curr = *it;
|
||||
for (func_entry * curr : m_entries) {
|
||||
new_fi->insert_new_entry(curr->get_args(), curr->get_result());
|
||||
}
|
||||
new_fi->set_else(m_else);
|
||||
|
@ -141,9 +136,11 @@ void func_interp::set_else(expr * e) {
|
|||
return;
|
||||
|
||||
reset_interp_cache();
|
||||
|
||||
TRACE("func_interp", tout << "set_else: " << expr_ref(e, m()) << "\n";);
|
||||
|
||||
ptr_vector<expr> args;
|
||||
while (e && is_fi_entry_expr(e, args)) {
|
||||
TRACE("func_interp", tout << "fi entry expr: " << mk_ismt2_pp(e, m()) << std::endl;);
|
||||
insert_entry(args.c_ptr(), to_app(e)->get_arg(1));
|
||||
e = to_app(e)->get_arg(2);
|
||||
}
|
||||
|
@ -161,10 +158,7 @@ bool func_interp::is_constant() const {
|
|||
return false;
|
||||
if (!is_ground(m_else))
|
||||
return false;
|
||||
ptr_vector<func_entry>::const_iterator it = m_entries.begin();
|
||||
ptr_vector<func_entry>::const_iterator end = m_entries.end();
|
||||
for (; it != end; ++it) {
|
||||
func_entry * curr = *it;
|
||||
for (func_entry* curr : m_entries) {
|
||||
if (curr->get_result() != m_else)
|
||||
return false;
|
||||
}
|
||||
|
@ -177,10 +171,7 @@ bool func_interp::is_constant() const {
|
|||
args_are_values to true if for all entries e e.args_are_values() is true.
|
||||
*/
|
||||
func_entry * func_interp::get_entry(expr * const * args) const {
|
||||
ptr_vector<func_entry>::const_iterator it = m_entries.begin();
|
||||
ptr_vector<func_entry>::const_iterator end = m_entries.end();
|
||||
for (; it != end; ++it) {
|
||||
func_entry * curr = *it;
|
||||
for (func_entry* curr : m_entries) {
|
||||
if (curr->eq_args(m(), m_arity, args))
|
||||
return curr;
|
||||
}
|
||||
|
@ -224,7 +215,7 @@ bool func_interp::eval_else(expr * const * args, expr_ref & result) const {
|
|||
return false;
|
||||
var_subst s(m_manager, false);
|
||||
SASSERT(!s.std_order()); // (VAR 0) <- args[0], (VAR 1) <- args[1], ...
|
||||
s(m_else, m_arity, args, result);
|
||||
result = s(m_else, m_arity, args);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -237,10 +228,7 @@ expr * func_interp::get_max_occ_result() const {
|
|||
obj_map<expr, unsigned> num_occs;
|
||||
expr * r_max = nullptr;
|
||||
unsigned max = 0;
|
||||
ptr_vector<func_entry>::const_iterator it = m_entries.begin();
|
||||
ptr_vector<func_entry>::const_iterator end = m_entries.end();
|
||||
for (; it != end; ++it) {
|
||||
func_entry * curr = *it;
|
||||
for (func_entry * curr : m_entries) {
|
||||
expr * r = curr->get_result();
|
||||
unsigned occs = 0;
|
||||
num_occs.find(r, occs);
|
||||
|
@ -262,15 +250,11 @@ void func_interp::compress() {
|
|||
return; // nothing to be done
|
||||
if (!is_ground(m_else))
|
||||
return; // forall entries e in m_entries e.get_result() is ground
|
||||
unsigned i = 0;
|
||||
unsigned j = 0;
|
||||
unsigned sz = m_entries.size();
|
||||
m_args_are_values = true;
|
||||
for (; i < sz; i++) {
|
||||
func_entry * curr = m_entries[i];
|
||||
for (func_entry * curr : m_entries) {
|
||||
if (curr->get_result() != m_else) {
|
||||
m_entries[j] = curr;
|
||||
j++;
|
||||
m_entries[j++] = curr;
|
||||
if (!curr->args_are_values())
|
||||
m_args_are_values = false;
|
||||
}
|
||||
|
@ -278,10 +262,58 @@ void func_interp::compress() {
|
|||
curr->deallocate(m_manager, m_arity);
|
||||
}
|
||||
}
|
||||
if (j < sz) {
|
||||
if (j < m_entries.size()) {
|
||||
reset_interp_cache();
|
||||
m_entries.shrink(j);
|
||||
}
|
||||
// other compression, if else is a default branch.
|
||||
// or function encode identity.
|
||||
if (m_manager.is_false(m_else)) {
|
||||
expr_ref new_else(get_interp(), m_manager);
|
||||
for (func_entry * curr : m_entries) {
|
||||
curr->deallocate(m_manager, m_arity);
|
||||
}
|
||||
m_entries.reset();
|
||||
reset_interp_cache();
|
||||
m_manager.inc_ref(new_else);
|
||||
m_manager.dec_ref(m_else);
|
||||
m_else = new_else;
|
||||
}
|
||||
else if (!m_entries.empty() && is_identity()) {
|
||||
for (func_entry * curr : m_entries) {
|
||||
curr->deallocate(m_manager, m_arity);
|
||||
}
|
||||
m_entries.reset();
|
||||
reset_interp_cache();
|
||||
expr_ref new_else(m_manager.mk_var(0, m_manager.get_sort(m_else)), m_manager);
|
||||
m_manager.inc_ref(new_else);
|
||||
m_manager.dec_ref(m_else);
|
||||
m_else = new_else;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief check if function is identity
|
||||
*/
|
||||
bool func_interp::is_identity() const {
|
||||
if (m_arity != 1) return false;
|
||||
if (m_else == nullptr) return false;
|
||||
|
||||
// all entries map a value to itself
|
||||
for (func_entry * curr : m_entries) {
|
||||
if (curr->get_arg(0) != curr->get_result()) return false;
|
||||
if (curr->get_result() == m_else) return false;
|
||||
}
|
||||
if (is_var(m_else)) return true;
|
||||
if (!m_manager.is_value(m_else)) return false;
|
||||
sort_size const& sz = m_manager.get_sort(m_else)->get_num_elements();
|
||||
if (!sz.is_finite()) return false;
|
||||
|
||||
//
|
||||
// the else entry is a value not covered by other entries
|
||||
// it, together with the entries covers the entire domain.
|
||||
//
|
||||
return (sz.size() == m_entries.size() + 1);
|
||||
}
|
||||
|
||||
expr * func_interp::get_interp_core() const {
|
||||
|
@ -289,10 +321,10 @@ expr * func_interp::get_interp_core() const {
|
|||
return nullptr;
|
||||
expr * r = m_else;
|
||||
ptr_buffer<expr> vars;
|
||||
ptr_vector<func_entry>::const_iterator it = m_entries.begin();
|
||||
ptr_vector<func_entry>::const_iterator end = m_entries.end();
|
||||
for (; it != end; ++it) {
|
||||
func_entry * curr = *it;
|
||||
for (func_entry * curr : m_entries) {
|
||||
if (m_else == curr->get_result()) {
|
||||
continue;
|
||||
}
|
||||
if (vars.empty()) {
|
||||
for (unsigned i = 0; i < m_arity; i++) {
|
||||
vars.push_back(m_manager.mk_var(i, m_manager.get_sort(curr->get_arg(i))));
|
||||
|
@ -303,12 +335,17 @@ expr * func_interp::get_interp_core() const {
|
|||
eqs.push_back(m_manager.mk_eq(vars[i], curr->get_arg(i)));
|
||||
}
|
||||
SASSERT(eqs.size() == m_arity);
|
||||
expr * cond;
|
||||
if (m_arity == 1)
|
||||
cond = eqs.get(0);
|
||||
else
|
||||
cond = m_manager.mk_and(eqs.size(), eqs.c_ptr());
|
||||
r = m_manager.mk_ite(cond, curr->get_result(), r);
|
||||
expr * cond = mk_and(m_manager, eqs.size(), eqs.c_ptr());
|
||||
expr * th = curr->get_result();
|
||||
if (m_manager.is_true(th)) {
|
||||
r = m_manager.mk_or(cond, r);
|
||||
}
|
||||
else if (m_manager.is_false(th)) {
|
||||
r = m_manager.mk_and(m_manager.mk_not(cond), r);
|
||||
}
|
||||
else {
|
||||
r = m_manager.mk_ite(cond, th, r);
|
||||
}
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
@ -327,12 +364,9 @@ expr * func_interp::get_interp() const {
|
|||
func_interp * func_interp::translate(ast_translation & translator) const {
|
||||
func_interp * new_fi = alloc(func_interp, translator.to(), m_arity);
|
||||
|
||||
ptr_vector<func_entry>::const_iterator it = m_entries.begin();
|
||||
ptr_vector<func_entry>::const_iterator end = m_entries.end();
|
||||
for (; it != end; ++it) {
|
||||
func_entry * curr = *it;
|
||||
for (func_entry * curr : m_entries) {
|
||||
ptr_buffer<expr> new_args;
|
||||
for (unsigned i=0; i<m_arity; i++)
|
||||
for (unsigned i = 0; i < m_arity; i++)
|
||||
new_args.push_back(translator(curr->get_arg(i)));
|
||||
new_fi->insert_new_entry(new_args.c_ptr(), translator(curr->get_result()));
|
||||
}
|
||||
|
|
|
@ -57,6 +57,7 @@ public:
|
|||
expr * get_result() const { return m_result; }
|
||||
expr * get_arg(unsigned idx) const { return m_args[idx]; }
|
||||
expr * const * get_args() const { return m_args; }
|
||||
|
||||
/**
|
||||
\brief Return true if m.are_equal(m_args[i], args[i]) for all i in [0, arity)
|
||||
*/
|
||||
|
@ -101,6 +102,8 @@ public:
|
|||
func_entry * get_entry(expr * const * args) const;
|
||||
bool eval_else(expr * const * args, expr_ref & result) const;
|
||||
unsigned num_entries() const { return m_entries.size(); }
|
||||
ptr_vector<func_entry>::const_iterator begin() const { return m_entries.begin(); }
|
||||
ptr_vector<func_entry>::const_iterator end() const { return m_entries.end(); }
|
||||
func_entry const * const * get_entries() const { return m_entries.c_ptr(); }
|
||||
func_entry const * get_entry(unsigned idx) const { return m_entries[idx]; }
|
||||
|
||||
|
@ -113,6 +116,7 @@ public:
|
|||
|
||||
private:
|
||||
bool is_fi_entry_expr(expr * e, ptr_vector<expr> & args);
|
||||
bool is_identity() const;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -16,34 +16,36 @@ Author:
|
|||
Revision History:
|
||||
|
||||
--*/
|
||||
#include "model/model.h"
|
||||
#include "util/top_sort.h"
|
||||
#include "ast/ast_pp.h"
|
||||
#include "ast/ast_ll_pp.h"
|
||||
#include "ast/rewriter/var_subst.h"
|
||||
#include "ast/rewriter/th_rewriter.h"
|
||||
#include "ast/array_decl_plugin.h"
|
||||
#include "ast/well_sorted.h"
|
||||
#include "ast/used_symbols.h"
|
||||
#include "ast/for_each_expr.h"
|
||||
#include "ast/for_each_ast.h"
|
||||
#include "model/model.h"
|
||||
#include "model/model_evaluator.h"
|
||||
|
||||
model::model(ast_manager & m):
|
||||
model_core(m),
|
||||
m_mev(*this) {
|
||||
m_mev(*this),
|
||||
m_cleaned(false) {
|
||||
}
|
||||
|
||||
model::~model() {
|
||||
for (auto & kv : m_usort2universe) {
|
||||
m_manager.dec_ref(kv.m_key);
|
||||
m_manager.dec_array_ref(kv.m_value->size(), kv.m_value->c_ptr());
|
||||
m.dec_ref(kv.m_key);
|
||||
m.dec_array_ref(kv.m_value->size(), kv.m_value->c_ptr());
|
||||
dealloc(kv.m_value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void model::copy_const_interps(model const & source) {
|
||||
for (auto const& kv : source.m_interp) {
|
||||
for (auto const& kv : source.m_interp)
|
||||
register_decl(kv.m_key, kv.m_value);
|
||||
}
|
||||
}
|
||||
|
||||
void model::copy_func_interps(model const & source) {
|
||||
|
@ -57,13 +59,11 @@ void model::copy_usort_interps(model const & source) {
|
|||
}
|
||||
|
||||
model * model::copy() const {
|
||||
model * m = alloc(model, m_manager);
|
||||
|
||||
m->copy_const_interps(*this);
|
||||
m->copy_func_interps(*this);
|
||||
m->copy_usort_interps(*this);
|
||||
|
||||
return m;
|
||||
model * mdl = alloc(model, m);
|
||||
mdl->copy_const_interps(*this);
|
||||
mdl->copy_func_interps(*this);
|
||||
mdl->copy_usort_interps(*this);
|
||||
return mdl;
|
||||
}
|
||||
|
||||
bool model::eval_expr(expr * e, expr_ref & result, bool model_completion) {
|
||||
|
@ -94,13 +94,13 @@ struct model::value_proc : public some_value_proc {
|
|||
|
||||
expr * model::get_some_value(sort * s) {
|
||||
value_proc p(*this);
|
||||
return m_manager.get_some_value(s, &p);
|
||||
return m.get_some_value(s, &p);
|
||||
}
|
||||
|
||||
ptr_vector<expr> const & model::get_universe(sort * s) const {
|
||||
ptr_vector<expr> * u = nullptr;
|
||||
m_usort2universe.find(s, u);
|
||||
SASSERT(u != 0);
|
||||
SASSERT(u != nullptr);
|
||||
return *u;
|
||||
}
|
||||
|
||||
|
@ -120,11 +120,11 @@ sort * model::get_uninterpreted_sort(unsigned idx) const {
|
|||
|
||||
void model::register_usort(sort * s, unsigned usize, expr * const * universe) {
|
||||
sort2universe::obj_map_entry * entry = m_usort2universe.insert_if_not_there2(s, 0);
|
||||
m_manager.inc_array_ref(usize, universe);
|
||||
m.inc_array_ref(usize, universe);
|
||||
if (entry->get_data().m_value == 0) {
|
||||
// new entry
|
||||
m_usorts.push_back(s);
|
||||
m_manager.inc_ref(s);
|
||||
m.inc_ref(s);
|
||||
ptr_vector<expr> * new_u = alloc(ptr_vector<expr>);
|
||||
new_u->append(usize, universe);
|
||||
entry->get_data().m_value = new_u;
|
||||
|
@ -133,7 +133,7 @@ void model::register_usort(sort * s, unsigned usize, expr * const * universe) {
|
|||
// updating
|
||||
ptr_vector<expr> * u = entry->get_data().m_value;
|
||||
SASSERT(u);
|
||||
m_manager.dec_array_ref(u->size(), u->c_ptr());
|
||||
m.dec_array_ref(u->size(), u->c_ptr());
|
||||
u->append(usize, universe);
|
||||
}
|
||||
}
|
||||
|
@ -154,8 +154,8 @@ model * model::translate(ast_translation & translator) const {
|
|||
// Translate usort interps
|
||||
for (auto const& kv : m_usort2universe) {
|
||||
ptr_vector<expr> new_universe;
|
||||
for (unsigned i=0; i < kv.m_value->size(); i++)
|
||||
new_universe.push_back(translator(kv.m_value->get(i)));
|
||||
for (expr* e : *kv.m_value)
|
||||
new_universe.push_back(translator(e));
|
||||
res->register_usort(translator(kv.m_key),
|
||||
new_universe.size(),
|
||||
new_universe.c_ptr());
|
||||
|
@ -164,22 +164,322 @@ model * model::translate(ast_translation & translator) const {
|
|||
return res;
|
||||
}
|
||||
|
||||
struct model::top_sort : public ::top_sort<func_decl> {
|
||||
th_rewriter m_rewrite;
|
||||
obj_map<func_decl, unsigned> m_occur_count;
|
||||
|
||||
top_sort(ast_manager& m):
|
||||
m_rewrite(m)
|
||||
{}
|
||||
|
||||
void add_occurs(func_decl* f) {
|
||||
m_occur_count.insert(f, occur_count(f) + 1);
|
||||
}
|
||||
|
||||
unsigned occur_count(func_decl* f) const {
|
||||
unsigned count = 0;
|
||||
m_occur_count.find(f, count);
|
||||
return count;
|
||||
}
|
||||
|
||||
~top_sort() override {}
|
||||
};
|
||||
|
||||
void model::compress() {
|
||||
if (m_cleaned) return;
|
||||
|
||||
// stratify m_finterp and m_decls in a topological sort
|
||||
// such that functions f1 < f2 then f1 does not use f2.
|
||||
// then for each function in order clean-up the interpretations
|
||||
// by substituting in auxiliary definitions that can be eliminated.
|
||||
|
||||
func_decl_ref_vector pinned(m);
|
||||
while (true) {
|
||||
top_sort ts(m);
|
||||
collect_deps(ts);
|
||||
ts.topological_sort();
|
||||
for (func_decl * f : ts.top_sorted()) {
|
||||
cleanup_interp(ts, f);
|
||||
}
|
||||
|
||||
func_decl_set removed;
|
||||
ts.m_occur_count.reset();
|
||||
for (func_decl * f : ts.top_sorted()) {
|
||||
collect_occs(ts, f);
|
||||
}
|
||||
|
||||
// remove auxiliary declarations that are not used.
|
||||
for (func_decl * f : ts.top_sorted()) {
|
||||
if (f->is_skolem() && ts.occur_count(f) == 0) {
|
||||
pinned.push_back(f);
|
||||
unregister_decl(f);
|
||||
removed.insert(f);
|
||||
}
|
||||
}
|
||||
if (removed.empty()) break;
|
||||
remove_decls(m_decls, removed);
|
||||
remove_decls(m_func_decls, removed);
|
||||
remove_decls(m_const_decls, removed);
|
||||
}
|
||||
m_cleaned = true;
|
||||
reset_eval_cache();
|
||||
}
|
||||
|
||||
|
||||
void model::collect_deps(top_sort& ts) {
|
||||
for (auto const& kv : m_finterp) {
|
||||
ts.insert(kv.m_key, collect_deps(ts, kv.m_value));
|
||||
}
|
||||
for (auto const& kv : m_interp) {
|
||||
ts.insert(kv.m_key, collect_deps(ts, kv.m_value));
|
||||
}
|
||||
}
|
||||
|
||||
struct model::deps_collector {
|
||||
model& m;
|
||||
top_sort& ts;
|
||||
func_decl_set& s;
|
||||
array_util autil;
|
||||
deps_collector(model& m, top_sort& ts, func_decl_set& s): m(m), ts(ts), s(s), autil(m.get_manager()) {}
|
||||
void operator()(app* a) {
|
||||
func_decl* f = a->get_decl();
|
||||
if (autil.is_as_array(f)) {
|
||||
f = autil.get_as_array_func_decl(a);
|
||||
}
|
||||
if (m.has_interpretation(f)) {
|
||||
s.insert(f);
|
||||
ts.add_occurs(f);
|
||||
}
|
||||
}
|
||||
void operator()(expr* ) {}
|
||||
};
|
||||
|
||||
struct model::occs_collector {
|
||||
top_sort& ts;
|
||||
occs_collector(top_sort& ts): ts(ts) {}
|
||||
void operator()(func_decl* f) {
|
||||
ts.add_occurs(f);
|
||||
}
|
||||
void operator()(ast* ) {}
|
||||
};
|
||||
|
||||
|
||||
model::func_decl_set* model::collect_deps(top_sort& ts, expr * e) {
|
||||
func_decl_set* s = alloc(func_decl_set);
|
||||
deps_collector collector(*this, ts, *s);
|
||||
if (e) for_each_expr(collector, e);
|
||||
return s;
|
||||
}
|
||||
|
||||
model::func_decl_set* model::collect_deps(top_sort& ts, func_interp * fi) {
|
||||
func_decl_set* s = alloc(func_decl_set);
|
||||
deps_collector collector(*this, ts, *s);
|
||||
fi->compress();
|
||||
expr* e = fi->get_else();
|
||||
if (e) for_each_expr(collector, e);
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
\brief Inline interpretations of skolem functions
|
||||
*/
|
||||
|
||||
void model::cleanup_interp(top_sort& ts, func_decl* f) {
|
||||
unsigned pid = ts.partition_id(f);
|
||||
expr * e1 = get_const_interp(f);
|
||||
if (e1) {
|
||||
expr_ref e2 = cleanup_expr(ts, e1, pid);
|
||||
if (e2 != e1)
|
||||
register_decl(f, e2);
|
||||
return;
|
||||
}
|
||||
func_interp* fi = get_func_interp(f);
|
||||
if (fi) {
|
||||
e1 = fi->get_else();
|
||||
expr_ref e2 = cleanup_expr(ts, e1, pid);
|
||||
if (e1 != e2)
|
||||
fi->set_else(e2);
|
||||
}
|
||||
}
|
||||
|
||||
void model::collect_occs(top_sort& ts, func_decl* f) {
|
||||
expr * e = get_const_interp(f);
|
||||
if (e) {
|
||||
collect_occs(ts, e);
|
||||
}
|
||||
else {
|
||||
func_interp* fi = get_func_interp(f);
|
||||
if (fi) {
|
||||
e = fi->get_else();
|
||||
collect_occs(ts, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void model::collect_occs(top_sort& ts, expr* e) {
|
||||
occs_collector collector(ts);
|
||||
for_each_ast(collector, e);
|
||||
}
|
||||
|
||||
bool model::can_inline_def(top_sort& ts, func_decl* f) {
|
||||
if (ts.occur_count(f) <= 1) return true;
|
||||
func_interp* fi = get_func_interp(f);
|
||||
if (!fi) return false;
|
||||
if (fi->get_else() == nullptr) return false;
|
||||
expr* e = fi->get_else();
|
||||
obj_hashtable<expr> subs;
|
||||
ptr_buffer<expr> todo;
|
||||
todo.push_back(e);
|
||||
while (!todo.empty()) {
|
||||
if (fi->num_entries() + subs.size() > 8) return false;
|
||||
expr* e = todo.back();
|
||||
todo.pop_back();
|
||||
if (subs.contains(e)) continue;
|
||||
subs.insert(e);
|
||||
if (is_app(e)) {
|
||||
for (expr* arg : *to_app(e)) {
|
||||
todo.push_back(arg);
|
||||
}
|
||||
}
|
||||
else if (is_quantifier(e)) {
|
||||
todo.push_back(to_quantifier(e)->get_expr());
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
expr_ref model::cleanup_expr(top_sort& ts, expr* e, unsigned current_partition) {
|
||||
if (!e) return expr_ref(0, m);
|
||||
|
||||
TRACE("model", tout << "cleaning up:\n" << mk_pp(e, m) << "\n";);
|
||||
|
||||
obj_map<expr, expr*> cache;
|
||||
expr_ref_vector trail(m);
|
||||
ptr_buffer<expr, 128> todo;
|
||||
ptr_buffer<expr> args;
|
||||
todo.push_back(e);
|
||||
array_util autil(m);
|
||||
func_interp* fi = nullptr;
|
||||
unsigned pid = 0;
|
||||
expr_ref new_t(m);
|
||||
|
||||
while (!todo.empty()) {
|
||||
expr* a = todo.back();
|
||||
switch(a->get_kind()) {
|
||||
case AST_APP: {
|
||||
app * t = to_app(a);
|
||||
func_decl* f = t->get_decl();
|
||||
bool visited = true;
|
||||
|
||||
args.reset();
|
||||
for (expr* t_arg : *t) {
|
||||
expr * arg = nullptr;
|
||||
if (!cache.find(t_arg, arg)) {
|
||||
visited = false;
|
||||
todo.push_back(t_arg);
|
||||
}
|
||||
else {
|
||||
args.push_back(arg);
|
||||
}
|
||||
}
|
||||
if (!visited) {
|
||||
continue;
|
||||
}
|
||||
fi = nullptr;
|
||||
if (autil.is_as_array(a)) {
|
||||
func_decl* f = autil.get_as_array_func_decl(a);
|
||||
// only expand auxiliary definitions that occur once.
|
||||
if (can_inline_def(ts, f)) {
|
||||
fi = get_func_interp(f);
|
||||
}
|
||||
}
|
||||
|
||||
if (fi && fi->get_interp()) {
|
||||
f = autil.get_as_array_func_decl(a);
|
||||
expr_ref_vector sargs(m);
|
||||
sort_ref_vector vars(m);
|
||||
svector<symbol> var_names;
|
||||
for (unsigned i = 0; i < f->get_arity(); ++i) {
|
||||
var_names.push_back(symbol(i));
|
||||
vars.push_back(f->get_domain(f->get_arity() - i - 1));
|
||||
}
|
||||
new_t = m.mk_lambda(vars.size(), vars.c_ptr(), var_names.c_ptr(), fi->get_interp());
|
||||
}
|
||||
else if (f->is_skolem() && can_inline_def(ts, f) && (fi = get_func_interp(f)) &&
|
||||
fi->get_interp() && (!ts.partition_ids().find(f, pid) || pid != current_partition)) {
|
||||
var_subst vs(m);
|
||||
// ? TBD args.reverse();
|
||||
new_t = vs(fi->get_interp(), args.size(), args.c_ptr());
|
||||
}
|
||||
#if 0
|
||||
else if (is_uninterp_const(a) && !get_const_interp(f)) {
|
||||
new_t = get_some_value(f->get_range());
|
||||
register_decl(f, new_t);
|
||||
}
|
||||
#endif
|
||||
else {
|
||||
new_t = ts.m_rewrite.mk_app(f, args.size(), args.c_ptr());
|
||||
}
|
||||
|
||||
if (t != new_t.get()) trail.push_back(new_t);
|
||||
todo.pop_back();
|
||||
cache.insert(t, new_t);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
SASSERT(a != nullptr);
|
||||
cache.insert(a, a);
|
||||
todo.pop_back();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ts.m_rewrite(cache[e], new_t);
|
||||
return new_t;
|
||||
}
|
||||
|
||||
void model::remove_decls(ptr_vector<func_decl> & decls, func_decl_set const & s) {
|
||||
unsigned j = 0;
|
||||
for (func_decl* f : decls) {
|
||||
if (!s.contains(f)) {
|
||||
decls[j++] = f;
|
||||
}
|
||||
}
|
||||
decls.shrink(j);
|
||||
}
|
||||
|
||||
|
||||
expr_ref model::get_inlined_const_interp(func_decl* f) {
|
||||
expr* v = get_const_interp(f);
|
||||
if (!v) return expr_ref(0, m);
|
||||
top_sort st(m);
|
||||
expr_ref result1(v, m);
|
||||
expr_ref result2 = cleanup_expr(st, v, UINT_MAX);
|
||||
while (result1 != result2) {
|
||||
result1 = result2;
|
||||
result2 = cleanup_expr(st, result1, UINT_MAX);
|
||||
}
|
||||
return result2;
|
||||
}
|
||||
|
||||
expr_ref model::operator()(expr* t) {
|
||||
return m_mev(t);
|
||||
}
|
||||
|
||||
expr_ref_vector model::operator()(expr_ref_vector const& ts) {
|
||||
expr_ref_vector rs(m());
|
||||
expr_ref_vector rs(m);
|
||||
for (expr* t : ts) rs.push_back((*this)(t));
|
||||
return rs;
|
||||
}
|
||||
|
||||
bool model::is_true(expr* t) {
|
||||
return m().is_true((*this)(t));
|
||||
return m.is_true((*this)(t));
|
||||
}
|
||||
|
||||
bool model::is_false(expr* t) {
|
||||
return m().is_false((*this)(t));
|
||||
return m.is_false((*this)(t));
|
||||
}
|
||||
|
||||
bool model::is_true(expr_ref_vector const& ts) {
|
||||
|
|
|
@ -30,12 +30,28 @@ typedef ref<model> model_ref;
|
|||
class model : public model_core {
|
||||
protected:
|
||||
typedef obj_map<sort, ptr_vector<expr>*> sort2universe;
|
||||
typedef obj_hashtable<func_decl> func_decl_set;
|
||||
|
||||
ptr_vector<sort> m_usorts;
|
||||
sort2universe m_usort2universe;
|
||||
model_evaluator m_mev;
|
||||
bool m_cleaned;
|
||||
struct value_proc;
|
||||
|
||||
struct deps_collector;
|
||||
struct occs_collector;
|
||||
struct top_sort;
|
||||
|
||||
func_decl_set* collect_deps(top_sort& ts, expr * e);
|
||||
func_decl_set* collect_deps(top_sort& ts, func_interp* fi);
|
||||
void collect_deps(top_sort& ts);
|
||||
void collect_occs(top_sort& ts, func_decl* f);
|
||||
void collect_occs(top_sort& ts, expr* e);
|
||||
void cleanup_interp(top_sort& ts, func_decl * f);
|
||||
expr_ref cleanup_expr(top_sort& ts, expr* e, unsigned current_partition);
|
||||
void remove_decls(ptr_vector<func_decl> & decls, func_decl_set const & s);
|
||||
bool can_inline_def(top_sort& ts, func_decl* f);
|
||||
|
||||
public:
|
||||
model(ast_manager & m);
|
||||
~model() override;
|
||||
|
@ -54,6 +70,8 @@ public:
|
|||
sort * get_uninterpreted_sort(unsigned idx) const override;
|
||||
bool has_uninterpreted_sort(sort * s) const;
|
||||
|
||||
expr_ref get_inlined_const_interp(func_decl* f);
|
||||
|
||||
//
|
||||
// Primitives for building models
|
||||
//
|
||||
|
@ -63,6 +81,8 @@ public:
|
|||
//
|
||||
model * translate(ast_translation & translator) const;
|
||||
|
||||
void compress();
|
||||
|
||||
void set_model_completion(bool f) { m_mev.set_model_completion(f); }
|
||||
void updt_params(params_ref const & p) { m_mev.updt_params(p); }
|
||||
|
||||
|
@ -94,7 +114,5 @@ public:
|
|||
};
|
||||
};
|
||||
|
||||
std::ostream& operator<<(std::ostream& out, model_core const& m);
|
||||
|
||||
|
||||
#endif /* MODEL_H_ */
|
||||
|
|
|
@ -147,7 +147,7 @@ void model2expr(model& md, expr_ref& result) {
|
|||
}
|
||||
if (f->get_arity() > 0) {
|
||||
var_subst vs(m, false);
|
||||
vs(tmp, rev_vars.size(), rev_vars.c_ptr(), tmp);
|
||||
tmp = vs(tmp, rev_vars.size(), rev_vars.c_ptr());
|
||||
tmp = m.mk_forall(sorts.size(), sorts.c_ptr(), names.c_ptr(), tmp);
|
||||
}
|
||||
conjs.push_back(tmp);
|
||||
|
|
|
@ -20,12 +20,12 @@ Revision History:
|
|||
|
||||
model_core::~model_core() {
|
||||
for (auto & kv : m_interp) {
|
||||
m_manager.dec_ref(kv.m_key);
|
||||
m_manager.dec_ref(kv.m_value);
|
||||
m.dec_ref(kv.m_key);
|
||||
m.dec_ref(kv.m_value);
|
||||
}
|
||||
|
||||
for (auto & kv : m_finterp) {
|
||||
m_manager.dec_ref(kv.m_key);
|
||||
m.dec_ref(kv.m_key);
|
||||
dealloc(kv.m_value);
|
||||
}
|
||||
}
|
||||
|
@ -47,32 +47,33 @@ bool model_core::eval(func_decl* f, expr_ref & r) const {
|
|||
|
||||
void model_core::register_decl(func_decl * d, expr * v) {
|
||||
SASSERT(d->get_arity() == 0);
|
||||
TRACE("model", tout << "register " << d->get_name() << "\n";);
|
||||
decl2expr::obj_map_entry * entry = m_interp.insert_if_not_there2(d, nullptr);
|
||||
if (entry->get_data().m_value == nullptr) {
|
||||
// new entry
|
||||
m_decls.push_back(d);
|
||||
m_const_decls.push_back(d);
|
||||
m_manager.inc_ref(d);
|
||||
m_manager.inc_ref(v);
|
||||
m.inc_ref(d);
|
||||
m.inc_ref(v);
|
||||
entry->get_data().m_value = v;
|
||||
}
|
||||
else {
|
||||
// replacing entry
|
||||
m_manager.inc_ref(v);
|
||||
m_manager.dec_ref(entry->get_data().m_value);
|
||||
m.inc_ref(v);
|
||||
m.dec_ref(entry->get_data().m_value);
|
||||
entry->get_data().m_value = v;
|
||||
}
|
||||
}
|
||||
|
||||
void model_core::register_decl(func_decl * d, func_interp * fi) {
|
||||
SASSERT(d->get_arity() > 0);
|
||||
SASSERT(&fi->m() == &m_manager);
|
||||
SASSERT(&fi->m() == &m);
|
||||
decl2finterp::obj_map_entry * entry = m_finterp.insert_if_not_there2(d, nullptr);
|
||||
if (entry->get_data().m_value == nullptr) {
|
||||
// new entry
|
||||
m_decls.push_back(d);
|
||||
m_func_decls.push_back(d);
|
||||
m_manager.inc_ref(d);
|
||||
m.inc_ref(d);
|
||||
entry->get_data().m_value = fi;
|
||||
}
|
||||
else {
|
||||
|
@ -85,23 +86,23 @@ void model_core::register_decl(func_decl * d, func_interp * fi) {
|
|||
|
||||
void model_core::unregister_decl(func_decl * d) {
|
||||
decl2expr::obj_map_entry * ec = m_interp.find_core(d);
|
||||
if (ec && ec->get_data().m_value != 0) {
|
||||
if (ec) {
|
||||
auto k = ec->get_data().m_key;
|
||||
auto v = ec->get_data().m_value;
|
||||
m_interp.remove(d);
|
||||
m_const_decls.erase(d);
|
||||
m_manager.dec_ref(k);
|
||||
m_manager.dec_ref(v);
|
||||
m.dec_ref(k);
|
||||
m.dec_ref(v);
|
||||
return;
|
||||
}
|
||||
|
||||
decl2finterp::obj_map_entry * ef = m_finterp.find_core(d);
|
||||
if (ef && ef->get_data().m_value != 0) {
|
||||
if (ef) {
|
||||
auto k = ef->get_data().m_key;
|
||||
auto v = ef->get_data().m_value;
|
||||
m_finterp.remove(d);
|
||||
m_func_decls.erase(d);
|
||||
m_manager.dec_ref(k);
|
||||
m.dec_ref(k);
|
||||
dealloc(v);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,7 +27,7 @@ class model_core {
|
|||
protected:
|
||||
typedef obj_map<func_decl, expr *> decl2expr;
|
||||
typedef obj_map<func_decl, func_interp*> decl2finterp;
|
||||
ast_manager & m_manager;
|
||||
ast_manager & m;
|
||||
unsigned m_ref_count;
|
||||
decl2expr m_interp; //!< interpretation for uninterpreted constants
|
||||
decl2finterp m_finterp; //!< interpretation for uninterpreted functions
|
||||
|
@ -36,11 +36,10 @@ protected:
|
|||
ptr_vector<func_decl> m_func_decls;
|
||||
|
||||
public:
|
||||
model_core(ast_manager & m):m_manager(m), m_ref_count(0) { }
|
||||
model_core(ast_manager & m):m(m), m_ref_count(0) { }
|
||||
virtual ~model_core();
|
||||
|
||||
ast_manager & get_manager() const { return m_manager; }
|
||||
ast_manager& m() const { return m_manager; }
|
||||
ast_manager & get_manager() const { return m; }
|
||||
|
||||
unsigned get_num_decls() const { return m_decls.size(); }
|
||||
func_decl * get_decl(unsigned i) const { return m_decls[i]; }
|
||||
|
@ -65,6 +64,11 @@ public:
|
|||
|
||||
virtual expr * get_some_value(sort * s) = 0;
|
||||
|
||||
expr * get_some_const_interp(func_decl * d) {
|
||||
expr * r = get_const_interp(d);
|
||||
if (r) return r;
|
||||
return get_some_value(d->get_range());
|
||||
}
|
||||
//
|
||||
// Reference counting
|
||||
//
|
||||
|
@ -78,4 +82,7 @@ public:
|
|||
|
||||
};
|
||||
|
||||
std::ostream& operator<<(std::ostream& out, model_core const& m);
|
||||
|
||||
|
||||
#endif
|
||||
|
|
|
@ -16,10 +16,12 @@ Author:
|
|||
Revision History:
|
||||
|
||||
--*/
|
||||
#include "util/cooperate.h"
|
||||
#include "model/model.h"
|
||||
#include "model/model_evaluator_params.hpp"
|
||||
#include "ast/rewriter/rewriter_types.h"
|
||||
#include "model/model_evaluator.h"
|
||||
#include "model/model_v2_pp.h"
|
||||
#include "ast/rewriter/rewriter_types.h"
|
||||
#include "ast/rewriter/bool_rewriter.h"
|
||||
#include "ast/rewriter/arith_rewriter.h"
|
||||
#include "ast/rewriter/bv_rewriter.h"
|
||||
|
@ -29,7 +31,6 @@ Revision History:
|
|||
#include "ast/rewriter/array_rewriter.h"
|
||||
#include "ast/rewriter/fpa_rewriter.h"
|
||||
#include "ast/rewriter/rewriter_def.h"
|
||||
#include "util/cooperate.h"
|
||||
#include "ast/ast_pp.h"
|
||||
#include "ast/ast_util.h"
|
||||
#include "model/model_smt2_pp.h"
|
||||
|
@ -274,7 +275,7 @@ struct evaluator_cfg : public default_rewriter_cfg {
|
|||
fi->set_else(m.get_some_value(f->get_range()));
|
||||
|
||||
var_subst vs(m, false);
|
||||
vs(fi->get_interp(), num, args, result);
|
||||
result = vs(fi->get_interp(), num, args);
|
||||
return BR_REWRITE_FULL;
|
||||
}
|
||||
|
||||
|
|
|
@ -304,6 +304,6 @@ void model_smt2_pp(std::ostream & out, ast_manager & m, model_core const & md, u
|
|||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& out, model_core const& m) {
|
||||
model_smt2_pp(out, m.m(), m, 0);
|
||||
model_smt2_pp(out, m.get_manager(), m, 0);
|
||||
return out;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue