3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-07-19 10:52:02 +00:00

integrate lambda expressions

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
Nikolaj Bjorner 2018-06-26 07:23:04 -07:00
parent bf4edef761
commit 520ce9a5ee
139 changed files with 2243 additions and 1506 deletions

View file

@ -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()));
}