3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-04-23 09:05:31 +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

@ -26,6 +26,9 @@ Revision History:
#include "util/string_buffer.h"
#include "ast/ast_util.h"
#include "ast/ast_smt2_pp.h"
#include "ast/array_decl_plugin.h"
#include "ast/ast_translation.h"
// -----------------------------------
//
@ -360,13 +363,14 @@ app::app(func_decl * decl, unsigned num_args, expr * const * args):
//
// -----------------------------------
quantifier::quantifier(bool forall, unsigned num_decls, sort * const * decl_sorts, symbol const * decl_names, expr * body,
quantifier::quantifier(quantifier_kind k, unsigned num_decls, sort * const * decl_sorts, symbol const * decl_names, expr * body, sort* s,
int weight, symbol const & qid, symbol const & skid, unsigned num_patterns, expr * const * patterns,
unsigned num_no_patterns, expr * const * no_patterns):
expr(AST_QUANTIFIER),
m_forall(forall),
m_kind(k),
m_num_decls(num_decls),
m_expr(body),
m_sort(s),
m_depth(::get_depth(body) + 1),
m_weight(weight),
m_has_unused_vars(true),
@ -385,6 +389,25 @@ quantifier::quantifier(bool forall, unsigned num_decls, sort * const * decl_sort
memcpy(const_cast<expr **>(get_no_patterns()), no_patterns, sizeof(expr *) * num_no_patterns);
}
quantifier::quantifier(unsigned num_decls, sort * const * decl_sorts, symbol const * decl_names, expr * body, sort* s):
expr(AST_QUANTIFIER),
m_kind(lambda_k),
m_num_decls(num_decls),
m_expr(body),
m_sort(s),
m_depth(::get_depth(body) + 1),
m_weight(0),
m_has_unused_vars(true),
m_has_labels(::has_labels(body)),
m_qid(symbol()),
m_skid(symbol()),
m_num_patterns(0),
m_num_no_patterns(0) {
memcpy(const_cast<sort **>(get_decl_sorts()), decl_sorts, sizeof(sort *) * num_decls);
memcpy(const_cast<symbol*>(get_decl_names()), decl_names, sizeof(symbol) * num_decls);
}
// -----------------------------------
//
// Auxiliary functions
@ -392,21 +415,16 @@ quantifier::quantifier(bool forall, unsigned num_decls, sort * const * decl_sort
// -----------------------------------
sort * get_sort(expr const * n) {
while (true) {
switch(n->get_kind()) {
case AST_APP:
return to_app(n)->get_decl()->get_range();
case AST_VAR:
return to_var(n)->get_sort();
case AST_QUANTIFIER:
// The sort of the quantifier is the sort of the nested expression.
// This code assumes the given expression is well-sorted.
n = to_quantifier(n)->get_expr();
break;
default:
UNREACHABLE();
return nullptr;
}
switch(n->get_kind()) {
case AST_APP:
return to_app(n)->get_decl()->get_range();
case AST_VAR:
return to_var(n)->get_sort();
case AST_QUANTIFIER:
return to_quantifier(n)->get_sort();
default:
UNREACHABLE();
return 0;
}
}
@ -466,7 +484,7 @@ bool compare_nodes(ast const * n1, ast const * n2) {
to_var(n1)->get_sort() == to_var(n2)->get_sort();
case AST_QUANTIFIER:
return
to_quantifier(n1)->is_forall() == to_quantifier(n2)->is_forall() &&
to_quantifier(n1)->get_kind() == to_quantifier(n2)->get_kind() &&
to_quantifier(n1)->get_num_decls() == to_quantifier(n2)->get_num_decls() &&
compare_arrays(to_quantifier(n1)->get_decl_sorts(),
to_quantifier(n2)->get_decl_sorts(),
@ -566,7 +584,7 @@ unsigned get_node_hash(ast const * n) {
case AST_QUANTIFIER:
a = ast_array_hash(to_quantifier(n)->get_decl_sorts(),
to_quantifier(n)->get_num_decls(),
to_quantifier(n)->is_forall() ? 31 : 19);
to_quantifier(n)->get_kind() == forall_k ? 31 : 19);
b = to_quantifier(n)->get_num_patterns();
c = to_quantifier(n)->get_expr()->hash();
mix(a,b,c);
@ -689,7 +707,8 @@ bool basic_decl_plugin::check_proof_sorts(basic_op_kind k, unsigned arity, sort
for (unsigned i = 0; i < arity - 1; i++)
if (domain[i] != m_proof_sort)
return false;
return domain[arity-1] == m_bool_sort || domain[arity-1] == m_proof_sort;
#define is_array(_x_) true
return domain[arity-1] == m_bool_sort || domain[arity-1] == m_proof_sort || is_array(domain[arity-1]);
}
}
@ -704,7 +723,8 @@ bool basic_decl_plugin::check_proof_args(basic_op_kind k, unsigned num_args, exp
return false;
return
m_manager->get_sort(args[num_args - 1]) == m_bool_sort ||
m_manager->get_sort(args[num_args - 1]) == m_proof_sort;
m_manager->get_sort(args[num_args - 1]) == m_proof_sort ||
is_lambda(args[num_args-1]);
}
}
@ -818,6 +838,7 @@ func_decl * basic_decl_plugin::mk_proof_decl(basic_op_kind k, unsigned num_paren
case PR_TRANSITIVITY_STAR: return mk_proof_decl("trans*", k, num_parents, m_transitivity_star_decls);
case PR_MONOTONICITY: return mk_proof_decl("monotonicity", k, num_parents, m_monotonicity_decls);
case PR_QUANT_INTRO: return mk_proof_decl("quant-intro", k, 1, m_quant_intro_decl);
case PR_BIND: UNREACHABLE();
case PR_DISTRIBUTIVITY: return mk_proof_decl("distributivity", k, num_parents, m_distributivity_decls);
case PR_AND_ELIM: return mk_proof_decl("and-elim", k, 1, m_and_elim_decl);
case PR_NOT_OR_ELIM: return mk_proof_decl("not-or-elim", k, 1, m_not_or_elim_decl);
@ -1054,6 +1075,10 @@ func_decl * basic_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters
// eq and oeq must have at least two arguments, they can have more since they are chainable
case OP_EQ: return arity >= 2 ? mk_eq_decl_core("=", OP_EQ, join(arity, domain), m_eq_decls) : nullptr;
case OP_OEQ: return arity >= 2 ? mk_eq_decl_core("~", OP_OEQ, join(arity, domain), m_oeq_decls) : nullptr;
case PR_BIND: {
func_decl_info info(m_family_id, PR_BIND);
return m_manager->mk_func_decl(symbol("proof-bind"), arity, domain, m_proof_sort, info);
}
case OP_DISTINCT: {
func_decl_info info(m_family_id, OP_DISTINCT);
info.set_pairwise();
@ -1097,6 +1122,11 @@ func_decl * basic_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters
case OP_OEQ: return num_args >= 2 ? mk_eq_decl_core("~", OP_OEQ, join(num_args, args), m_oeq_decls) : nullptr;
case OP_DISTINCT:
return decl_plugin::mk_func_decl(k, num_parameters, parameters, num_args, args, range);
case PR_BIND: {
ptr_buffer<sort> sorts;
for (unsigned i = 0; i < num_args; ++i) sorts.push_back(m_manager->get_sort(args[i]));
return mk_func_decl(k, num_parameters, parameters, num_args, sorts.c_ptr(), range);
}
default:
break;
}
@ -1218,7 +1248,6 @@ func_decl * model_value_decl_plugin::mk_func_decl(decl_kind k, unsigned num_para
unsigned arity, sort * const * domain, sort * range) {
SASSERT(k == OP_MODEL_VALUE);
if (arity != 0 || num_parameters != 2 || !parameters[0].is_int() || !parameters[1].is_ast() || !is_sort(parameters[1].get_ast())) {
UNREACHABLE();
m_manager->raise_exception("invalid model value");
return nullptr;
}
@ -1290,7 +1319,8 @@ ast_manager::ast_manager(proof_gen_mode m, char const * trace_file, bool is_form
m_proof_mode(m),
m_trace_stream(nullptr),
m_trace_stream_owner(false),
m_rec_fun(":rec-fun") {
m_rec_fun(":rec-fun"),
m_lambda_def(":lambda-def") {
if (trace_file) {
m_trace_stream = alloc(std::fstream, trace_file, std::ios_base::out);
@ -1312,7 +1342,8 @@ ast_manager::ast_manager(proof_gen_mode m, std::fstream * trace_stream, bool is_
m_proof_mode(m),
m_trace_stream(trace_stream),
m_trace_stream_owner(false),
m_rec_fun(":rec-fun") {
m_rec_fun(":rec-fun"),
m_lambda_def(":lambda-def") {
if (!is_format_manager)
m_format_manager = alloc(ast_manager, PGM_DISABLED, trace_stream, true);
@ -1508,7 +1539,6 @@ void ast_manager::raise_exception(char const * msg) {
throw ast_exception(msg);
}
#include "ast/ast_translation.h"
void ast_manager::copy_families_plugins(ast_manager const & from) {
TRACE("copy_families_plugins",
@ -1761,6 +1791,7 @@ ast * ast_manager::register_node_core(ast * n) {
case AST_QUANTIFIER:
inc_array_ref(to_quantifier(n)->get_num_decls(), to_quantifier(n)->get_decl_sorts());
inc_ref(to_quantifier(n)->get_expr());
inc_ref(to_quantifier(n)->get_sort());
inc_array_ref(to_quantifier(n)->get_num_patterns(), to_quantifier(n)->get_patterns());
inc_array_ref(to_quantifier(n)->get_num_no_patterns(), to_quantifier(n)->get_no_patterns());
break;
@ -1824,6 +1855,7 @@ void ast_manager::delete_node(ast * n) {
case AST_QUANTIFIER:
dec_array_ref(worklist, to_quantifier(n)->get_num_decls(), to_quantifier(n)->get_decl_sorts());
dec_ref(worklist, to_quantifier(n)->get_expr());
dec_ref(worklist, to_quantifier(n)->get_sort());
dec_array_ref(worklist, to_quantifier(n)->get_num_patterns(), to_quantifier(n)->get_patterns());
dec_array_ref(worklist, to_quantifier(n)->get_num_no_patterns(), to_quantifier(n)->get_no_patterns());
break;
@ -2338,7 +2370,7 @@ bool ast_manager::is_pattern(expr const * n, ptr_vector<expr> &args) {
}
quantifier * ast_manager::mk_quantifier(bool forall, unsigned num_decls, sort * const * decl_sorts, symbol const * decl_names,
quantifier * ast_manager::mk_quantifier(quantifier_kind k, unsigned num_decls, sort * const * decl_sorts, symbol const * decl_names,
expr * body, int weight , symbol const & qid, symbol const & skid,
unsigned num_patterns, expr * const * patterns,
unsigned num_no_patterns, expr * const * no_patterns) {
@ -2353,7 +2385,17 @@ quantifier * ast_manager::mk_quantifier(bool forall, unsigned num_decls, sort *
}});
unsigned sz = quantifier::get_obj_size(num_decls, num_patterns, num_no_patterns);
void * mem = allocate_node(sz);
quantifier * new_node = new (mem) quantifier(forall, num_decls, decl_sorts, decl_names, body,
sort* s = nullptr;
if (k == lambda_k) {
array_util autil(*this);
s = autil.mk_array_sort(num_decls, decl_sorts, ::get_sort(body));
}
else {
s = mk_bool_sort();
}
quantifier * new_node = new (mem) quantifier(k, num_decls, decl_sorts, decl_names, body, s,
weight, qid, skid, num_patterns, patterns,
num_no_patterns, no_patterns);
quantifier * r = register_node(new_node);
@ -2370,6 +2412,18 @@ quantifier * ast_manager::mk_quantifier(bool forall, unsigned num_decls, sort *
return r;
}
quantifier * ast_manager::mk_lambda(unsigned num_decls, sort * const * decl_sorts, symbol const * decl_names, expr * body) {
SASSERT(body);
unsigned sz = quantifier::get_obj_size(num_decls, 0, 0);
void * mem = allocate_node(sz);
array_util autil(*this);
sort* s = autil.mk_array_sort(num_decls, decl_sorts, ::get_sort(body));
quantifier * new_node = new (mem) quantifier(num_decls, decl_sorts, decl_names, body, s);
quantifier * r = register_node(new_node);
return r;
}
// Return true if the patterns of q are the given ones.
static bool same_patterns(quantifier * q, unsigned num_patterns, expr * const * patterns) {
if (num_patterns != q->get_num_patterns())
@ -2393,7 +2447,7 @@ static bool same_no_patterns(quantifier * q, unsigned num_no_patterns, expr * co
quantifier * ast_manager::update_quantifier(quantifier * q, unsigned num_patterns, expr * const * patterns, expr * body) {
if (q->get_expr() == body && same_patterns(q, num_patterns, patterns))
return q;
return mk_quantifier(q->is_forall(),
return mk_quantifier(q->get_kind(),
q->get_num_decls(),
q->get_decl_sorts(),
q->get_decl_names(),
@ -2410,7 +2464,7 @@ quantifier * ast_manager::update_quantifier(quantifier * q, unsigned num_pattern
quantifier * ast_manager::update_quantifier(quantifier * q, unsigned num_patterns, expr * const * patterns, unsigned num_no_patterns, expr * const * no_patterns, expr * body) {
if (q->get_expr() == body && same_patterns(q, num_patterns, patterns) && same_no_patterns(q, num_no_patterns, no_patterns))
return q;
return mk_quantifier(q->is_forall(),
return mk_quantifier(q->get_kind(),
q->get_num_decls(),
q->get_decl_sorts(),
q->get_decl_names(),
@ -2427,7 +2481,7 @@ quantifier * ast_manager::update_quantifier(quantifier * q, unsigned num_pattern
quantifier * ast_manager::update_quantifier(quantifier * q, expr * body) {
if (q->get_expr() == body)
return q;
return mk_quantifier(q->is_forall(),
return mk_quantifier(q->get_kind(),
q->get_num_decls(),
q->get_decl_sorts(),
q->get_decl_names(),
@ -2445,7 +2499,7 @@ quantifier * ast_manager::update_quantifier_weight(quantifier * q, int w) {
if (q->get_weight() == w)
return q;
TRACE("update_quantifier_weight", tout << "#" << q->get_id() << " " << q->get_weight() << " -> " << w << "\n";);
return mk_quantifier(q->is_forall(),
return mk_quantifier(q->get_kind(),
q->get_num_decls(),
q->get_decl_sorts(),
q->get_decl_names(),
@ -2459,10 +2513,10 @@ quantifier * ast_manager::update_quantifier_weight(quantifier * q, int w) {
q->get_no_patterns());
}
quantifier * ast_manager::update_quantifier(quantifier * q, bool is_forall, expr * body) {
if (q->get_expr() == body && q->is_forall() == is_forall)
quantifier * ast_manager::update_quantifier(quantifier * q, quantifier_kind k, expr * body) {
if (q->get_expr() == body && q->get_kind() == k)
return q;
return mk_quantifier(is_forall,
return mk_quantifier(k,
q->get_num_decls(),
q->get_decl_sorts(),
q->get_decl_names(),
@ -2476,10 +2530,10 @@ quantifier * ast_manager::update_quantifier(quantifier * q, bool is_forall, expr
q->get_no_patterns());
}
quantifier * ast_manager::update_quantifier(quantifier * q, bool is_forall, unsigned num_patterns, expr * const * patterns, expr * body) {
if (q->get_expr() == body && q->is_forall() == is_forall && same_patterns(q, num_patterns, patterns))
quantifier * ast_manager::update_quantifier(quantifier * q, quantifier_kind k, unsigned num_patterns, expr * const * patterns, expr * body) {
if (q->get_expr() == body && q->get_kind() == k && same_patterns(q, num_patterns, patterns))
return q;
return mk_quantifier(is_forall,
return mk_quantifier(k,
q->get_num_decls(),
q->get_decl_sorts(),
q->get_decl_names(),
@ -2786,11 +2840,17 @@ proof * ast_manager::mk_oeq_congruence(app * f1, app * f2, unsigned num_proofs,
return mk_monotonicity(mk_func_decl(m_basic_family_id, OP_OEQ, 0, nullptr, 2, d), f1, f2, num_proofs, proofs);
}
proof * ast_manager::mk_bind_proof(quantifier * q, proof * p) {
expr* b = mk_lambda(q->get_num_decls(), q->get_decl_sorts(), q->get_decl_names(), p);
return mk_app(m_basic_family_id, PR_BIND, b);
}
proof * ast_manager::mk_quant_intro(quantifier * q1, quantifier * q2, proof * p) {
if (!p) return nullptr;
SASSERT(q1->get_num_decls() == q2->get_num_decls());
SASSERT(has_fact(p));
SASSERT(is_eq(get_fact(p)));
if (!p) return nullptr;
SASSERT(q1->get_num_decls() == q2->get_num_decls());
SASSERT(has_fact(p));
SASSERT(is_eq(get_fact(p)) || is_lambda(get_fact(p)));
return mk_app(m_basic_family_id, PR_QUANT_INTRO, p, mk_iff(q1, q2));
}

View file

@ -793,11 +793,18 @@ public:
//
// -----------------------------------
enum quantifier_kind {
forall_k,
exists_k,
lambda_k
};
class quantifier : public expr {
friend class ast_manager;
bool m_forall;
quantifier_kind m_kind;
unsigned m_num_decls;
expr * m_expr;
sort * m_sort;
unsigned m_depth;
// extra fields
int m_weight;
@ -813,12 +820,18 @@ class quantifier : public expr {
return sizeof(quantifier) + num_decls * (sizeof(sort *) + sizeof(symbol)) + (num_patterns + num_no_patterns) * sizeof(expr*);
}
quantifier(bool forall, unsigned num_decls, sort * const * decl_sorts, symbol const * decl_names, expr * body,
quantifier(quantifier_kind k, unsigned num_decls, sort * const * decl_sorts, symbol const * decl_names, expr * body, sort* s,
int weight, symbol const & qid, symbol const & skid, unsigned num_patterns, expr * const * patterns,
unsigned num_no_patterns, expr * const * no_patterns);
quantifier(unsigned num_decls, sort * const * decl_sorts, symbol const * decl_names, expr * body, sort* sort);
public:
bool is_forall() const { return m_forall; }
bool is_exists() const { return !m_forall; }
quantifier_kind get_kind() const { return m_kind; }
// bool is_forall() const { return m_kind == forall_k; }
// bool is_exists() const { return m_kind == exists_k; }
// bool is_lambda() const { return m_kind == lambda_k; }
unsigned get_num_decls() const { return m_num_decls; }
sort * const * get_decl_sorts() const { return reinterpret_cast<sort * const *>(m_patterns_decls); }
symbol const * get_decl_names() const { return reinterpret_cast<symbol const *>(get_decl_sorts() + m_num_decls); }
@ -826,6 +839,8 @@ public:
symbol const & get_decl_name(unsigned idx) const { return get_decl_names()[idx]; }
expr * get_expr() const { return m_expr; }
sort * get_sort() const { return m_sort; }
unsigned get_depth() const { return m_depth; }
int get_weight() const { return m_weight; }
@ -844,6 +859,7 @@ public:
void set_no_unused_vars() { m_has_unused_vars = false; }
bool has_labels() const { return m_has_labels; }
unsigned get_num_children() const { return 1 + get_num_patterns() + get_num_no_patterns(); }
expr * get_child(unsigned idx) const {
@ -871,8 +887,9 @@ inline bool is_app(ast const * n) { return n->get_kind() == AST_APP; }
inline bool is_var(ast const * n) { return n->get_kind() == AST_VAR; }
inline bool is_var(ast const * n, unsigned& idx) { return is_var(n) && (idx = static_cast<var const*>(n)->get_idx(), true); }
inline bool is_quantifier(ast const * n) { return n->get_kind() == AST_QUANTIFIER; }
inline bool is_forall(ast const * n) { return is_quantifier(n) && static_cast<quantifier const *>(n)->is_forall(); }
inline bool is_exists(ast const * n) { return is_quantifier(n) && static_cast<quantifier const *>(n)->is_exists(); }
inline bool is_forall(ast const * n) { return is_quantifier(n) && static_cast<quantifier const *>(n)->get_kind() == forall_k; }
inline bool is_exists(ast const * n) { return is_quantifier(n) && static_cast<quantifier const *>(n)->get_kind() == exists_k; }
inline bool is_lambda(ast const * n) { return is_quantifier(n) && static_cast<quantifier const *>(n)->get_kind() == lambda_k; }
// -----------------------------------
//
@ -950,7 +967,7 @@ protected:
family_id m_family_id;
virtual void set_manager(ast_manager * m, family_id id) {
SASSERT(m_manager == 0);
SASSERT(m_manager == nullptr);
m_manager = m;
m_family_id = id;
}
@ -1043,7 +1060,7 @@ enum basic_sort_kind {
enum basic_op_kind {
OP_TRUE, OP_FALSE, OP_EQ, OP_DISTINCT, OP_ITE, OP_AND, OP_OR, OP_XOR, OP_NOT, OP_IMPLIES, OP_OEQ, LAST_BASIC_OP,
PR_UNDEF, PR_TRUE, PR_ASSERTED, PR_GOAL, PR_MODUS_PONENS, PR_REFLEXIVITY, PR_SYMMETRY, PR_TRANSITIVITY, PR_TRANSITIVITY_STAR, PR_MONOTONICITY, PR_QUANT_INTRO,
PR_UNDEF, PR_TRUE, PR_ASSERTED, PR_GOAL, PR_MODUS_PONENS, PR_REFLEXIVITY, PR_SYMMETRY, PR_TRANSITIVITY, PR_TRANSITIVITY_STAR, PR_MONOTONICITY, PR_QUANT_INTRO, PR_BIND,
PR_DISTRIBUTIVITY, PR_AND_ELIM, PR_NOT_OR_ELIM, PR_REWRITE, PR_REWRITE_STAR, PR_PULL_QUANT,
PR_PUSH_QUANT, PR_ELIM_UNUSED_VARS, PR_DER, PR_QUANT_INST,
@ -1487,6 +1504,7 @@ protected:
#endif
ast_manager * m_format_manager; // hack for isolating format objects in a different manager.
symbol m_rec_fun;
symbol m_lambda_def;
void init();
@ -1594,9 +1612,12 @@ public:
bool contains(ast * a) const { return m_ast_table.contains(a); }
bool is_rec_fun_def(quantifier* q) const { return q->get_qid() == m_rec_fun; }
bool is_lambda_def(quantifier* q) const { return q->get_qid() == m_lambda_def; }
symbol const& rec_fun_qid() const { return m_rec_fun; }
symbol const& lambda_def_qid() const { return m_lambda_def; }
unsigned get_num_asts() const { return m_ast_table.size(); }
void debug_ref_count() { m_debug_ref_count = true; }
@ -1892,7 +1913,7 @@ public:
public:
quantifier * mk_quantifier(bool forall, unsigned num_decls, sort * const * decl_sorts, symbol const * decl_names, expr * body,
quantifier * mk_quantifier(quantifier_kind k, unsigned num_decls, sort * const * decl_sorts, symbol const * decl_names, expr * body,
int weight = 0, symbol const & qid = symbol::null, symbol const & skid = symbol::null,
unsigned num_patterns = 0, expr * const * patterns = nullptr,
unsigned num_no_patterns = 0, expr * const * no_patterns = nullptr);
@ -1901,7 +1922,7 @@ public:
int weight = 0, symbol const & qid = symbol::null, symbol const & skid = symbol::null,
unsigned num_patterns = 0, expr * const * patterns = nullptr,
unsigned num_no_patterns = 0, expr * const * no_patterns = nullptr) {
return mk_quantifier(true, num_decls, decl_sorts, decl_names, body, weight, qid, skid, num_patterns, patterns,
return mk_quantifier(forall_k, num_decls, decl_sorts, decl_names, body, weight, qid, skid, num_patterns, patterns,
num_no_patterns, no_patterns);
}
@ -1909,10 +1930,12 @@ public:
int weight = 0, symbol const & qid = symbol::null, symbol const & skid = symbol::null,
unsigned num_patterns = 0, expr * const * patterns = nullptr,
unsigned num_no_patterns = 0, expr * const * no_patterns = nullptr) {
return mk_quantifier(false, num_decls, decl_sorts, decl_names, body, weight, qid, skid, num_patterns, patterns,
return mk_quantifier(exists_k, num_decls, decl_sorts, decl_names, body, weight, qid, skid, num_patterns, patterns,
num_no_patterns, no_patterns);
}
quantifier * mk_lambda(unsigned num_decls, sort * const * decl_sorts, symbol const * decl_names, expr * body);
quantifier * update_quantifier(quantifier * q, unsigned new_num_patterns, expr * const * new_patterns, expr * new_body);
quantifier * update_quantifier(quantifier * q, unsigned new_num_patterns, expr * const * new_patterns, unsigned new_num_no_patterns, expr * const * new_no_patterns, expr * new_body);
@ -1921,9 +1944,9 @@ public:
quantifier * update_quantifier_weight(quantifier * q, int new_weight);
quantifier * update_quantifier(quantifier * q, bool new_is_forall, expr * new_body);
quantifier * update_quantifier(quantifier * q, quantifier_kind new_kind, expr * new_body);
quantifier * update_quantifier(quantifier * q, bool new_is_forall, unsigned new_num_patterns, expr * const * new_patterns, expr * new_body);
quantifier * update_quantifier(quantifier * q, quantifier_kind new_kind, unsigned new_num_patterns, expr * const * new_patterns, expr * new_body);
// -----------------------------------
//
@ -2213,6 +2236,7 @@ public:
proof * mk_rewrite(expr * s, expr * t);
proof * mk_oeq_rewrite(expr * s, expr * t);
proof * mk_rewrite_star(expr * s, expr * t, unsigned num_proofs, proof * const * proofs);
proof * mk_bind_proof(quantifier * q, proof * p);
proof * mk_pull_quant(expr * e, quantifier * q);
proof * mk_push_quant(quantifier * q, expr * e);
proof * mk_elim_unused_vars(quantifier * q, expr * r);

View file

@ -242,7 +242,7 @@ public:
void operator()(quantifier * n) {
display_def_header(n);
m_out << "(" << (n->is_forall() ? "forall" : "exists") << " ";
m_out << "(" << (n->get_kind() == forall_k ? "forall" : (n->get_kind() == exists_k ? "exists" : "lambda")) << " ";
unsigned num_decls = n->get_num_decls();
m_out << "(vars ";
for (unsigned i = 0; i < num_decls; i++) {

View file

@ -102,7 +102,7 @@ bool lt(ast * n1, ast * n2) {
UNREACHABLE();
return false;
case AST_QUANTIFIER:
check_bool(to_quantifier(n1)->is_forall(), to_quantifier(n2)->is_forall());
check_value(to_quantifier(n1)->get_kind(), to_quantifier(n2)->get_kind());
check_value(to_quantifier(n1)->get_num_decls(), to_quantifier(n2)->get_num_decls());
check_value(to_quantifier(n1)->get_num_patterns(), to_quantifier(n2)->get_num_patterns());
check_value(to_quantifier(n1)->get_num_no_patterns(), to_quantifier(n2)->get_num_no_patterns());

View file

@ -994,7 +994,7 @@ class smt2_printer {
}
format * f_decls = pp_var_decls(q);
format * fs[2] = { f_decls, f_body };
char const * header = q->is_forall() ? "forall" : "exists";
char const * header = q->get_kind() == forall_k ? "forall" : (q->get_kind() == exists_k ? "exists" : "lambda");
format * f = mk_seq3<format**, f2f>(m(), fs, fs+2, f2f(), header, 1, SMALL_INDENT);
info f_info = m_info_stack.back();

View file

@ -495,11 +495,10 @@ class smt_printer {
m_qlists.push_back(q);
m_out << "(";
if (q->is_forall()) {
m_out << "forall ";
}
else {
m_out << "exists ";
switch (q->get_kind()) {
case forall_k: m_out << "forall "; break;
case exists_k: m_out << "exists "; break;
case lambda_k: m_out << "lambda "; break;
}
m_out << "(";
for (unsigned i = 0; i < q->get_num_decls(); ++i) {

View file

@ -279,7 +279,7 @@ ast * ast_translation::process(ast const * _n) {
expr ** pats = reinterpret_cast<expr**>(m_result_stack.c_ptr() + fr.m_rpos + num_decls + 1);
unsigned num_no_pats = to_quantifier(n)->get_num_no_patterns();
expr ** no_pats = pats + num_pats;
quantifier * new_q = m_to_manager.mk_quantifier(to_quantifier(n)->is_forall(),
quantifier * new_q = m_to_manager.mk_quantifier(to_quantifier(n)->get_kind(),
num_decls,
dsorts,
dnames,

View file

@ -115,7 +115,7 @@ void expr_abstract(ast_manager& m, unsigned base, unsigned num_bound, expr* cons
tout << result << "\n";);
}
expr_ref mk_quantifier(bool is_forall, ast_manager& m, unsigned num_bound, app* const* bound, expr* n) {
expr_ref mk_quantifier(quantifier_kind k, ast_manager& m, unsigned num_bound, app* const* bound, expr* n) {
expr_ref result(m);
expr_abstract(m, 0, num_bound, (expr* const*)bound, n, result);
if (num_bound > 0) {
@ -125,7 +125,7 @@ expr_ref mk_quantifier(bool is_forall, ast_manager& m, unsigned num_bound, app*
sorts.push_back(m.get_sort(bound[i]));
names.push_back(bound[i]->get_decl()->get_name());
}
result = m.mk_quantifier(is_forall, num_bound, sorts.c_ptr(), names.c_ptr(), result);
result = m.mk_quantifier(k, num_bound, sorts.c_ptr(), names.c_ptr(), result);
}
TRACE("expr_abstract",
tout << expr_ref(n, m) << "\n";
@ -137,9 +137,9 @@ expr_ref mk_quantifier(bool is_forall, ast_manager& m, unsigned num_bound, app*
}
expr_ref mk_forall(ast_manager& m, unsigned num_bound, app* const* bound, expr* n) {
return mk_quantifier(true, m, num_bound, bound, n);
return mk_quantifier(forall_k, m, num_bound, bound, n);
}
expr_ref mk_exists(ast_manager& m, unsigned num_bound, app* const* bound, expr* n) {
return mk_quantifier(false, m, num_bound, bound, n);
return mk_quantifier(exists_k, m, num_bound, bound, n);
}

View file

@ -194,6 +194,9 @@ bool fpa2bv_rewriter_cfg::reduce_quantifier(quantifier * old_q,
expr * const * new_no_patterns,
expr_ref & result,
proof_ref & result_pr) {
if (is_lambda(old_q)) {
return false;
}
unsigned curr_sz = m_bindings.size();
SASSERT(old_q->get_num_decls() <= curr_sz);
unsigned num_decls = old_q->get_num_decls();
@ -217,7 +220,7 @@ bool fpa2bv_rewriter_cfg::reduce_quantifier(quantifier * old_q,
new_decl_names.push_back(n);
}
}
result = m().mk_quantifier(old_q->is_forall(), new_decl_sorts.size(), new_decl_sorts.c_ptr(), new_decl_names.c_ptr(),
result = m().mk_quantifier(old_q->get_kind(), new_decl_sorts.size(), new_decl_sorts.c_ptr(), new_decl_names.c_ptr(),
new_body, old_q->get_weight(), old_q->get_qid(), old_q->get_skid(),
old_q->get_num_patterns(), new_patterns, old_q->get_num_no_patterns(), new_no_patterns);
result_pr = nullptr;

View file

@ -23,7 +23,7 @@ Revision History:
#include "ast/ast_ll_pp.h"
bool macro_finder::is_macro(expr * n, app_ref & head, expr_ref & def) {
if (!is_quantifier(n) || !to_quantifier(n)->is_forall())
if (!is_forall(n))
return false;
TRACE("macro_finder", tout << "processing: " << mk_pp(n, m) << "\n";);
expr * body = to_quantifier(n)->get_expr();
@ -46,7 +46,7 @@ bool macro_finder::is_macro(expr * n, app_ref & head, expr_ref & def) {
For case 2 & 3, the new quantifiers are stored in new_exprs and new_prs.
*/
bool macro_finder::is_arith_macro(expr * n, proof * pr, expr_dependency * dep, expr_ref_vector & new_exprs, proof_ref_vector & new_prs, expr_dependency_ref_vector & new_deps) {
if (!is_quantifier(n) || !to_quantifier(n)->is_forall())
if (!is_forall(n))
return false;
expr * body = to_quantifier(n)->get_expr();
unsigned num_decls = to_quantifier(n)->get_num_decls();
@ -117,7 +117,7 @@ bool macro_finder::is_arith_macro(expr * n, proof * pr, expr_dependency * dep, e
}
bool macro_finder::is_arith_macro(expr * n, proof * pr, vector<justified_expr>& new_fmls) {
if (!is_quantifier(n) || !to_quantifier(n)->is_forall())
if (!is_forall(n))
return false;
expr * body = to_quantifier(n)->get_expr();
unsigned num_decls = to_quantifier(n)->get_num_decls();

View file

@ -283,13 +283,11 @@ struct macro_manager::macro_expander_cfg : public default_rewriter_cfg {
subst_args[nidx] = n->get_arg(i);
}
var_subst s(m);
expr_ref rr(m);
s(def, num, subst_args.c_ptr(), rr);
expr_ref rr = s(def, num, subst_args.c_ptr());
m_trail.push_back(rr);
r = rr;
if (m.proofs_enabled()) {
expr_ref instance(m);
s(q->get_expr(), num, subst_args.c_ptr(), instance);
expr_ref instance = s(q->get_expr(), num, subst_args.c_ptr());
proof * qi_pr = m.mk_quant_inst(m.mk_or(m.mk_not(q), instance), num, subst_args.c_ptr());
proof * q_pr = nullptr;
mm.m_decl2macro_pr.find(d, q_pr);

View file

@ -334,7 +334,7 @@ bool macro_util::is_pseudo_head(expr * n, unsigned num_decls, app_ref & head, ap
where t is a ground term, (f X) is the head.
*/
bool macro_util::is_pseudo_predicate_macro(expr * n, app_ref & head, app_ref & t, expr_ref & def) {
if (!is_quantifier(n) || !to_quantifier(n)->is_forall())
if (!is_forall(n))
return false;
TRACE("macro_util", tout << "processing: " << mk_pp(n, m_manager) << "\n";);
expr * body = to_quantifier(n)->get_expr();
@ -485,7 +485,7 @@ void macro_util::normalize_expr(app * head, unsigned num_decls, expr * t, expr_r
if (var_mapping[i] != 0)
tout << "#" << i << " -> " << mk_ll_pp(var_mapping[i], m_manager);
});
subst(t, var_mapping.size(), var_mapping.c_ptr(), norm_t);
norm_t = subst(t, var_mapping.size(), var_mapping.c_ptr());
}
else {
norm_t = t;

View file

@ -155,7 +155,7 @@ bool quasi_macros::is_quasi_macro(expr * e, app_ref & a, expr_ref & t) const {
// f[X] contains all universally quantified variables, and f does not occur in T[X].
TRACE("quasi_macros", tout << "Checking for quasi macro: " << mk_pp(e, m_manager) << std::endl;);
if (is_quantifier(e) && to_quantifier(e)->is_forall()) {
if (is_forall(e)) {
quantifier * q = to_quantifier(e);
expr * qe = q->get_expr();
if ((m_manager.is_eq(qe))) {
@ -251,7 +251,7 @@ void quasi_macros::quasi_macro_to_macro(quantifier * q, app * a, expr * t, quant
eq = m_manager.mk_eq(appl, ite);
macro = m_manager.mk_quantifier(true, new_var_names_rev.size(),
macro = m_manager.mk_quantifier(forall_k, new_var_names_rev.size(),
new_qsorts_rev.c_ptr(), new_var_names_rev.c_ptr(), eq);
}

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

View file

@ -77,6 +77,11 @@ public:
*/
bool mk_pos_name(expr * e, expr_ref & new_def, proof_ref & new_def_pr, app_ref & n, proof_ref & pr);
/**
\brief Create a definition for 'n' using 'e'.
*/
expr_ref mk_definition(expr * e, app * n);
void push();
void pop(unsigned num_scopes);
void reset();

View file

@ -22,7 +22,7 @@ Notes:
class name_exprs_core : public name_exprs {
struct cfg : public default_rewriter_cfg {
ast_manager & m_manager;
ast_manager & m;
defined_names & m_defined_names;
expr_predicate & m_pred;
@ -33,7 +33,7 @@ class name_exprs_core : public name_exprs {
proof_ref_vector * m_def_proofs;
cfg(ast_manager & m, defined_names & n, expr_predicate & pred):
m_manager(m),
m(m),
m_defined_names(n),
m_pred(pred),
m_r(m),
@ -43,12 +43,12 @@ class name_exprs_core : public name_exprs {
}
void gen_name_for_expr(expr * n, expr * & t, proof * & t_pr) {
expr_ref new_def(m_manager);
proof_ref new_def_pr(m_manager);
expr_ref new_def(m);
proof_ref new_def_pr(m);
if (m_defined_names.mk_name(n, new_def, new_def_pr, m_r, m_pr)) {
m_def_exprs->push_back(new_def);
if (m_manager.proofs_enabled())
if (m.proofs_enabled())
m_def_proofs->push_back(new_def_pr);
}
@ -57,7 +57,7 @@ class name_exprs_core : public name_exprs {
}
bool get_subst(expr * s, expr * & t, proof * & t_pr) {
TRACE("name_exprs", tout << "get_subst:\n" << mk_ismt2_pp(s, m_manager) << "\n";);
TRACE("name_exprs", tout << "get_subst:\n" << mk_ismt2_pp(s, m) << "\n";);
if (m_pred(s)) {
gen_name_for_expr(s, t, t_pr);
return true;
@ -84,7 +84,7 @@ public:
m_cfg.m_def_exprs = &new_defs;
m_cfg.m_def_proofs = &new_def_proofs;
m_rw(n, r, p);
TRACE("name_exprs", tout << mk_ismt2_pp(n, m_rw.m()) << "\n---->\n" << mk_ismt2_pp(r, m_rw.m()) << "\n";);
TRACE("name_exprs", tout << mk_ismt2_pp(n, m_rw.m()) << "\n---->\n" << r << "\n";);
}
@ -99,11 +99,11 @@ name_exprs * mk_expr_namer(ast_manager & m, defined_names & n, expr_predicate &
class name_quantifier_labels : public name_exprs_core {
class pred : public expr_predicate {
ast_manager & m_manager;
ast_manager & m;
public:
pred(ast_manager & m):m_manager(m) {}
pred(ast_manager & m):m(m) {}
bool operator()(expr * t) override {
return is_quantifier(t) || m_manager.is_label(t);
return is_quantifier(t) || m.is_label(t);
}
};
@ -124,16 +124,16 @@ name_exprs * mk_quantifier_label_namer(ast_manager & m, defined_names & n) {
class name_nested_formulas : public name_exprs_core {
struct pred : public expr_predicate {
ast_manager & m_manager;
ast_manager & m;
expr * m_root;
pred(ast_manager & m):m_manager(m), m_root(nullptr) {}
pred(ast_manager & m):m(m), m_root(0) {}
bool operator()(expr * t) override {
TRACE("name_exprs", tout << "name_nested_formulas::pred:\n" << mk_ismt2_pp(t, m_manager) << "\n";);
TRACE("name_exprs", tout << "name_nested_formulas::pred:\n" << mk_ismt2_pp(t, m) << "\n";);
if (is_app(t))
return to_app(t)->get_family_id() == m_manager.get_basic_family_id() && to_app(t)->get_num_args() > 0 && t != m_root;
return m_manager.is_label(t) || is_quantifier(t);
return to_app(t)->get_family_id() == m.get_basic_family_id() && to_app(t)->get_num_args() > 0 && t != m_root;
return m.is_label(t) || is_quantifier(t);
}
};

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) {

View file

@ -49,7 +49,8 @@ struct pull_quant::imp {
if (is_quantifier(child)) {
quantifier * q = to_quantifier(child);
expr * body = q->get_expr();
result = m_manager.update_quantifier(q, !q->is_forall(), m_manager.mk_not(body));
quantifier_kind k = q->get_kind() == forall_k ? exists_k : forall_k;
result = m_manager.update_quantifier(q, k, m_manager.mk_not(body));
return true;
}
else {
@ -149,7 +150,7 @@ struct pull_quant::imp {
// 3) MBQI
std::reverse(var_sorts.begin(), var_sorts.end());
std::reverse(var_names.begin(), var_names.end());
result = m_manager.mk_quantifier(forall_children,
result = m_manager.mk_quantifier(forall_children ? forall_k : exists_k,
var_sorts.size(),
var_sorts.c_ptr(),
var_names.c_ptr(),
@ -220,9 +221,7 @@ struct pull_quant::imp {
expr_ref_buffer new_args(m_manager);
expr_ref new_arg(m_manager);
ptr_buffer<proof> proofs;
unsigned num = to_app(n)->get_num_args();
for (unsigned i = 0; i < num; i++) {
expr * arg = to_app(n)->get_arg(i);
for (expr * arg : *to_app(n)) {
pull_quant1(arg , new_arg);
new_args.push_back(new_arg);
if (new_arg != arg)
@ -277,10 +276,13 @@ struct pull_quant::imp {
expr_ref & result,
proof_ref & result_pr) {
if (old_q->is_exists()) {
if (is_exists(old_q)) {
UNREACHABLE();
return false;
}
if (is_lambda(old_q)) {
return false;
}
if (!is_forall(new_body))
return false;

View file

@ -53,7 +53,7 @@ expr_pattern_match::match_quantifier(quantifier* qf, app_ref_vector& patterns, u
m_regs[0] = qf->get_expr();
for (unsigned i = 0; i < m_precompiled.size(); ++i) {
quantifier* qf2 = m_precompiled[i].get();
if (qf2->is_forall() != qf->is_forall()) {
if (qf2->get_kind() != qf->get_kind() || is_lambda(qf)) {
continue;
}
if (qf2->get_num_decls() != qf->get_num_decls()) {

View file

@ -582,7 +582,7 @@ bool pattern_inference_cfg::reduce_quantifier(
proof_ref & result_pr) {
TRACE("pattern_inference", tout << "processing:\n" << mk_pp(q, m) << "\n";);
if (!q->is_forall()) {
if (!is_forall(q)) {
return false;
}
@ -673,6 +673,7 @@ bool pattern_inference_cfg::reduce_quantifier(
new_q = m.update_quantifier_weight(new_q, weight);
if (m.proofs_enabled()) {
proof* new_body_pr = m.mk_reflexivity(new_body);
new_body_pr = m.mk_bind_proof(new_q, new_body_pr);
result_pr = m.mk_quant_intro(q, new_q, new_body_pr);
}
@ -690,7 +691,7 @@ bool pattern_inference_cfg::reduce_quantifier(
}
new_q = m.update_quantifier(result2, new_patterns.size(), (expr**) new_patterns.c_ptr(), result2->get_expr());
if (m.proofs_enabled()) {
result_pr = m.mk_transitivity(new_pr, m.mk_quant_intro(result2, new_q, m.mk_reflexivity(new_q->get_expr())));
result_pr = m.mk_transitivity(new_pr, m.mk_quant_intro(result2, new_q, m.mk_bind_proof(new_q, m.mk_reflexivity(new_q->get_expr()))));
}
TRACE("pattern_inference", tout << "pulled quantifier:\n" << mk_pp(new_q, m) << "\n";);
}

View file

@ -346,7 +346,7 @@ bool proof_checker::check1_basic(proof* p, expr_ref_vector& side_conditions) {
to_quantifier(t1.get())->get_expr() == s1.get() &&
to_quantifier(t2.get())->get_expr() == s2.get() &&
to_quantifier(t1.get())->get_num_decls() == to_quantifier(t2.get())->get_num_decls() &&
to_quantifier(t1.get())->is_forall() == to_quantifier(t2.get())->is_forall()) {
to_quantifier(t1.get())->get_kind() == to_quantifier(t2.get())->get_kind()) {
quantifier* q1 = to_quantifier(t1.get());
quantifier* q2 = to_quantifier(t2.get());
for (unsigned i = 0; i < q1->get_num_decls(); ++i) {
@ -734,9 +734,10 @@ bool proof_checker::check1_basic(proof* p, expr_ref_vector& side_conditions) {
is_forall = true;
}
if (is_quantifier(e)) {
q = to_quantifier(e);
SASSERT(!is_lambda(e));
q = to_quantifier(e);
// TBD check that quantifier is properly instantiated
return is_forall == q->is_forall();
return is_forall == ::is_forall(q);
}
}
UNREACHABLE();
@ -784,7 +785,7 @@ bool proof_checker::check1_basic(proof* p, expr_ref_vector& side_conditions) {
// SASSERT(to_quantifier(premise)->get_num_decls() == sub.size());
premise = to_quantifier(premise)->get_expr();
}
vs(premise, sub.size(), sub.c_ptr(), premise);
premise = vs(premise, sub.size(), sub.c_ptr());
}
fmls.push_back(premise.get());
TRACE("proof_checker",
@ -974,7 +975,7 @@ bool proof_checker::match_app(expr const* e, func_decl_ref& d, expr_ref_vector&
bool proof_checker::match_quantifier(expr const* e, bool& is_univ, sort_ref_vector& sorts, expr_ref& body) const {
if (is_quantifier(e)) {
quantifier const* q = to_quantifier(e);
is_univ = q->is_forall();
is_univ = is_forall(q);
body = q->get_expr();
for (unsigned i = 0; i < q->get_num_decls(); ++i) {
sorts.push_back(q->get_decl_sort(i));

View file

@ -975,9 +975,7 @@ private:
void compose(expr_ref_vector& sub, expr_ref_vector const& s0) {
for (unsigned i = 0; i < sub.size(); ++i) {
expr_ref e(m);
var_subst(m, false)(sub[i].get(), s0.size(), s0.c_ptr(), e);
sub[i] = e;
sub[i] = var_subst(m, false)(sub[i].get(), s0.size(), s0.c_ptr());
}
}
@ -995,7 +993,7 @@ private:
tout << sub.size() << "\n";);
return;
}
var_subst(m, false)(q->get_expr(), sub.size(), sub.c_ptr(), fml);
fml = var_subst(m, false)(q->get_expr(), sub.size(), sub.c_ptr());
}
};

View file

@ -20,6 +20,7 @@ Notes:
#include "ast/rewriter/array_rewriter_params.hpp"
#include "ast/ast_lt.h"
#include "ast/ast_pp.h"
#include "ast/rewriter/var_subst.h"
void array_rewriter::updt_params(params_ref const & _p) {
array_rewriter_params p(_p);
@ -196,6 +197,17 @@ br_status array_rewriter::mk_select_core(unsigned num_args, expr * const * args,
return BR_DONE;
}
if (is_lambda(args[0])) {
// anywhere lambda reduction as opposed to whnf
// select(lambda(X) M, N) -> M[N/X]
quantifier* q = to_quantifier(args[0]);
SASSERT(q->get_num_decls() == num_args - 1);
var_subst subst(m());
result = subst(q->get_expr(), num_args - 1, args + 1);
return BR_REWRITE_FULL;
}
if (m_util.is_as_array(args[0])) {
// select(as-array[f], I) --> f(I)
func_decl * f = m_util.get_as_array_func_decl(to_app(args[0]));

View file

@ -636,7 +636,7 @@ MK_PARAMETRIC_UNARY_REDUCE(reduce_sign_extend, mk_sign_extend);
new_decl_names.push_back(n);
}
}
result = m().mk_quantifier(old_q->is_forall(), new_decl_sorts.size(), new_decl_sorts.c_ptr(), new_decl_names.c_ptr(),
result = m().mk_quantifier(old_q->get_kind(), new_decl_sorts.size(), new_decl_sorts.c_ptr(), new_decl_names.c_ptr(),
new_body, old_q->get_weight(), old_q->get_qid(), old_q->get_skid(),
old_q->get_num_patterns(), new_patterns, old_q->get_num_no_patterns(), new_no_patterns);
result_pr = nullptr;

View file

@ -588,58 +588,39 @@ br_status bool_rewriter::try_ite_value(app * ite, app * val, expr_ref & result)
VERIFY(m().is_ite(ite, cond, t, e));
SASSERT(m().is_value(val));
if (m().is_value(t) && m().is_value(e)) {
if (t != val && e != val) {
TRACE("try_ite_value", tout << mk_ismt2_pp(t, m()) << " " << mk_ismt2_pp(e, m()) << " " << mk_ismt2_pp(val, m()) << "\n";
tout << t << " " << e << " " << val << "\n";);
result = m().mk_false();
}
else if (t == val && e == val) {
if (m().are_distinct(val, e)) {
result = m().mk_and(m().mk_eq(t, val), cond);
return BR_REWRITE2;
}
if (m().are_distinct(val, t)) {
result = m().mk_and(m().mk_eq(e, val), m().mk_not(cond));
return BR_REWRITE2;
}
if (m().are_equal(val, t)) {
if (m().are_equal(val, e)) {
result = m().mk_true();
}
else if (t == val) {
result = cond;
return BR_DONE;
}
else {
SASSERT(e == val);
mk_not(cond, result);
result = m().mk_or(m().mk_eq(e, val), cond);
}
return BR_DONE;
return BR_REWRITE2;
}
if (m_ite_extra_rules) {
if (m().is_value(t)) {
if (val == t) {
result = m().mk_or(cond, m().mk_eq(val, e));
}
else {
mk_not(cond, result);
result = m().mk_and(result, m().mk_eq(val, e));
}
return BR_REWRITE2;
}
if (m().is_value(e)) {
if (val == e) {
mk_not(cond, result);
result = m().mk_or(result, m().mk_eq(val, t));
}
else {
result = m().mk_and(cond, m().mk_eq(val, t));
}
return BR_REWRITE2;
}
if (m().are_equal(val, e)) {
result = m().mk_or(m().mk_eq(t, val), m().mk_not(cond));
return BR_REWRITE2;
}
{
expr* cond2, *t2, *e2;
if (m().is_ite(t, cond2, t2, e2) && m().is_value(t2) && m().is_value(e2)) {
try_ite_value(to_app(t), val, result);
result = m().mk_ite(cond, result, m().mk_eq(e, val));
return BR_REWRITE2;
}
if (m().is_ite(e, cond2, t2, e2) && m().is_value(t2) && m().is_value(e2)) {
try_ite_value(to_app(e), val, result);
result = m().mk_ite(cond, m().mk_eq(t, val), result);
return BR_REWRITE2;
}
expr* cond2 = nullptr, *t2 = nullptr, *e2 = nullptr;
if (m().is_ite(t, cond2, t2, e2) && m().is_value(t2) && m().is_value(e2)) {
try_ite_value(to_app(t), val, result);
result = m().mk_ite(cond, result, m().mk_eq(e, val));
return BR_REWRITE2;
}
if (m().is_ite(e, cond2, t2, e2) && m().is_value(t2) && m().is_value(e2)) {
try_ite_value(to_app(e), val, result);
result = m().mk_ite(cond, m().mk_eq(t, val), result);
return BR_REWRITE2;
}
return BR_FAILED;

View file

@ -87,20 +87,16 @@ bool bv_elim_cfg::reduce_quantifier(quantifier * q,
expr* const* sub = subst_map.c_ptr();
unsigned sub_size = subst_map.size();
subst(old_body, sub_size, sub, new_body);
new_body = subst(old_body, sub_size, sub);
for (unsigned j = 0; j < q->get_num_patterns(); j++) {
expr_ref pat(m);
subst(new_patterns[j], sub_size, sub, pat);
pats.push_back(pat);
pats.push_back(subst(new_patterns[j], sub_size, sub));
}
for (unsigned j = 0; j < q->get_num_no_patterns(); j++) {
expr_ref nopat(m);
subst(new_no_patterns[j], sub_size, sub, nopat);
no_pats.push_back(nopat);
no_pats.push_back(subst(new_no_patterns[j], sub_size, sub));
}
result = m.mk_quantifier(true,
result = m.mk_quantifier(forall_k,
names.size(),
sorts.c_ptr(),
names.c_ptr(),

View file

@ -133,7 +133,7 @@ void der::operator()(quantifier * q, expr_ref & r, proof_ref & pr) {
// Eliminate variables that have become unused
if (reduced && is_forall(r)) {
quantifier * q = to_quantifier(r);
elim_unused_vars(m_manager, q, params_ref(), r);
r = elim_unused_vars(m_manager, q, params_ref());
if (m_manager.proofs_enabled()) {
proof * p1 = m_manager.mk_elim_unused_vars(q, r);
pr = m_manager.mk_transitivity(pr, p1);
@ -343,8 +343,7 @@ void der::create_substitution(unsigned sz) {
expr_ref cur(m_map[m_order[i]], m_manager);
// do all the previous substitutions before inserting
expr_ref r(m_manager);
m_subst(cur, m_subst_map.size(), m_subst_map.c_ptr(), r);
expr_ref r = m_subst(cur, m_subst_map.size(), m_subst_map.c_ptr());
unsigned inx = sz - m_order[i]- 1;
SASSERT(m_subst_map[inx]==0);
@ -369,21 +368,18 @@ void der::apply_substitution(quantifier * q, expr_ref & r) {
unsigned sz = m_new_args.size();
expr_ref t(m_manager);
t = (sz == 1) ? m_new_args[0] : m_manager.mk_or(sz, m_new_args.c_ptr());
expr_ref new_e(m_manager);
m_subst(t, m_subst_map.size(), m_subst_map.c_ptr(), new_e);
expr_ref new_e = m_subst(t, m_subst_map.size(), m_subst_map.c_ptr());
// don't forget to update the quantifier patterns
expr_ref_buffer new_patterns(m_manager);
expr_ref_buffer new_no_patterns(m_manager);
for (unsigned j = 0; j < q->get_num_patterns(); j++) {
expr_ref new_pat(m_manager);
m_subst(q->get_pattern(j), m_subst_map.size(), m_subst_map.c_ptr(), new_pat);
expr_ref new_pat = m_subst(q->get_pattern(j), m_subst_map.size(), m_subst_map.c_ptr());
new_patterns.push_back(new_pat);
}
for (unsigned j = 0; j < q->get_num_no_patterns(); j++) {
expr_ref new_nopat(m_manager);
m_subst(q->get_no_pattern(j), m_subst_map.size(), m_subst_map.c_ptr(), new_nopat);
expr_ref new_nopat = m_subst(q->get_no_pattern(j), m_subst_map.size(), m_subst_map.c_ptr());
new_no_patterns.push_back(new_nopat);
}

View file

@ -100,7 +100,7 @@ void distribute_forall::reduce1_app(app * a) {
void distribute_forall::reduce1_quantifier(quantifier * q) {
// This transformation is applied after skolemization/quantifier elimination. So, all quantifiers are universal.
SASSERT(q->is_forall());
SASSERT(q->get_kind() == forall_k);
// This transformation is applied after basic pre-processing steps.
// So, we can assume that
@ -126,8 +126,7 @@ void distribute_forall::reduce1_quantifier(quantifier * q) {
br.mk_not(arg, not_arg);
quantifier_ref tmp_q(m_manager);
tmp_q = m_manager.update_quantifier(q, not_arg);
expr_ref new_q(m_manager);
elim_unused_vars(m_manager, tmp_q, params_ref(), new_q);
expr_ref new_q = elim_unused_vars(m_manager, tmp_q, params_ref());
new_args.push_back(new_q);
}
expr_ref result(m_manager);

View file

@ -114,7 +114,7 @@ bool elim_bounds_cfg::reduce_quantifier(quantifier * q,
expr * const * new_no_patterns,
expr_ref & result,
proof_ref & result_pr) {
if (!q->is_forall()) {
if (!is_forall(q)) {
return false;
}
unsigned num_vars = q->get_num_decls();
@ -194,7 +194,7 @@ bool elim_bounds_cfg::reduce_quantifier(quantifier * q,
}
quantifier_ref new_q(m);
new_q = m.update_quantifier(q, new_body);
elim_unused_vars(m, new_q, params_ref(), result);
result = elim_unused_vars(m, new_q, params_ref());
result_pr = m.mk_rewrite(q, result);
TRACE("elim_bounds", tout << mk_pp(q, m) << "\n" << result << "\n";);
return true;

View file

@ -159,6 +159,8 @@ struct enum2bv_rewriter::imp {
expr * const * new_no_patterns,
expr_ref & result,
proof_ref & result_pr) {
if (q->get_kind() == lambda_k) return false;
m_sorts.reset();
expr_ref_vector bounds(m);
bool found = false;
@ -182,15 +184,20 @@ struct enum2bv_rewriter::imp {
}
expr_ref new_body_ref(old_body, m), tmp(m);
if (!bounds.empty()) {
if (q->is_forall()) {
switch (q->get_kind()) {
case forall_k:
new_body_ref = m.mk_implies(mk_and(bounds), new_body_ref);
}
else {
break;
case exists_k:
bounds.push_back(new_body_ref);
new_body_ref = mk_and(bounds);
break;
case lambda_k:
UNREACHABLE();
break;
}
}
result = m.mk_quantifier(q->is_forall(), q->get_num_decls(), m_sorts.c_ptr(), q->get_decl_names(), new_body_ref,
result = m.mk_quantifier(q->get_kind(), q->get_num_decls(), m_sorts.c_ptr(), q->get_decl_names(), new_body_ref,
q->get_weight(), q->get_qid(), q->get_skid(),
q->get_num_patterns(), new_patterns,
q->get_num_no_patterns(), new_no_patterns);

View file

@ -32,7 +32,7 @@ bool simplify_inj_axiom(ast_manager & m, quantifier * q, expr_ref & result) {
expr* arg1 = nullptr, * arg2 = nullptr, *narg = nullptr;
expr* app1 = nullptr, * app2 = nullptr;
expr* var1 = nullptr, * var2 = nullptr;
if (q->is_forall() && m.is_or(n, arg1, arg2)) {
if (is_forall(q) && m.is_or(n, arg1, arg2)) {
if (m.is_not(arg2))
std::swap(arg1, arg2);
if (m.is_not(arg1, narg) &&

View file

@ -79,12 +79,12 @@ public:
vars.push_back(a);
}
expr * const * exprs = (expr* const*) (vars.c_ptr() + vars.size()- nd);
instantiate(m, q, exprs, result);
result = instantiate(m, q, exprs);
}
unsigned pull_quantifier(bool is_forall, expr_ref& fml, ptr_vector<sort>* sorts, svector<symbol>* names, bool use_fresh, bool rewrite_ok) {
unsigned pull_quantifier(bool _is_forall, expr_ref& fml, ptr_vector<sort>* sorts, svector<symbol>* names, bool use_fresh, bool rewrite_ok) {
unsigned index = var_counter().get_next_var(fml);
while (is_quantifier(fml) && (is_forall == to_quantifier(fml)->is_forall())) {
while (is_quantifier(fml) && _is_forall == is_forall(fml)) {
quantifier* q = to_quantifier(fml);
index += q->get_num_decls();
if (names) {
@ -99,7 +99,7 @@ public:
return index;
}
app_ref_vector vars(m);
pull_quantifier(is_forall, fml, vars, use_fresh, rewrite_ok);
pull_quantifier(_is_forall, fml, vars, use_fresh, rewrite_ok);
if (vars.empty()) {
return index;
}
@ -277,12 +277,16 @@ private:
}
case AST_QUANTIFIER: {
quantifier* q = to_quantifier(fml);
expr_ref tmp(m);
if (!is_compatible(qt, q->is_forall())) {
if (is_lambda(q)) {
result = fml;
break;
}
set_quantifier_type(qt, q->is_forall());
expr_ref tmp(m);
if (!is_compatible(qt, is_forall(q))) {
result = fml;
break;
}
set_quantifier_type(qt, is_forall(q));
extract_quantifier(q, vars, tmp, use_fresh);
pull_quantifier(tmp, qt, vars, result, use_fresh, rewrite_ok);
break;

View file

@ -208,12 +208,10 @@ void rewriter_core::cleanup() {
#ifdef _TRACE
void rewriter_core::display_stack(std::ostream & out, unsigned pp_depth) {
svector<frame>::iterator it = m_frame_stack.begin();
svector<frame>::iterator end = m_frame_stack.end();
for (; it != end; ++it) {
out << mk_bounded_pp(it->m_curr, m(), pp_depth) << "\n";
out << "state: " << it->m_state << "\n";
out << "cache: " << it->m_cache_result << ", new_child: " << it->m_new_child << ", max-depth: " << it->m_max_depth << ", i: " << it->m_i << "\n";
for (frame& f : m_frame_stack) {
out << mk_bounded_pp(f.m_curr, m(), pp_depth) << "\n";
out << "state: " << f.m_state << "\n";
out << "cache: " << f.m_cache_result << ", new_child: " << f.m_new_child << ", max-depth: " << f.m_max_depth << ", i: " << f.m_i << "\n";
out << "------------------\n";
}
}

View file

@ -350,11 +350,13 @@ public:
void update_inv_binding_at(unsigned i, expr* binding);
void operator()(expr * t, expr_ref & result, proof_ref & result_pr);
void operator()(expr * t, expr_ref & result) { operator()(t, result, m_pr); }
void operator()(expr * n, unsigned num_bindings, expr * const * bindings, expr_ref & result) {
expr_ref operator()(expr * n, unsigned num_bindings, expr * const * bindings) {
expr_ref result(m());
SASSERT(!m_proof_gen);
reset();
set_inv_bindings(num_bindings, bindings);
operator()(n, result);
return result;
}
void resume(expr_ref & result, proof_ref & result_pr);

View file

@ -542,7 +542,7 @@ void rewriter_tpl<Config>::process_quantifier(quantifier * q, frame & fr) {
}
result_stack().shrink(fr.m_spos);
result_stack().push_back(m_r.get());
SASSERT(m().is_bool(m_r));
SASSERT(m().get_sort(q) == m().get_sort(m_r));
if (!ProofGen) {
SASSERT(num_decls <= m_bindings.size());
m_bindings.shrink(m_bindings.size() - num_decls);

View file

@ -36,7 +36,7 @@ expr_ref sym_expr::accept(expr* e) {
switch (m_ty) {
case t_pred: {
var_subst subst(m);
subst(m_t, 1, &e, result);
result = subst(m_t, 1, &e);
break;
}
case t_char:

View file

@ -16,6 +16,7 @@ Author:
Notes:
--*/
#include "util/cooperate.h"
#include "ast/rewriter/th_rewriter.h"
#include "ast/rewriter/rewriter_params.hpp"
#include "ast/rewriter/bool_rewriter.h"
@ -28,10 +29,9 @@ Notes:
#include "ast/rewriter/pb_rewriter.h"
#include "ast/rewriter/seq_rewriter.h"
#include "ast/rewriter/rewriter_def.h"
#include "ast/rewriter/var_subst.h"
#include "ast/expr_substitution.h"
#include "ast/ast_smt2_pp.h"
#include "util/cooperate.h"
#include "ast/rewriter/var_subst.h"
#include "ast/ast_util.h"
#include "ast/well_sorted.h"
@ -606,7 +606,8 @@ struct th_rewriter_cfg : public default_rewriter_cfg {
quantifier_ref q1(m());
proof * p1 = nullptr;
if (is_quantifier(new_body) &&
to_quantifier(new_body)->is_forall() == old_q->is_forall() &&
to_quantifier(new_body)->get_kind() == old_q->get_kind() &&
to_quantifier(new_body)->get_kind() != lambda_k &&
!old_q->has_patterns() &&
!to_quantifier(new_body)->has_patterns()) {
@ -619,7 +620,7 @@ struct th_rewriter_cfg : public default_rewriter_cfg {
sorts.append(nested_q->get_num_decls(), nested_q->get_decl_sorts());
names.append(nested_q->get_num_decls(), nested_q->get_decl_names());
q1 = m().mk_quantifier(old_q->is_forall(),
q1 = m().mk_quantifier(old_q->get_kind(),
sorts.size(),
sorts.c_ptr(),
names.c_ptr(),
@ -653,17 +654,19 @@ struct th_rewriter_cfg : public default_rewriter_cfg {
SASSERT(is_well_sorted(m(), q1));
}
elim_unused_vars(m(), q1, params_ref(), result);
SASSERT(m().get_sort(old_q) == m().get_sort(q1));
result = elim_unused_vars(m(), q1, params_ref());
TRACE("reduce_quantifier", tout << "after elim_unused_vars:\n" << mk_ismt2_pp(result, m()) << "\n";);
TRACE("reduce_quantifier", tout << "after elim_unused_vars:\n" << result << "\n";);
result_pr = nullptr;
if (m().proofs_enabled()) {
proof * p2 = nullptr;
if (q1.get() != result.get())
if (q1.get() != result.get() && q1->get_kind() != lambda_k)
p2 = m().mk_elim_unused_vars(q1, result);
result_pr = m().mk_transitivity(p1, p2);
}
SASSERT(m().get_sort(old_q) == m().get_sort(result));
return true;
}
@ -784,8 +787,8 @@ void th_rewriter::operator()(expr * t, expr_ref & result, proof_ref & result_pr)
m_imp->operator()(t, result, result_pr);
}
void th_rewriter::operator()(expr * n, unsigned num_bindings, expr * const * bindings, expr_ref & result) {
m_imp->operator()(n, num_bindings, bindings, result);
expr_ref th_rewriter::operator()(expr * n, unsigned num_bindings, expr * const * bindings) {
return m_imp->operator()(n, num_bindings, bindings);
}
void th_rewriter::set_substitution(expr_substitution * s) {

View file

@ -45,7 +45,7 @@ public:
void operator()(expr_ref& term);
void operator()(expr * t, expr_ref & result);
void operator()(expr * t, expr_ref & result, proof_ref & result_pr);
void operator()(expr * n, unsigned num_bindings, expr * const * bindings, expr_ref & result);
expr_ref operator()(expr * n, unsigned num_bindings, expr * const * bindings);
expr_ref mk_app(func_decl* f, unsigned num_args, expr* const* args);

View file

@ -23,10 +23,11 @@ Notes:
#include "ast/well_sorted.h"
#include "ast/for_each_expr.h"
void var_subst::operator()(expr * n, unsigned num_args, expr * const * args, expr_ref & result) {
expr_ref var_subst::operator()(expr * n, unsigned num_args, expr * const * args) {
expr_ref result(m_reducer.m());
if (is_ground(n)) {
result = n;
return;
return result;
}
SASSERT(is_well_sorted(result.m(), n));
m_reducer.reset();
@ -41,6 +42,7 @@ void var_subst::operator()(expr * n, unsigned num_args, expr * const * args, exp
for (unsigned i = 0; i < num_args; i++) tout << mk_ismt2_pp(args[i], m_reducer.m()) << "\n";
tout << "\n------>\n";
tout << mk_ismt2_pp(result, m_reducer.m()) << "\n";);
return result;
}
unused_vars_eliminator::unused_vars_eliminator(ast_manager & m, params_ref const & params) :
@ -49,16 +51,22 @@ unused_vars_eliminator::unused_vars_eliminator(ast_manager & m, params_ref const
m_ignore_patterns_on_ground_qbody = m_params.get_bool("ignore_patterns_on_ground_qbody", true);
}
void unused_vars_eliminator::operator()(quantifier* q, expr_ref & result) {
expr_ref unused_vars_eliminator::operator()(quantifier* q) {
expr_ref result(m);
SASSERT(is_well_sorted(m, q));
TRACE("elim_unused_vars", tout << expr_ref(q, m) << "\n";);
if (is_lambda(q)) {
result = q;
return result;
}
if (m_ignore_patterns_on_ground_qbody && is_ground(q->get_expr())) {
// Ignore patterns if the body is a ground formula.
result = q->get_expr();
return;
return result;
}
if (!q->may_have_unused_vars()) {
result = q;
return;
return result;
}
m_used.reset();
m_used.process(q->get_expr());
@ -73,7 +81,7 @@ void unused_vars_eliminator::operator()(quantifier* q, expr_ref & result) {
if (m_used.uses_all_vars(num_decls)) {
q->set_no_unused_vars();
result = q;
return;
return result;
}
ptr_buffer<sort> used_decl_sorts;
@ -120,11 +128,11 @@ void unused_vars_eliminator::operator()(quantifier* q, expr_ref & result) {
expr_ref new_expr(m);
m_subst(q->get_expr(), var_mapping.size(), var_mapping.c_ptr(), new_expr);
new_expr = m_subst(q->get_expr(), var_mapping.size(), var_mapping.c_ptr());
if (num_removed == num_decls) {
result = new_expr;
return;
return result;
}
expr_ref tmp(m);
@ -132,15 +140,15 @@ void unused_vars_eliminator::operator()(quantifier* q, expr_ref & result) {
expr_ref_buffer new_no_patterns(m);
for (unsigned i = 0; i < num_patterns; i++) {
m_subst(q->get_pattern(i), var_mapping.size(), var_mapping.c_ptr(), tmp);
tmp = m_subst(q->get_pattern(i), var_mapping.size(), var_mapping.c_ptr());
new_patterns.push_back(tmp);
}
for (unsigned i = 0; i < num_no_patterns; i++) {
m_subst(q->get_no_pattern(i), var_mapping.size(), var_mapping.c_ptr(), tmp);
tmp = m_subst(q->get_no_pattern(i), var_mapping.size(), var_mapping.c_ptr());
new_no_patterns.push_back(tmp);
}
result = m.mk_quantifier(q->is_forall(),
result = m.mk_quantifier(q->get_kind(),
used_decl_sorts.size(),
used_decl_sorts.c_ptr(),
used_decl_names.c_ptr(),
@ -154,24 +162,28 @@ void unused_vars_eliminator::operator()(quantifier* q, expr_ref & result) {
new_no_patterns.c_ptr());
to_quantifier(result)->set_no_unused_vars();
SASSERT(is_well_sorted(m, result));
return result;
}
void elim_unused_vars(ast_manager & m, quantifier * q, params_ref const & params, expr_ref & result) {
expr_ref elim_unused_vars(ast_manager & m, quantifier * q, params_ref const & params) {
unused_vars_eliminator el(m, params);
el(q, result);
expr_ref result = el(q);
TRACE("elim_unused_vars", tout << expr_ref(q, m) << " -> " << result << "\n";);
return result;
}
void instantiate(ast_manager & m, quantifier * q, expr * const * exprs, expr_ref & result) {
expr_ref instantiate(ast_manager & m, quantifier * q, expr * const * exprs) {
var_subst subst(m);
expr_ref new_expr(m);
subst(q->get_expr(), q->get_num_decls(), exprs, new_expr);
TRACE("var_subst", tout << mk_pp(q, m) << "\n" << mk_pp(new_expr, m) << "\n";);
expr_ref new_expr(m), result(m);
new_expr = subst(q->get_expr(), q->get_num_decls(), exprs);
TRACE("var_subst", tout << mk_pp(q, m) << "\n" << new_expr << "\n";);
inv_var_shifter shift(m);
shift(new_expr, q->get_num_decls(), result);
SASSERT(is_well_sorted(m, result));
TRACE("instantiate_bug", tout << mk_ismt2_pp(q, m) << "\nusing\n";
for (unsigned i = 0; i < q->get_num_decls(); i++) tout << mk_ismt2_pp(exprs[i], m) << "\n";
tout << "\n----->\n" << mk_ismt2_pp(result, m) << "\n";);
return result;
}
static void get_free_vars_offset(expr_sparse_mark& mark, ptr_vector<expr>& todo, unsigned offset, expr* e, ptr_vector<sort>& sorts) {

View file

@ -48,7 +48,7 @@ public:
Otherwise, (VAR 0) is stored in the first position, (VAR 1) in the second, and so on.
*/
void operator()(expr * n, unsigned num_args, expr * const * args, expr_ref & result);
expr_ref operator()(expr * n, unsigned num_args, expr * const * args);
void reset() { m_reducer.reset(); }
};
@ -63,10 +63,10 @@ class unused_vars_eliminator {
bool m_ignore_patterns_on_ground_qbody;
public:
unused_vars_eliminator(ast_manager & m, params_ref const & params);
void operator()(quantifier* q, expr_ref& r);
expr_ref operator()(quantifier* q);
};
void elim_unused_vars(ast_manager & m, quantifier * q, params_ref const & params, expr_ref & r);
expr_ref elim_unused_vars(ast_manager & m, quantifier * q, params_ref const & params);
/**
\brief Instantiate quantifier q using the given exprs.
@ -77,7 +77,7 @@ void elim_unused_vars(ast_manager & m, quantifier * q, params_ref const & params
...
(VAR (q->get_num_decls() - 1)) is stored in the first position of the array.
*/
void instantiate(ast_manager & m, quantifier * q, expr * const * exprs, expr_ref & result);
expr_ref instantiate(ast_manager & m, quantifier * q, expr * const * exprs);
/**
\brief Enumerate set of free variables in expression.

View file

@ -35,9 +35,10 @@ struct well_sorted_proc {
void operator()(quantifier * n) {
expr const * e = n->get_expr();
if (!m_manager.is_bool(e)) {
if (!is_lambda(n) && !m_manager.is_bool(e)) {
warning_msg("quantifier's body must be a boolean.");
m_error = true;
UNREACHABLE();
}
}