3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-08-06 19:21:22 +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

@ -17,16 +17,16 @@ Notes:
Major revision on 2011-10-06
--*/
#include "util/warning.h"
#include "util/cooperate.h"
#include "ast/normal_forms/nnf.h"
#include "ast/normal_forms/nnf_params.hpp"
#include "util/warning.h"
#include "ast/used_vars.h"
#include "ast/well_sorted.h"
#include "ast/rewriter/var_subst.h"
#include "ast/normal_forms/name_exprs.h"
#include "ast/act_cache.h"
#include "util/cooperate.h"
#include "ast/rewriter/var_subst.h"
#include "ast/normal_forms/name_exprs.h"
#include "ast/ast_smt2_pp.h"
@ -67,36 +67,42 @@ enum nnf_mode {
class skolemizer {
typedef act_cache cache;
ast_manager & m_manager;
ast_manager & m;
symbol m_sk_hack;
bool m_sk_hack_enabled;
cache m_cache;
cache m_cache_pr;
void process(quantifier * q, expr_ref & r, proof_ref & p) {
if (q->get_kind() == lambda_k) {
TRACE("nnf", tout << expr_ref(q, m) << "\n";);
r = q;
p = nullptr;
return;
}
used_vars uv;
uv(q);
SASSERT(is_well_sorted(m(), q));
SASSERT(is_well_sorted(m, q));
unsigned sz = uv.get_max_found_var_idx_plus_1();
ptr_buffer<sort> sorts;
expr_ref_vector args(m());
expr_ref_vector args(m);
for (unsigned i = 0; i < sz; i++) {
sort * s = uv.get(i);
if (s != nullptr) {
sorts.push_back(s);
args.push_back(m().mk_var(i, s));
args.push_back(m.mk_var(i, s));
}
}
TRACE("skolemizer", tout << "skid: " << q->get_skid() << "\n";);
expr_ref_vector substitution(m());
expr_ref_vector substitution(m);
unsigned num_decls = q->get_num_decls();
for (unsigned i = num_decls; i > 0; ) {
--i;
sort * r = q->get_decl_sort(i);
func_decl * sk_decl = m().mk_fresh_func_decl(q->get_decl_name(i), q->get_skid(), sorts.size(), sorts.c_ptr(), r);
app * sk = m().mk_app(sk_decl, args.size(), args.c_ptr());
func_decl * sk_decl = m.mk_fresh_func_decl(q->get_decl_name(i), q->get_skid(), sorts.size(), sorts.c_ptr(), r);
app * sk = m.mk_app(sk_decl, args.size(), args.c_ptr());
substitution.push_back(sk);
}
//
@ -106,7 +112,7 @@ class skolemizer {
for (unsigned i = 0; i < sz; i++) {
sort * s = uv.get(i);
if (s != nullptr)
substitution.push_back(m().mk_var(i, s));
substitution.push_back(m.mk_var(i, s));
else
substitution.push_back(nullptr);
}
@ -118,9 +124,9 @@ class skolemizer {
//
// (VAR 0) should be in the last position of substitution.
//
var_subst s(m());
SASSERT(is_well_sorted(m(), q->get_expr()));
expr_ref tmp(m());
var_subst s(m);
SASSERT(is_well_sorted(m, q->get_expr()));
expr_ref tmp(m);
expr * body = q->get_expr();
if (m_sk_hack_enabled) {
unsigned num_patterns = q->get_num_patterns();
@ -128,27 +134,27 @@ class skolemizer {
expr * p = q->get_pattern(i);
if (is_sk_hack(p)) {
expr * sk_hack = to_app(p)->get_arg(0);
if (q->is_forall()) // check whether is in negative/positive context.
tmp = m().mk_or(body, m().mk_not(sk_hack)); // negative context
if (q->get_kind() == forall_k) // check whether is in negative/positive context.
tmp = m.mk_or(body, m.mk_not(sk_hack)); // negative context
else
tmp = m().mk_and(body, sk_hack); // positive context
tmp = m.mk_and(body, sk_hack); // positive context
body = tmp;
}
}
}
s(body, substitution.size(), substitution.c_ptr(), r);
r = s(body, substitution.size(), substitution.c_ptr());
p = nullptr;
if (m().proofs_enabled()) {
if (q->is_forall())
p = m().mk_skolemization(m().mk_not(q), m().mk_not(r));
if (m.proofs_enabled()) {
if (q->get_kind() == forall_k)
p = m.mk_skolemization(m.mk_not(q), m.mk_not(r));
else
p = m().mk_skolemization(q, r);
p = m.mk_skolemization(q, r);
}
}
public:
skolemizer(ast_manager & m):
m_manager(m),
m(m),
m_sk_hack("sk_hack"),
m_sk_hack_enabled(false),
m_cache(m),
@ -159,25 +165,23 @@ public:
m_sk_hack_enabled = f;
}
ast_manager & m() const { return m_manager; }
void operator()(quantifier * q, expr_ref & r, proof_ref & p) {
r = m_cache.find(q);
if (r.get() != nullptr) {
p = nullptr;
if (m().proofs_enabled())
if (m.proofs_enabled())
p = static_cast<proof*>(m_cache_pr.find(q));
}
else {
process(q, r, p);
m_cache.insert(q, r);
if (m().proofs_enabled())
if (m.proofs_enabled())
m_cache_pr.insert(q, p);
}
}
bool is_sk_hack(expr * p) const {
SASSERT(m().is_pattern(p));
SASSERT(m.is_pattern(p));
if (to_app(p)->get_num_args() != 1)
return false;
expr * body = to_app(p)->get_arg(0);
@ -186,7 +190,7 @@ public:
func_decl * f = to_app(body)->get_decl();
if (!(f->get_name() == m_sk_hack && f->get_arity() == 1))
return false;
if (!m().is_bool(body)) {
if (!m.is_bool(body)) {
warning_msg("sk_hack constant must return a Boolean");
return false;
}
@ -233,8 +237,8 @@ struct nnf::imp {
#define POS_NQ_CIDX 1 // positive polarity and not nested in a quantifier
#define NEG_Q_CIDX 2 // negative polarity and nested in a quantifier
#define POS_Q_CIDX 3 // positive polarity and nested in a quantifier
ast_manager & m_manager;
ast_manager & m;
vector<frame> m_frame_stack;
expr_ref_vector m_result_stack;
@ -263,7 +267,7 @@ struct nnf::imp {
unsigned long long m_max_memory; // in bytes
imp(ast_manager & m, defined_names & n, params_ref const & p):
m_manager(m),
m(m),
m_result_stack(m),
m_todo_defs(m),
m_todo_proofs(m),
@ -279,9 +283,9 @@ struct nnf::imp {
m_name_quant = mk_quantifier_label_namer(m, n);
}
ast_manager & m() const { return m_manager; }
// ast_manager & m() const { return m; }
bool proofs_enabled() const { return m().proofs_enabled(); }
bool proofs_enabled() const { return m.proofs_enabled(); }
~imp() {
for (unsigned i = 0; i < 4; i++) {
@ -334,7 +338,7 @@ struct nnf::imp {
}
void push_frame(expr * t, bool pol, bool in_q, bool cache_res) {
m_frame_stack.push_back(frame(expr_ref(t, m()), pol, in_q, cache_res, m_result_stack.size()));
m_frame_stack.push_back(frame(expr_ref(t, m), pol, in_q, cache_res, m_result_stack.size()));
}
static unsigned get_cache_idx(bool pol, bool in_q) {
@ -382,8 +386,8 @@ struct nnf::imp {
cooperate("nnf");
if (memory::get_allocation_size() > m_max_memory)
throw nnf_exception(Z3_MAX_MEMORY_MSG);
if (m().canceled())
throw nnf_exception(m().limit().get_cancel_msg());
if (m.canceled())
throw nnf_exception(m.limit().get_cancel_msg());
}
void set_new_child_flag() {
@ -397,16 +401,16 @@ struct nnf::imp {
}
void skip(expr * t, bool pol) {
expr * r = pol ? t : m().mk_not(t);
expr * r = pol ? t : m.mk_not(t);
m_result_stack.push_back(r);
if (proofs_enabled()) {
m_result_pr_stack.push_back(m().mk_oeq_reflexivity(r));
m_result_pr_stack.push_back(m.mk_oeq_reflexivity(r));
SASSERT(m_result_stack.size() == m_result_pr_stack.size());
}
}
bool visit(expr * t, bool pol, bool in_q) {
SASSERT(m().is_bool(t));
SASSERT(m.is_bool(t));
if (m_mode == NNF_SKOLEM || (m_mode == NNF_QUANT && !in_q)) {
if (!has_quantifiers(t) && !has_labels(t)) {
@ -456,12 +460,12 @@ struct nnf::imp {
proof * mk_proof(bool pol, unsigned num_parents, proof * const * parents, app * old_e, app * new_e) {
if (pol) {
if (old_e->get_decl() == new_e->get_decl())
return m().mk_oeq_congruence(old_e, new_e, num_parents, parents);
else
return m().mk_nnf_pos(old_e, new_e, num_parents, parents);
return m.mk_oeq_congruence(old_e, new_e, num_parents, parents);
else
return m.mk_nnf_pos(old_e, new_e, num_parents, parents);
}
else
return m().mk_nnf_neg(old_e, new_e, num_parents, parents);
else
return m.mk_nnf_neg(old_e, new_e, num_parents, parents);
}
bool process_and_or(app * t, frame & fr) {
@ -473,11 +477,11 @@ struct nnf::imp {
return false;
}
app * r;
if (m().is_and(t) == fr.m_pol)
r = m().mk_and(t->get_num_args(), m_result_stack.c_ptr() + fr.m_spos);
if (m.is_and(t) == fr.m_pol)
r = m.mk_and(t->get_num_args(), m_result_stack.c_ptr() + fr.m_spos);
else
r = m().mk_or(t->get_num_args(), m_result_stack.c_ptr() + fr.m_spos);
r = m.mk_or(t->get_num_args(), m_result_stack.c_ptr() + fr.m_spos);
m_result_stack.shrink(fr.m_spos);
m_result_stack.push_back(r);
if (proofs_enabled()) {
@ -500,7 +504,7 @@ struct nnf::imp {
if (proofs_enabled()) {
pr = m_result_pr_stack.back();
if (!fr.m_pol) {
pr = m().mk_nnf_neg(t, r, 1, &pr);
pr = m.mk_nnf_neg(t, r, 1, &pr);
m_result_pr_stack.pop_back();
m_result_pr_stack.push_back(pr);
SASSERT(m_result_stack.size() == m_result_pr_stack.size());
@ -526,10 +530,10 @@ struct nnf::imp {
app * r;
if (fr.m_pol)
r = m().mk_or(2, m_result_stack.c_ptr() + fr.m_spos);
r = m.mk_or(2, m_result_stack.c_ptr() + fr.m_spos);
else
r = m().mk_and(2, m_result_stack.c_ptr() + fr.m_spos);
r = m.mk_and(2, m_result_stack.c_ptr() + fr.m_spos);
m_result_stack.shrink(fr.m_spos);
m_result_stack.push_back(r);
if (proofs_enabled()) {
@ -570,7 +574,7 @@ struct nnf::imp {
expr * _then = rs[2];
expr * _else = rs[3];
app * r = m().mk_and(m().mk_or(_not_cond, _then), m().mk_or(_cond, _else));
app * r = m.mk_and(m.mk_or(_not_cond, _then), m.mk_or(_cond, _else));
m_result_stack.shrink(fr.m_spos);
m_result_stack.push_back(r);
if (proofs_enabled()) {
@ -582,7 +586,7 @@ struct nnf::imp {
return true;
}
bool is_eq(app * t) const { return m().is_eq(t); }
bool is_eq(app * t) const { return m.is_eq(t); }
bool process_iff_xor(app * t, frame & fr) {
SASSERT(t->get_num_args() == 2);
@ -614,10 +618,10 @@ struct nnf::imp {
expr * not_rhs = rs[3];
app * r;
if (is_eq(t) == fr.m_pol)
r = m().mk_and(m().mk_or(not_lhs, rhs), m().mk_or(lhs, not_rhs));
if (is_eq(t) == fr.m_pol)
r = m.mk_and(m.mk_or(not_lhs, rhs), m.mk_or(lhs, not_rhs));
else
r = m().mk_and(m().mk_or(lhs, rhs), m().mk_or(not_lhs, not_rhs));
r = m.mk_and(m.mk_or(lhs, rhs), m.mk_or(not_lhs, not_rhs));
m_result_stack.shrink(fr.m_spos);
m_result_stack.push_back(r);
if (proofs_enabled()) {
@ -630,7 +634,7 @@ struct nnf::imp {
}
bool process_eq(app * t, frame & fr) {
if (m().is_iff(t))
if (m.is_bool(t->get_arg(0)))
return process_iff_xor(t, fr);
else
return process_default(t, fr);
@ -639,21 +643,20 @@ struct nnf::imp {
bool process_default(app * t, frame & fr) {
SASSERT(fr.m_i == 0);
if (m_mode == NNF_FULL || t->has_quantifiers() || t->has_labels()) {
expr_ref n2(m());
proof_ref pr2(m());
expr_ref n2(m);
proof_ref pr2(m);
if (m_mode == NNF_FULL || (m_mode != NNF_SKOLEM && fr.m_in_q))
m_name_nested_formulas->operator()(t, m_todo_defs, m_todo_proofs, n2, pr2);
else
m_name_quant->operator()(t, m_todo_defs, m_todo_proofs, n2, pr2);
if (!fr.m_pol)
n2 = m().mk_not(n2);
n2 = m.mk_not(n2);
m_result_stack.push_back(n2);
if (proofs_enabled()) {
if (!fr.m_pol) {
proof * prs[1] = { pr2 };
pr2 = m().mk_oeq_congruence(m().mk_not(t), static_cast<app*>(n2.get()), 1, prs);
pr2 = m.mk_oeq_congruence(m.mk_not(t), static_cast<app*>(n2.get()), 1, prs);
}
m_result_pr_stack.push_back(pr2);
SASSERT(m_result_stack.size() == m_result_pr_stack.size());
@ -681,24 +684,24 @@ struct nnf::imp {
buffer<symbol> names;
bool pos;
m().is_label(t, pos, names);
expr_ref r(m());
proof_ref pr(m());
m.is_label(t, pos, names);
expr_ref r(m);
proof_ref pr(m);
if (fr.m_pol == pos) {
expr * lbl_lit = m().mk_label_lit(names.size(), names.c_ptr());
r = m().mk_and(arg, lbl_lit);
expr * lbl_lit = m.mk_label_lit(names.size(), names.c_ptr());
r = m.mk_and(arg, lbl_lit);
if (proofs_enabled()) {
expr_ref aux(m_manager);
aux = m().mk_label(true, names.size(), names.c_ptr(), arg);
pr = m().mk_transitivity(mk_proof(fr.m_pol, 1, &arg_pr, t, to_app(aux)),
m().mk_iff_oeq(m().mk_rewrite(aux, r)));
expr_ref aux(m);
aux = m.mk_label(true, names.size(), names.c_ptr(), arg);
pr = m.mk_transitivity(mk_proof(fr.m_pol, 1, &arg_pr, t, to_app(aux)),
m.mk_iff_oeq(m.mk_rewrite(aux, r)));
}
}
else {
r = arg;
if (proofs_enabled()) {
proof * p1 = m().mk_iff_oeq(m().mk_rewrite(t, t->get_arg(0)));
pr = m().mk_transitivity(p1, arg_pr);
proof * p1 = m.mk_iff_oeq(m.mk_rewrite(t, t->get_arg(0)));
pr = m.mk_transitivity(p1, arg_pr);
}
}
@ -713,9 +716,9 @@ struct nnf::imp {
}
bool process_app(app * t, frame & fr) {
TRACE("nnf", tout << mk_ismt2_pp(t, m()) << "\n";);
SASSERT(m().is_bool(t));
if (t->get_family_id() == m().get_basic_family_id()) {
TRACE("nnf", tout << mk_ismt2_pp(t, m) << "\n";);
SASSERT(m.is_bool(t));
if (t->get_family_id() == m.get_basic_family_id()) {
switch (static_cast<basic_op_kind>(t->get_decl_kind())) {
case OP_AND: case OP_OR:
return process_and_or(t, fr);
@ -734,7 +737,7 @@ struct nnf::imp {
}
}
if (m().is_label(t)) {
if (m.is_label(t)) {
return process_label(t, fr);
}
@ -747,28 +750,51 @@ struct nnf::imp {
}
bool process_quantifier(quantifier * q, frame & fr) {
expr_ref r(m());
proof_ref pr(m());
TRACE("nnf", tout << expr_ref(q, m) << "\n";);
expr_ref r(m);
proof_ref pr(m);
if (fr.m_i == 0) {
fr.m_i = 1;
if (q->is_forall() == fr.m_pol || !m_skolemize) {
if (is_lambda(q)) {
if (!visit(q->get_expr(), fr.m_pol, true))
return false;
}
else if (is_forall(q) == fr.m_pol || !m_skolemize) {
if (!visit(q->get_expr(), fr.m_pol, true))
return false;
}
else {
m_skolemizer(q, r, pr);
if (!visit(r, !q->is_forall(), fr.m_in_q))
if (!visit(r, !is_forall(q), fr.m_in_q))
return false;
}
}
if (q->is_forall() == fr.m_pol || !m_skolemize) {
if (is_lambda(q)) {
expr * new_expr = m_result_stack.back();
quantifier * new_q = m.update_quantifier(q, new_expr);
proof * new_q_pr = nullptr;
if (proofs_enabled()) {
// proof * new_expr_pr = m_result_pr_stack.back();
new_q_pr = m.mk_rewrite(q, new_q); // TBD use new_expr_pr
}
m_result_stack.pop_back();
m_result_stack.push_back(new_q);
if (proofs_enabled()) {
m_result_pr_stack.pop_back();
m_result_pr_stack.push_back(new_q_pr);
SASSERT(m_result_stack.size() == m_result_pr_stack.size());
}
return true;
}
else if (is_forall(q) == fr.m_pol || !m_skolemize) {
expr * new_expr = m_result_stack.back();
proof * new_expr_pr = proofs_enabled() ? m_result_pr_stack.back() : nullptr;
ptr_buffer<expr> new_patterns;
if (q->is_forall() == fr.m_pol) {
if (is_forall(q) == fr.m_pol) {
// collect non sk_hack patterns
unsigned num_patterns = q->get_num_patterns();
for (unsigned i = 0; i < num_patterns; i++) {
@ -785,14 +811,19 @@ struct nnf::imp {
quantifier * new_q = nullptr;
proof * new_q_pr = nullptr;
if (fr.m_pol) {
new_q = m().update_quantifier(q, new_patterns.size(), new_patterns.c_ptr(), new_expr);
if (proofs_enabled())
new_q_pr = m().mk_nnf_pos(q, new_q, 1, &new_expr_pr);
new_q = m.update_quantifier(q, new_patterns.size(), new_patterns.c_ptr(), new_expr);
if (proofs_enabled()) {
new_expr_pr = m.mk_bind_proof(q, new_expr_pr);
new_q_pr = m.mk_nnf_pos(q, new_q, 1, &new_expr_pr);
}
}
else {
new_q = m().update_quantifier(q, !q->is_forall(), new_patterns.size(), new_patterns.c_ptr(), new_expr);
if (proofs_enabled())
new_q_pr = m().mk_nnf_neg(q, new_q, 1, &new_expr_pr);
quantifier_kind k = is_forall(q)? exists_k : forall_k;
new_q = m.update_quantifier(q, k, new_patterns.size(), new_patterns.c_ptr(), new_expr);
if (proofs_enabled()) {
new_expr_pr = m.mk_bind_proof(q, new_expr_pr);
new_q_pr = m.mk_nnf_neg(q, new_q, 1, &new_expr_pr);
}
}
m_result_stack.pop_back();
@ -809,7 +840,7 @@ struct nnf::imp {
// However, the proof must be updated
if (proofs_enabled()) {
m_skolemizer(q, r, pr); // retrieve the proof
pr = m().mk_transitivity(pr, m_result_pr_stack.back());
pr = m.mk_transitivity(pr, m_result_pr_stack.back());
m_result_pr_stack.pop_back();
m_result_pr_stack.push_back(pr);
SASSERT(m_result_stack.size() == m_result_pr_stack.size());
@ -827,14 +858,14 @@ struct nnf::imp {
result_pr = m_result_pr_stack.back();
m_result_pr_stack.pop_back();
if (result_pr.get() == nullptr)
result_pr = m().mk_reflexivity(t);
result_pr = m.mk_reflexivity(t);
SASSERT(m_result_pr_stack.empty());
}
}
void process(expr * t, expr_ref & result, proof_ref & result_pr) {
TRACE("nnf", tout << "processing:\n" << mk_ismt2_pp(t, m()) << "\n";);
SASSERT(m().is_bool(t));
TRACE("nnf", tout << "processing:\n" << mk_ismt2_pp(t, m) << "\n";);
SASSERT(m.is_bool(t));
if (visit(t, true /* positive polarity */, false /* not nested in quantifier */)) {
recover_result(t, result, result_pr);
@ -883,13 +914,13 @@ struct nnf::imp {
unsigned old_sz2 = new_def_proofs.size();
for (unsigned i = 0; i < m_todo_defs.size(); i++) {
expr_ref dr(m());
proof_ref dpr(m());
expr_ref dr(m);
proof_ref dpr(m);
process(m_todo_defs.get(i), dr, dpr);
new_defs.push_back(dr);
if (proofs_enabled()) {
proof * new_pr = m().mk_modus_ponens(m_todo_proofs.get(i), dpr);
new_def_proofs.push_back(new_pr);
proof * new_pr = m.mk_modus_ponens(m_todo_proofs.get(i), dpr);
new_def_proofs.push_back(new_pr);
}
}
std::reverse(new_defs.c_ptr() + old_sz1, new_defs.c_ptr() + new_defs.size());
@ -909,7 +940,7 @@ nnf::~nnf() {
void nnf::operator()(expr * n, expr_ref_vector & new_defs, proof_ref_vector & new_def_proofs, expr_ref & r, proof_ref & p) {
m_imp->operator()(n, new_defs, new_def_proofs, r, p);
TRACE("nnf_result", tout << mk_ismt2_pp(n, m_imp->m()) << "\nNNF result:\n" << mk_ismt2_pp(r, m_imp->m()) << "\n";);
TRACE("nnf_result", tout << expr_ref(n, r.get_manager()) << "\nNNF result:\n" << new_defs << "\n" << r << "\n";);
}
void nnf::updt_params(params_ref const & p) {