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:
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()));
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue