3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-06-16 02:46:16 +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

@ -16,17 +16,19 @@ Author:
Revision History:
--*/
#include "ast/normal_forms/defined_names.h"
#include "util/obj_hashtable.h"
#include "ast/normal_forms/defined_names.h"
#include "ast/used_vars.h"
#include "ast/rewriter/var_subst.h"
#include "ast/ast_smt2_pp.h"
#include "ast/ast_pp.h"
#include "ast/ast_util.h"
#include "ast/array_decl_plugin.h"
struct defined_names::impl {
typedef obj_map<expr, app *> expr2name;
typedef obj_map<expr, proof *> expr2proof;
ast_manager & m_manager;
ast_manager & m;
symbol m_z3name;
/**
@ -60,9 +62,9 @@ struct defined_names::impl {
app * gen_name(expr * e, sort_ref_buffer & var_sorts, buffer<symbol> & var_names);
void cache_new_name(expr * e, app * name);
void cache_new_name_intro_proof(expr * e, proof * pr);
void bound_vars(sort_ref_buffer const & sorts, buffer<symbol> const & names, expr * def_conjunct, app * name, expr_ref & result);
void bound_vars(sort_ref_buffer const & sorts, buffer<symbol> const & names, expr * def_conjunct, app * name, expr_ref_buffer & result);
virtual void mk_definition(expr * e, app * n, sort_ref_buffer & var_sorts, buffer<symbol> const & var_names, expr_ref & new_def);
void bound_vars(sort_ref_buffer const & sorts, buffer<symbol> const & names, expr * def_conjunct, app * name, expr_ref & result, symbol const& qid = symbol::null);
void bound_vars(sort_ref_buffer const & sorts, buffer<symbol> const & names, expr * def_conjunct, app * name, expr_ref_buffer & result, symbol const& qid = symbol::null);
virtual void mk_definition(expr * e, app * n, sort_ref_buffer & var_sorts, buffer<symbol> & var_names, expr_ref & new_def);
bool mk_name(expr * e, expr_ref & new_def, proof_ref & new_def_pr, app_ref & n, proof_ref & pr);
void push_scope();
void pop_scope(unsigned num_scopes);
@ -74,12 +76,13 @@ struct defined_names::impl {
struct defined_names::pos_impl : public defined_names::impl {
pos_impl(ast_manager & m, char const * fresh_prefix):impl(m, fresh_prefix) {}
void mk_definition(expr * e, app * n, sort_ref_buffer & var_sorts, buffer<symbol> const & var_names, expr_ref & new_def) override;
void mk_definition(expr * e, app * n, sort_ref_buffer & var_sorts, buffer<symbol> & var_names, expr_ref & new_def) override;
};
defined_names::impl::impl(ast_manager & m, char const * prefix):
m_manager(m),
m(m),
m_exprs(m),
m_names(m),
m_apply_proofs(m) {
@ -107,20 +110,20 @@ app * defined_names::impl::gen_name(expr * e, sort_ref_buffer & var_sorts, buffe
sort * s = uv.get(i);
if (s) {
domain.push_back(s);
new_args.push_back(m_manager.mk_var(i, s));
new_args.push_back(m.mk_var(i, s));
var_sorts.push_back(s);
}
else {
var_sorts.push_back(m_manager.mk_bool_sort()); // could be any sort.
var_sorts.push_back(m.mk_bool_sort()); // could be any sort.
}
var_names.push_back(symbol(i));
}
sort * range = m_manager.get_sort(e);
func_decl * new_skolem_decl = m_manager.mk_fresh_func_decl(m_z3name, symbol::null, domain.size(), domain.c_ptr(), range);
app * n = m_manager.mk_app(new_skolem_decl, new_args.size(), new_args.c_ptr());
TRACE("mk_definition_bug", tout << "gen_name: " << mk_ismt2_pp(n, m_manager) << "\n";
for (unsigned i = 0; i < var_sorts.size(); i++) tout << mk_pp(var_sorts[i], m_manager) << " ";
sort * range = m.get_sort(e);
func_decl * new_skolem_decl = m.mk_fresh_func_decl(m_z3name, symbol::null, domain.size(), domain.c_ptr(), range);
app * n = m.mk_app(new_skolem_decl, new_args.size(), new_args.c_ptr());
TRACE("mk_definition_bug", tout << "gen_name: " << mk_ismt2_pp(n, m) << "\n";
for (unsigned i = 0; i < var_sorts.size(); i++) tout << mk_pp(var_sorts[i], m) << " ";
tout << "\n";);
return n;
}
@ -148,22 +151,22 @@ void defined_names::impl::cache_new_name_intro_proof(expr * e, proof * pr) {
A quantifier is added around \c def_conjunct, if sorts and names are not empty.
In this case, The application \c name is used as a pattern for the new quantifier.
*/
void defined_names::impl::bound_vars(sort_ref_buffer const & sorts, buffer<symbol> const & names, expr * def_conjunct, app * name, expr_ref & result) {
void defined_names::impl::bound_vars(sort_ref_buffer const & sorts, buffer<symbol> const & names, expr * def_conjunct, app * name, expr_ref & result, symbol const& qid) {
SASSERT(sorts.size() == names.size());
if (sorts.empty())
result = def_conjunct;
else {
expr * patterns[1] = { m_manager.mk_pattern(name) };
quantifier_ref q(m_manager);
q = m_manager.mk_forall(sorts.size(),
expr * patterns[1] = { m.mk_pattern(name) };
quantifier_ref q(m);
q = m.mk_forall(sorts.size(),
sorts.c_ptr(),
names.c_ptr(),
def_conjunct,
1, symbol::null, symbol::null,
1, qid, symbol::null,
1, patterns);
TRACE("mk_definition_bug", tout << "before elim_unused_vars:\n" << mk_ismt2_pp(q, m_manager) << "\n";);
elim_unused_vars(m_manager, q, params_ref(), result);
TRACE("mk_definition_bug", tout << "after elim_unused_vars:\n" << mk_ismt2_pp(result, m_manager) << "\n";);
TRACE("mk_definition_bug", tout << "before elim_unused_vars:\n" << mk_ismt2_pp(q, m) << "\n";);
result = elim_unused_vars(m, q, params_ref());
TRACE("mk_definition_bug", tout << "after elim_unused_vars:\n" << result << "\n";);
}
}
@ -172,44 +175,81 @@ void defined_names::impl::bound_vars(sort_ref_buffer const & sorts, buffer<symbo
A quantifier is added around \c def_conjunct, if sorts and names are not empty.
In this case, The application \c name is used as a pattern for the new quantifier.
*/
void defined_names::impl::bound_vars(sort_ref_buffer const & sorts, buffer<symbol> const & names, expr * def_conjunct, app * name, expr_ref_buffer & result) {
expr_ref tmp(m_manager);
bound_vars(sorts, names, def_conjunct, name, tmp);
void defined_names::impl::bound_vars(sort_ref_buffer const & sorts, buffer<symbol> const & names, expr * def_conjunct, app * name, expr_ref_buffer & result, symbol const& qid) {
expr_ref tmp(m);
bound_vars(sorts, names, def_conjunct, name, tmp, qid);
result.push_back(tmp);
}
#define MK_OR m_manager.mk_or
#define MK_NOT m_manager.mk_not
#define MK_EQ m_manager.mk_eq
#define MK_OR m.mk_or
#define MK_NOT m.mk_not
#define MK_EQ m.mk_eq
void defined_names::impl::mk_definition(expr * e, app * n, sort_ref_buffer & var_sorts, buffer<symbol> const & var_names, expr_ref & new_def) {
expr_ref_buffer defs(m_manager);
if (m_manager.is_bool(e)) {
void defined_names::impl::mk_definition(expr * e, app * n, sort_ref_buffer & var_sorts, buffer<symbol> & var_names, expr_ref & new_def) {
expr_ref_buffer defs(m);
if (m.is_bool(e)) {
bound_vars(var_sorts, var_names, MK_OR(MK_NOT(n), e), n, defs);
bound_vars(var_sorts, var_names, MK_OR(n, MK_NOT(e)), n, defs);
}
else if (m_manager.is_term_ite(e)) {
else if (m.is_term_ite(e)) {
bound_vars(var_sorts, var_names, MK_OR(MK_NOT(to_app(e)->get_arg(0)), MK_EQ(n, to_app(e)->get_arg(1))), n, defs);
bound_vars(var_sorts, var_names, MK_OR(to_app(e)->get_arg(0), MK_EQ(n, to_app(e)->get_arg(2))), n, defs);
}
else if (is_lambda(e)) {
// n(y) = \x . M[x,y]
// =>
// n(y)[x] = M, forall x y
//
// NB. The pattern is incomplete.
// consider store(a, i, v) == \lambda j . if i = j then v else a[j]
// the instantiation rules for store(a, i, v) are:
// sotre(a, i, v)[j] = if i = j then v else a[j] with patterns {a[j], store(a, i, v)} { store(a, i, v)[j] }
// The first pattern is not included.
// TBD use a model-based scheme for exracting instantiations instead of
// using multi-patterns.
//
quantifier* q = to_quantifier(e);
expr_ref_vector args(m);
expr_ref n2(m), n3(m);
var_shifter vs(m);
vs(n, q->get_num_decls(), n2);
args.push_back(n2);
var_sorts.append(q->get_num_decls(), q->get_decl_sorts());
var_names.append(q->get_num_decls(), q->get_decl_names());
for (unsigned i = 0; i < q->get_num_decls(); ++i) {
args.push_back(m.mk_var(q->get_num_decls() - i - 1, q->get_decl_sort(i)));
}
array_util autil(m);
func_decl * f = 0;
if (autil.is_as_array(n2, f)) {
n3 = m.mk_app(f, args.size()-1, args.c_ptr() + 1);
}
else {
n3 = autil.mk_select(args.size(), args.c_ptr());
}
bound_vars(var_sorts, var_names, MK_EQ(q->get_expr(), n3), to_app(n3), defs, m.lambda_def_qid());
}
else {
bound_vars(var_sorts, var_names, MK_EQ(e, n), n, defs);
}
new_def = defs.size() == 1 ? defs[0] : m_manager.mk_and(defs.size(), defs.c_ptr());
new_def = mk_and(m, defs.size(), defs.c_ptr());
}
void defined_names::pos_impl::mk_definition(expr * e, app * n, sort_ref_buffer & var_sorts, buffer<symbol> const & var_names, expr_ref & new_def) {
void defined_names::pos_impl::mk_definition(expr * e, app * n, sort_ref_buffer & var_sorts, buffer<symbol> & var_names, expr_ref & new_def) {
bound_vars(var_sorts, var_names, MK_OR(MK_NOT(n), e), n, new_def);
}
bool defined_names::impl::mk_name(expr * e, expr_ref & new_def, proof_ref & new_def_pr, app_ref & n, proof_ref & pr) {
TRACE("mk_definition_bug", tout << "making name for:\n" << mk_ismt2_pp(e, m_manager) << "\n";);
TRACE("mk_definition_bug", tout << "making name for:\n" << mk_ismt2_pp(e, m) << "\n";);
app * n_ptr;
if (m_expr2name.find(e, n_ptr)) {
TRACE("mk_definition_bug", tout << "name for expression is already cached..., returning false...\n";);
n = n_ptr;
if (m_manager.proofs_enabled()) {
if (m.proofs_enabled()) {
proof * pr_ptr = nullptr;
m_expr2proof.find(e, pr_ptr);
SASSERT(pr_ptr);
@ -218,24 +258,24 @@ bool defined_names::impl::mk_name(expr * e, expr_ref & new_def, proof_ref & new_
return false;
}
else {
sort_ref_buffer var_sorts(m_manager);
sort_ref_buffer var_sorts(m);
buffer<symbol> var_names;
n = gen_name(e, var_sorts, var_names);
cache_new_name(e, n);
TRACE("mk_definition_bug", tout << "name: " << mk_ismt2_pp(n, m_manager) << "\n";);
TRACE("mk_definition_bug", tout << "name: " << mk_ismt2_pp(n, m) << "\n";);
// variables are in reverse order in quantifiers
std::reverse(var_sorts.c_ptr(), var_sorts.c_ptr() + var_sorts.size());
std::reverse(var_names.c_ptr(), var_names.c_ptr() + var_names.size());
mk_definition(e, n, var_sorts, var_names, new_def);
TRACE("mk_definition_bug", tout << "new_def:\n" << mk_ismt2_pp(new_def, m_manager) << "\n";);
TRACE("mk_definition_bug", tout << "new_def:\n" << mk_ismt2_pp(new_def, m) << "\n";);
if (m_manager.proofs_enabled()) {
new_def_pr = m_manager.mk_def_intro(new_def);
pr = m_manager.mk_apply_def(e, n, new_def_pr);
if (m.proofs_enabled()) {
new_def_pr = m.mk_def_intro(new_def);
pr = m.mk_apply_def(e, n, new_def_pr);
cache_new_name_intro_proof(e, pr);
}
return true;
@ -257,7 +297,7 @@ void defined_names::impl::pop_scope(unsigned num_scopes) {
SASSERT(sz == m_names.size());
while (old_sz != sz) {
--sz;
if (m_manager.proofs_enabled()) {
if (m.proofs_enabled()) {
m_expr2proof.erase(m_exprs.back());
m_apply_proofs.pop_back();
}
@ -296,6 +336,15 @@ bool defined_names::mk_pos_name(expr * e, expr_ref & new_def, proof_ref & new_de
return m_pos_impl->mk_name(e, new_def, new_def_pr, n, pr);
}
expr_ref defined_names::mk_definition(expr * e, app * n) {
ast_manager& m = m_impl->m;
sort_ref_buffer var_sorts(m);
expr_ref new_def(m);
buffer<symbol> var_names;
m_impl->mk_definition(e, n, var_sorts, var_names, new_def);
return new_def;
}
void defined_names::push() {
m_impl->push_scope();
m_pos_impl->push_scope();