3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-04-23 09:05:31 +00:00

merge with master branch

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
Nikolaj Bjorner 2017-09-19 09:39:22 -07:00
commit 651587ce01
1602 changed files with 40496 additions and 27837 deletions

View file

@ -23,6 +23,7 @@ z3_add_component(ast
expr_map.cpp
expr_stat.cpp
expr_substitution.cpp
factor_equivs.cpp
for_each_ast.cpp
for_each_expr.cpp
format.cpp

View file

@ -17,7 +17,7 @@ Author:
Notes:
--*/
#include"act_cache.h"
#include "ast/act_cache.h"
#define MIN_MAX_UNUSED 1024
#define INITIAL_CAPACITY 128

View file

@ -20,9 +20,9 @@ Notes:
#ifndef ACT_CACHE_H_
#define ACT_CACHE_H_
#include"ast.h"
#include"obj_hashtable.h"
#include"chashtable.h"
#include "ast/ast.h"
#include "util/obj_hashtable.h"
#include "util/chashtable.h"
class act_cache {
ast_manager & m_manager;

View file

@ -16,11 +16,11 @@ Author:
Revision History:
--*/
#include"arith_decl_plugin.h"
#include"warning.h"
#include"algebraic_numbers.h"
#include"id_gen.h"
#include"ast_smt2_pp.h"
#include "ast/arith_decl_plugin.h"
#include "util/warning.h"
#include "math/polynomial/algebraic_numbers.h"
#include "util/id_gen.h"
#include "ast/ast_smt2_pp.h"
struct arith_decl_plugin::algebraic_numbers_wrapper {
unsynch_mpq_manager m_qmanager;
@ -81,8 +81,9 @@ app * arith_decl_plugin::mk_numeral(algebraic_numbers::anum const & val, bool is
return mk_numeral(rval, is_int);
}
else {
if (is_int)
if (is_int) {
m_manager->raise_exception("invalid irrational value passed as an integer");
}
unsigned idx = aw().mk_id(val);
parameter p(idx, true);
SASSERT(p.is_external());
@ -214,18 +215,8 @@ void arith_decl_plugin::set_manager(ast_manager * m, family_id id) {
m_e = m->mk_const(e_decl);
m->inc_ref(m_e);
func_decl * z_pw_z_int = m->mk_const_decl(symbol("0^0-int"), i, func_decl_info(id, OP_0_PW_0_INT));
m_0_pw_0_int = m->mk_const(z_pw_z_int);
m->inc_ref(m_0_pw_0_int);
func_decl * z_pw_z_real = m->mk_const_decl(symbol("0^0-real"), r, func_decl_info(id, OP_0_PW_0_REAL));
m_0_pw_0_real = m->mk_const(z_pw_z_real);
m->inc_ref(m_0_pw_0_real);
MK_OP(m_neg_root_decl, "neg-root", OP_NEG_ROOT, r);
MK_UNARY(m_div_0_decl, "/0", OP_DIV_0, r);
MK_UNARY(m_idiv_0_decl, "div0", OP_IDIV_0, i);
MK_UNARY(m_mod_0_decl, "mod0", OP_MOD_0, i);
MK_UNARY(m_u_asin_decl, "asin-u", OP_U_ASIN, r);
MK_UNARY(m_u_acos_decl, "acos-u", OP_U_ACOS, r);
}
@ -278,12 +269,7 @@ arith_decl_plugin::arith_decl_plugin():
m_atanh_decl(0),
m_pi(0),
m_e(0),
m_0_pw_0_int(0),
m_0_pw_0_real(0),
m_neg_root_decl(0),
m_div_0_decl(0),
m_idiv_0_decl(0),
m_mod_0_decl(0),
m_u_asin_decl(0),
m_u_acos_decl(0),
m_convert_int_numerals_to_real(false) {
@ -338,12 +324,7 @@ void arith_decl_plugin::finalize() {
DEC_REF(m_atanh_decl);
DEC_REF(m_pi);
DEC_REF(m_e);
DEC_REF(m_0_pw_0_int);
DEC_REF(m_0_pw_0_real);
DEC_REF(m_neg_root_decl);
DEC_REF(m_div_0_decl);
DEC_REF(m_idiv_0_decl);
DEC_REF(m_mod_0_decl);
DEC_REF(m_u_asin_decl);
DEC_REF(m_u_acos_decl);
m_manager->dec_array_ref(m_small_ints.size(), m_small_ints.c_ptr());
@ -391,18 +372,24 @@ inline func_decl * arith_decl_plugin::mk_func_decl(decl_kind k, bool is_real) {
case OP_ATANH: return m_atanh_decl;
case OP_PI: return m_pi->get_decl();
case OP_E: return m_e->get_decl();
case OP_0_PW_0_INT: return m_0_pw_0_int->get_decl();
case OP_0_PW_0_REAL: return m_0_pw_0_real->get_decl();
//case OP_0_PW_0_INT: return m_0_pw_0_int->get_decl();
//case OP_0_PW_0_REAL: return m_0_pw_0_real->get_decl();
case OP_NEG_ROOT: return m_neg_root_decl;
case OP_DIV_0: return m_div_0_decl;
case OP_IDIV_0: return m_idiv_0_decl;
case OP_MOD_0: return m_mod_0_decl;
//case OP_DIV_0: return m_div_0_decl;
//case OP_IDIV_0: return m_idiv_0_decl;
//case OP_MOD_0: return m_mod_0_decl;
case OP_U_ASIN: return m_u_asin_decl;
case OP_U_ACOS: return m_u_acos_decl;
default: return 0;
}
}
void arith_decl_plugin::check_arity(unsigned arity, unsigned expected_arity) {
if (arity != expected_arity) {
m_manager->raise_exception("invalid number of arguments passed to function");
}
}
inline decl_kind arith_decl_plugin::fix_kind(decl_kind k, unsigned arity) {
if (k == OP_SUB && arity == 1) {
return OP_UMINUS;
@ -482,9 +469,9 @@ static bool has_real_arg(ast_manager * m, unsigned num_args, expr * const * args
static bool is_const_op(decl_kind k) {
return
k == OP_PI ||
k == OP_E ||
k == OP_0_PW_0_INT ||
k == OP_0_PW_0_REAL;
k == OP_E;
//k == OP_0_PW_0_INT ||
//k == OP_0_PW_0_REAL;
}
func_decl * arith_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters,

View file

@ -19,7 +19,7 @@ Revision History:
#ifndef ARITH_DECL_PLUGIN_H_
#define ARITH_DECL_PLUGIN_H_
#include"ast.h"
#include "ast/ast.h"
class sexpr;
namespace algebraic_numbers {
@ -70,12 +70,7 @@ enum arith_op_kind {
OP_PI,
OP_E,
// under-specified symbols
OP_0_PW_0_INT, // 0^0 for integers
OP_0_PW_0_REAL, // 0^0 for reals
OP_NEG_ROOT, // x^n when n is even and x is negative
OP_DIV_0, // x/0
OP_IDIV_0, // x div 0
OP_MOD_0, // x mod 0
OP_U_ASIN, // asin(x) for x < -1 or x > 1
OP_U_ACOS, // acos(x) for x < -1 or x > 1
LAST_ARITH_OP
@ -141,12 +136,7 @@ protected:
app * m_pi;
app * m_e;
app * m_0_pw_0_int;
app * m_0_pw_0_real;
func_decl * m_neg_root_decl;
func_decl * m_div_0_decl;
func_decl * m_idiv_0_decl;
func_decl * m_mod_0_decl;
func_decl * m_u_asin_decl;
func_decl * m_u_acos_decl;
ptr_vector<app> m_small_ints;
@ -157,6 +147,7 @@ protected:
func_decl * mk_func_decl(decl_kind k, bool is_real);
virtual void set_manager(ast_manager * m, family_id id);
decl_kind fix_kind(decl_kind k, unsigned arity);
void check_arity(unsigned arity, unsigned expected_arity);
func_decl * mk_num_decl(unsigned num_parameters, parameter const * parameters, unsigned arity);
public:
@ -206,10 +197,6 @@ public:
app * mk_e() const { return m_e; }
app * mk_0_pw_0_int() const { return m_0_pw_0_int; }
app * mk_0_pw_0_real() const { return m_0_pw_0_real; }
virtual expr * get_some_value(sort * s);
virtual bool is_considered_uninterpreted(func_decl * f) {
@ -217,12 +204,7 @@ public:
return false;
switch (f->get_decl_kind())
{
case OP_0_PW_0_INT:
case OP_0_PW_0_REAL:
case OP_NEG_ROOT:
case OP_DIV_0:
case OP_IDIV_0:
case OP_MOD_0:
case OP_U_ASIN:
case OP_U_ACOS:
return true;
@ -275,9 +257,9 @@ public:
bool is_uminus(expr const * n) const { return is_app_of(n, m_afid, OP_UMINUS); }
bool is_mul(expr const * n) const { return is_app_of(n, m_afid, OP_MUL); }
bool is_div(expr const * n) const { return is_app_of(n, m_afid, OP_DIV); }
bool is_div0(expr const * n) const { return is_app_of(n, m_afid, OP_DIV_0); }
//bool is_div0(expr const * n) const { return is_app_of(n, m_afid, OP_DIV_0); }
bool is_idiv(expr const * n) const { return is_app_of(n, m_afid, OP_IDIV); }
bool is_idiv0(expr const * n) const { return is_app_of(n, m_afid, OP_IDIV_0); }
//bool is_idiv0(expr const * n) const { return is_app_of(n, m_afid, OP_IDIV_0); }
bool is_mod(expr const * n) const { return is_app_of(n, m_afid, OP_MOD); }
bool is_rem(expr const * n) const { return is_app_of(n, m_afid, OP_REM); }
bool is_to_real(expr const * n) const { return is_app_of(n, m_afid, OP_TO_REAL); }
@ -388,16 +370,16 @@ public:
app * mk_lt(expr * arg1, expr * arg2) const { return m_manager.mk_app(m_afid, OP_LT, arg1, arg2); }
app * mk_gt(expr * arg1, expr * arg2) const { return m_manager.mk_app(m_afid, OP_GT, arg1, arg2); }
app * mk_add(unsigned num_args, expr * const * args) { return m_manager.mk_app(m_afid, OP_ADD, num_args, args); }
app * mk_add(expr * arg1, expr * arg2) { return m_manager.mk_app(m_afid, OP_ADD, arg1, arg2); }
app * mk_add(expr * arg1, expr * arg2, expr* arg3) { return m_manager.mk_app(m_afid, OP_ADD, arg1, arg2, arg3); }
app * mk_add(unsigned num_args, expr * const * args) const { return m_manager.mk_app(m_afid, OP_ADD, num_args, args); }
app * mk_add(expr * arg1, expr * arg2) const { return m_manager.mk_app(m_afid, OP_ADD, arg1, arg2); }
app * mk_add(expr * arg1, expr * arg2, expr* arg3) const { return m_manager.mk_app(m_afid, OP_ADD, arg1, arg2, arg3); }
app * mk_sub(expr * arg1, expr * arg2) { return m_manager.mk_app(m_afid, OP_SUB, arg1, arg2); }
app * mk_sub(unsigned num_args, expr * const * args) { return m_manager.mk_app(m_afid, OP_SUB, num_args, args); }
app * mk_mul(expr * arg1, expr * arg2) { return m_manager.mk_app(m_afid, OP_MUL, arg1, arg2); }
app * mk_mul(expr * arg1, expr * arg2, expr* arg3) { return m_manager.mk_app(m_afid, OP_MUL, arg1, arg2, arg3); }
app * mk_mul(unsigned num_args, expr * const * args) { return m_manager.mk_app(m_afid, OP_MUL, num_args, args); }
app * mk_uminus(expr * arg) { return m_manager.mk_app(m_afid, OP_UMINUS, arg); }
app * mk_sub(expr * arg1, expr * arg2) const { return m_manager.mk_app(m_afid, OP_SUB, arg1, arg2); }
app * mk_sub(unsigned num_args, expr * const * args) const { return m_manager.mk_app(m_afid, OP_SUB, num_args, args); }
app * mk_mul(expr * arg1, expr * arg2) const { return m_manager.mk_app(m_afid, OP_MUL, arg1, arg2); }
app * mk_mul(expr * arg1, expr * arg2, expr* arg3) const { return m_manager.mk_app(m_afid, OP_MUL, arg1, arg2, arg3); }
app * mk_mul(unsigned num_args, expr * const * args) const { return m_manager.mk_app(m_afid, OP_MUL, num_args, args); }
app * mk_uminus(expr * arg) const { return m_manager.mk_app(m_afid, OP_UMINUS, arg); }
app * mk_div(expr * arg1, expr * arg2) { return m_manager.mk_app(m_afid, OP_DIV, arg1, arg2); }
app * mk_idiv(expr * arg1, expr * arg2) { return m_manager.mk_app(m_afid, OP_IDIV, arg1, arg2); }
app * mk_rem(expr * arg1, expr * arg2) { return m_manager.mk_app(m_afid, OP_REM, arg1, arg2); }
@ -424,11 +406,6 @@ public:
app * mk_pi() { return plugin().mk_pi(); }
app * mk_e() { return plugin().mk_e(); }
app * mk_0_pw_0_int() { return plugin().mk_0_pw_0_int(); }
app * mk_0_pw_0_real() { return plugin().mk_0_pw_0_real(); }
app * mk_div0(expr * arg) { return m_manager.mk_app(m_afid, OP_DIV_0, arg); }
app * mk_idiv0(expr * arg) { return m_manager.mk_app(m_afid, OP_IDIV_0, arg); }
app * mk_mod0(expr * arg) { return m_manager.mk_app(m_afid, OP_MOD_0, arg); }
app * mk_neg_root(expr * arg1, expr * arg2) { return m_manager.mk_app(m_afid, OP_NEG_ROOT, arg1, arg2); }
app * mk_u_asin(expr * arg) { return m_manager.mk_app(m_afid, OP_U_ASIN, arg); }
app * mk_u_acos(expr * arg) { return m_manager.mk_app(m_afid, OP_U_ACOS, arg); }

View file

@ -17,10 +17,10 @@ Revision History:
--*/
#include<sstream>
#include"array_decl_plugin.h"
#include"warning.h"
#include"ast_pp.h"
#include"ast_ll_pp.h"
#include "ast/array_decl_plugin.h"
#include "util/warning.h"
#include "ast/ast_pp.h"
#include "ast/ast_ll_pp.h"
array_decl_plugin::array_decl_plugin():
m_store_sym("store"),
@ -546,7 +546,7 @@ expr * array_decl_plugin::get_some_value(sort * s) {
return m_manager->mk_app(m_family_id, OP_CONST_ARRAY, 1, &p, 1, &v);
}
bool array_decl_plugin::is_fully_interp(sort const * s) const {
bool array_decl_plugin::is_fully_interp(sort * s) const {
SASSERT(s->is_sort_of(m_family_id, ARRAY_SORT));
unsigned sz = get_array_arity(s);
for (unsigned i = 0; i < sz; i++) {
@ -556,9 +556,9 @@ bool array_decl_plugin::is_fully_interp(sort const * s) const {
return m_manager->is_fully_interp(get_array_range(s));
}
func_decl * array_recognizers::get_as_array_func_decl(app * n) const {
func_decl * array_recognizers::get_as_array_func_decl(expr * n) const {
SASSERT(is_as_array(n));
return to_func_decl(n->get_decl()->get_parameter(0).get_ast());
return to_func_decl(to_app(n)->get_decl()->get_parameter(0).get_ast());
}
array_util::array_util(ast_manager& m):

View file

@ -19,7 +19,7 @@ Revision History:
#ifndef ARRAY_DECL_PLUGIN_H_
#define ARRAY_DECL_PLUGIN_H_
#include"ast.h"
#include "ast/ast.h"
inline sort* get_array_range(sort const * s) {
@ -127,7 +127,7 @@ class array_decl_plugin : public decl_plugin {
virtual expr * get_some_value(sort * s);
virtual bool is_fully_interp(sort const * s) const;
virtual bool is_fully_interp(sort * s) const;
};
class array_recognizers {
@ -148,7 +148,7 @@ public:
bool is_const(func_decl* f) const { return is_decl_of(f, m_fid, OP_CONST_ARRAY); }
bool is_map(func_decl* f) const { return is_decl_of(f, m_fid, OP_ARRAY_MAP); }
bool is_as_array(func_decl* f) const { return is_decl_of(f, m_fid, OP_AS_ARRAY); }
func_decl * get_as_array_func_decl(app * n) const;
func_decl * get_as_array_func_decl(expr * n) const;
};
class array_util : public array_recognizers {

View file

@ -18,14 +18,14 @@ Revision History:
--*/
#include<sstream>
#include<cstring>
#include"ast.h"
#include"ast_pp.h"
#include"ast_ll_pp.h"
#include"buffer.h"
#include"warning.h"
#include"string_buffer.h"
#include"ast_util.h"
#include"ast_smt2_pp.h"
#include "ast/ast.h"
#include "ast/ast_pp.h"
#include "ast/ast_ll_pp.h"
#include "util/buffer.h"
#include "util/warning.h"
#include "util/string_buffer.h"
#include "ast/ast_util.h"
#include "ast/ast_smt2_pp.h"
// -----------------------------------
//
@ -35,7 +35,7 @@ Revision History:
parameter::~parameter() {
if (m_kind == PARAM_RATIONAL) {
reinterpret_cast<rational *>(m_rational)->~rational();
dealloc(m_rational);
}
}
@ -50,14 +50,14 @@ parameter& parameter::operator=(parameter const& other) {
return *this;
}
if (m_kind == PARAM_RATIONAL) {
reinterpret_cast<rational *>(m_rational)->~rational();
dealloc(m_rational);
}
m_kind = other.m_kind;
switch(other.m_kind) {
case PARAM_INT: m_int = other.get_int(); break;
case PARAM_AST: m_ast = other.get_ast(); break;
case PARAM_SYMBOL: new (m_symbol) symbol(other.get_symbol()); break;
case PARAM_RATIONAL: new (m_rational) rational(other.get_rational()); break;
case PARAM_SYMBOL: m_symbol = other.m_symbol; break;
case PARAM_RATIONAL: m_rational = alloc(rational, other.get_rational()); break;
case PARAM_DOUBLE: m_dval = other.m_dval; break;
case PARAM_EXTERNAL: m_ext_id = other.m_ext_id; break;
default:
@ -188,18 +188,14 @@ decl_info::decl_info(decl_info const& other) :
void decl_info::init_eh(ast_manager & m) {
vector<parameter>::iterator it = m_parameters.begin();
vector<parameter>::iterator end = m_parameters.end();
for (; it != end; ++it) {
it->init_eh(m);
for (parameter & p : m_parameters) {
p.init_eh(m);
}
}
void decl_info::del_eh(ast_manager & m) {
vector<parameter>::iterator it = m_parameters.begin();
vector<parameter>::iterator end = m_parameters.end();
for (; it != end; ++it) {
it->del_eh(m, m_family_id);
for (parameter & p : m_parameters) {
p.del_eh(m, m_family_id);
}
}
@ -1291,10 +1287,8 @@ decl_kind user_sort_plugin::register_name(symbol s) {
decl_plugin * user_sort_plugin::mk_fresh() {
user_sort_plugin * p = alloc(user_sort_plugin);
svector<symbol>::iterator it = m_sort_names.begin();
svector<symbol>::iterator end = m_sort_names.end();
for (; it != end; ++it)
p->register_name(*it);
for (symbol const& s : m_sort_names)
p->register_name(s);
return p;
}
@ -1414,26 +1408,20 @@ ast_manager::~ast_manager() {
dec_ref(m_true);
dec_ref(m_false);
dec_ref(m_undef_proof);
ptr_vector<decl_plugin>::iterator it = m_plugins.begin();
ptr_vector<decl_plugin>::iterator end = m_plugins.end();
for (; it != end; ++it) {
if (*it)
(*it)->finalize();
for (decl_plugin* p : m_plugins) {
if (p)
p->finalize();
}
it = m_plugins.begin();
for (; it != end; ++it) {
if (*it)
dealloc(*it);
for (decl_plugin* p : m_plugins) {
if (p)
dealloc(p);
}
m_plugins.reset();
while (!m_ast_table.empty()) {
DEBUG_CODE(std::cout << "ast_manager LEAKED: " << m_ast_table.size() << std::endl;);
ptr_vector<ast> roots;
ast_mark mark;
ast_table::iterator it_a = m_ast_table.begin();
ast_table::iterator end_a = m_ast_table.end();
for (; it_a != end_a; ++it_a) {
ast* n = (*it_a);
for (ast * n : m_ast_table) {
switch (n->get_kind()) {
case AST_SORT: {
sort_info* info = to_sort(n)->get_info();
@ -1466,9 +1454,7 @@ ast_manager::~ast_manager() {
break;
}
}
it_a = m_ast_table.begin();
for (; it_a != end_a; ++it_a) {
ast* n = *it_a;
for (ast * n : m_ast_table) {
if (!mark.is_marked(n)) {
roots.push_back(n);
}
@ -1543,12 +1529,15 @@ 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",
tout << "target:\n";
for (family_id fid = 0; m_family_manager.has_family(fid); fid++) {
tout << "fid: " << fid << " fidname: " << get_family_name(fid) << "\n";
});
ast_translation trans(const_cast<ast_manager&>(from), *this, false);
for (family_id fid = 0; from.m_family_manager.has_family(fid); fid++) {
SASSERT(from.is_builtin_family_id(fid) == is_builtin_family_id(fid));
SASSERT(!from.is_builtin_family_id(fid) || m_family_manager.has_family(fid));
@ -1569,6 +1558,9 @@ void ast_manager::copy_families_plugins(ast_manager const & from) {
SASSERT(new_p->get_family_id() == fid);
SASSERT(has_plugin(fid));
}
if (from.has_plugin(fid)) {
get_plugin(fid)->inherit(from.get_plugin(fid), trans);
}
SASSERT(from.m_family_manager.has_family(fid) == m_family_manager.has_family(fid));
SASSERT(from.get_family_id(fid_name) == get_family_id(fid_name));
SASSERT(!from.has_plugin(fid) || has_plugin(fid));
@ -1663,11 +1655,8 @@ bool ast_manager::is_bool(expr const * n) const {
#ifdef Z3DEBUG
bool ast_manager::slow_not_contains(ast const * n) {
ast_table::iterator it = m_ast_table.begin();
ast_table::iterator end = m_ast_table.end();
unsigned num = 0;
for (; it != end; ++it) {
ast * curr = *it;
for (ast * curr : m_ast_table) {
if (compare_nodes(curr, n)) {
TRACE("nondet_bug",
tout << "id1: " << curr->get_id() << ", id2: " << n->get_id() << "\n";
@ -1935,6 +1924,35 @@ sort * ast_manager::mk_sort(symbol const & name, sort_info * info) {
return register_node(new_node);
}
sort * ast_manager::substitute(sort* s, unsigned n, sort * const * src, sort * const * dst) {
for (unsigned i = 0; i < n; ++i) {
if (s == src[i]) return dst[i];
}
vector<parameter> ps;
bool change = false;
sort_ref_vector sorts(*this);
for (unsigned i = 0; i < s->get_num_parameters(); ++i) {
parameter const& p = s->get_parameter(i);
if (p.is_ast()) {
SASSERT(is_sort(p.get_ast()));
change = true;
sorts.push_back(substitute(to_sort(p.get_ast()), n, src, dst));
ps.push_back(parameter(sorts.back()));
}
else {
ps.push_back(p);
}
}
if (!change) {
return s;
}
decl_info dinfo(s->get_family_id(), s->get_decl_kind(), ps.size(), ps.c_ptr(), s->private_parameters());
sort_info sinfo(dinfo, s->get_num_elements());
return mk_sort(s->get_name(), &sinfo);
}
sort * ast_manager::mk_uninterpreted_sort(symbol const & name, unsigned num_parameters, parameter const * parameters) {
user_sort_plugin * plugin = get_user_sort_plugin();
decl_kind kind = plugin->register_name(name);
@ -2177,7 +2195,10 @@ app * ast_manager::mk_app(func_decl * decl, unsigned num_args, expr * const * ar
throw ast_exception(buffer.str().c_str());
}
app * r = 0;
if (num_args > 2 && !decl->is_flat_associative()) {
if (num_args == 1 && decl->is_chainable() && decl->get_arity() == 2) {
r = mk_true();
}
else if (num_args > 2 && !decl->is_flat_associative()) {
if (decl->is_right_associative()) {
unsigned j = num_args - 1;
r = mk_app_core(decl, args[j-1], args[j]);
@ -2206,7 +2227,7 @@ app * ast_manager::mk_app(func_decl * decl, unsigned num_args, expr * const * ar
r = mk_app_core(decl, num_args, args);
}
SASSERT(r != 0);
TRACE("app_ground", tout << "ground: " << r->is_ground() << "\n" << mk_ll_pp(r, *this) << "\n";);
TRACE("app_ground", tout << "ground: " << r->is_ground() << " id: " << r->get_id() << "\n" << mk_ll_pp(r, *this) << "\n";);
return r;
}
@ -2351,6 +2372,7 @@ quantifier * ast_manager::mk_quantifier(bool forall, unsigned num_decls, sort *
SASSERT(num_decls > 0);
DEBUG_CODE({
for (unsigned i = 0; i < num_patterns; ++i) {
TRACE("ast", tout << i << " " << mk_pp(patterns[i], *this) << "\n";);
SASSERT(is_pattern(patterns[i]));
}});
unsigned sz = quantifier::get_obj_size(num_decls, num_patterns, num_no_patterns);
@ -2576,7 +2598,7 @@ expr * ast_manager::get_some_value(sort * s) {
return mk_model_value(0, s);
}
bool ast_manager::is_fully_interp(sort const * s) const {
bool ast_manager::is_fully_interp(sort * s) const {
if (is_uninterp(s))
return false;
family_id fid = s->get_family_id();

View file

@ -19,32 +19,32 @@ Revision History:
#ifndef AST_H_
#define AST_H_
#include"vector.h"
#include"hashtable.h"
#include"buffer.h"
#include"symbol.h"
#include"rational.h"
#include"hash.h"
#include"optional.h"
#include"trace.h"
#include"bit_vector.h"
#include"symbol_table.h"
#include"tptr.h"
#include"memory_manager.h"
#include"small_object_allocator.h"
#include"obj_ref.h"
#include"ref_vector.h"
#include"ref_buffer.h"
#include"obj_mark.h"
#include"obj_hashtable.h"
#include"id_gen.h"
#include"map.h"
#include"parray.h"
#include"dictionary.h"
#include"chashtable.h"
#include"z3_exception.h"
#include"dependency.h"
#include"rlimit.h"
#include "util/vector.h"
#include "util/hashtable.h"
#include "util/buffer.h"
#include "util/symbol.h"
#include "util/rational.h"
#include "util/hash.h"
#include "util/optional.h"
#include "util/trace.h"
#include "util/bit_vector.h"
#include "util/symbol_table.h"
#include "util/tptr.h"
#include "util/memory_manager.h"
#include "util/small_object_allocator.h"
#include "util/obj_ref.h"
#include "util/ref_vector.h"
#include "util/ref_buffer.h"
#include "util/obj_mark.h"
#include "util/obj_hashtable.h"
#include "util/id_gen.h"
#include "util/map.h"
#include "util/parray.h"
#include "util/dictionary.h"
#include "util/chashtable.h"
#include "util/z3_exception.h"
#include "util/dependency.h"
#include "util/rlimit.h"
#define RECYCLE_FREE_AST_INDICES
@ -102,8 +102,8 @@ private:
union {
int m_int; // for PARAM_INT
ast* m_ast; // for PARAM_AST
char m_symbol[sizeof(symbol)]; // for PARAM_SYMBOL
char m_rational[sizeof(rational)]; // for PARAM_RATIONAL
void const* m_symbol; // for PARAM_SYMBOL
rational* m_rational; // for PARAM_RATIONAL
double m_dval; // for PARAM_DOUBLE (remark: this is not used in float_decl_plugin)
unsigned m_ext_id; // for PARAM_EXTERNAL
};
@ -114,12 +114,10 @@ public:
explicit parameter(int val): m_kind(PARAM_INT), m_int(val) {}
explicit parameter(unsigned val): m_kind(PARAM_INT), m_int(val) {}
explicit parameter(ast * p): m_kind(PARAM_AST), m_ast(p) {}
explicit parameter(symbol const & s): m_kind(PARAM_SYMBOL) { new (m_symbol) symbol(s); }
explicit parameter(rational const & r): m_kind(PARAM_RATIONAL) { new (m_rational) rational(r); }
explicit parameter(symbol const & s): m_kind(PARAM_SYMBOL), m_symbol(s.c_ptr()) {}
explicit parameter(rational const & r): m_kind(PARAM_RATIONAL), m_rational(alloc(rational, r)) {}
explicit parameter(double d):m_kind(PARAM_DOUBLE), m_dval(d) {}
explicit parameter(const char *s):m_kind(PARAM_SYMBOL) {
new (m_symbol) symbol(s);
}
explicit parameter(const char *s):m_kind(PARAM_SYMBOL), m_symbol(symbol(s).c_ptr()) {}
explicit parameter(unsigned ext_id, bool):m_kind(PARAM_EXTERNAL), m_ext_id(ext_id) {}
parameter(parameter const&);
@ -156,8 +154,8 @@ public:
int get_int() const { SASSERT(is_int()); return m_int; }
ast * get_ast() const { SASSERT(is_ast()); return m_ast; }
symbol const & get_symbol() const { SASSERT(is_symbol()); return *(reinterpret_cast<const symbol *>(m_symbol)); }
rational const & get_rational() const { SASSERT(is_rational()); return *(reinterpret_cast<const rational *>(m_rational)); }
symbol get_symbol() const { SASSERT(is_symbol()); return symbol::mk_symbol_from_c_ptr(m_symbol); }
rational const & get_rational() const { SASSERT(is_rational()); return *m_rational; }
double get_double() const { SASSERT(is_double()); return m_dval; }
unsigned get_ext_id() const { SASSERT(is_external()); return m_ext_id; }
@ -337,13 +335,17 @@ public:
unsigned num_parameters = 0, parameter const * parameters = 0, bool private_parameters = false):
decl_info(family_id, k, num_parameters, parameters, private_parameters), m_num_elements(num_elements) {
}
sort_info(sort_info const& other) : decl_info(other), m_num_elements(other.m_num_elements) {
sort_info(sort_info const& other) : decl_info(other), m_num_elements(other.m_num_elements) {
}
sort_info(decl_info const& di, sort_size const& num_elements) :
decl_info(di), m_num_elements(num_elements) {}
~sort_info() {}
bool is_infinite() const { return m_num_elements.is_infinite(); }
bool is_very_big() const { return m_num_elements.is_very_big(); }
sort_size const & get_num_elements() const { return m_num_elements; }
void set_num_elements(sort_size const& s) { m_num_elements = s; }
};
std::ostream & operator<<(std::ostream & out, sort_info const & info);
@ -569,6 +571,7 @@ public:
bool is_very_big() const { return get_info() == 0 || get_info()->is_very_big(); }
bool is_sort_of(family_id fid, decl_kind k) const { return get_family_id() == fid && get_decl_kind() == k; }
sort_size const & get_num_elements() const { return get_info()->get_num_elements(); }
void set_num_elements(sort_size const& s) { get_info()->set_num_elements(s); }
unsigned get_size() const { return get_obj_size(); }
};
@ -892,6 +895,8 @@ struct ast_eq_proc {
}
};
class ast_translation;
class ast_table : public chashtable<ast*, obj_ptr_hash<ast>, ast_eq_proc> {
public:
void erase(ast * n);
@ -927,6 +932,8 @@ protected:
m_family_id = id;
}
virtual void inherit(decl_plugin* other_p, ast_translation& ) { }
friend class ast_manager;
public:
@ -990,7 +997,7 @@ public:
// Return true if the interpreted sort s does not depend on uninterpreted sorts.
// This may be the case, for example, for array and datatype sorts.
virtual bool is_fully_interp(sort const * s) const { return true; }
virtual bool is_fully_interp(sort * s) const { return true; }
// Event handlers for deleting/translating PARAM_EXTERNAL
virtual void del(parameter const & p) {}
@ -1657,6 +1664,8 @@ public:
sort * mk_sort(family_id fid, decl_kind k, unsigned num_parameters = 0, parameter const * parameters = 0);
sort * substitute(sort* s, unsigned n, sort * const * src, sort * const * dst);
sort * mk_bool_sort() const { return m_bool_sort; }
sort * mk_proof_sort() const { return m_proof_sort; }
@ -1669,7 +1678,7 @@ public:
\brief A sort is "fully" interpreted if it is interpreted,
and doesn't depend on other uninterpreted sorts.
*/
bool is_fully_interp(sort const * s) const;
bool is_fully_interp(sort * s) const;
func_decl * mk_func_decl(family_id fid, decl_kind k, unsigned num_parameters, parameter const * parameters,
unsigned arity, sort * const * domain, sort * range = 0);
@ -2021,8 +2030,8 @@ public:
app * mk_not(expr * n) { return mk_app(m_basic_family_id, OP_NOT, n); }
app * mk_distinct(unsigned num_args, expr * const * args);
app * mk_distinct_expanded(unsigned num_args, expr * const * args);
app * mk_true() { return m_true; }
app * mk_false() { return m_false; }
app * mk_true() const { return m_true; }
app * mk_false() const { return m_false; }
app * mk_bool_val(bool b) { return b?m_true:m_false; }
app * mk_interp(expr * arg) { return mk_app(m_basic_family_id, OP_INTERP, arg); }
@ -2472,6 +2481,7 @@ public:
void operator()(AST * n) { m_manager.inc_ref(n); }
};
#endif /* AST_H_ */

View file

@ -18,8 +18,8 @@ Revision History:
--*/
#include<iostream>
#include"for_each_ast.h"
#include"arith_decl_plugin.h"
#include "ast/for_each_ast.h"
#include "ast/arith_decl_plugin.h"
// #define AST_LL_PP_SHOW_FAMILY_NAME

View file

@ -19,7 +19,7 @@ Revision History:
#ifndef AST_LL_PP_H_
#define AST_LL_PP_H_
#include"ast.h"
#include "ast/ast.h"
#include<iostream>
void ast_ll_pp(std::ostream & out, ast_manager & m, ast * n, bool only_exprs=true, bool compact=true);

View file

@ -16,7 +16,7 @@ Author:
Revision History:
--*/
#include"ast.h"
#include "ast/ast.h"
#define check_symbol(S1,S2) if (S1 != S2) return lt(S1,S2)
#define check_value(V1,V2) if (V1 != V2) return V1 < V2

View file

@ -21,7 +21,7 @@ Revision History:
#ifndef AST_PP_H_
#define AST_PP_H_
#include"ast_smt2_pp.h"
#include "ast/ast_smt2_pp.h"
struct mk_pp : public mk_ismt2_pp {
mk_pp(ast * t, ast_manager & m, params_ref const & p, unsigned indent = 0, unsigned num_vars = 0, char const * var_prefix = 0):

View file

@ -17,9 +17,9 @@ Revision History:
--*/
#include "ast_pp_util.h"
#include "ast_smt2_pp.h"
#include "ast_smt_pp.h"
#include "ast/ast_pp_util.h"
#include "ast/ast_smt2_pp.h"
#include "ast/ast_smt_pp.h"
void ast_pp_util::collect(expr* e) {
coll.visit(e);

View file

@ -19,7 +19,7 @@ Revision History:
#ifndef AST_PP_UTIL_H_
#define AST_PP_UTIL_H_
#include "decl_collector.h"
#include "ast/decl_collector.h"
class ast_pp_util {
ast_manager& m;

View file

@ -16,8 +16,8 @@ Author:
Revision History:
--*/
#include"ast_printer.h"
#include"pp.h"
#include "ast/ast_printer.h"
#include "ast/pp.h"
class simple_ast_printer_context : public ast_printer_context {
ast_manager & m_manager;

View file

@ -19,8 +19,8 @@ Revision History:
#ifndef AST_PRINTER_H_
#define AST_PRINTER_H_
#include"ast.h"
#include"ast_smt2_pp.h"
#include "ast/ast.h"
#include "ast/ast_smt2_pp.h"
class ast_printer {
public:

View file

@ -18,13 +18,13 @@ Author:
Revision History:
--*/
#include"ast_smt2_pp.h"
#include"shared_occs.h"
#include"pp.h"
#include"ast_ll_pp.h"
#include"ast_pp.h"
#include"algebraic_numbers.h"
#include"pp_params.hpp"
#include "ast/ast_smt2_pp.h"
#include "ast/shared_occs.h"
#include "ast/pp.h"
#include "ast/ast_ll_pp.h"
#include "ast/ast_pp.h"
#include "math/polynomial/algebraic_numbers.h"
#include "ast/pp_params.hpp"
using namespace format_ns;
#define ALIAS_PREFIX "a"
@ -43,6 +43,9 @@ format * smt2_pp_environment::pp_fdecl_name(symbol const & s, unsigned & len) co
len = static_cast<unsigned>(str.length());
return mk_string(m, str.c_str());
}
else if (!s.bare_str()) {
return mk_string(m, "null");
}
else {
len = static_cast<unsigned>(strlen(s.bare_str()));
return mk_string(m, s.bare_str());
@ -431,16 +434,16 @@ format_ns::format * smt2_pp_environment::pp_sort(sort * s) {
fs.push_back(pp_sort(to_sort(s->get_parameter(0).get_ast())));
return mk_seq1(m, fs.begin(), fs.end(), f2f(), get_sutil().is_seq(s)?"Seq":"RegEx");
}
#if 0
if (get_dtutil().is_datatype(s)) {
ptr_buffer<format> fs;
unsigned sz = get_dtutil().get_datatype_num_parameter_sorts(s);
for (unsigned i = 0; i < sz; i++) {
fs.push_back(pp_sort(get_dtutil().get_datatype_parameter_sort(s, i)));
if (sz > 0) {
ptr_buffer<format> fs;
for (unsigned i = 0; i < sz; i++) {
fs.push_back(pp_sort(get_dtutil().get_datatype_parameter_sort(s, i)));
}
return mk_seq1(m, fs.begin(), fs.end(), f2f(), s->get_name().str().c_str());
}
return mk_seq1(m, fs.begin(), fs.end(), f2f(), s->get_name().str().c_str());
}
#endif
return format_ns::mk_string(get_manager(), s->get_name().str().c_str());
}
@ -1222,15 +1225,15 @@ mk_ismt2_pp::mk_ismt2_pp(ast * t, ast_manager & m, unsigned indent, unsigned num
std::ostream& operator<<(std::ostream& out, mk_ismt2_pp const & p) {
smt2_pp_environment_dbg env(p.m_manager);
if (is_expr(p.m_ast)) {
if (p.m_ast == 0) {
out << "null";
}
else if (is_expr(p.m_ast)) {
ast_smt2_pp(out, to_expr(p.m_ast), env, p.m_params, p.m_indent, p.m_num_vars, p.m_var_prefix);
}
else if (is_sort(p.m_ast)) {
ast_smt2_pp(out, to_sort(p.m_ast), env, p.m_params, p.m_indent);
}
else if (p.m_ast == 0) {
out << "null";
}
else {
SASSERT(is_func_decl(p.m_ast));
ast_smt2_pp(out, to_func_decl(p.m_ast), env, p.m_params, p.m_indent);

View file

@ -22,16 +22,16 @@ Revision History:
#ifndef AST_SMT2_PP_H_
#define AST_SMT2_PP_H_
#include"format.h"
#include"params.h"
#include"arith_decl_plugin.h"
#include"bv_decl_plugin.h"
#include"array_decl_plugin.h"
#include"fpa_decl_plugin.h"
#include"dl_decl_plugin.h"
#include"seq_decl_plugin.h"
#include"datatype_decl_plugin.h"
#include"smt2_util.h"
#include "ast/format.h"
#include "util/params.h"
#include "ast/arith_decl_plugin.h"
#include "ast/bv_decl_plugin.h"
#include "ast/array_decl_plugin.h"
#include "ast/fpa_decl_plugin.h"
#include "ast/dl_decl_plugin.h"
#include "ast/seq_decl_plugin.h"
#include "ast/datatype_decl_plugin.h"
#include "util/smt2_util.h"
class smt2_pp_environment {
protected:

View file

@ -21,17 +21,17 @@ Revision History:
#include<sstream>
#include<iostream>
#include"ast_smt_pp.h"
#include"arith_decl_plugin.h"
#include"bv_decl_plugin.h"
#include"array_decl_plugin.h"
#include"datatype_decl_plugin.h"
#include"fpa_decl_plugin.h"
#include"vector.h"
#include"for_each_ast.h"
#include"decl_collector.h"
#include"smt2_util.h"
#include"seq_decl_plugin.h"
#include "util/vector.h"
#include "util/smt2_util.h"
#include "ast/ast_smt_pp.h"
#include "ast/arith_decl_plugin.h"
#include "ast/bv_decl_plugin.h"
#include "ast/array_decl_plugin.h"
#include "ast/datatype_decl_plugin.h"
#include "ast/seq_decl_plugin.h"
#include "ast/fpa_decl_plugin.h"
#include "ast/for_each_ast.h"
#include "ast/decl_collector.h"
// ---------------------------------------
// smt_renaming
@ -174,7 +174,6 @@ class smt_printer {
symbol m_logic;
symbol m_AUFLIRA;
bool m_no_lets;
bool m_is_smt2;
bool m_simplify_implies;
expr* m_top;
@ -199,37 +198,30 @@ class smt_printer {
}
void pp_id(expr* n) {
if (m_is_smt2) {
m_out << (is_bool(n)?"$x":(is_proof(n)?"@x":"?x")) << n->get_id();
}
else {
m_out << (is_bool(n)?"$x":"?x") << n->get_id();
}
m_out << (is_bool(n)?"$x":(is_proof(n)?"@x":"?x")) << n->get_id();
}
void pp_decl(func_decl* d) {
symbol sym = m_renaming.get_symbol(d->get_name());
if (d->get_family_id() == m_dt_fid) {
m_out << sym;
}
else if (m_manager.is_ite(d)) {
if (!m_is_smt2 && is_bool(d->get_range())) {
m_out << "if_then_else";
datatype_util util(m_manager);
if (util.is_recognizer(d)) {
visit_params(false, sym, d->get_num_parameters(), d->get_parameters());
}
else {
m_out << "ite";
m_out << sym;
}
}
else if (!m_is_smt2 && m_manager.is_implies(d)) {
m_out << "implies";
else if (m_manager.is_ite(d)) {
m_out << "ite";
}
else if (m_is_smt2 && m_manager.is_iff(d)) {
else if (m_manager.is_iff(d)) {
m_out << "=";
}
else if (m_is_smt2 && m_manager.is_implies(d)) {
else if (m_manager.is_implies(d)) {
m_out << "=>";
}
else if (m_is_smt2 && is_decl_of(d, m_arith_fid, OP_UMINUS)) {
else if (is_decl_of(d, m_arith_fid, OP_UMINUS)) {
m_out << "-";
}
else {
@ -251,28 +243,23 @@ class smt_printer {
return;
}
if (m_is_smt2) {
if (is_sort_symbol && sym == symbol("String")) {
m_out << "String";
return;
}
if (is_sort_symbol &&
sym != symbol("BitVec") &&
sym != symbol("FloatingPoint") &&
sym != symbol("RoundingMode")) {
m_out << "(" << sym << " ";
}
else if (!is_sort_symbol && is_sort_param(num_params, params)) {
m_out << "(as " << sym << " ";
}
else {
m_out << "(_ " << sym << " ";
}
if (is_sort_symbol && sym == symbol("String")) {
m_out << "String";
return;
}
if (is_sort_symbol &&
sym != symbol("BitVec") &&
sym != symbol("FloatingPoint") &&
sym != symbol("RoundingMode")) {
m_out << "(" << sym << " ";
}
else if (!is_sort_symbol && is_sort_param(num_params, params)) {
m_out << "(as " << sym << " ";
}
else {
m_out << sym << "[";
m_out << "(_ " << sym << " ";
}
for (unsigned i = 0; i < num_params; ++i) {
parameter const& p = params[i];
if (p.is_ast()) {
@ -293,20 +280,10 @@ class smt_printer {
m_out << p;
}
if (i + 1 < num_params) {
if (m_is_smt2) {
m_out << " ";
}
else {
m_out << ": ";
}
m_out << " ";
}
}
if (m_is_smt2) {
m_out << ")";
}
else {
m_out << "]";
}
m_out << ")";
}
bool is_auflira() const {
@ -315,9 +292,7 @@ class smt_printer {
void visit_sort(sort* s, bool bool2int = false) {
symbol sym;
if (bool2int && is_bool(s) && !m_is_smt2) {
sym = symbol("Int");
} else if (s->is_sort_of(m_bv_fid, BV_SORT)) {
if (s->is_sort_of(m_bv_fid, BV_SORT)) {
sym = symbol("BitVec");
}
else if (s->is_sort_of(m_arith_fid, REAL_SORT)) {
@ -329,51 +304,16 @@ class smt_printer {
else if (s->is_sort_of(m_arith_fid, INT_SORT)) {
sym = s->get_name();
}
else if (s->is_sort_of(m_array_fid, ARRAY_SORT) && m_is_smt2) {
else if (s->is_sort_of(m_array_fid, ARRAY_SORT)) {
sym = "Array";
}
else if (s->is_sort_of(m_array_fid, ARRAY_SORT) && !m_is_smt2) {
unsigned num_params = s->get_num_parameters();
SASSERT(num_params >= 2);
if (is_auflira()) {
sort* rng = to_sort(s->get_parameter(1).get_ast());
if (rng->get_family_id() == m_array_fid) {
m_out << "Array2";
}
else {
m_out << "Array1";
}
return;
}
sort* s1 = to_sort(s->get_parameter(0).get_ast());
sort* s2 = to_sort(s->get_parameter(1).get_ast());
if (num_params == 2 &&
s1->is_sort_of(m_bv_fid, BV_SORT) &&
s2->is_sort_of(m_bv_fid, BV_SORT)) {
m_out << "Array";
m_out << "[" << s1->get_parameter(0).get_int();
m_out << ":" << s2->get_parameter(0).get_int() << "]";
return;
}
m_out << "(Array ";
for (unsigned i = 0; i < num_params; ++i) {
visit_sort(to_sort(s->get_parameter(i).get_ast()));
if (i + 1 < num_params) {
m_out << " ";
}
}
m_out << ")";
return;
}
else if (s->is_sort_of(m_dt_fid, DATATYPE_SORT)) {
m_out << m_renaming.get_symbol(s->get_name());
#if 0
datatype_util util(m_manager);
unsigned num_sorts = util.get_datatype_num_parameter_sorts(s);
if (num_sorts > 0) {
m_out << "(";
}
m_out << m_renaming.get_symbol(s->get_name());
if (num_sorts > 0) {
for (unsigned i = 0; i < num_sorts; ++i) {
m_out << " ";
@ -381,7 +321,6 @@ class smt_printer {
}
m_out << ")";
}
#endif
return;
}
else {
@ -403,20 +342,7 @@ class smt_printer {
void pp_arg(expr *arg, app *parent)
{
if (!m_is_smt2 && is_bool(arg) && is_var(arg) && parent->get_family_id() == m_basic_fid) {
m_out << "(not (= ";
pp_marked_expr(arg);
m_out << " 0))";
} else if (!m_is_smt2 && is_bool(arg) && !is_var(arg) &&
parent->get_family_id() != m_basic_fid &&
parent->get_family_id() != m_dt_fid) {
m_out << "(ite ";
pp_marked_expr(arg);
m_out << " 1 0)";
} else {
pp_marked_expr(arg);
}
pp_marked_expr(arg);
}
void visit_app(app* n) {
@ -431,12 +357,7 @@ class smt_printer {
if (m_autil.is_numeral(n, val, is_int)) {
if (val.is_neg()) {
val.neg();
if (m_is_smt2) {
m_out << "(- ";
}
else {
m_out << "(~ ";
}
m_out << "(- ";
display_rational(val, is_int);
m_out << ")";
}
@ -458,12 +379,7 @@ class smt_printer {
m_out << "\"";
}
else if (m_bvutil.is_numeral(n, val, bv_size)) {
if (m_is_smt2) {
m_out << "(_ bv" << val << " " << bv_size << ")";
}
else {
m_out << "bv" << val << "[" << bv_size << "]";
}
m_out << "(_ bv" << val << " " << bv_size << ")";
}
else if (m_futil.is_numeral(n, float_val)) {
m_out << "((_ to_fp " <<
@ -473,37 +389,17 @@ class smt_printer {
}
else if (m_bvutil.is_bit2bool(n)) {
unsigned bit = n->get_decl()->get_parameter(0).get_int();
if (m_is_smt2) {
m_out << "(= ((_ extract " << bit << " " << bit << ") ";
pp_marked_expr(n->get_arg(0));
m_out << ") (_ bv1 1))";
}
else {
m_out << "(= (extract[" << bit << ":" << bit << "] ";
pp_marked_expr(n->get_arg(0));
m_out << ") bv1[1])";
}
m_out << "(= ((_ extract " << bit << " " << bit << ") ";
pp_marked_expr(n->get_arg(0));
m_out << ") (_ bv1 1))";
}
else if (m_manager.is_label(n, pos, names) && names.size() >= 1) {
if (m_is_smt2) {
m_out << "(! ";
pp_marked_expr(n->get_arg(0));
m_out << (pos?":lblpos":":lblneg") << " " << m_renaming.get_symbol(names[0]) << ")";
}
else {
m_out << "(" << (pos?"lblpos":"lblneg") << " " << m_renaming.get_symbol(names[0]) << " ";
expr* ch = n->get_arg(0);
pp_marked_expr(ch);
m_out << ")";
}
m_out << "(! ";
pp_marked_expr(n->get_arg(0));
m_out << (pos?":lblpos":":lblneg") << " " << m_renaming.get_symbol(names[0]) << ")";
}
else if (m_manager.is_label_lit(n, names) && names.size() >= 1) {
if (m_is_smt2) {
m_out << "(! true :lblpos " << m_renaming.get_symbol(names[0]) << ")";
}
else {
m_out << "(lblpos " << m_renaming.get_symbol(names[0]) << " true )";
}
m_out << "(! true :lblpos " << m_renaming.get_symbol(names[0]) << ")";
}
else if (num_args == 0) {
if (decl->private_parameters()) {
@ -533,7 +429,8 @@ class smt_printer {
pp_arg(curr, n);
m_out << ")";
} else if (m_manager.is_distinct(decl)) {
}
else if (m_manager.is_distinct(decl)) {
ptr_vector<expr> args(num_args, n->get_args());
unsigned idx = 0;
m_out << "(and";
@ -581,14 +478,11 @@ class smt_printer {
void print_no_lets(expr *e)
{
smt_printer p(m_out, m_manager, m_qlists, m_renaming, m_logic, true, m_simplify_implies, m_is_smt2, m_indent, m_num_var_names, m_var_names);
smt_printer p(m_out, m_manager, m_qlists, m_renaming, m_logic, true, m_simplify_implies, true, m_indent, m_num_var_names, m_var_names);
p(e);
}
void print_bound(symbol const& name) {
if (!m_is_smt2 && (name.is_numerical() || '?' != name.bare_str()[0])) {
m_out << "?";
}
m_out << name;
}
@ -602,9 +496,7 @@ class smt_printer {
else {
m_out << "exists ";
}
if (m_is_smt2) {
m_out << "(";
}
m_out << "(";
for (unsigned i = 0; i < q->get_num_decls(); ++i) {
sort* s = q->get_decl_sort(i);
m_out << "(";
@ -613,15 +505,13 @@ class smt_printer {
visit_sort(s, true);
m_out << ") ";
}
if (m_is_smt2) {
m_out << ")";
}
m_out << ")";
if (m_is_smt2 && (q->get_num_patterns() > 0 || q->get_qid() != symbol::null)) {
if ((q->get_num_patterns() > 0 || q->get_qid() != symbol::null)) {
m_out << "(! ";
}
{
smt_printer p(m_out, m_manager, m_qlists, m_renaming, m_logic, false, m_is_smt2, m_simplify_implies, m_indent, m_num_var_names, m_var_names);
smt_printer p(m_out, m_manager, m_qlists, m_renaming, m_logic, false, true, m_simplify_implies, m_indent, m_num_var_names, m_var_names);
p(q->get_expr());
}
@ -640,28 +530,18 @@ class smt_printer {
}
}
if (m_is_smt2) {
m_out << " :pattern ( ";
}
else {
m_out << " :pat { ";
}
m_out << " :pattern ( ";
for (unsigned j = 0; j < pat->get_num_args(); ++j) {
print_no_lets(pat->get_arg(j));
m_out << " ";
}
if (m_is_smt2) {
m_out << ")";
}
else {
m_out << "}";
}
m_out << ")";
}
if (q->get_qid() != symbol::null)
m_out << " :qid " << q->get_qid();
if (m_is_smt2 && (q->get_num_patterns() > 0 || q->get_qid() != symbol::null)) {
if ((q->get_num_patterns() > 0 || q->get_qid() != symbol::null)) {
m_out << ")";
}
m_out << ")";
@ -725,21 +605,11 @@ class smt_printer {
}
void visit_expr(expr* n) {
if (m_is_smt2) {
m_out << "(let ((";
}
else if (is_bool(n)) {
m_out << "(flet (";
}
else {
m_out << "(let (";
}
m_out << "(let ((";
pp_id(n);
m_out << " ";
pp_expr(n);
if (m_is_smt2) {
m_out << ")";
}
m_out << ")";
m_out << ")";
newline();
}
@ -851,7 +721,6 @@ public:
m_AUFLIRA("AUFLIRA"),
// It's much easier to read those testcases with that.
m_no_lets(no_lets),
m_is_smt2(is_smt2),
m_simplify_implies(simplify_implies)
{
m_basic_fid = m.get_basic_family_id();
@ -905,91 +774,59 @@ public:
}
void pp_dt(ast_mark& mark, sort* s) {
SASSERT(s->is_sort_of(m_dt_fid, DATATYPE_SORT));
datatype_util util(m_manager);
ptr_vector<func_decl> const* decls;
ptr_vector<sort> rec_sorts;
SASSERT(util.is_datatype(s));
rec_sorts.push_back(s);
mark.mark(s, true);
sort_ref_vector ps(m_manager);
ptr_vector<datatype::def> defs;
util.get_defs(s, defs);
// collect siblings and sorts that have not already been printed.
for (unsigned h = 0; h < rec_sorts.size(); ++h) {
s = rec_sorts[h];
decls = util.get_datatype_constructors(s);
for (unsigned i = 0; i < decls->size(); ++i) {
func_decl* f = (*decls)[i];
for (unsigned j = 0; j < f->get_arity(); ++j) {
sort* s2 = f->get_domain(j);
if (!mark.is_marked(s2)) {
if (m_manager.is_uninterp(s2)) {
pp_sort_decl(mark, s2);
}
else if (!util.is_datatype(s2)) {
// skip
}
else if (util.are_siblings(s, s2)) {
rec_sorts.push_back(s2);
mark.mark(s2, true);
}
else {
pp_sort_decl(mark, s2);
}
}
for (datatype::def* d : defs) {
sort_ref sr = d->instantiate(ps);
if (mark.is_marked(sr)) return; // already processed
mark.mark(sr, true);
}
m_out << "(declare-datatypes (";
bool first_def = true;
for (datatype::def* d : defs) {
if (!first_def) m_out << "\n "; else first_def = false;
m_out << "(" << d->name() << " " << d->params().size() << ")";
}
m_out << ") (";
bool first_sort = true;
for (datatype::def* d : defs) {
if (!first_sort) m_out << "\n "; else first_sort = false;
if (!d->params().empty()) {
m_out << "(par (";
bool first_param = true;
for (sort* s : d->params()) {
if (!first_param) m_out << " "; else first_param = false;
visit_sort(s);
}
m_out << ")";
}
}
if (m_is_smt2) {
// TBD: datatypes may be declared parametrically.
// get access to parametric generalization, or print
// monomorphic specialization with a tag that gets reused at use-point.
m_out << "(declare-datatypes () (";
}
else {
m_out << ":datatypes (";
}
for (unsigned si = 0; si < rec_sorts.size(); ++si) {
s = rec_sorts[si];
m_out << "(";
m_out << m_renaming.get_symbol(s->get_name());
m_out << m_renaming.get_symbol(d->name());
m_out << " ";
decls = util.get_datatype_constructors(s);
for (unsigned i = 0; i < decls->size(); ++i) {
func_decl* f = (*decls)[i];
ptr_vector<func_decl> const& accs = *util.get_constructor_accessors(f);
if (m_is_smt2 || accs.size() > 0) {
m_out << "(";
}
m_out << m_renaming.get_symbol(f->get_name());
if (!accs.empty() || !m_is_smt2) {
m_out << " ";
}
for (unsigned j = 0; j < accs.size(); ++j) {
func_decl* a = accs[j];
m_out << "(" << m_renaming.get_symbol(a->get_name()) << " ";
visit_sort(a->get_range());
bool first_constr = true;
for (datatype::constructor* f : *d) {
if (!first_constr) m_out << " "; else first_constr = false;
m_out << "(";
m_out << m_renaming.get_symbol(f->name());
for (datatype::accessor* a : *f) {
m_out << " (" << m_renaming.get_symbol(a->name()) << " ";
visit_sort(a->range());
m_out << ")";
if (j + 1 < accs.size()) m_out << " ";
}
if (m_is_smt2 || accs.size() > 0) {
m_out << ")";
if (i + 1 < decls->size()) {
m_out << " ";
}
}
m_out << ")";
}
if (!d->params().empty()) {
m_out << ")";
}
m_out << ")";
if (si + 1 < rec_sorts.size()) {
m_out << " ";
}
}
if (m_is_smt2) {
m_out << ")";
}
m_out << ")";
m_out << "))";
newline();
}
@ -1002,12 +839,7 @@ public:
pp_dt(mark, s);
}
else {
if (m_is_smt2) {
m_out << "(declare-sort ";
}
else {
m_out << ":extrasorts (";
}
m_out << "(declare-sort ";
visit_sort(s);
m_out << ")";
newline();
@ -1021,29 +853,16 @@ public:
}
void operator()(func_decl* d) {
if (m_is_smt2) {
m_out << "(declare-fun ";
pp_decl(d);
m_out << "(";
for (unsigned i = 0; i < d->get_arity(); ++i) {
if (i > 0) m_out << " ";
visit_sort(d->get_domain(i), true);
}
m_out << ") ";
visit_sort(d->get_range());
m_out << ")";
}
else {
m_out << "(";
pp_decl(d);
for (unsigned i = 0; i < d->get_arity(); ++i) {
m_out << " ";
visit_sort(d->get_domain(i), true);
}
m_out << " ";
visit_sort(d->get_range());
m_out << ")";
m_out << "(declare-fun ";
pp_decl(d);
m_out << "(";
for (unsigned i = 0; i < d->get_arity(); ++i) {
if (i > 0) m_out << " ";
visit_sort(d->get_domain(i), true);
}
m_out << ") ";
visit_sort(d->get_range());
m_out << ")";
}
void visit_pred(func_decl* d) {

View file

@ -19,9 +19,9 @@ Revision History:
#ifndef AST_SMT_PP_H_
#define AST_SMT_PP_H_
#include"ast.h"
#include "ast/ast.h"
#include<string>
#include"map.h"
#include "util/map.h"
class smt_renaming {
typedef map<symbol, symbol, symbol_hash_proc, symbol_eq_proc> symbol2symbol;

View file

@ -22,8 +22,8 @@ Revision History:
#ifndef AST_TRAIL_H_
#define AST_TRAIL_H_
#include"ast.h"
#include"trail.h"
#include "ast/ast.h"
#include "util/trail.h"
template<typename S, typename T>

View file

@ -16,13 +16,13 @@ Author:
Revision History:
--*/
#include "arith_decl_plugin.h"
#include "bv_decl_plugin.h"
#include "datatype_decl_plugin.h"
#include "array_decl_plugin.h"
#include "format.h"
#include "ast_translation.h"
#include "ast_ll_pp.h"
#include "ast/arith_decl_plugin.h"
#include "ast/bv_decl_plugin.h"
#include "ast/datatype_decl_plugin.h"
#include "ast/array_decl_plugin.h"
#include "ast/format.h"
#include "ast/ast_translation.h"
#include "ast/ast_ll_pp.h"
ast_translation::~ast_translation() {
reset_cache();
@ -37,11 +37,9 @@ void ast_translation::cleanup() {
}
void ast_translation::reset_cache() {
obj_map<ast, ast*>::iterator it = m_cache.begin();
obj_map<ast, ast*>::iterator end = m_cache.end();
for (; it != end; ++it) {
m_from_manager.dec_ref(it->m_key);
m_to_manager.dec_ref(it->m_value);
for (auto & kv : m_cache) {
m_from_manager.dec_ref(kv.m_key);
m_to_manager.dec_ref(kv.m_value);
}
m_cache.reset();
}

View file

@ -21,7 +21,7 @@ Revision History:
#ifndef AST_TRANSLATION_H_
#define AST_TRANSLATION_H_
#include"ast.h"
#include "ast/ast.h"
class ast_translation {
struct frame {

View file

@ -16,7 +16,7 @@ Author:
Revision History:
--*/
#include "ast_util.h"
#include "ast/ast_util.h"
app * mk_list_assoc_app(ast_manager & m, func_decl * f, unsigned num_args, expr * const * args) {
SASSERT(f->is_associative());

View file

@ -19,8 +19,8 @@ Revision History:
#ifndef AST_UTIL_H_
#define AST_UTIL_H_
#include"ast.h"
#include"obj_hashtable.h"
#include "ast/ast.h"
#include "util/obj_hashtable.h"
template<typename C>
void remove_duplicates(C & v) {

View file

@ -17,11 +17,11 @@ Revision History:
--*/
#include<sstream>
#include"bv_decl_plugin.h"
#include"arith_decl_plugin.h"
#include"warning.h"
#include"ast_pp.h"
#include"ast_smt2_pp.h"
#include "ast/bv_decl_plugin.h"
#include "ast/arith_decl_plugin.h"
#include "util/warning.h"
#include "ast/ast_pp.h"
#include "ast/ast_smt2_pp.h"
bv_decl_plugin::bv_decl_plugin():
m_bv_sym("bv"),
@ -784,6 +784,12 @@ bool bv_recognizers::is_numeral(expr const * n, rational & val, unsigned & bv_si
return true;
}
bool bv_recognizers::is_numeral(expr const * n, rational & val) const {
unsigned bv_size = 0;
return is_numeral(n, val, bv_size);
}
bool bv_recognizers::is_allone(expr const * e) const {
rational r;
unsigned bv_size;
@ -847,7 +853,7 @@ bv_util::bv_util(ast_manager & m):
m_plugin = static_cast<bv_decl_plugin*>(m.get_plugin(m.mk_family_id("bv")));
}
app * bv_util::mk_numeral(rational const & val, sort* s) {
app * bv_util::mk_numeral(rational const & val, sort* s) const {
if (!is_bv_sort(s)) {
return 0;
}
@ -855,7 +861,7 @@ app * bv_util::mk_numeral(rational const & val, sort* s) {
return mk_numeral(val, bv_size);
}
app * bv_util::mk_numeral(rational const & val, unsigned bv_size) {
app * bv_util::mk_numeral(rational const & val, unsigned bv_size) const {
parameter p1(val);
parameter p[2] = { p1, parameter(static_cast<int>(bv_size)) };
return m_manager.mk_app(get_fid(), OP_BV_NUM, 2, p, 0, 0);

View file

@ -19,7 +19,7 @@ Revision History:
#ifndef BV_DECL_PLUGIN_H_
#define BV_DECL_PLUGIN_H_
#include"ast.h"
#include "ast/ast.h"
enum bv_sort_kind {
BV_SORT
@ -293,6 +293,7 @@ public:
family_id get_fid() const { return m_afid; }
family_id get_family_id() const { return get_fid(); }
bool is_numeral(expr const * n, rational & val) const;
bool is_numeral(expr const * n, rational & val, unsigned & bv_size) const;
bool is_numeral(expr const * n) const { return is_app_of(n, get_fid(), OP_BV_NUM); }
bool is_allone(expr const * e) const;
@ -381,9 +382,9 @@ public:
ast_manager & get_manager() const { return m_manager; }
app * mk_numeral(rational const & val, sort* s);
app * mk_numeral(rational const & val, unsigned bv_size);
app * mk_numeral(uint64 u, unsigned bv_size) { return mk_numeral(rational(u, rational::ui64()), bv_size); }
app * mk_numeral(rational const & val, sort* s) const;
app * mk_numeral(rational const & val, unsigned bv_size) const;
app * mk_numeral(uint64 u, unsigned bv_size) const { return mk_numeral(rational(u, rational::ui64()), bv_size); }
sort * mk_sort(unsigned bv_size);
unsigned get_bv_size(sort const * s) const {

File diff suppressed because it is too large Load diff

View file

@ -1,5 +1,5 @@
/*++
Copyright (c) 2006 Microsoft Corporation
Copyright (c) 2017 Microsoft Corporation
Module Name:
@ -11,49 +11,390 @@ Abstract:
Author:
Leonardo de Moura (leonardo) 2008-01-09.
Nikolaj Bjorner (nbjorner) 2017-9-1
Revision History:
rewritten to support SMTLIB-2.6 parameters from
Leonardo de Moura (leonardo) 2008-01-09.
--*/
#ifndef DATATYPE_DECL_PLUGIN_H_
#define DATATYPE_DECL_PLUGIN_H_
#include"ast.h"
#include"tptr.h"
#include"buffer.h"
#include"obj_hashtable.h"
#include "ast/ast.h"
#include "util/buffer.h"
#include "util/symbol_table.h"
#include "util/obj_hashtable.h"
enum datatype_sort_kind {
enum sort_kind {
DATATYPE_SORT
};
enum datatype_op_kind {
enum op_kind {
OP_DT_CONSTRUCTOR,
OP_DT_RECOGNISER,
OP_DT_ACCESSOR,
OP_DT_IS,
OP_DT_ACCESSOR,
OP_DT_UPDATE_FIELD,
LAST_DT_OP
};
/**
\brief Auxiliary class used to declare inductive datatypes.
It may be a sort or an integer. If it is an integer,
then it represents a reference to a recursive type.
namespace datatype {
For example, consider the datatypes
Datatype
Tree = tree(value:Real, children:TreeList)
TreeList = cons_t(first_t:Tree, rest_t:Tree)
| nil_t
End
The recursive occurrences of Tree and TreeList will have idx 0 and
1 respectively.
class util;
class def;
class accessor;
class constructor;
class accessor {
symbol m_name;
sort_ref m_range;
unsigned m_index; // reference to recursive data-type may only get resolved after all mutually recursive data-types are procssed.
constructor* m_constructor;
public:
accessor(ast_manager& m, symbol const& n, sort* range):
m_name(n),
m_range(range, m),
m_index(UINT_MAX)
{}
accessor(ast_manager& m, symbol const& n, unsigned index):
m_name(n),
m_range(m),
m_index(index)
{}
sort* range() const { return m_range; }
void fix_range(sort_ref_vector const& dts);
symbol const& name() const { return m_name; }
func_decl_ref instantiate(sort_ref_vector const& ps) const;
func_decl_ref instantiate(sort* dt) const;
void attach(constructor* d) { m_constructor = d; }
constructor const& get_constructor() const { return *m_constructor; }
def const& get_def() const;
util& u() const;
accessor* translate(ast_translation& tr);
};
class constructor {
symbol m_name;
symbol m_recognizer;
ptr_vector<accessor> m_accessors;
def* m_def;
public:
constructor(symbol n, symbol const& r): m_name(n), m_recognizer(r) {}
~constructor();
void add(accessor* a) { m_accessors.push_back(a); a->attach(this); }
symbol const& name() const { return m_name; }
symbol const& recognizer() const { return m_recognizer; }
ptr_vector<accessor> const& accessors() const { return m_accessors; }
ptr_vector<accessor>::const_iterator begin() const { return m_accessors.begin(); }
ptr_vector<accessor>::const_iterator end() const { return m_accessors.end(); }
ptr_vector<accessor>::iterator begin() { return m_accessors.begin(); }
ptr_vector<accessor>::iterator end() { return m_accessors.end(); }
func_decl_ref instantiate(sort_ref_vector const& ps) const;
func_decl_ref instantiate(sort* dt) const;
void attach(def* d) { m_def = d; }
def const& get_def() const { return *m_def; }
util& u() const;
constructor* translate(ast_translation& tr);
};
namespace param_size {
class size {
unsigned m_ref;
public:
size(): m_ref(0) {}
virtual ~size() {}
void inc_ref() { ++m_ref; }
void dec_ref() { --m_ref; if (m_ref == 0) dealloc(this); }
static size* mk_offset(sort_size const& s);
static size* mk_param(sort_ref& p);
static size* mk_plus(size* a1, size* a2);
static size* mk_times(size* a1, size* a2);
static size* mk_plus(ptr_vector<size>& szs);
static size* mk_times(ptr_vector<size>& szs);
static size* mk_power(size* a1, size* a2);
virtual size* subst(obj_map<sort, size*>& S) = 0;
virtual sort_size eval(obj_map<sort, sort_size> const& S) = 0;
};
struct offset : public size {
sort_size m_offset;
offset(sort_size const& s): m_offset(s) {}
virtual ~offset() {}
virtual size* subst(obj_map<sort,size*>& S) { return this; }
virtual sort_size eval(obj_map<sort, sort_size> const& S) { return m_offset; }
};
struct plus : public size {
size* m_arg1, *m_arg2;
plus(size* a1, size* a2): m_arg1(a1), m_arg2(a2) { a1->inc_ref(); a2->inc_ref();}
virtual ~plus() { m_arg1->dec_ref(); m_arg2->dec_ref(); }
virtual size* subst(obj_map<sort,size*>& S) { return mk_plus(m_arg1->subst(S), m_arg2->subst(S)); }
virtual sort_size eval(obj_map<sort, sort_size> const& S) {
sort_size s1 = m_arg1->eval(S);
sort_size s2 = m_arg2->eval(S);
if (s1.is_infinite()) return s1;
if (s2.is_infinite()) return s2;
if (s1.is_very_big()) return s1;
if (s2.is_very_big()) return s2;
rational r = rational(s1.size(), rational::ui64()) + rational(s2.size(), rational::ui64());
return sort_size(r);
}
};
struct times : public size {
size* m_arg1, *m_arg2;
times(size* a1, size* a2): m_arg1(a1), m_arg2(a2) { a1->inc_ref(); a2->inc_ref(); }
virtual ~times() { m_arg1->dec_ref(); m_arg2->dec_ref(); }
virtual size* subst(obj_map<sort,size*>& S) { return mk_times(m_arg1->subst(S), m_arg2->subst(S)); }
virtual sort_size eval(obj_map<sort, sort_size> const& S) {
sort_size s1 = m_arg1->eval(S);
sort_size s2 = m_arg2->eval(S);
if (s1.is_infinite()) return s1;
if (s2.is_infinite()) return s2;
if (s1.is_very_big()) return s1;
if (s2.is_very_big()) return s2;
rational r = rational(s1.size(), rational::ui64()) * rational(s2.size(), rational::ui64());
return sort_size(r);
}
};
struct power : public size {
size* m_arg1, *m_arg2;
power(size* a1, size* a2): m_arg1(a1), m_arg2(a2) { a1->inc_ref(); a2->inc_ref(); }
virtual ~power() { m_arg1->dec_ref(); m_arg2->dec_ref(); }
virtual size* subst(obj_map<sort,size*>& S) { return mk_power(m_arg1->subst(S), m_arg2->subst(S)); }
virtual sort_size eval(obj_map<sort, sort_size> const& S) {
sort_size s1 = m_arg1->eval(S);
sort_size s2 = m_arg2->eval(S);
// s1^s2
if (s1.is_infinite()) return s1;
if (s2.is_infinite()) return s2;
if (s1.is_very_big()) return s1;
if (s2.is_very_big()) return s2;
if (s1.size() == 1) return s1;
if (s2.size() == 1) return s1;
if (s1.size() > (2 << 20) || s2.size() > 10) return sort_size::mk_very_big();
rational r = ::power(rational(s1.size(), rational::ui64()), static_cast<unsigned>(s2.size()));
return sort_size(r);
}
};
struct sparam : public size {
sort_ref m_param;
sparam(sort_ref& p): m_param(p) {}
virtual ~sparam() {}
virtual size* subst(obj_map<sort,size*>& S) { return S[m_param]; }
virtual sort_size eval(obj_map<sort, sort_size> const& S) { return S[m_param]; }
};
};
class def {
ast_manager& m;
util& m_util;
symbol m_name;
unsigned m_class_id;
param_size::size* m_sort_size;
sort_ref_vector m_params;
mutable sort_ref m_sort;
ptr_vector<constructor> m_constructors;
public:
def(ast_manager& m, util& u, symbol const& n, unsigned class_id, unsigned num_params, sort * const* params):
m(m),
m_util(u),
m_name(n),
m_class_id(class_id),
m_sort_size(0),
m_params(m, num_params, params),
m_sort(m)
{}
~def() {
if (m_sort_size) m_sort_size->dec_ref();
for (constructor* c : m_constructors) dealloc(c);
m_constructors.reset();
}
void add(constructor* c) {
m_constructors.push_back(c);
c->attach(this);
}
symbol const& name() const { return m_name; }
unsigned id() const { return m_class_id; }
sort_ref instantiate(sort_ref_vector const& ps) const;
ptr_vector<constructor> const& constructors() const { return m_constructors; }
ptr_vector<constructor>::const_iterator begin() const { return m_constructors.begin(); }
ptr_vector<constructor>::const_iterator end() const { return m_constructors.end(); }
ptr_vector<constructor>::iterator begin() { return m_constructors.begin(); }
ptr_vector<constructor>::iterator end() { return m_constructors.end(); }
sort_ref_vector const& params() const { return m_params; }
util& u() const { return m_util; }
param_size::size* sort_size() { return m_sort_size; }
void set_sort_size(param_size::size* p) { m_sort_size = p; p->inc_ref(); m_sort = 0; }
def* translate(ast_translation& tr, util& u);
};
namespace decl {
class plugin : public decl_plugin {
mutable scoped_ptr<util> m_util;
map<symbol, def*, symbol_hash_proc, symbol_eq_proc> m_defs;
svector<symbol> m_def_block;
unsigned m_class_id;
util & u() const;
virtual void inherit(decl_plugin* other_p, ast_translation& tr);
public:
plugin(): m_class_id(0) {}
virtual ~plugin();
virtual void finalize();
virtual decl_plugin * mk_fresh() { return alloc(plugin); }
virtual sort * mk_sort(decl_kind k, unsigned num_parameters, parameter const * parameters);
virtual func_decl * mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters,
unsigned arity, sort * const * domain, sort * range);
virtual expr * get_some_value(sort * s);
virtual bool is_fully_interp(sort * s) const;
virtual bool is_value(app* e) const;
virtual bool is_unique_value(app * e) const { return is_value(e); }
virtual void get_op_names(svector<builtin_name> & op_names, symbol const & logic);
void begin_def_block() { m_class_id++; m_def_block.reset(); }
void end_def_block();
def* mk(symbol const& name, unsigned n, sort * const * params);
void remove(symbol const& d);
bool mk_datatypes(unsigned num_datatypes, def * const * datatypes, unsigned num_params, sort* const* sort_params, sort_ref_vector & new_sorts);
def const& get_def(sort* s) const { return *(m_defs[datatype_name(s)]); }
def& get_def(symbol const& s) { return *(m_defs[s]); }
bool is_declared(sort* s) const { return m_defs.contains(datatype_name(s)); }
private:
bool is_value_visit(expr * arg, ptr_buffer<app> & todo) const;
func_decl * mk_update_field(
unsigned num_parameters, parameter const * parameters,
unsigned arity, sort * const * domain, sort * range);
func_decl * mk_constructor(
unsigned num_parameters, parameter const * parameters,
unsigned arity, sort * const * domain, sort * range);
func_decl * mk_accessor(
unsigned num_parameters, parameter const * parameters,
unsigned arity, sort * const * domain, sort * range);
func_decl * mk_recognizer(
unsigned num_parameters, parameter const * parameters,
unsigned arity, sort * const * domain, sort * range);
func_decl * mk_is(
unsigned num_parameters, parameter const * parameters,
unsigned arity, sort * const * domain, sort * range);
symbol datatype_name(sort * s) const {
//SASSERT(u().is_datatype(s));
return s->get_parameter(0).get_symbol();
}
};
}
class util {
ast_manager & m;
family_id m_family_id;
mutable decl::plugin* m_plugin;
obj_map<sort, ptr_vector<func_decl> *> m_datatype2constructors;
obj_map<sort, func_decl *> m_datatype2nonrec_constructor;
obj_map<func_decl, ptr_vector<func_decl> *> m_constructor2accessors;
obj_map<func_decl, func_decl *> m_constructor2recognizer;
obj_map<func_decl, func_decl *> m_recognizer2constructor;
obj_map<func_decl, func_decl *> m_accessor2constructor;
obj_map<sort, bool> m_is_recursive;
obj_map<sort, bool> m_is_enum;
mutable obj_map<sort, bool> m_is_fully_interp;
mutable ast_ref_vector m_asts;
ptr_vector<ptr_vector<func_decl> > m_vectors;
unsigned m_start;
mutable ptr_vector<sort> m_fully_interp_trail;
func_decl * get_non_rec_constructor_core(sort * ty, ptr_vector<sort> & forbidden_set);
friend class decl::plugin;
bool is_recursive_core(sort * s) const;
sort_size get_datatype_size(sort* s0);
void compute_datatype_size_functions(svector<symbol> const& names);
param_size::size* get_sort_size(sort_ref_vector const& params, sort* s);
bool is_well_founded(unsigned num_types, sort* const* sorts);
def& get_def(symbol const& s) { return m_plugin->get_def(s); }
void get_subsorts(sort* s, ptr_vector<sort>& sorts) const;
public:
util(ast_manager & m);
~util();
ast_manager & get_manager() const { return m; }
// sort * mk_datatype_sort(symbol const& name, unsigned n, sort* const* params);
bool is_datatype(sort const* s) const { return is_sort_of(s, m_family_id, DATATYPE_SORT); }
bool is_enum_sort(sort* s);
bool is_recursive(sort * ty);
bool is_constructor(func_decl * f) const { return is_decl_of(f, m_family_id, OP_DT_CONSTRUCTOR); }
bool is_recognizer(func_decl * f) const { return is_recognizer0(f) || is_is(f); }
bool is_recognizer0(func_decl * f) const { return is_decl_of(f, m_family_id, OP_DT_RECOGNISER); }
bool is_is(func_decl * f) const { return is_decl_of(f, m_family_id, OP_DT_IS); }
bool is_accessor(func_decl * f) const { return is_decl_of(f, m_family_id, OP_DT_ACCESSOR); }
bool is_update_field(func_decl * f) const { return is_decl_of(f, m_family_id, OP_DT_UPDATE_FIELD); }
bool is_constructor(app * f) const { return is_app_of(f, m_family_id, OP_DT_CONSTRUCTOR); }
bool is_recognizer0(app * f) const { return is_app_of(f, m_family_id, OP_DT_RECOGNISER);}
bool is_is(app * f) const { return is_app_of(f, m_family_id, OP_DT_IS);}
bool is_recognizer(app * f) const { return is_recognizer0(f) || is_is(f); }
bool is_accessor(app * f) const { return is_app_of(f, m_family_id, OP_DT_ACCESSOR); }
bool is_update_field(app * f) const { return is_app_of(f, m_family_id, OP_DT_UPDATE_FIELD); }
ptr_vector<func_decl> const * get_datatype_constructors(sort * ty);
unsigned get_datatype_num_constructors(sort * ty);
unsigned get_datatype_num_parameter_sorts(sort * ty);
sort* get_datatype_parameter_sort(sort * ty, unsigned idx);
func_decl * get_non_rec_constructor(sort * ty);
func_decl * get_constructor_recognizer(func_decl * constructor);
ptr_vector<func_decl> const * get_constructor_accessors(func_decl * constructor);
func_decl * get_accessor_constructor(func_decl * accessor);
func_decl * get_recognizer_constructor(func_decl * recognizer) const;
family_id get_family_id() const { return m_family_id; }
bool are_siblings(sort * s1, sort * s2);
bool is_func_decl(op_kind k, unsigned num_params, parameter const* params, func_decl* f);
bool is_constructor_of(unsigned num_params, parameter const* params, func_decl* f);
void reset();
bool is_declared(sort* s) const;
void display_datatype(sort *s, std::ostream& strm);
bool is_fully_interp(sort * s) const;
sort_ref_vector datatype_params(sort * s) const;
unsigned get_constructor_idx(func_decl * f) const;
unsigned get_recognizer_constructor_idx(func_decl * f) const;
decl::plugin* get_plugin() { return m_plugin; }
void get_defs(sort* s, ptr_vector<def>& defs);
def const& get_def(sort* s) const;
};
};
typedef datatype::accessor accessor_decl;
typedef datatype::constructor constructor_decl;
typedef datatype::def datatype_decl;
typedef datatype::decl::plugin datatype_decl_plugin;
typedef datatype::util datatype_util;
This is a transient value, it is only used to declare a set of
recursive datatypes.
*/
class type_ref {
void * m_data;
public:
@ -67,181 +408,29 @@ public:
int get_idx() const { return UNBOXINT(m_data); }
};
class accessor_decl;
class constructor_decl;
class datatype_decl;
class datatype_util;
inline accessor_decl * mk_accessor_decl(ast_manager& m, symbol const & n, type_ref const & t) {
if (t.is_idx()) {
return alloc(accessor_decl, m, n, t.get_idx());
}
else {
return alloc(accessor_decl, m, n, t.get_sort());
}
}
inline constructor_decl * mk_constructor_decl(symbol const & n, symbol const & r, unsigned num_accessors, accessor_decl * * acs) {
constructor_decl* c = alloc(constructor_decl, n, r);
for (unsigned i = 0; i < num_accessors; ++i) {
c->add(acs[i]);
}
return c;
}
accessor_decl * mk_accessor_decl(symbol const & n, type_ref const & t);
void del_accessor_decl(accessor_decl * d);
void del_accessor_decls(unsigned num, accessor_decl * const * as);
// Remark: the constructor becomes the owner of the accessor_decls
constructor_decl * mk_constructor_decl(symbol const & n, symbol const & r, unsigned num_accessors, accessor_decl * const * acs);
void del_constructor_decl(constructor_decl * d);
void del_constructor_decls(unsigned num, constructor_decl * const * cs);
// Remark: the datatype becomes the owner of the constructor_decls
datatype_decl * mk_datatype_decl(symbol const & n, unsigned num_constructors, constructor_decl * const * cs);
void del_datatype_decl(datatype_decl * d);
void del_datatype_decls(unsigned num, datatype_decl * const * ds);
datatype_decl * mk_datatype_decl(datatype_util& u, symbol const & n, unsigned num_params, sort*const* params, unsigned num_constructors, constructor_decl * const * cs);
inline void del_datatype_decl(datatype_decl * d) {}
inline void del_datatype_decls(unsigned num, datatype_decl * const * ds) {}
class datatype_decl_plugin : public decl_plugin {
mutable scoped_ptr<datatype_util> m_util;
datatype_util & get_util() const;
public:
datatype_decl_plugin() {}
virtual ~datatype_decl_plugin();
virtual void finalize();
virtual decl_plugin * mk_fresh() { return alloc(datatype_decl_plugin); }
/**
Contract for sort:
parameters[0] - (int) n - number of recursive types.
parameters[1] - (int) i - index 0..n-1 of which type is defined.
parameters[2] - (int) p - number of type parameters.
for j = 0..p-1
parameters[3 + j] - (sort) s - type parameter
c_offset := 3 + p
for j in 0..n-1
parameters[c_offset + 2*j] - (symbol) name of the type
parameters[c_offset + 2*j + 1] - (int) o - offset where the constructors are defined.
for each offset o at parameters[2 + 2*j + 1] for some j in 0..n-1
parameters[o] - (int) m - number of constructors
parameters[o+1] - (int) k_1 - offset for constructor definition
...
parameters[o+m] - (int) k_m - offset for constructor definition
for each offset k_i at parameters[o+s] for some s in 0..m-1
parameters[k_i] - (symbol) name of the constructor
parameters[k_i+1] - (symbol) name of the recognizer
parameters[k_i+2] - (int) m' - number of accessors
parameters[k_i+3+2*r] - (symbol) name of the r accessor
parameters[k_i+3+2*r+1] - (int or type_ast) type of the accessor. If integer, then the value must be in [0..n-1], and it
represents an reference to the recursive type.
The idea with the additional offsets is that
access to relevant constructors and types can be performed using
a few address calculations.
*/
virtual sort * mk_sort(decl_kind k, unsigned num_parameters, parameter const * parameters);
/**
Contract for constructors
parameters[0] - (ast) datatype ast.
parmaeters[1] - (int) constructor idx.
Contract for accessors
parameters[0] - (ast) datatype ast.
parameters[1] - (int) constructor idx.
parameters[2] - (int) accessor idx.
Contract for tester
parameters[0] - (ast) datatype ast.
parameters[1] - (int) constructor idx.
*/
virtual func_decl * mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters,
unsigned arity, sort * const * domain, sort * range);
bool mk_datatypes(unsigned num_datatypes, datatype_decl * const * datatypes, unsigned num_params, sort* const* sort_params, sort_ref_vector & new_sorts);
virtual expr * get_some_value(sort * s);
virtual bool is_fully_interp(sort const * s) const;
virtual bool is_value(app* e) const;
virtual bool is_unique_value(app * e) const { return is_value(e); }
virtual void get_op_names(svector<builtin_name> & op_names, symbol const & logic);
static unsigned constructor_offset(sort const* s);
static unsigned constructor_offset(parameter const& p);
static unsigned constructor_offset(parameter const* ps);
static unsigned constructor_offset(sort const* s, unsigned tid);
static unsigned constructor_offset(parameter const* ps, unsigned tid);
private:
bool is_value_visit(expr * arg, ptr_buffer<app> & todo) const;
func_decl * mk_update_field(
unsigned num_parameters, parameter const * parameters,
unsigned arity, sort * const * domain, sort * range);
};
class datatype_util {
ast_manager & m_manager;
family_id m_family_id;
func_decl * get_constructor(sort * ty, unsigned c_id) const;
obj_map<sort, ptr_vector<func_decl> *> m_datatype2constructors;
obj_map<sort, func_decl *> m_datatype2nonrec_constructor;
obj_map<func_decl, ptr_vector<func_decl> *> m_constructor2accessors;
obj_map<func_decl, func_decl *> m_constructor2recognizer;
obj_map<func_decl, func_decl *> m_recognizer2constructor;
obj_map<func_decl, func_decl *> m_accessor2constructor;
obj_map<sort, bool> m_is_recursive;
obj_map<sort, bool> m_is_enum;
ast_ref_vector m_asts;
ptr_vector<ptr_vector<func_decl> > m_vectors;
unsigned m_start;
func_decl * get_non_rec_constructor_core(sort * ty, ptr_vector<sort> & forbidden_set);
func_decl * get_constructor(sort * ty, unsigned c_id);
public:
datatype_util(ast_manager & m);
~datatype_util();
ast_manager & get_manager() const { return m_manager; }
bool is_datatype(sort * s) const { return is_sort_of(s, m_family_id, DATATYPE_SORT); }
bool is_enum_sort(sort* s);
bool is_recursive(sort * ty);
bool is_constructor(func_decl * f) const { return is_decl_of(f, m_family_id, OP_DT_CONSTRUCTOR); }
bool is_recognizer(func_decl * f) const { return is_decl_of(f, m_family_id, OP_DT_RECOGNISER); }
bool is_accessor(func_decl * f) const { return is_decl_of(f, m_family_id, OP_DT_ACCESSOR); }
bool is_update_field(func_decl * f) const { return is_decl_of(f, m_family_id, OP_DT_UPDATE_FIELD); }
bool is_constructor(app * f) const { return is_app_of(f, m_family_id, OP_DT_CONSTRUCTOR); }
bool is_recognizer(app * f) const { return is_app_of(f, m_family_id, OP_DT_RECOGNISER); }
bool is_accessor(app * f) const { return is_app_of(f, m_family_id, OP_DT_ACCESSOR); }
bool is_update_field(app * f) const { return is_app_of(f, m_family_id, OP_DT_UPDATE_FIELD); }
ptr_vector<func_decl> const * get_datatype_constructors(sort * ty);
unsigned get_datatype_num_constructors(sort * ty) {
SASSERT(is_datatype(ty));
unsigned tid = ty->get_parameter(1).get_int();
unsigned o = datatype_decl_plugin::constructor_offset(ty, tid);
return ty->get_parameter(o).get_int();
}
unsigned get_datatype_num_parameter_sorts(sort * ty) {
SASSERT(is_datatype(ty));
return ty->get_parameter(2).get_int();
}
sort* get_datatype_parameter_sort(sort * ty, unsigned idx) {
SASSERT(is_datatype(ty));
SASSERT(idx < get_datatype_num_parameter_sorts(ty));
return to_sort(ty->get_parameter(3 + idx).get_ast());
}
unsigned get_constructor_idx(func_decl * f) const { SASSERT(is_constructor(f)); return f->get_parameter(1).get_int(); }
unsigned get_recognizer_constructor_idx(func_decl * f) const { SASSERT(is_recognizer(f)); return f->get_parameter(1).get_int(); }
func_decl * get_non_rec_constructor(sort * ty);
func_decl * get_constructor_recognizer(func_decl * constructor);
ptr_vector<func_decl> const * get_constructor_accessors(func_decl * constructor);
func_decl * get_accessor_constructor(func_decl * accessor);
func_decl * get_recognizer_constructor(func_decl * recognizer);
family_id get_family_id() const { return m_family_id; }
bool are_siblings(sort * s1, sort * s2);
bool is_func_decl(datatype_op_kind k, unsigned num_params, parameter const* params, func_decl* f);
bool is_constructor_of(unsigned num_params, parameter const* params, func_decl* f);
void reset();
void display_datatype(sort *s, std::ostream& strm);
};
#endif /* DATATYPE_DECL_PLUGIN_H_ */

View file

@ -17,7 +17,7 @@ Author:
Revision History:
--*/
#include"decl_collector.h"
#include "ast/decl_collector.h"
void decl_collector::visit_sort(sort * n) {
family_id fid = n->get_family_id();

View file

@ -20,8 +20,8 @@ Revision History:
#ifndef SMT_DECL_COLLECTOR_H_
#define SMT_DECL_COLLECTOR_H_
#include"ast.h"
#include"datatype_decl_plugin.h"
#include "ast/ast.h"
#include "ast/datatype_decl_plugin.h"
class decl_collector {
ast_manager & m_manager;

View file

@ -18,12 +18,12 @@ Revision History:
--*/
#include<sstream>
#include "ast_pp.h"
#include "array_decl_plugin.h"
#include "datatype_decl_plugin.h"
#include "dl_decl_plugin.h"
#include "warning.h"
#include "reg_decl_plugins.h"
#include "ast/ast_pp.h"
#include "ast/array_decl_plugin.h"
#include "ast/datatype_decl_plugin.h"
#include "ast/dl_decl_plugin.h"
#include "util/warning.h"
#include "ast/reg_decl_plugins.h"
namespace datalog {

View file

@ -19,9 +19,9 @@ Revision History:
#ifndef DL_DECL_PLUGIN_H_
#define DL_DECL_PLUGIN_H_
#include"ast.h"
#include "arith_decl_plugin.h"
#include "bv_decl_plugin.h"
#include "ast/ast.h"
#include "ast/arith_decl_plugin.h"
#include "ast/bv_decl_plugin.h"
namespace datalog {

View file

@ -17,13 +17,13 @@ Author:
Notes:
--*/
#include"expr2polynomial.h"
#include"expr2var.h"
#include"arith_decl_plugin.h"
#include"ast_smt2_pp.h"
#include"z3_exception.h"
#include"cooperate.h"
#include"common_msgs.h"
#include "ast/expr2polynomial.h"
#include "ast/expr2var.h"
#include "ast/arith_decl_plugin.h"
#include "ast/ast_smt2_pp.h"
#include "util/z3_exception.h"
#include "util/cooperate.h"
#include "util/common_msgs.h"
struct expr2polynomial::imp {
struct frame {

View file

@ -20,8 +20,8 @@ Notes:
#ifndef EXPR2POLYNOMIAL_H_
#define EXPR2POLYNOMIAL_H_
#include"ast.h"
#include"polynomial.h"
#include "ast/ast.h"
#include "math/polynomial/polynomial.h"
class expr2var;

View file

@ -20,9 +20,9 @@ Author:
Notes:
--*/
#include"expr2var.h"
#include"ast_smt2_pp.h"
#include"ref_util.h"
#include "ast/expr2var.h"
#include "ast/ast_smt2_pp.h"
#include "util/ref_util.h"
void expr2var::insert(expr * n, var v) {
if (!is_uninterp_const(n)) {

View file

@ -23,8 +23,8 @@ Notes:
#ifndef EXPR2VAR_H_
#define EXPR2VAR_H_
#include"ast.h"
#include"obj_hashtable.h"
#include "ast/ast.h"
#include "util/obj_hashtable.h"
/**
\brief The mapping between Z3 expressions and (low level) variables.

View file

@ -17,8 +17,8 @@ Notes:
--*/
#include "expr_abstract.h"
#include "map.h"
#include "ast/expr_abstract.h"
#include "util/map.h"
void expr_abstractor::operator()(unsigned base, unsigned num_bound, expr* const* bound, expr* n, expr_ref& result) {

View file

@ -19,7 +19,7 @@ Notes:
#ifndef EXPR_ABSTRACT_H_
#define EXPR_ABSTRACT_H_
#include"ast.h"
#include "ast/ast.h"
class expr_abstractor {
ast_manager& m;

View file

@ -19,7 +19,7 @@ Revision History:
--*/
#include "expr_functors.h"
#include "ast/expr_functors.h"
// ----------
// check_pred

View file

@ -22,8 +22,8 @@ Revision History:
#ifndef EXPR_FUNCTORS_H_
#define EXPR_FUNCTORS_H_
#include "ast.h"
#include "expr_map.h"
#include "ast/ast.h"
#include "ast/expr_map.h"
class i_expr_pred {
public:

View file

@ -18,8 +18,8 @@ Author:
Notes:
--*/
#include"expr_map.h"
#include"dec_ref_util.h"
#include "ast/expr_map.h"
#include "util/dec_ref_util.h"
expr_map::expr_map(ast_manager & m):
m_manager(m),

View file

@ -21,8 +21,8 @@ Notes:
#ifndef EXPR_MAP_H_
#define EXPR_MAP_H_
#include"ast.h"
#include"obj_hashtable.h"
#include "ast/ast.h"
#include "util/obj_hashtable.h"
/**
\brief Map from expressions to expressions+proofs.

View file

@ -19,8 +19,8 @@ Author:
Revision History:
--*/
#include"for_each_expr.h"
#include"expr_stat.h"
#include "ast/for_each_expr.h"
#include "ast/expr_stat.h"
void get_expr_stat(expr * n, expr_stat & r) {
typedef std::pair<expr *, unsigned> pair;

View file

@ -16,8 +16,8 @@ Author:
Notes:
--*/
#include"expr_substitution.h"
#include"ref_util.h"
#include "ast/expr_substitution.h"
#include "util/ref_util.h"
typedef obj_map<expr, proof*> expr2proof;
typedef obj_map<expr, expr_dependency*> expr2expr_dependency;

View file

@ -19,7 +19,7 @@ Notes:
#ifndef EXPR_SUBSTITUTION_H_
#define EXPR_SUBSTITUTION_H_
#include"ast.h"
#include "ast/ast.h"
class expr_substitution {
ast_manager & m_manager;
@ -52,4 +52,38 @@ public:
void cleanup();
};
class scoped_expr_substitution {
expr_substitution& m_subst;
expr_ref_vector m_trail;
unsigned_vector m_trail_lim;
public:
scoped_expr_substitution(expr_substitution& s): m_subst(s), m_trail(s.m()) {}
~scoped_expr_substitution() {}
void insert(expr * s, expr * def, proof * def_pr = 0, expr_dependency * def_dep = 0) {
if (!m_subst.contains(s)) {
m_subst.insert(s, def, def_pr, def_dep);
m_trail.push_back(s);
}
}
void reset() { m_subst.reset(); m_trail.reset(); m_trail_lim.reset(); }
void push() { m_trail_lim.push_back(m_trail.size()); }
void pop(unsigned n) {
if (n > 0) {
unsigned new_sz = m_trail_lim.size() - n;
unsigned old_sz = m_trail_lim[new_sz];
for (unsigned i = old_sz; i < m_trail.size(); ++i) m_subst.erase(m_trail[i].get());
m_trail.resize(old_sz);
m_trail_lim.resize(new_sz);
}
}
bool empty() const { return m_subst.empty(); }
expr* find(expr * e) { proof* pr; expr* d = 0; if (find(e, d, pr)) return d; else return e; }
bool find(expr * s, expr * & def, proof * & def_pr) { return m_subst.find(s, def, def_pr); }
bool find(expr * s, expr * & def, proof * & def_pr, expr_dependency * & def_dep) { return m_subst.find(s, def, def_pr, def_dep); }
bool contains(expr * s) { return m_subst.contains(s); }
void cleanup() { m_subst.cleanup(); }
};
#endif

109
src/ast/factor_equivs.cpp Normal file
View file

@ -0,0 +1,109 @@
/*++
Copyright (c) 2017 Arie Gurfinkel
Module Name:
factor_equivs.cpp
Abstract:
Factor equivalence classes out of an expression.
"Equivalence class structure" for objs. Uses a union_find structure internally.
Operations are :
-Declare a new equivalence class with a single element
-Merge two equivalence classes
-Retrieve whether two elements are in the same equivalence class
-Iterate on all the elements of the equivalence class of a given element
-Iterate on all equivalence classes (and then within them)
Author:
Julien Braine
Arie Gurfinkel
Revision History:
*/
#include "ast/factor_equivs.h"
#include "ast/arith_decl_plugin.h"
/**
Factors input vector v into equivalence classes and the rest
*/
void factor_eqs(expr_ref_vector &v, expr_equiv_class &equiv) {
ast_manager &m = v.get_manager();
arith_util arith(m);
expr *e1 = 0, *e2 = 0;
flatten_and(v);
unsigned j = 0;
for (unsigned i = 0; i < v.size(); ++i) {
if (m.is_eq(v.get(i), e1, e2)) {
if (arith.is_zero(e1)) {
std::swap(e1, e2);
}
// y + -1*x == 0
expr* a0 = 0, *a1 = 0, *x = 0;
if (arith.is_zero(e2) && arith.is_add(e1, a0, a1)) {
if (arith.is_times_minus_one(a1, x)) {
e1 = a0;
e2 = x;
}
else if (arith.is_times_minus_one(a0, x)) {
e1 = a1;
e2 = x;
}
}
equiv.merge(e1, e2);
}
else {
if (j < i) {
v[j] = v.get(i);
}
j++;
}
}
v.shrink(j);
}
/**
* converts equivalence classes to equalities
*/
void equiv_to_expr(expr_equiv_class &equiv, expr_ref_vector &out) {
ast_manager &m = out.get_manager();
for (auto eq_class : equiv) {
expr *rep = nullptr;
for (expr *elem : eq_class) {
if (!m.is_value(elem)) {
rep = elem;
break;
}
}
SASSERT(rep);
for (expr *elem : eq_class) {
if (rep != elem) {
out.push_back (m.mk_eq (rep, elem));
}
}
}
}
/**
* expands equivalence classes to all derivable equalities
*/
bool equiv_to_expr_full(expr_equiv_class &equiv, expr_ref_vector &out) {
ast_manager &m = out.get_manager();
bool dirty = false;
for (auto eq_class : equiv) {
for (auto a = eq_class.begin(), end = eq_class.end(); a != end; ++a) {
expr_equiv_class::iterator b(a);
for (++b; b != end; ++b) {
out.push_back(m.mk_eq(*a, *b));
dirty = true;
}
}
}
return dirty;
}

183
src/ast/factor_equivs.h Normal file
View file

@ -0,0 +1,183 @@
/*++
Copyright (c) 2017 Arie Gurfinkel
Module Name:
factor_equivs.h
Abstract:
Factor equivalence classes out of an expression.
"Equivalence class structure" for objs. Uses a union_find structure internally.
Operations are :
-Declare a new equivalence class with a single element
-Merge two equivalence classes
-Retrieve whether two elements are in the same equivalence class
-Iterate on all the elements of the equivalence class of a given element
-Iterate on all equivalence classes (and then within them)
Author:
Julien Braine
Arie Gurfinkel
Revision History:
*/
#ifndef FACTOR_EQUIVS_H_
#define FACTOR_EQUIVS_H_
#include "util/union_find.h"
#include "ast/ast_util.h"
///All functions naturally add their parameters to the union_find class
template<typename OBJ, typename Manager>
class obj_equiv_class {
basic_union_find m_uf;
obj_map<OBJ, unsigned> m_to_int;
ref_vector<OBJ, Manager> m_to_obj;
unsigned add_elem_impl(OBJ*o) {
unsigned id = m_to_obj.size();
m_to_int.insert(o, id);
m_to_obj.push_back(o);
return id;
}
unsigned add_if_not_there(OBJ*o) {
unsigned id;
if(!m_to_int.find(o, id)) {
id = add_elem_impl(o);
}
return id;
}
public:
class iterator;
class equiv_iterator;
friend class iterator;
friend class equiv_iterator;
obj_equiv_class(Manager& m) : m_to_obj(m) {}
void add_elem(OBJ*o) {
SASSERT(!m_to_int.find(o));
add_elem_impl(o);
}
//Invalidates all iterators
void merge(OBJ* a, OBJ* b) {
unsigned v1 = add_if_not_there(a);
unsigned v2 = add_if_not_there(b);
unsigned tmp1 = m_uf.find(v1);
unsigned tmp2 = m_uf.find(v2);
m_uf.merge(tmp1, tmp2);
}
void reset() {
m_uf.reset();
m_to_int.reset();
m_to_obj.reset();
}
bool are_equiv(OBJ*a, OBJ*b) {
unsigned id1 = add_if_not_there(a);
unsigned id2 = add_if_not_there(b);
return m_uf.find(id1) == m_uf.find(id2);
}
class iterator {
friend class obj_equiv_class;
private :
const obj_equiv_class& m_ouf;
unsigned m_curr_id;
bool m_first;
iterator(const obj_equiv_class& uf, unsigned id, bool f) :
m_ouf(uf), m_curr_id(id), m_first(f) {}
public :
OBJ*operator*() {return m_ouf.m_to_obj[m_curr_id];}
iterator& operator++() {
m_curr_id = m_ouf.m_uf.next(m_curr_id);
m_first = false;
return *this;
}
bool operator==(const iterator& o) {
SASSERT(&m_ouf == &o.m_ouf);
return m_first == o.m_first && m_curr_id == o.m_curr_id;
}
bool operator!=(const iterator& o) {return !(*this == o);}
};
iterator begin(OBJ*o) {
unsigned id = add_if_not_there(o);
return iterator(*this, id, true);
}
iterator end(OBJ*o) {
unsigned id = add_if_not_there(o);
return iterator(*this, id, false);
}
class eq_class {
private :
iterator m_begin;
iterator m_end;
public :
eq_class(const iterator& a, const iterator& b) : m_begin(a), m_end(b) {}
iterator begin() {return m_begin;}
iterator end() {return m_end;}
};
class equiv_iterator {
friend class obj_equiv_class;
private :
const obj_equiv_class& m_ouf;
unsigned m_rootnb;
equiv_iterator(const obj_equiv_class& uf, unsigned nb) :
m_ouf(uf), m_rootnb(nb) {
while(m_rootnb != m_ouf.m_to_obj.size() &&
m_ouf.m_uf.is_root(m_rootnb) != true)
{ m_rootnb++; }
}
public :
eq_class operator*() {
return eq_class(iterator(m_ouf, m_rootnb, true),
iterator(m_ouf, m_rootnb, false));
}
equiv_iterator& operator++() {
do {
m_rootnb++;
} while(m_rootnb != m_ouf.m_to_obj.size() &&
m_ouf.m_uf.is_root(m_rootnb) != true);
return *this;
}
bool operator==(const equiv_iterator& o) {
SASSERT(&m_ouf == &o.m_ouf);
return m_rootnb == o.m_rootnb;
}
bool operator!=(const equiv_iterator& o) {return !(*this == o);}
};
equiv_iterator begin() {return equiv_iterator(*this, 0);}
equiv_iterator end() {return equiv_iterator(*this, m_to_obj.size());}
};
typedef obj_equiv_class<expr, ast_manager> expr_equiv_class;
/**
* Factors input vector v into equivalence classes and the rest
*/
void factor_eqs(expr_ref_vector &v, expr_equiv_class &equiv);
/**
* converts equivalence classes to equalities
*/
void equiv_to_expr(expr_equiv_class &equiv, expr_ref_vector &out);
/**
* expands equivalence classes to all derivable equalities
*/
bool equiv_to_expr_full(expr_equiv_class &equiv, expr_ref_vector &out);
#endif

View file

@ -17,7 +17,7 @@ Revision History:
--*/
#include"for_each_ast.h"
#include "ast/for_each_ast.h"
struct ast_counter_proc {
unsigned m_num;

View file

@ -19,9 +19,9 @@ Revision History:
#ifndef FOR_EACH_AST_H_
#define FOR_EACH_AST_H_
#include"ast.h"
#include"trace.h"
#include"map.h"
#include "ast/ast.h"
#include "util/trace.h"
#include "util/map.h"
template<typename T>
bool for_each_ast_args(ptr_vector<ast> & stack, ast_mark & visited, unsigned num_args, T * const * args) {

View file

@ -17,7 +17,7 @@ Revision History:
--*/
#include"for_each_expr.h"
#include "ast/for_each_expr.h"
struct expr_counter_proc {
unsigned m_num;

View file

@ -19,8 +19,8 @@ Revision History:
#ifndef FOR_EACH_EXPR_H_
#define FOR_EACH_EXPR_H_
#include"ast.h"
#include"trace.h"
#include "ast/ast.h"
#include "util/trace.h"
template<typename ForEachProc, typename ExprMark, bool MarkAll, bool IgnorePatterns>
void for_each_expr_core(ForEachProc & proc, ExprMark & visited, expr * n) {

View file

@ -16,8 +16,8 @@ Author:
Revision History:
--*/
#include"format.h"
#include"recurse_expr_def.h"
#include "ast/format.h"
#include "ast/recurse_expr_def.h"
namespace format_ns {

View file

@ -19,7 +19,7 @@ Revision History:
#ifndef FORMAT_H_
#define FORMAT_H_
#include"ast.h"
#include "ast/ast.h"
namespace format_ns {
typedef app format;

View file

@ -5,7 +5,7 @@ z3_add_component(fpa
fpa2bv_rewriter.cpp
COMPONENT_DEPENDENCIES
ast
simplifier
rewriter
model
util
PYG_FILES

View file

@ -18,12 +18,12 @@ Notes:
--*/
#include<math.h>
#include"ast_smt2_pp.h"
#include"well_sorted.h"
#include"th_rewriter.h"
#include"fpa_rewriter.h"
#include "ast/ast_smt2_pp.h"
#include "ast/well_sorted.h"
#include "ast/rewriter/th_rewriter.h"
#include "ast/rewriter/fpa_rewriter.h"
#include"bv2fpa_converter.h"
#include "ast/fpa/bv2fpa_converter.h"
bv2fpa_converter::bv2fpa_converter(ast_manager & m) :

View file

@ -19,11 +19,11 @@ Notes:
#ifndef BV2FPA_CONVERTER_H_
#define BV2FPA_CONVERTER_H_
#include"fpa_decl_plugin.h"
#include"bv_decl_plugin.h"
#include"th_rewriter.h"
#include"model_core.h"
#include"fpa2bv_converter.h"
#include "ast/fpa_decl_plugin.h"
#include "ast/bv_decl_plugin.h"
#include "ast/rewriter/th_rewriter.h"
#include "model/model_core.h"
#include "ast/fpa/fpa2bv_converter.h"
class bv2fpa_converter {

View file

@ -18,12 +18,12 @@ Notes:
--*/
#include<math.h>
#include"ast_smt2_pp.h"
#include"well_sorted.h"
#include"th_rewriter.h"
#include "ast/ast_smt2_pp.h"
#include "ast/well_sorted.h"
#include "ast/rewriter/th_rewriter.h"
#include"fpa2bv_converter.h"
#include"fpa_rewriter.h"
#include "ast/fpa/fpa2bv_converter.h"
#include "ast/rewriter/fpa_rewriter.h"
#define BVULT(X,Y,R) { expr_ref bvult_eq(m), bvult_not(m); m_simp.mk_eq(X, Y, bvult_eq); m_simp.mk_not(bvult_eq, bvult_not); expr_ref t(m); t = m_bv_util.mk_ule(X,Y); m_simp.mk_and(t, bvult_not, R); }
@ -1476,6 +1476,10 @@ void fpa2bv_converter::mk_fma(func_decl * f, unsigned num, expr * const * args,
mk_ite(c71, zero_cond, z, v7);
// else comes the fused multiplication.
expr_ref one_1(m), zero_1(m);
one_1 = m_bv_util.mk_numeral(1, 1);
zero_1 = m_bv_util.mk_numeral(0, 1);
unsigned ebits = m_util.get_ebits(f->get_range());
unsigned sbits = m_util.get_sbits(f->get_range());
@ -1516,7 +1520,8 @@ void fpa2bv_converter::mk_fma(func_decl * f, unsigned num, expr * const * args,
mul_sgn = m_bv_util.mk_bv_xor(2, signs);
dbg_decouple("fpa2bv_fma_mul_sgn", mul_sgn);
mul_exp = m_bv_util.mk_bv_add(m_bv_util.mk_bv_sub(a_exp_ext, a_lz_ext),
mul_exp = m_bv_util.mk_bv_add(
m_bv_util.mk_bv_sub(a_exp_ext, a_lz_ext),
m_bv_util.mk_bv_sub(b_exp_ext, b_lz_ext));
dbg_decouple("fpa2bv_fma_mul_exp", mul_exp);
@ -1529,11 +1534,15 @@ void fpa2bv_converter::mk_fma(func_decl * f, unsigned num, expr * const * args,
// The product has the form [-1][0].[2*sbits - 2].
// Extend c
c_sig = m_bv_util.mk_zero_extend(1, m_bv_util.mk_concat(c_sig, m_bv_util.mk_numeral(0, sbits-1)));
expr_ref c_sig_ext(m);
c_sig_ext = m_bv_util.mk_zero_extend(1, m_bv_util.mk_concat(c_sig, m_bv_util.mk_numeral(0, sbits+2)));
c_exp_ext = m_bv_util.mk_bv_sub(c_exp_ext, c_lz_ext);
mul_sig = m_bv_util.mk_concat(mul_sig, m_bv_util.mk_numeral(0, 3));
SASSERT(m_bv_util.get_bv_size(mul_sig) == 2 * sbits);
SASSERT(m_bv_util.get_bv_size(c_sig) == 2 * sbits);
SASSERT(m_bv_util.get_bv_size(mul_sig) == 2*sbits+3);
SASSERT(m_bv_util.get_bv_size(c_sig_ext) == 2*sbits+3);
dbg_decouple("fpa2bv_fma_c_sig_ext", c_sig_ext);
dbg_decouple("fpa2bv_fma_c_exp_ext", c_exp_ext);
expr_ref swap_cond(m);
swap_cond = m_bv_util.mk_sle(mul_exp, c_exp_ext);
@ -1542,10 +1551,10 @@ void fpa2bv_converter::mk_fma(func_decl * f, unsigned num, expr * const * args,
expr_ref e_sgn(m), e_sig(m), e_exp(m), f_sgn(m), f_sig(m), f_exp(m);
m_simp.mk_ite(swap_cond, c_sgn, mul_sgn, e_sgn);
m_simp.mk_ite(swap_cond, c_sig, mul_sig, e_sig); // has 2 * sbits
m_simp.mk_ite(swap_cond, c_sig_ext, mul_sig, e_sig); // has 2 * sbits + 3
m_simp.mk_ite(swap_cond, c_exp_ext, mul_exp, e_exp); // has ebits + 2
m_simp.mk_ite(swap_cond, mul_sgn, c_sgn, f_sgn);
m_simp.mk_ite(swap_cond, mul_sig, c_sig, f_sig); // has 2 * sbits
m_simp.mk_ite(swap_cond, mul_sig, c_sig_ext, f_sig); // has 2 * sbits + 3
m_simp.mk_ite(swap_cond, mul_exp, c_exp_ext, f_exp); // has ebits + 2
SASSERT(is_well_sorted(m, e_sgn));
@ -1555,11 +1564,16 @@ void fpa2bv_converter::mk_fma(func_decl * f, unsigned num, expr * const * args,
SASSERT(is_well_sorted(m, f_sig));
SASSERT(is_well_sorted(m, f_exp));
SASSERT(m_bv_util.get_bv_size(e_sig) == 2 * sbits);
SASSERT(m_bv_util.get_bv_size(f_sig) == 2 * sbits);
SASSERT(m_bv_util.get_bv_size(e_sig) == 2*sbits+3);
SASSERT(m_bv_util.get_bv_size(f_sig) == 2*sbits+3);
SASSERT(m_bv_util.get_bv_size(e_exp) == ebits + 2);
SASSERT(m_bv_util.get_bv_size(f_exp) == ebits + 2);
dbg_decouple("fpa2bv_fma_e_sig", e_sig);
dbg_decouple("fpa2bv_fma_e_exp", e_exp);
dbg_decouple("fpa2bv_fma_f_sig", f_sig);
dbg_decouple("fpa2bv_fma_f_exp", f_exp);
expr_ref res_sgn(m), res_sig(m), res_exp(m);
expr_ref exp_delta(m);
@ -1568,7 +1582,7 @@ void fpa2bv_converter::mk_fma(func_decl * f, unsigned num, expr * const * args,
// cap the delta
expr_ref cap(m), cap_le_delta(m);
cap = m_bv_util.mk_numeral(2*sbits, ebits+2);
cap = m_bv_util.mk_numeral(2*sbits+3, ebits+2);
cap_le_delta = m_bv_util.mk_ule(cap, exp_delta);
m_simp.mk_ite(cap_le_delta, cap, exp_delta, exp_delta);
SASSERT(m_bv_util.get_bv_size(exp_delta) == ebits+2);
@ -1576,61 +1590,63 @@ void fpa2bv_converter::mk_fma(func_decl * f, unsigned num, expr * const * args,
dbg_decouple("fpa2bv_fma_add_exp_delta_capped", exp_delta);
// Alignment shift with sticky bit computation.
expr_ref shifted_big(m), shifted_f_sig(m), sticky_raw(m);
expr_ref shifted_big(m), shifted_f_sig(m);
expr_ref alignment_sticky_raw(m), alignment_sticky(m);
shifted_big = m_bv_util.mk_bv_lshr(
m_bv_util.mk_concat(f_sig, m_bv_util.mk_numeral(0, sbits)),
m_bv_util.mk_zero_extend((3*sbits)-(ebits+2), exp_delta));
shifted_f_sig = m_bv_util.mk_extract(3*sbits-1, sbits, shifted_big);
sticky_raw = m_bv_util.mk_extract(sbits-1, 0, shifted_big);
SASSERT(m_bv_util.get_bv_size(shifted_f_sig) == 2 * sbits);
SASSERT(is_well_sorted(m, shifted_f_sig));
expr_ref sticky(m);
sticky = m_bv_util.mk_zero_extend(2*sbits-1, m.mk_app(m_bv_util.get_fid(), OP_BREDOR, sticky_raw.get()));
SASSERT(is_well_sorted(m, sticky));
dbg_decouple("fpa2bv_fma_f_sig_sticky_raw", sticky_raw);
dbg_decouple("fpa2bv_fma_f_sig_sticky", sticky);
expr * or_args[2] = { shifted_f_sig, sticky };
shifted_f_sig = m_bv_util.mk_bv_or(2, or_args);
m_bv_util.mk_zero_extend((3*sbits+3)-(ebits+2), exp_delta));
shifted_f_sig = m_bv_util.mk_extract(3*sbits+2, sbits, shifted_big);
alignment_sticky_raw = m_bv_util.mk_extract(sbits-1, 0, shifted_big);
alignment_sticky = m.mk_app(m_bv_util.get_fid(), OP_BREDOR, alignment_sticky_raw.get());
dbg_decouple("fpa2bv_fma_shifted_f_sig", shifted_f_sig);
dbg_decouple("fpa2bv_fma_f_sig_alignment_sticky", alignment_sticky);
SASSERT(is_well_sorted(m, alignment_sticky));
SASSERT(m_bv_util.get_bv_size(shifted_f_sig) == 2*sbits+3);
SASSERT(is_well_sorted(m, shifted_f_sig));
// Significant addition.
// Two extra bits for catching the overflow.
// Two extra bits for the sign and for catching overflows.
e_sig = m_bv_util.mk_zero_extend(2, e_sig);
shifted_f_sig = m_bv_util.mk_zero_extend(2, shifted_f_sig);
expr_ref eq_sgn(m);
m_simp.mk_eq(e_sgn, f_sgn, eq_sgn);
dbg_decouple("fpa2bv_fma_eq_sgn", eq_sgn);
SASSERT(m_bv_util.get_bv_size(e_sig) == 2*sbits + 2);
SASSERT(m_bv_util.get_bv_size(shifted_f_sig) == 2*sbits + 2);
SASSERT(m_bv_util.get_bv_size(e_sig) == 2*sbits+5);
SASSERT(m_bv_util.get_bv_size(shifted_f_sig) == 2*sbits+5);
dbg_decouple("fpa2bv_fma_add_e_sig", e_sig);
dbg_decouple("fpa2bv_fma_add_shifted_f_sig", shifted_f_sig);
expr_ref sum(m), e_plus_f(m), e_minus_f(m);
expr_ref sum(m), e_plus_f(m), e_minus_f(m), sticky_wide(m);
sticky_wide = m_bv_util.mk_zero_extend(2*sbits+4, alignment_sticky);
e_plus_f = m_bv_util.mk_bv_add(e_sig, shifted_f_sig);
e_minus_f = m_bv_util.mk_bv_sub(e_sig, shifted_f_sig),
m_simp.mk_ite(eq_sgn, e_plus_f, e_minus_f, sum);
e_plus_f = m.mk_ite(m.mk_eq(m_bv_util.mk_extract(0, 0, e_plus_f), zero_1),
m_bv_util.mk_bv_add(e_plus_f, sticky_wide),
e_plus_f);
e_minus_f = m_bv_util.mk_bv_sub(e_sig, shifted_f_sig);
e_minus_f = m.mk_ite(m.mk_eq(m_bv_util.mk_extract(0, 0, e_minus_f), zero_1),
m_bv_util.mk_bv_sub(e_minus_f, sticky_wide),
e_minus_f);
SASSERT(is_well_sorted(m, shifted_f_sig));
dbg_decouple("fpa2bv_fma_f_sig_or_sticky", shifted_f_sig);
m_simp.mk_ite(eq_sgn, e_plus_f, e_minus_f, sum);
SASSERT(m_bv_util.get_bv_size(sum) == 2*sbits+5);
SASSERT(is_well_sorted(m, sum));
dbg_decouple("fpa2bv_fma_add_sum", sum);
expr_ref sign_bv(m), n_sum(m);
sign_bv = m_bv_util.mk_extract(2*sbits+1, 2*sbits+1, sum);
sign_bv = m_bv_util.mk_extract(2*sbits+4, 2*sbits+4, sum);
n_sum = m_bv_util.mk_bv_neg(sum);
expr_ref res_sig_eq(m), sig_abs(m), one_1(m);
one_1 = m_bv_util.mk_numeral(1, 1);
m_simp.mk_eq(sign_bv, one_1, res_sig_eq);
m_simp.mk_ite(res_sig_eq, n_sum, sum, sig_abs);
dbg_decouple("fpa2bv_fma_add_sign_bv", sign_bv);
dbg_decouple("fpa2bv_fma_add_n_sum", n_sum);
dbg_decouple("fpa2bv_fma_add_sig_abs", sig_abs);
res_exp = e_exp;
expr_ref res_sig_eq(m), sig_abs(m);
m_simp.mk_eq(sign_bv, one_1, res_sig_eq);
m_simp.mk_ite(res_sig_eq, n_sum, sum, sig_abs);
dbg_decouple("fpa2bv_fma_add_sig_abs", sig_abs);
family_id bvfid = m_bv_util.get_fid();
expr_ref res_sgn_c1(m), res_sgn_c2(m), res_sgn_c3(m);
@ -1643,44 +1659,76 @@ void fpa2bv_converter::mk_fma(func_decl * f, unsigned num, expr * const * args,
res_sgn_c3 = m.mk_app(bvfid, OP_BAND, e_sgn, f_sgn);
expr * res_sgn_or_args[3] = { res_sgn_c1, res_sgn_c2, res_sgn_c3 };
res_sgn = m_bv_util.mk_bv_or(3, res_sgn_or_args);
dbg_decouple("fpa2bv_fma_res_sgn", res_sgn);
expr_ref is_sig_neg(m);
is_sig_neg = m.mk_eq(one_1, m_bv_util.mk_extract(2*sbits+4, 2*sbits+4, sig_abs));
sig_abs = m.mk_ite(is_sig_neg, m_bv_util.mk_bv_neg(sig_abs), sig_abs);
dbg_decouple("fpa2bv_fma_is_sig_neg", is_sig_neg);
// Result could have overflown into 4.xxx.
SASSERT(m_bv_util.get_bv_size(sig_abs) == 2 * sbits + 2);
expr_ref ovfl_into_4(m);
ovfl_into_4 = m.mk_eq(m_bv_util.mk_extract(2 * sbits + 1, 2 * sbits, sig_abs),
m_bv_util.mk_numeral(1, 2));
dbg_decouple("fpa2bv_fma_ovfl_into_4", ovfl_into_4);
if (sbits > 5) {
expr_ref sticky_raw(m), sig_upper(m), sticky_redd(m), res_sig_norm(m);
sticky_raw = m_bv_util.mk_extract(sbits - 4, 0, sig_abs);
sig_upper = m_bv_util.mk_extract(2 * sbits, sbits - 3, sig_abs);
SASSERT(m_bv_util.get_bv_size(sig_upper) == sbits + 4);
sticky_redd = m.mk_app(bvfid, OP_BREDOR, sticky_raw.get());
sticky = m_bv_util.mk_zero_extend(sbits + 3, sticky_redd);
expr * res_or_args[2] = { sig_upper, sticky };
res_sig_norm = m_bv_util.mk_bv_or(2, res_or_args);
SASSERT(m_bv_util.get_bv_size(sig_abs) == 2*sbits+5);
expr_ref extra(m), extra_is_zero(m);
extra = m_bv_util.mk_extract(2*sbits+4, 2*sbits+3, sig_abs);
extra_is_zero = m.mk_eq(extra, m_bv_util.mk_numeral(0, 2));
dbg_decouple("fpa2bv_fma_extra", extra);
expr_ref sticky_raw_ovfl(m), sig_upper_ovfl(m), sticky_redd_ovfl(m), sticky_ovfl(m), res_sig_ovfl(m);
sticky_raw_ovfl = m_bv_util.mk_extract(sbits - 4, 0, sig_abs);
sig_upper_ovfl = m_bv_util.mk_extract(2 * sbits, sbits - 3, sig_abs);
SASSERT(m_bv_util.get_bv_size(sig_upper_ovfl) == sbits + 4);
sticky_redd_ovfl = m.mk_app(bvfid, OP_BREDOR, sticky_raw_ovfl.get());
sticky_ovfl = m_bv_util.mk_zero_extend(sbits + 3, sticky_redd_ovfl);
expr * res_or_args_ovfl[2] = { sig_upper_ovfl, sticky_ovfl };
res_sig_ovfl = m_bv_util.mk_bv_or(2, res_or_args_ovfl);
res_exp = m.mk_ite(extra_is_zero, e_exp, m_bv_util.mk_bv_add(e_exp, m_bv_util.mk_numeral(1, ebits + 2)));
res_sig = m.mk_ite(ovfl_into_4, res_sig_ovfl, res_sig_norm);
res_exp = m.mk_ite(ovfl_into_4, m_bv_util.mk_bv_add(res_exp, m_bv_util.mk_numeral(1, ebits+2)),
res_exp);
}
else {
unsigned too_short = 6 - sbits;
// Renormalize
expr_ref zero_e2(m), min_exp(m), sig_lz(m), max_exp_delta(m), sig_lz_capped(m), renorm_delta(m);
zero_e2 = m_bv_util.mk_numeral(0, ebits + 2);
mk_min_exp(ebits, min_exp);
min_exp = m_bv_util.mk_sign_extend(2, min_exp);
mk_leading_zeros(sig_abs, ebits+2, sig_lz);
sig_lz = m_bv_util.mk_bv_sub(sig_lz, m_bv_util.mk_numeral(2, ebits+2));
max_exp_delta = m_bv_util.mk_bv_sub(res_exp, min_exp);
sig_lz_capped = m.mk_ite(m_bv_util.mk_sle(sig_lz, max_exp_delta), sig_lz, max_exp_delta);
renorm_delta = m.mk_ite(m_bv_util.mk_sle(zero_e2, sig_lz_capped), sig_lz_capped, zero_e2);
res_exp = m_bv_util.mk_bv_sub(res_exp, renorm_delta);
sig_abs = m_bv_util.mk_bv_shl(sig_abs, m_bv_util.mk_zero_extend(2*sbits+3-ebits, renorm_delta));
dbg_decouple("fpa2bv_fma_min_exp", min_exp);
dbg_decouple("fpa2bv_fma_max_exp_delta", max_exp_delta);
dbg_decouple("fpa2bv_fma_sig_lz", sig_lz);
dbg_decouple("fpa2bv_fma_sig_lz_capped", sig_lz_capped);
dbg_decouple("fpa2bv_fma_renorm_delta", renorm_delta);
unsigned too_short = 0;
if (sbits < 5) {
too_short = 6 - sbits + 1;
sig_abs = m_bv_util.mk_concat(sig_abs, m_bv_util.mk_numeral(0, too_short));
res_sig = m_bv_util.mk_extract(sbits + 3, 0, sig_abs);
}
dbg_decouple("fpa2bv_fma_add_sum_sticky", sticky);
dbg_decouple("fpa2bv_fma_sig_abs", sig_abs);
expr_ref sig_abs_h1(m), sticky_h1(m), sticky_h1_red(m), sig_abs_h1_f(m), res_sig_1(m);
sticky_h1 = m_bv_util.mk_extract(sbits+too_short-2, 0, sig_abs);
sig_abs_h1 = m_bv_util.mk_extract(2*sbits+too_short+4, sbits-1+too_short, sig_abs);
sticky_h1_red = m_bv_util.mk_zero_extend(sbits+5, m.mk_app(m_bv_util.get_fid(), OP_BREDOR, sticky_h1.get()));
expr * sticky_h1_red_args[2] = { sig_abs_h1, sticky_h1_red };
sig_abs_h1_f = m_bv_util.mk_bv_or(2, sticky_h1_red_args);
res_sig_1 = m_bv_util.mk_extract(sbits+3, 0, sig_abs_h1_f);
SASSERT(m_bv_util.get_bv_size(sticky_h1) == sbits+too_short-1);
SASSERT(m_bv_util.get_bv_size(sig_abs_h1) == sbits+6);
SASSERT(m_bv_util.get_bv_size(sticky_h1_red) == sbits+6);
SASSERT(m_bv_util.get_bv_size(sig_abs_h1_f) == sbits+6);
SASSERT(m_bv_util.get_bv_size(res_sig_1) == sbits+4);
expr_ref sig_abs_h2(m), sticky_h2(m), sticky_h2_red(m), sig_abs_h2_f(m), res_sig_2(m);
sticky_h2 = m_bv_util.mk_extract(sbits+too_short-1, 0, sig_abs);
sig_abs_h2 = m_bv_util.mk_extract(2*sbits+too_short+4, sbits+too_short, sig_abs);
sticky_h2_red = m_bv_util.mk_zero_extend(sbits+4, m.mk_app(m_bv_util.get_fid(), OP_BREDOR, sticky_h1.get()));
expr * sticky_h2_red_args[2] = { sig_abs_h2, sticky_h2_red };
sig_abs_h2_f = m_bv_util.mk_zero_extend(1, m_bv_util.mk_bv_or(2, sticky_h2_red_args));
res_sig_2 = m_bv_util.mk_extract(sbits+3, 0, sig_abs_h2_f);
SASSERT(m_bv_util.get_bv_size(sticky_h2) == sbits+too_short);
SASSERT(m_bv_util.get_bv_size(sig_abs_h2) == sbits+5);
SASSERT(m_bv_util.get_bv_size(sticky_h2_red) == sbits+5);
SASSERT(m_bv_util.get_bv_size(sig_abs_h2_f) == sbits+6);
SASSERT(m_bv_util.get_bv_size(res_sig_2) == sbits+4);
res_sig = m.mk_ite(extra_is_zero, res_sig_1, res_sig_2);
dbg_decouple("fpa2bv_fma_res_sig", res_sig);
dbg_decouple("fpa2bv_fma_res_exp", res_exp);
SASSERT(m_bv_util.get_bv_size(res_sig) == sbits + 4);
expr_ref is_zero_sig(m), nil_sbits4(m);
@ -2666,13 +2714,21 @@ void fpa2bv_converter::mk_to_fp_real_int(func_decl * f, unsigned num, expr * con
SASSERT(m_util.is_bv2rm(args[0]));
expr * bv_rm = to_app(args[0])->get_arg(0);
rational e;
if (!m_arith_util.is_numeral(args[1], e))
UNREACHABLE();
SASSERT((m_arith_util.is_int(args[1]) && m_arith_util.is_real(args[2])) ||
(m_arith_util.is_real(args[1]) && m_arith_util.is_int(args[2])));
rational q;
if (!m_arith_util.is_numeral(args[2], q))
UNREACHABLE();
rational q, e;
if (m_arith_util.is_int(args[1]) && m_arith_util.is_real(args[2])) {
if (!m_arith_util.is_numeral(args[1], e) ||
!m_arith_util.is_numeral(args[2], q))
UNREACHABLE();
}
else {
if (!m_arith_util.is_numeral(args[2], e) ||
!m_arith_util.is_numeral(args[1], q))
UNREACHABLE();
}
SASSERT(e.is_int64());
SASSERT(m_mpz_manager.eq(e.to_mpq().denominator(), 1));
@ -3882,15 +3938,12 @@ void fpa2bv_converter::round(sort * s, expr_ref & rm, expr_ref & sgn, expr_ref &
SASSERT(m_bv_util.get_bv_size(sig) == sbits+4);
SASSERT(m_bv_util.get_bv_size(exp) == ebits+2);
// bool UNFen = false;
// bool OVFen = false;
expr_ref e_min(m), e_max(m);
mk_min_exp(ebits, e_min);
mk_max_exp(ebits, e_max);
TRACE("fpa2bv_dbg", tout << "e_min = " << mk_ismt2_pp(e_min, m) << std::endl <<
"e_max = " << mk_ismt2_pp(e_max, m) << std::endl;);
TRACE("fpa2bv_dbg", tout << "e_min = " << mk_ismt2_pp(e_min, m) << std::endl;
tout << "e_max = " << mk_ismt2_pp(e_max, m) << std::endl;);
expr_ref OVF1(m), e_top_three(m), sigm1(m), e_eq_emax_and_sigm1(m), e_eq_emax(m);
expr_ref e3(m), ne3(m), e2(m), e1(m), e21(m), one_1(m), h_exp(m), sh_exp(m), th_exp(m);
@ -4003,7 +4056,6 @@ void fpa2bv_converter::round(sort * s, expr_ref & rm, expr_ref & sgn, expr_ref &
SASSERT(is_well_sorted(m, sig));
SASSERT(m_bv_util.get_bv_size(sig) == sbits+2);
// CMW: The (OVF1 && OVFen) and (TINY && UNFen) cases are never taken.
expr_ref ext_emin(m);
ext_emin = m_bv_util.mk_zero_extend(2, e_min);
m_simp.mk_ite(TINY, ext_emin, beta, exp);
@ -4106,7 +4158,6 @@ void fpa2bv_converter::round(sort * s, expr_ref & rm, expr_ref & sgn, expr_ref &
dbg_decouple("fpa2bv_rnd_rm_is_to_neg", rm_is_to_neg);
dbg_decouple("fpa2bv_rnd_rm_is_to_pos", rm_is_to_pos);
expr_ref sgn_is_zero(m), zero1(m);
zero1 = m_bv_util.mk_numeral(0, 1);
m_simp.mk_eq(sgn, zero1, sgn_is_zero);

View file

@ -19,17 +19,17 @@ Notes:
#ifndef FPA2BV_CONVERTER_H_
#define FPA2BV_CONVERTER_H_
#include"ast.h"
#include"obj_hashtable.h"
#include"ref_util.h"
#include"fpa_decl_plugin.h"
#include"bv_decl_plugin.h"
#include"array_decl_plugin.h"
#include"datatype_decl_plugin.h"
#include"dl_decl_plugin.h"
#include"pb_decl_plugin.h"
#include"seq_decl_plugin.h"
#include"basic_simplifier_plugin.h"
#include "ast/ast.h"
#include "util/obj_hashtable.h"
#include "util/ref_util.h"
#include "ast/fpa_decl_plugin.h"
#include "ast/bv_decl_plugin.h"
#include "ast/array_decl_plugin.h"
#include "ast/datatype_decl_plugin.h"
#include "ast/dl_decl_plugin.h"
#include "ast/pb_decl_plugin.h"
#include "ast/seq_decl_plugin.h"
#include "ast/rewriter/bool_rewriter.h"
class fpa2bv_converter {
public:
@ -39,7 +39,7 @@ public:
protected:
ast_manager & m;
basic_simplifier_plugin m_simp;
bool_rewriter m_simp;
fpa_util m_util;
bv_util m_bv_util;
arith_util m_arith_util;

View file

@ -18,10 +18,10 @@ Notes:
--*/
#include"rewriter_def.h"
#include"fpa2bv_rewriter.h"
#include"cooperate.h"
#include"fpa2bv_rewriter_params.hpp"
#include "ast/rewriter/rewriter_def.h"
#include "ast/fpa/fpa2bv_rewriter.h"
#include "util/cooperate.h"
#include "ast/fpa/fpa2bv_rewriter_params.hpp"
fpa2bv_rewriter_cfg::fpa2bv_rewriter_cfg(ast_manager & m, fpa2bv_converter & c, params_ref const & p) :

View file

@ -20,9 +20,9 @@ Notes:
#ifndef FPA2BV_REWRITER_H_
#define FPA2BV_REWRITER_H_
#include"rewriter.h"
#include"bv_decl_plugin.h"
#include"fpa2bv_converter.h"
#include "ast/rewriter/rewriter.h"
#include "ast/bv_decl_plugin.h"
#include "ast/fpa/fpa2bv_converter.h"
struct fpa2bv_rewriter_cfg : public default_rewriter_cfg {
ast_manager & m_manager;

View file

@ -16,9 +16,9 @@ Author:
Revision History:
--*/
#include"fpa_decl_plugin.h"
#include"arith_decl_plugin.h"
#include"bv_decl_plugin.h"
#include "ast/fpa_decl_plugin.h"
#include "ast/arith_decl_plugin.h"
#include "ast/bv_decl_plugin.h"
fpa_decl_plugin::fpa_decl_plugin():
m_values(m_fm),

View file

@ -19,11 +19,11 @@ Revision History:
#ifndef fpa_decl_plugin_H_
#define fpa_decl_plugin_H_
#include"ast.h"
#include"id_gen.h"
#include"arith_decl_plugin.h"
#include"bv_decl_plugin.h"
#include"mpf.h"
#include "ast/ast.h"
#include "util/id_gen.h"
#include "ast/arith_decl_plugin.h"
#include "ast/bv_decl_plugin.h"
#include "util/mpf.h"
enum fpa_sort_kind {
FLOATING_POINT_SORT,

View file

@ -16,9 +16,9 @@ Author:
Revision History:
--*/
#include"func_decl_dependencies.h"
#include"for_each_expr.h"
#include"ast_util.h"
#include "ast/func_decl_dependencies.h"
#include "ast/for_each_expr.h"
#include "ast/ast_util.h"
struct collect_dependencies_proc {
ast_manager & m_manager;

View file

@ -19,8 +19,8 @@ Revision History:
#ifndef FUNC_DECL_DEPENDENCIES_H_
#define FUNC_DECL_DEPENDENCIES_H_
#include"ast.h"
#include"obj_hashtable.h"
#include "ast/ast.h"
#include "util/obj_hashtable.h"
// Set of dependencies
typedef obj_hashtable<func_decl> func_decl_set;

View file

@ -16,9 +16,9 @@ Author:
Revision History:
--*/
#include"ast.h"
#include"expr_delta_pair.h"
#include"hashtable.h"
#include "ast/ast.h"
#include "ast/expr_delta_pair.h"
#include "util/hashtable.h"
class contains_vars {
typedef hashtable<expr_delta_pair, obj_hash<expr_delta_pair>, default_eq<expr_delta_pair> > cache;

52
src/ast/justified_expr.h Normal file
View file

@ -0,0 +1,52 @@
#ifndef JUSTIFIED_EXPR_H_
#define JUSTIFIED_EXPR_H_
#include "ast/ast.h"
class justified_expr {
ast_manager& m;
expr* m_fml;
proof* m_proof;
public:
justified_expr(ast_manager& m, expr* fml, proof* p):
m(m),
m_fml(fml),
m_proof(p) {
SASSERT(fml);
m.inc_ref(fml);
m.inc_ref(p);
}
justified_expr& operator=(justified_expr const& other) {
SASSERT(&m == &other.m);
if (this != &other) {
m.inc_ref(other.get_fml());
m.inc_ref(other.get_proof());
m.dec_ref(m_fml);
m.dec_ref(m_proof);
m_fml = other.get_fml();
m_proof = other.get_proof();
}
return *this;
}
justified_expr(justified_expr const& other):
m(other.m),
m_fml(other.m_fml),
m_proof(other.m_proof)
{
m.inc_ref(m_fml);
m.inc_ref(m_proof);
}
~justified_expr() {
m.dec_ref(m_fml);
m.dec_ref(m_proof);
}
expr* get_fml() const { return m_fml; }
proof* get_proof() const { return m_proof; }
};
#endif

View file

@ -18,8 +18,8 @@ Author:
Notes:
--*/
#include"macro_substitution.h"
#include"ref_util.h"
#include "ast/macro_substitution.h"
#include "util/ref_util.h"
typedef obj_map<func_decl, proof*> func_decl2proof;
typedef obj_map<func_decl, expr_dependency*> func_decl2expr_dependency;

View file

@ -21,7 +21,7 @@ Notes:
#ifndef MACRO_SUBSTITUTION_H_
#define MACRO_SUBSTITUTION_H_
#include"ast.h"
#include "ast/ast.h"
class macro_substitution {
ast_manager & m_manager;

View file

@ -5,5 +5,5 @@ z3_add_component(macros
macro_util.cpp
quasi_macros.cpp
COMPONENT_DEPENDENCIES
simplifier
rewriter
)

View file

@ -17,100 +17,167 @@ Revision History:
--*/
#include"macro_finder.h"
#include"occurs.h"
#include"ast_pp.h"
#include"ast_ll_pp.h"
#include "ast/macros/macro_finder.h"
#include "ast/occurs.h"
#include "ast/ast_pp.h"
#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())
return false;
TRACE("macro_finder", tout << "processing: " << mk_pp(n, m_manager) << "\n";);
TRACE("macro_finder", tout << "processing: " << mk_pp(n, m) << "\n";);
expr * body = to_quantifier(n)->get_expr();
unsigned num_decls = to_quantifier(n)->get_num_decls();
return m_util.is_simple_macro(body, num_decls, head, def);
}
/**
\brief Detect macros of the form
\brief Detect macros of the form
1- (forall (X) (= (+ (f X) (R X)) c))
2- (forall (X) (<= (+ (f X) (R X)) c))
3- (forall (X) (>= (+ (f X) (R X)) c))
The second and third cases are first converted into
(forall (X) (= (f X) (+ c (* -1 (R x)) (k X))))
and
and
(forall (X) (<= (k X) 0)) when case 2
(forall (X) (>= (k X) 0)) when case 3
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_ref_vector & new_exprs, proof_ref_vector & 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())
return false;
arith_simplifier_plugin * as = get_arith_simp();
arith_util & autil = as->get_arith_util();
expr * body = to_quantifier(n)->get_expr();
unsigned num_decls = to_quantifier(n)->get_num_decls();
if (!autil.is_le(body) && !autil.is_ge(body) && !m_manager.is_eq(body))
if (!m_autil.is_le(body) && !m_autil.is_ge(body) && !m.is_eq(body))
return false;
if (!as->is_add(to_app(body)->get_arg(0)))
if (!m_autil.is_add(to_app(body)->get_arg(0)))
return false;
app_ref head(m_manager);
expr_ref def(m_manager);
app_ref head(m);
expr_ref def(m);
bool inv = false;
if (!m_util.is_arith_macro(body, num_decls, head, def, inv))
return false;
app_ref new_body(m_manager);
if (!inv || m_manager.is_eq(body))
new_body = m_manager.mk_app(to_app(body)->get_decl(), head, def);
else if (as->is_le(body))
new_body = autil.mk_ge(head, def);
else
new_body = autil.mk_le(head, def);
app_ref new_body(m);
quantifier_ref new_q(m_manager);
new_q = m_manager.update_quantifier(to_quantifier(n), new_body);
if (!inv || m.is_eq(body))
new_body = m.mk_app(to_app(body)->get_decl(), head, def);
else if (m_autil.is_le(body))
new_body = m_autil.mk_ge(head, def);
else
new_body = m_autil.mk_le(head, def);
quantifier_ref new_q(m);
new_q = m.update_quantifier(to_quantifier(n), new_body);
proof * new_pr = 0;
if (m_manager.proofs_enabled()) {
proof * rw = m_manager.mk_rewrite(n, new_q);
new_pr = m_manager.mk_modus_ponens(pr, rw);
if (m.proofs_enabled()) {
proof * rw = m.mk_rewrite(n, new_q);
new_pr = m.mk_modus_ponens(pr, rw);
}
if (m_manager.is_eq(body)) {
expr_dependency * new_dep = dep;
if (m.is_eq(body)) {
return m_macro_manager.insert(head->get_decl(), new_q, new_pr, new_dep);
}
// is ge or le
//
TRACE("macro_finder", tout << "is_arith_macro: is_ge or is_le\n";);
func_decl * f = head->get_decl();
func_decl * k = m.mk_fresh_func_decl(f->get_name(), symbol::null, f->get_arity(), f->get_domain(), f->get_range());
app * k_app = m.mk_app(k, head->get_num_args(), head->get_args());
expr_ref_buffer new_rhs_args(m);
expr_ref new_rhs2(m_autil.mk_add(def, k_app), m);
expr * body1 = m.mk_eq(head, new_rhs2);
expr * body2 = m.mk_app(new_body->get_decl(), k_app, m_autil.mk_int(0));
quantifier * q1 = m.update_quantifier(new_q, body1);
expr * patterns[1] = { m.mk_pattern(k_app) };
quantifier * q2 = m.update_quantifier(new_q, 1, patterns, body2);
new_exprs.push_back(q1);
new_exprs.push_back(q2);
if (m.proofs_enabled()) {
// new_pr : new_q
// rw : [rewrite] new_q ~ q1 & q2
// mp : [modus_pones new_pr rw] q1 & q2
// pr1 : [and-elim mp] q1
// pr2 : [and-elim mp] q2
app * q1q2 = m.mk_and(q1,q2);
proof * rw = m.mk_oeq_rewrite(new_q, q1q2);
proof * mp = m.mk_modus_ponens(new_pr, rw);
proof * pr1 = m.mk_and_elim(mp, 0);
proof * pr2 = m.mk_and_elim(mp, 1);
new_prs.push_back(pr1);
new_prs.push_back(pr2);
}
if (dep) {
new_deps.push_back(new_dep);
new_deps.push_back(new_dep);
}
return true;
}
bool macro_finder::is_arith_macro(expr * n, proof * pr, vector<justified_expr>& new_fmls) {
if (!is_quantifier(n) || !to_quantifier(n)->is_forall())
return false;
expr * body = to_quantifier(n)->get_expr();
unsigned num_decls = to_quantifier(n)->get_num_decls();
if (!m_autil.is_le(body) && !m_autil.is_ge(body) && !m.is_eq(body))
return false;
if (!m_autil.is_add(to_app(body)->get_arg(0)))
return false;
app_ref head(m);
expr_ref def(m);
bool inv = false;
if (!m_util.is_arith_macro(body, num_decls, head, def, inv))
return false;
app_ref new_body(m);
if (!inv || m.is_eq(body))
new_body = m.mk_app(to_app(body)->get_decl(), head, def);
else if (m_autil.is_le(body))
new_body = m_autil.mk_ge(head, def);
else
new_body = m_autil.mk_le(head, def);
quantifier_ref new_q(m);
new_q = m.update_quantifier(to_quantifier(n), new_body);
proof * new_pr = 0;
if (m.proofs_enabled()) {
proof * rw = m.mk_rewrite(n, new_q);
new_pr = m.mk_modus_ponens(pr, rw);
}
if (m.is_eq(body)) {
return m_macro_manager.insert(head->get_decl(), new_q, new_pr);
}
// is ge or le
//
TRACE("macro_finder", tout << "is_arith_macro: is_ge or is_le\n";);
func_decl * f = head->get_decl();
func_decl * k = m_manager.mk_fresh_func_decl(f->get_name(), symbol::null, f->get_arity(), f->get_domain(), f->get_range());
app * k_app = m_manager.mk_app(k, head->get_num_args(), head->get_args());
expr_ref_buffer new_rhs_args(m_manager);
expr_ref new_rhs2(m_manager);
as->mk_add(def, k_app, new_rhs2);
expr * body1 = m_manager.mk_eq(head, new_rhs2);
expr * body2 = m_manager.mk_app(new_body->get_decl(), k_app, as->mk_numeral(rational(0)));
quantifier * q1 = m_manager.update_quantifier(new_q, body1);
expr * patterns[1] = { m_manager.mk_pattern(k_app) };
quantifier * q2 = m_manager.update_quantifier(new_q, 1, patterns, body2);
new_exprs.push_back(q1);
new_exprs.push_back(q2);
if (m_manager.proofs_enabled()) {
func_decl * k = m.mk_fresh_func_decl(f->get_name(), symbol::null, f->get_arity(), f->get_domain(), f->get_range());
app * k_app = m.mk_app(k, head->get_num_args(), head->get_args());
expr_ref_buffer new_rhs_args(m);
expr_ref new_rhs2(m_autil.mk_add(def, k_app), m);
expr * body1 = m.mk_eq(head, new_rhs2);
expr * body2 = m.mk_app(new_body->get_decl(), k_app, m_autil.mk_int(0));
quantifier * q1 = m.update_quantifier(new_q, body1);
expr * patterns[1] = { m.mk_pattern(k_app) };
quantifier * q2 = m.update_quantifier(new_q, 1, patterns, body2);
proof* pr1 = 0, *pr2 = 0;
if (m.proofs_enabled()) {
// new_pr : new_q
// rw : [rewrite] new_q ~ q1 & q2
// mp : [modus_pones new_pr rw] q1 & q2
// pr1 : [and-elim mp] q1
// pr2 : [and-elim mp] q2
app * q1q2 = m_manager.mk_and(q1,q2);
proof * rw = m_manager.mk_oeq_rewrite(new_q, q1q2);
proof * mp = m_manager.mk_modus_ponens(new_pr, rw);
proof * pr1 = m_manager.mk_and_elim(mp, 0);
proof * pr2 = m_manager.mk_and_elim(mp, 1);
new_prs.push_back(pr1);
new_prs.push_back(pr2);
app * q1q2 = m.mk_and(q1,q2);
proof * rw = m.mk_oeq_rewrite(new_q, q1q2);
proof * mp = m.mk_modus_ponens(new_pr, rw);
pr1 = m.mk_and_elim(mp, 0);
pr2 = m.mk_and_elim(mp, 1);
}
new_fmls.push_back(justified_expr(m, q1, pr1));
new_fmls.push_back(justified_expr(m, q2, pr2));
return true;
}
@ -118,7 +185,7 @@ bool macro_finder::is_arith_macro(expr * n, proof * pr, expr_ref_vector & new_ex
n is of the form: (forall (X) (iff (= (f X) t) def[X]))
Convert it into:
(forall (X) (= (f X) (ite def[X] t (k X))))
(forall (X) (not (= (k X) t)))
@ -126,13 +193,13 @@ bool macro_finder::is_arith_macro(expr * n, proof * pr, expr_ref_vector & new_ex
The new quantifiers and proofs are stored in new_exprs and new_prs
*/
static void pseudo_predicate_macro2macro(ast_manager & m, app * head, app * t, expr * def, quantifier * q, proof * pr,
expr_ref_vector & new_exprs, proof_ref_vector & new_prs) {
static void pseudo_predicate_macro2macro(ast_manager & m, app * head, app * t, expr * def, quantifier * q, proof * pr, expr_dependency * dep,
expr_ref_vector & new_exprs, proof_ref_vector & new_prs, expr_dependency_ref_vector & new_deps ) {
func_decl * f = head->get_decl();
func_decl * k = m.mk_fresh_func_decl(f->get_name(), symbol::null, f->get_arity(), f->get_domain(), f->get_range());
app * k_app = m.mk_app(k, head->get_num_args(), head->get_args());
app * ite = m.mk_ite(def, t, k_app);
app * body_1 = m.mk_eq(head, ite);
app * body_1 = m.mk_eq(head, ite);
app * body_2 = m.mk_not(m.mk_eq(k_app, t));
quantifier * q1 = m.update_quantifier(q, body_1);
expr * pats[1] = { m.mk_pattern(k_app) };
@ -153,68 +220,158 @@ static void pseudo_predicate_macro2macro(ast_manager & m, app * head, app * t, e
new_prs.push_back(pr1);
new_prs.push_back(pr2);
}
new_deps.push_back(dep);
new_deps.push_back(dep);
}
static void pseudo_predicate_macro2macro(ast_manager & m, app * head, app * t, expr * def, quantifier * q, proof * pr,
vector<justified_expr>& new_fmls) {
func_decl * f = head->get_decl();
func_decl * k = m.mk_fresh_func_decl(f->get_name(), symbol::null, f->get_arity(), f->get_domain(), f->get_range());
app * k_app = m.mk_app(k, head->get_num_args(), head->get_args());
app * ite = m.mk_ite(def, t, k_app);
app * body_1 = m.mk_eq(head, ite);
app * body_2 = m.mk_not(m.mk_eq(k_app, t));
quantifier * q1 = m.update_quantifier(q, body_1);
proof * pr1 = 0, *pr2 = 0;
expr * pats[1] = { m.mk_pattern(k_app) };
quantifier * q2 = m.update_quantifier(q, 1, pats, body_2); // erase patterns
if (m.proofs_enabled()) {
// r : [rewrite] q ~ q1 & q2
// pr : q
// mp : [modus_pones pr pr1] q1 & q2
// pr1 : [and-elim mp] q1
// pr2 : [and-elim mp] q2
app * q1q2 = m.mk_and(q1,q2);
proof * r = m.mk_oeq_rewrite(q, q1q2);
proof * mp = m.mk_modus_ponens(pr, r);
pr1 = m.mk_and_elim(mp, 0);
pr2 = m.mk_and_elim(mp, 1);
}
new_fmls.push_back(justified_expr(m, q1, pr1));
new_fmls.push_back(justified_expr(m, q2, pr2));
}
macro_finder::macro_finder(ast_manager & m, macro_manager & mm):
m_manager(m),
m(m),
m_macro_manager(mm),
m_util(mm.get_util()) {
m_util(mm.get_util()),
m_autil(m) {
}
macro_finder::~macro_finder() {
}
bool macro_finder::expand_macros(unsigned num, expr * const * exprs, proof * const * prs, expr_ref_vector & new_exprs, proof_ref_vector & new_prs) {
bool macro_finder::expand_macros(unsigned num, expr * const * exprs, proof * const * prs, expr_dependency * const * deps, expr_ref_vector & new_exprs, proof_ref_vector & new_prs, expr_dependency_ref_vector & new_deps) {
TRACE("macro_finder", tout << "starting expand_macros:\n";
m_macro_manager.display(tout););
bool found_new_macro = false;
for (unsigned i = 0; i < num; i++) {
expr * n = exprs[i];
proof * pr = m_manager.proofs_enabled() ? prs[i] : 0;
expr_ref new_n(m_manager), def(m_manager);
proof_ref new_pr(m_manager);
m_macro_manager.expand_macros(n, pr, new_n, new_pr);
app_ref head(m_manager), t(m_manager);
if (is_macro(new_n, head, def) && m_macro_manager.insert(head->get_decl(), to_quantifier(new_n.get()), new_pr)) {
proof * pr = m.proofs_enabled() ? prs[i] : 0;
expr_dependency * depi = deps != 0 ? deps[i] : 0;
expr_ref new_n(m), def(m);
proof_ref new_pr(m);
expr_dependency_ref new_dep(m);
m_macro_manager.expand_macros(n, pr, depi, new_n, new_pr, new_dep);
app_ref head(m), t(m);
if (is_macro(new_n, head, def) && m_macro_manager.insert(head->get_decl(), to_quantifier(new_n.get()), new_pr, new_dep)) {
TRACE("macro_finder_found", tout << "found new macro: " << head->get_decl()->get_name() << "\n" << new_n << "\n";);
found_new_macro = true;
}
else if (is_arith_macro(new_n, new_pr, new_exprs, new_prs)) {
else if (is_arith_macro(new_n, new_pr, new_dep, new_exprs, new_prs, new_deps)) {
TRACE("macro_finder_found", tout << "found new arith macro:\n" << new_n << "\n";);
found_new_macro = true;
}
else if (m_util.is_pseudo_predicate_macro(new_n, head, t, def)) {
else if (m_util.is_pseudo_predicate_macro(new_n, head, t, def)) {
TRACE("macro_finder_found", tout << "found new pseudo macro:\n" << head << "\n" << t << "\n" << def << "\n";);
pseudo_predicate_macro2macro(m_manager, head, t, def, to_quantifier(new_n), new_pr, new_exprs, new_prs);
pseudo_predicate_macro2macro(m, head, t, def, to_quantifier(new_n), new_pr, new_dep, new_exprs, new_prs, new_deps);
found_new_macro = true;
}
else {
new_exprs.push_back(new_n);
if (m_manager.proofs_enabled())
if (m.proofs_enabled())
new_prs.push_back(new_pr);
if (deps != 0)
new_deps.push_back(new_dep);
}
}
return found_new_macro;
}
void macro_finder::operator()(unsigned num, expr * const * exprs, proof * const * prs, expr_ref_vector & new_exprs, proof_ref_vector & new_prs) {
void macro_finder::operator()(unsigned num, expr * const * exprs, proof * const * prs, expr_dependency * const * deps, expr_ref_vector & new_exprs, proof_ref_vector & new_prs, expr_dependency_ref_vector & new_deps) {
TRACE("macro_finder", tout << "processing macros...\n";);
expr_ref_vector _new_exprs(m_manager);
proof_ref_vector _new_prs(m_manager);
if (expand_macros(num, exprs, prs, _new_exprs, _new_prs)) {
expr_ref_vector _new_exprs(m);
proof_ref_vector _new_prs(m);
expr_dependency_ref_vector _new_deps(m);
if (expand_macros(num, exprs, prs, deps, _new_exprs, _new_prs, _new_deps)) {
while (true) {
expr_ref_vector old_exprs(m_manager);
proof_ref_vector old_prs(m_manager);
expr_ref_vector old_exprs(m);
proof_ref_vector old_prs(m);
expr_dependency_ref_vector old_deps(m);
_new_exprs.swap(old_exprs);
_new_prs.swap(old_prs);
_new_deps.swap(old_deps);
SASSERT(_new_exprs.empty());
SASSERT(_new_prs.empty());
if (!expand_macros(old_exprs.size(), old_exprs.c_ptr(), old_prs.c_ptr(), _new_exprs, _new_prs))
SASSERT(_new_deps.empty());
if (!expand_macros(old_exprs.size(), old_exprs.c_ptr(), old_prs.c_ptr(), old_deps.c_ptr(),
_new_exprs, _new_prs, _new_deps))
break;
}
}
new_exprs.append(_new_exprs);
new_prs.append(_new_prs);
new_deps.append(_new_deps);
}
bool macro_finder::expand_macros(unsigned num, justified_expr const * fmls, vector<justified_expr>& new_fmls) {
TRACE("macro_finder", tout << "starting expand_macros:\n";
m_macro_manager.display(tout););
bool found_new_macro = false;
for (unsigned i = 0; i < num; i++) {
expr * n = fmls[i].get_fml();
proof * pr = m.proofs_enabled() ? fmls[i].get_proof() : 0;
expr_ref new_n(m), def(m);
proof_ref new_pr(m);
expr_dependency_ref new_dep(m);
m_macro_manager.expand_macros(n, pr, 0, new_n, new_pr, new_dep);
app_ref head(m), t(m);
if (is_macro(new_n, head, def) && m_macro_manager.insert(head->get_decl(), to_quantifier(new_n.get()), new_pr)) {
TRACE("macro_finder_found", tout << "found new macro: " << head->get_decl()->get_name() << "\n" << new_n << "\n";);
found_new_macro = true;
}
else if (is_arith_macro(new_n, new_pr, new_fmls)) {
TRACE("macro_finder_found", tout << "found new arith macro:\n" << new_n << "\n";);
found_new_macro = true;
}
else if (m_util.is_pseudo_predicate_macro(new_n, head, t, def)) {
TRACE("macro_finder_found", tout << "found new pseudo macro:\n" << head << "\n" << t << "\n" << def << "\n";);
pseudo_predicate_macro2macro(m, head, t, def, to_quantifier(new_n), new_pr, new_fmls);
found_new_macro = true;
}
else {
new_fmls.push_back(justified_expr(m, new_n, new_pr));
}
}
return found_new_macro;
}
void macro_finder::operator()(unsigned n, justified_expr const* fmls, vector<justified_expr>& new_fmls) {
TRACE("macro_finder", tout << "processing macros...\n";);
vector<justified_expr> _new_fmls;
if (expand_macros(n, fmls, _new_fmls)) {
while (true) {
vector<justified_expr> old_fmls;
_new_fmls.swap(old_fmls);
SASSERT(_new_fmls.empty());
if (!expand_macros(old_fmls.size(), old_fmls.c_ptr(), _new_fmls))
break;
}
}
new_fmls.append(_new_fmls);
}

View file

@ -19,36 +19,32 @@ Revision History:
#ifndef MACRO_FINDER_H_
#define MACRO_FINDER_H_
#include"macro_manager.h"
#include"arith_simplifier_plugin.h"
#include "ast/macros/macro_manager.h"
bool is_macro_head(expr * n, unsigned num_decls);
bool is_simple_macro(ast_manager & m, expr * n, unsigned num_decls, obj_hashtable<func_decl> const * forbidden_set, app * & head, expr * & def);
inline bool is_simple_macro(ast_manager & m, expr * n, unsigned num_decls, app * & head, expr * & def) {
return is_simple_macro(m, n, num_decls, 0, head, def);
}
/**
\brief Macro finder is responsible for finding universally quantified sub-formulas that can be used
as macros.
*/
class macro_finder {
ast_manager & m_manager;
ast_manager & m;
macro_manager & m_macro_manager;
macro_util & m_util;
arith_simplifier_plugin * get_arith_simp() { return m_util.get_arith_simp(); }
bool expand_macros(unsigned num, expr * const * exprs, proof * const * prs, expr_ref_vector & new_exprs, proof_ref_vector & new_prs);
arith_util m_autil;
bool expand_macros(unsigned num, expr * const * exprs, proof * const * prs, expr_dependency * const* deps,
expr_ref_vector & new_exprs, proof_ref_vector & new_prs, expr_dependency_ref_vector& new_deps);
bool expand_macros(unsigned n, justified_expr const * fmls, vector<justified_expr>& new_fmls);
bool is_arith_macro(expr * n, proof * pr, expr_ref_vector & new_exprs, proof_ref_vector & new_prs);
bool is_arith_macro(expr * n, proof * pr, vector<justified_expr>& new_fmls);
bool 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);
bool is_macro(expr * n, app_ref & head, expr_ref & def);
bool is_pseudo_head(expr * n, unsigned num_decls, app * & head, app * & t);
bool is_pseudo_predicate_macro(expr * n, app * & head, app * & t, expr * & def);
public:
macro_finder(ast_manager & m, macro_manager & mm);
~macro_finder();
void operator()(unsigned n, expr * const * exprs, proof * const * prs, expr_ref_vector & new_exprs, proof_ref_vector & new_prs);
void operator()(unsigned n, expr * const * exprs, proof * const * prs, expr_dependency * const* deps, expr_ref_vector & new_exprs, proof_ref_vector & new_prs, expr_dependency_ref_vector & new_deps);
void operator()(unsigned n, justified_expr const* fmls, vector<justified_expr>& new_fmls);
};
#endif /* MACRO_FINDER_H_ */

View file

@ -19,19 +19,22 @@ Revision History:
Leonardo de Moura (leonardo) 2010-12-15: Moved dependency management to func_decl_dependencies.h
--*/
#include"macro_manager.h"
#include"for_each_expr.h"
#include"var_subst.h"
#include"ast_pp.h"
#include"recurse_expr_def.h"
#include "ast/macros/macro_manager.h"
#include "ast/for_each_expr.h"
#include "ast/rewriter/var_subst.h"
#include "ast/rewriter/th_rewriter.h"
#include "ast/rewriter/rewriter_def.h"
#include "ast/ast_pp.h"
#include "ast/recurse_expr_def.h"
macro_manager::macro_manager(ast_manager & m, simplifier & s):
m_manager(m),
m_simplifier(s),
m_util(m, s),
macro_manager::macro_manager(ast_manager & m):
m(m),
m_util(m),
m_decls(m),
m_macros(m),
m_macro_prs(m),
m_macro_deps(m),
m_forbidden(m),
m_deps(m) {
m_util.set_forbidden_set(&m_forbidden_set);
@ -60,13 +63,15 @@ void macro_manager::restore_decls(unsigned old_sz) {
for (unsigned i = old_sz; i < sz; i++) {
m_decl2macro.erase(m_decls.get(i));
m_deps.erase(m_decls.get(i));
if (m_manager.proofs_enabled())
if (m.proofs_enabled())
m_decl2macro_pr.erase(m_decls.get(i));
m_decl2macro_dep.erase(m_decls.get(i));
}
m_decls.shrink(old_sz);
m_macros.shrink(old_sz);
if (m_manager.proofs_enabled())
if (m.proofs_enabled())
m_macro_prs.shrink(old_sz);
m_macro_deps.shrink(old_sz);
}
void macro_manager::restore_forbidden(unsigned old_sz) {
@ -79,17 +84,19 @@ void macro_manager::restore_forbidden(unsigned old_sz) {
void macro_manager::reset() {
m_decl2macro.reset();
m_decl2macro_pr.reset();
m_decl2macro_dep.reset();
m_decls.reset();
m_macros.reset();
m_macro_prs.reset();
m_macro_deps.reset();
m_scopes.reset();
m_forbidden_set.reset();
m_forbidden.reset();
m_deps.reset();
}
bool macro_manager::insert(func_decl * f, quantifier * m, proof * pr) {
TRACE("macro_insert", tout << "trying to create macro: " << f->get_name() << "\n" << mk_pp(m, m_manager) << "\n";);
bool macro_manager::insert(func_decl * f, quantifier * q, proof * pr, expr_dependency* dep) {
TRACE("macro_insert", tout << "trying to create macro: " << f->get_name() << "\n" << mk_pp(q, m) << "\n";);
// if we already have a macro for f then return false;
if (m_decls.contains(f)) {
@ -99,7 +106,7 @@ bool macro_manager::insert(func_decl * f, quantifier * m, proof * pr) {
app * head;
expr * definition;
get_head_def(m, f, head, definition);
get_head_def(q, f, head, definition);
func_decl_set * s = m_deps.mk_func_decl_set();
m_deps.collect_func_decls(definition, s);
@ -108,13 +115,15 @@ bool macro_manager::insert(func_decl * f, quantifier * m, proof * pr) {
}
// add macro
m_decl2macro.insert(f, m);
m_decl2macro.insert(f, q);
m_decls.push_back(f);
m_macros.push_back(m);
if (m_manager.proofs_enabled()) {
m_macros.push_back(q);
if (m.proofs_enabled()) {
m_macro_prs.push_back(pr);
m_decl2macro_pr.insert(f, pr);
}
m_macro_deps.push_back(dep);
m_decl2macro_dep.insert(f, dep);
TRACE("macro_insert", tout << "A macro was successfully created for: " << f->get_name() << "\n";);
@ -150,9 +159,17 @@ void macro_manager::mark_forbidden(unsigned n, expr * const * exprs) {
for_each_expr(p, visited, exprs[i]);
}
void macro_manager::mark_forbidden(unsigned n, justified_expr const * exprs) {
expr_mark visited;
macro_manager_ns::proc p(m_forbidden_set, m_forbidden);
for (unsigned i = 0; i < n; i++)
for_each_expr(p, visited, exprs[i].get_fml());
}
void macro_manager::get_head_def(quantifier * q, func_decl * d, app * & head, expr * & def) const {
app * body = to_app(q->get_expr());
SASSERT(m_manager.is_eq(body) || m_manager.is_iff(body));
SASSERT(m.is_eq(body) || m.is_iff(body));
expr * lhs = to_app(body)->get_arg(0);
expr * rhs = to_app(body)->get_arg(1);
SASSERT(is_app_of(lhs, d) || is_app_of(rhs, d));
@ -177,7 +194,7 @@ void macro_manager::display(std::ostream & out) {
expr * def;
get_head_def(q, f, head, def);
SASSERT(q);
out << mk_pp(head, m_manager) << " ->\n" << mk_pp(def, m_manager) << "\n";
out << mk_pp(head, m) << " ->\n" << mk_pp(def, m) << "\n";
}
}
@ -188,132 +205,157 @@ func_decl * macro_manager::get_macro_interpretation(unsigned i, expr_ref & inter
expr * def;
get_head_def(q, f, head, def);
TRACE("macro_bug",
tout << f->get_name() << "\n" << mk_pp(head, m_manager) << "\n" << mk_pp(q, m_manager) << "\n";);
tout << f->get_name() << "\n" << mk_pp(head, m) << "\n" << mk_pp(q, m) << "\n";);
m_util.mk_macro_interpretation(head, q->get_num_decls(), def, interp);
return f;
}
macro_manager::macro_expander::macro_expander(ast_manager & m, macro_manager & mm, simplifier & s):
simplifier(m),
m_macro_manager(mm) {
// REMARK: theory simplifier should not be used by macro_expander...
// is_arith_macro rewrites a quantifer such as:
// forall (x Int) (= (+ x (+ (f x) 1)) 2)
// into
// forall (x Int) (= (f x) (+ 1 (* -1 x)))
// The goal is to make simple macro detection detect the arith macro.
// The arith simplifier will undo this transformation.
// borrow_plugins(s);
enable_ac_support(false);
}
struct macro_manager::macro_expander_cfg : public default_rewriter_cfg {
ast_manager& m;
macro_manager& mm;
expr_dependency_ref m_used_macro_dependencies;
expr_ref_vector m_trail;
macro_manager::macro_expander::~macro_expander() {
// release_plugins();
}
macro_expander_cfg(ast_manager& m, macro_manager& mm):
m(m),
mm(mm),
m_used_macro_dependencies(m),
m_trail(m)
{}
void macro_manager::macro_expander::reduce1_quantifier(quantifier * q) {
simplifier::reduce1_quantifier(q);
// If a macro was expanded in a pattern, we must erase it since it may not be a valid pattern anymore.
// The MAM assumes valid patterns, and it crashes if invalid patterns are provided.
// For example, it will crash if the pattern does not contain all variables.
//
// Alternative solution: use pattern_validation to check if the pattern is still valid.
// I'm not sure if this is a good solution, since the pattern may be meaningless after the macro expansion.
// So, I'm just erasing them.
expr * new_q_expr = 0;
proof * new_q_pr = 0;
get_cached(q, new_q_expr, new_q_pr);
if (!is_quantifier(new_q_expr))
return;
quantifier * new_q = to_quantifier(new_q_expr);
bool erase_patterns = false;
if (q->get_num_patterns() != new_q->get_num_patterns() ||
q->get_num_no_patterns() != new_q->get_num_no_patterns()) {
erase_patterns = true;
bool rewrite_patterns() const { return false; }
bool flat_assoc(func_decl * f) const { return false; }
br_status reduce_app(func_decl * f, unsigned num, expr * const * args, expr_ref & result, proof_ref & result_pr) {
result_pr = 0;
return BR_FAILED;
}
else {
for (unsigned i = 0; !erase_patterns && i < q->get_num_patterns(); i++) {
if (q->get_pattern(i) != new_q->get_pattern(i))
bool reduce_quantifier(quantifier * old_q,
expr * new_body,
expr * const * new_patterns,
expr * const * new_no_patterns,
expr_ref & result,
proof_ref & result_pr) {
// If a macro was expanded in a pattern, we must erase it since it may not be a valid pattern anymore.
// The MAM assumes valid patterns, and it crashes if invalid patterns are provided.
// For example, it will crash if the pattern does not contain all variables.
//
// Alternative solution: use pattern_validation to check if the pattern is still valid.
// I'm not sure if this is a good solution, since the pattern may be meaningless after the macro expansion.
// So, I'm just erasing them.
bool erase_patterns = false;
for (unsigned i = 0; !erase_patterns && i < old_q->get_num_patterns(); i++) {
if (old_q->get_pattern(i) != new_patterns[i])
erase_patterns = true;
}
for (unsigned i = 0; !erase_patterns && i < q->get_num_no_patterns(); i++) {
if (q->get_no_pattern(i) != new_q->get_no_pattern(i))
for (unsigned i = 0; !erase_patterns && i < old_q->get_num_no_patterns(); i++) {
if (old_q->get_no_pattern(i) != new_no_patterns[i])
erase_patterns = true;
}
if (erase_patterns) {
result = m.update_quantifier(old_q, 0, 0, 0, 0, new_body);
}
return erase_patterns;
}
if (erase_patterns) {
ast_manager & m = get_manager();
expr * new_new_q = m.update_quantifier(new_q, 0, 0, 0, 0, new_q->get_expr());
// we can use the same proof since new_new_q and new_q are identical modulo patterns/annotations
cache_result(q, new_new_q, new_q_pr);
}
}
bool macro_manager::macro_expander::get_subst(expr * _n, expr_ref & r, proof_ref & p) {
if (!is_app(_n))
bool get_subst(expr * _n, expr* & r, proof* & p) {
if (!is_app(_n))
return false;
app * n = to_app(_n);
quantifier * q = 0;
func_decl * d = n->get_decl();
TRACE("macro_manager", tout << "trying to expand:\n" << mk_pp(n, m) << "\nd:\n" << d->get_name() << "\n";);
if (mm.m_decl2macro.find(d, q)) {
TRACE("macro_manager", tout << "expanding: " << mk_pp(n, m) << "\n";);
app * head = 0;
expr * def = 0;
mm.get_head_def(q, d, head, def);
unsigned num = n->get_num_args();
SASSERT(head && def);
ptr_buffer<expr> subst_args;
subst_args.resize(num, 0);
for (unsigned i = 0; i < num; i++) {
var * v = to_var(head->get_arg(i));
SASSERT(v->get_idx() < num);
unsigned nidx = num - v->get_idx() - 1;
SASSERT(subst_args[nidx] == 0);
subst_args[nidx] = n->get_arg(i);
}
var_subst s(m);
expr_ref rr(m);
s(def, num, subst_args.c_ptr(), rr);
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);
proof * qi_pr = m.mk_quant_inst(m.mk_or(m.mk_not(q), instance), num, subst_args.c_ptr());
proof * q_pr = 0;
mm.m_decl2macro_pr.find(d, q_pr);
SASSERT(q_pr != 0);
proof * prs[2] = { qi_pr, q_pr };
p = m.mk_unit_resolution(2, prs);
}
else {
p = 0;
}
expr_dependency * ed = mm.m_decl2macro_dep.find(d);
m_used_macro_dependencies = m.mk_join(m_used_macro_dependencies, ed);
return true;
}
return false;
app * n = to_app(_n);
quantifier * q = 0;
func_decl * d = n->get_decl();
TRACE("macro_manager_bug", tout << "trying to expand:\n" << mk_pp(n, m) << "\nd:\n" << d->get_name() << "\n";);
if (m_macro_manager.m_decl2macro.find(d, q)) {
TRACE("macro_manager", tout << "expanding: " << mk_pp(n, m) << "\n";);
app * head = 0;
expr * def = 0;
m_macro_manager.get_head_def(q, d, head, def);
unsigned num = n->get_num_args();
SASSERT(head && def);
ptr_buffer<expr> subst_args;
subst_args.resize(num, 0);
for (unsigned i = 0; i < num; i++) {
var * v = to_var(head->get_arg(i));
SASSERT(v->get_idx() < num);
unsigned nidx = num - v->get_idx() - 1;
SASSERT(subst_args[nidx] == 0);
subst_args[nidx] = n->get_arg(i);
}
var_subst s(m);
s(def, num, subst_args.c_ptr(), r);
if (m.proofs_enabled()) {
expr_ref instance(m);
s(q->get_expr(), num, subst_args.c_ptr(), instance);
proof * qi_pr = m.mk_quant_inst(m.mk_or(m.mk_not(q), instance), num, subst_args.c_ptr());
proof * q_pr = 0;
m_macro_manager.m_decl2macro_pr.find(d, q_pr);
SASSERT(q_pr != 0);
proof * prs[2] = { qi_pr, q_pr };
p = m.mk_unit_resolution(2, prs);
}
else {
p = 0;
}
return true;
}
return false;
}
};
void macro_manager::expand_macros(expr * n, proof * pr, expr_ref & r, proof_ref & new_pr) {
struct macro_manager::macro_expander_rw : public rewriter_tpl<macro_manager::macro_expander_cfg> {
macro_expander_cfg m_cfg;
macro_expander_rw(ast_manager& m, macro_manager& mm):
rewriter_tpl<macro_manager::macro_expander_cfg>(m, m.proofs_enabled(), m_cfg),
m_cfg(m, mm)
{}
};
void macro_manager::expand_macros(expr * n, proof * pr, expr_dependency * dep, expr_ref & r, proof_ref & new_pr, expr_dependency_ref & new_dep) {
if (has_macros()) {
// Expand macros with "real" proof production support (NO rewrite*)
expr_ref old_n(m_manager);
proof_ref old_pr(m_manager);
expr_ref old_n(m);
proof_ref old_pr(m);
expr_dependency_ref old_dep(m);
old_n = n;
old_pr = pr;
old_dep = dep;
bool change = false;
for (;;) {
macro_expander proc(m_manager, *this, m_simplifier);
proof_ref n_eq_r_pr(m_manager);
TRACE("macro_manager_bug", tout << "expand_macros:\n" << mk_pp(n, m_manager) << "\n";);
macro_expander_rw proc(m, *this);
proof_ref n_eq_r_pr(m);
TRACE("macro_manager_bug", tout << "expand_macros:\n" << mk_pp(n, m) << "\n";);
proc(old_n, r, n_eq_r_pr);
new_pr = m_manager.mk_modus_ponens(old_pr, n_eq_r_pr);
new_pr = m.mk_modus_ponens(old_pr, n_eq_r_pr);
new_dep = m.mk_join(old_dep, proc.m_cfg.m_used_macro_dependencies);
if (r.get() == old_n.get())
return;
break;
old_n = r;
old_pr = new_pr;
old_dep = new_dep;
change = true;
}
// apply th_rewrite to the result.
if (change) {
th_rewriter rw(m);
proof_ref rw_pr(m);
expr_ref r1(r, m);
rw(r1, r, rw_pr);
new_pr = m.mk_modus_ponens(new_pr, rw_pr);
}
}
else {
r = n;
new_pr = pr;
new_dep = dep;
}
}

View file

@ -19,12 +19,12 @@ Revision History:
#ifndef MACRO_MANAGER_H_
#define MACRO_MANAGER_H_
#include"ast_util.h"
#include"obj_hashtable.h"
#include"simplifier.h"
#include"recurse_expr.h"
#include"func_decl_dependencies.h"
#include"macro_util.h"
#include "util/obj_hashtable.h"
#include "ast/ast_util.h"
#include "ast/justified_expr.h"
#include "ast/recurse_expr.h"
#include "ast/func_decl_dependencies.h"
#include "ast/macros/macro_util.h"
/**
\brief Macros are universally quantified formulas of the form:
@ -36,15 +36,16 @@ Revision History:
It has support for backtracking and tagging declarations in an expression as forbidded for being macros.
*/
class macro_manager {
ast_manager & m_manager;
simplifier & m_simplifier;
ast_manager & m;
macro_util m_util;
obj_map<func_decl, quantifier *> m_decl2macro; // func-decl -> quantifier
obj_map<func_decl, proof *> m_decl2macro_pr; // func-decl -> quantifier_proof
obj_map<func_decl, expr_dependency *> m_decl2macro_dep; // func-decl -> unsat core dependency
func_decl_ref_vector m_decls;
quantifier_ref_vector m_macros;
proof_ref_vector m_macro_prs;
expr_dependency_ref_vector m_macro_deps;
obj_hashtable<func_decl> m_forbidden_set;
func_decl_ref_vector m_forbidden;
struct scope {
@ -52,34 +53,27 @@ class macro_manager {
unsigned m_forbidden_lim;
};
svector<scope> m_scopes;
func_decl_dependencies m_deps;
void restore_decls(unsigned old_sz);
void restore_forbidden(unsigned old_sz);
class macro_expander : public simplifier {
protected:
macro_manager & m_macro_manager;
virtual bool get_subst(expr * n, expr_ref & r, proof_ref & p);
virtual void reduce1_quantifier(quantifier * q);
public:
macro_expander(ast_manager & m, macro_manager & mm, simplifier & s);
~macro_expander();
};
friend class macro_expander;
struct macro_expander_cfg;
struct macro_expander_rw;
public:
macro_manager(ast_manager & m, simplifier & s);
macro_manager(ast_manager & m);
~macro_manager();
ast_manager & get_manager() const { return m_manager; }
ast_manager & get_manager() const { return m; }
macro_util & get_util() { return m_util; }
bool insert(func_decl * f, quantifier * m, proof * pr);
bool insert(func_decl * f, quantifier * m, proof * pr, expr_dependency * dep = 0);
bool has_macros() const { return !m_macros.empty(); }
void push_scope();
void pop_scope(unsigned num_scopes);
void reset();
void mark_forbidden(unsigned n, expr * const * exprs);
void mark_forbidden(unsigned n, justified_expr const * exprs);
void mark_forbidden(expr * e) { mark_forbidden(1, &e); }
bool is_forbidden(func_decl * d) const { return m_forbidden_set.contains(d); }
obj_hashtable<func_decl> const & get_forbidden_set() const { return m_forbidden_set; }
@ -90,9 +84,9 @@ public:
func_decl * get_macro_interpretation(unsigned i, expr_ref & interp) const;
quantifier * get_macro_quantifier(func_decl * f) const { quantifier * q = 0; m_decl2macro.find(f, q); return q; }
void get_head_def(quantifier * q, func_decl * d, app * & head, expr * & def) const;
void expand_macros(expr * n, proof * pr, expr_ref & r, proof_ref & new_pr);
void expand_macros(expr * n, proof * pr, expr_dependency * dep, expr_ref & r, proof_ref & new_pr, expr_dependency_ref & new_dep);
};
#endif /* MACRO_MANAGER_H_ */

View file

@ -17,44 +17,26 @@ Author:
Revision History:
--*/
#include"macro_util.h"
#include"occurs.h"
#include"ast_util.h"
#include"arith_simplifier_plugin.h"
#include"bv_simplifier_plugin.h"
#include"var_subst.h"
#include"ast_pp.h"
#include"ast_ll_pp.h"
#include"for_each_expr.h"
#include"well_sorted.h"
#include"bool_rewriter.h"
#include "ast/macros/macro_util.h"
#include "ast/occurs.h"
#include "ast/ast_util.h"
#include "ast/rewriter/var_subst.h"
#include "ast/ast_pp.h"
#include "ast/ast_ll_pp.h"
#include "ast/for_each_expr.h"
#include "ast/well_sorted.h"
#include "ast/rewriter/bool_rewriter.h"
macro_util::macro_util(ast_manager & m, simplifier & s):
macro_util::macro_util(ast_manager & m):
m_manager(m),
m_bv(m),
m_simplifier(s),
m_arith_simp(0),
m_bv_simp(0),
m_arith(m),
m_arith_rw(m),
m_bv_rw(m),
m_forbidden_set(0),
m_curr_clause(0) {
}
arith_simplifier_plugin * macro_util::get_arith_simp() const {
if (m_arith_simp == 0) {
const_cast<macro_util*>(this)->m_arith_simp = static_cast<arith_simplifier_plugin*>(m_simplifier.get_plugin(m_manager.mk_family_id("arith")));
}
SASSERT(m_arith_simp != 0);
return m_arith_simp;
}
bv_simplifier_plugin * macro_util::get_bv_simp() const {
if (m_bv_simp == 0) {
const_cast<macro_util*>(this)->m_bv_simp = static_cast<bv_simplifier_plugin*>(m_simplifier.get_plugin(m_manager.mk_family_id("bv")));
}
SASSERT(m_bv_simp != 0);
return m_bv_simp;
}
bool macro_util::is_bv(expr * n) const {
return m_bv.is_bv(n);
@ -65,60 +47,83 @@ bool macro_util::is_bv_sort(sort * s) const {
}
bool macro_util::is_add(expr * n) const {
return get_arith_simp()->is_add(n) || m_bv.is_bv_add(n);
return m_arith.is_add(n) || m_bv.is_bv_add(n);
}
bool macro_util::is_times_minus_one(expr * n, expr * & arg) const {
return get_arith_simp()->is_times_minus_one(n, arg) || get_bv_simp()->is_times_minus_one(n, arg);
return m_arith_rw.is_times_minus_one(n, arg) || m_bv_rw.is_times_minus_one(n, arg);
}
bool macro_util::is_le(expr * n) const {
return get_arith_simp()->is_le(n) || m_bv.is_bv_ule(n) || m_bv.is_bv_sle(n);
return m_arith.is_le(n) || m_bv.is_bv_ule(n) || m_bv.is_bv_sle(n);
}
bool macro_util::is_le_ge(expr * n) const {
return get_arith_simp()->is_le_ge(n) || m_bv.is_bv_ule(n) || m_bv.is_bv_sle(n);
return m_arith.is_ge(n) || m_arith.is_le(n) || m_bv.is_bv_ule(n) || m_bv.is_bv_sle(n);
}
poly_simplifier_plugin * macro_util::get_poly_simp_for(sort * s) const {
if (is_bv_sort(s))
return get_bv_simp();
else
return get_arith_simp();
bool macro_util::is_var_plus_ground(expr * n, bool & inv, var * & v, expr_ref & t) {
return m_arith_rw.is_var_plus_ground(n, inv, v, t) || m_bv_rw.is_var_plus_ground(n, inv, v, t);
}
bool macro_util::is_zero_safe(expr * n) const {
if (m_bv_rw.is_bv(n)) {
return m_bv.is_zero(n);
}
else {
return m_arith_rw.is_zero(n);
}
}
app * macro_util::mk_zero(sort * s) const {
poly_simplifier_plugin * ps = get_poly_simp_for(s);
ps->set_curr_sort(s);
return ps->mk_zero();
if (m_bv.is_bv_sort(s)) {
return m_bv.mk_numeral(rational(0), s);
}
else {
return m_arith.mk_numeral(rational(0), s);
}
}
void macro_util::mk_sub(expr * t1, expr * t2, expr_ref & r) const {
if (is_bv(t1)) {
r = m_bv.mk_bv_sub(t1, t2);
m_bv_rw.mk_sub(t1, t2, r);
}
else {
get_arith_simp()->mk_sub(t1, t2, r);
m_arith_rw.mk_sub(t1, t2, r);
}
}
void macro_util::mk_add(expr * t1, expr * t2, expr_ref & r) const {
if (is_bv(t1)) {
r = m_bv.mk_bv_add(t1, t2);
m_bv_rw.mk_add(t1, t2, r);
}
else {
get_arith_simp()->mk_add(t1, t2, r);
m_arith_rw.mk_add(t1, t2, r);
}
}
void macro_util::mk_add(unsigned num_args, expr * const * args, sort * s, expr_ref & r) const {
if (num_args == 0) {
switch (num_args) {
case 0:
r = mk_zero(s);
return;
break;
case 1:
r = args[0];
break;
default:
if (m_bv.is_bv_sort(s)) {
r = args[0];
while (num_args >= 2) {
--num_args;
++args;
r = m_bv.mk_bv_add(r, args[0]);
}
}
else {
r = m_arith.mk_add(num_args, args);
}
break;
}
poly_simplifier_plugin * ps = get_poly_simp_for(s);
ps->set_curr_sort(s);
ps->mk_add(num_args, args, r);
}
/**
@ -241,13 +246,12 @@ bool macro_util::poly_contains_head(expr * n, func_decl * f, expr * exception) c
bool macro_util::is_arith_macro(expr * n, unsigned num_decls, app_ref & head, expr_ref & def, bool & inv) const {
// TODO: obsolete... we should move to collect_arith_macro_candidates
arith_simplifier_plugin * as = get_arith_simp();
if (!m_manager.is_eq(n) && !as->is_le(n) && !as->is_ge(n))
if (!m_manager.is_eq(n) && !m_arith.is_le(n) && !m_arith.is_ge(n))
return false;
expr * lhs = to_app(n)->get_arg(0);
expr * rhs = to_app(n)->get_arg(1);
if (!as->is_numeral(rhs))
if (!m_arith.is_numeral(rhs))
return false;
inv = false;
@ -272,7 +276,7 @@ bool macro_util::is_arith_macro(expr * n, unsigned num_decls, app_ref & head, ex
!poly_contains_head(lhs, to_app(arg)->get_decl(), arg)) {
h = arg;
}
else if (h == 0 && as->is_times_minus_one(arg, neg_arg) &&
else if (h == 0 && m_arith_rw.is_times_minus_one(arg, neg_arg) &&
is_macro_head(neg_arg, num_decls) &&
!is_forbidden(to_app(neg_arg)->get_decl()) &&
!poly_contains_head(lhs, to_app(neg_arg)->get_decl(), arg)) {
@ -287,11 +291,12 @@ bool macro_util::is_arith_macro(expr * n, unsigned num_decls, app_ref & head, ex
return false;
head = to_app(h);
expr_ref tmp(m_manager);
as->mk_add(args.size(), args.c_ptr(), tmp);
tmp = m_arith.mk_add(args.size(), args.c_ptr());
if (inv)
as->mk_sub(tmp, rhs, def);
mk_sub(tmp, rhs, def);
else
as->mk_sub(rhs, tmp, def);
mk_sub(rhs, tmp, def);
TRACE("macro_util", tout << def << "\n";);
return true;
}

View file

@ -20,14 +20,10 @@ Revision History:
#ifndef MACRO_UTIL_H_
#define MACRO_UTIL_H_
#include"ast.h"
#include"obj_hashtable.h"
#include"simplifier.h"
class poly_simplifier_plugin;
class arith_simplifier_plugin;
class bv_simplifier_plugin;
class basic_simplifier_plugin;
#include "ast/ast.h"
#include "util/obj_hashtable.h"
#include "ast/rewriter/arith_rewriter.h"
#include "ast/rewriter/bv_rewriter.h"
class macro_util {
public:
@ -63,9 +59,9 @@ public:
private:
ast_manager & m_manager;
bv_util m_bv;
simplifier & m_simplifier;
arith_simplifier_plugin * m_arith_simp;
bv_simplifier_plugin * m_bv_simp;
arith_util m_arith;
mutable arith_rewriter m_arith_rw;
mutable bv_rewriter m_bv_rw;
obj_hashtable<func_decl> * m_forbidden_set;
bool is_forbidden(func_decl * f) const { return m_forbidden_set != 0 && m_forbidden_set->contains(f); }
@ -94,11 +90,9 @@ private:
public:
macro_util(ast_manager & m, simplifier & s);
macro_util(ast_manager & m);
void set_forbidden_set(obj_hashtable<func_decl> * s) { m_forbidden_set = s; }
arith_simplifier_plugin * get_arith_simp() const;
bv_simplifier_plugin * get_bv_simp() const;
bool is_macro_head(expr * n, unsigned num_decls) const;
bool is_left_simple_macro(expr * n, unsigned num_decls, app_ref & head, expr_ref & def) const;
@ -113,6 +107,8 @@ public:
return is_arith_macro(n, num_decls, head, def, inv);
}
bool is_zero_safe(expr * n) const;
bool is_var_plus_ground(expr * n, bool & inv, var * & v, expr_ref & t);
bool is_pseudo_head(expr * n, unsigned num_decls, app_ref & head, app_ref & t);
bool is_pseudo_predicate_macro(expr * n, app_ref & head, app_ref & t, expr_ref & def);
@ -137,7 +133,6 @@ public:
void mk_sub(expr * t1, expr * t2, expr_ref & r) const;
void mk_add(expr * t1, expr * t2, expr_ref & r) const;
void mk_add(unsigned num_args, expr * const * args, sort * s, expr_ref & r) const;
poly_simplifier_plugin * get_poly_simp_for(sort * s) const;
};
#endif

View file

@ -16,22 +16,22 @@ Author:
Revision History:
--*/
#include"quasi_macros.h"
#include"for_each_expr.h"
#include"ast_pp.h"
#include"uint_set.h"
#include"var_subst.h"
#include "ast/macros/quasi_macros.h"
#include "ast/for_each_expr.h"
#include "ast/ast_pp.h"
#include "util/uint_set.h"
#include "ast/rewriter/var_subst.h"
quasi_macros::quasi_macros(ast_manager & m, macro_manager & mm, simplifier & s) :
m_manager(m),
quasi_macros::quasi_macros(ast_manager & m, macro_manager & mm) :
m_manager(m),
m_macro_manager(mm),
m_simplifier(s),
m_rewriter(m),
m_new_vars(m),
m_new_eqs(m),
m_new_qsorts(m) {
}
quasi_macros::~quasi_macros() {
quasi_macros::~quasi_macros() {
}
void quasi_macros::find_occurrences(expr * e) {
@ -41,7 +41,7 @@ void quasi_macros::find_occurrences(expr * e) {
// we remember whether we have seen an expr once, or more than once;
// when we see it the second time, we don't have to visit it another time,
// as we are only interested in finding unique function applications.
// as we are only interested in finding unique function applications.
m_visited_once.reset();
m_visited_more.reset();
@ -64,8 +64,8 @@ void quasi_macros::find_occurrences(expr * e) {
if (is_non_ground_uninterp(cur)) {
func_decl * f = to_app(cur)->get_decl();
m_occurrences.insert_if_not_there(f, 0);
occurrences_map::iterator it = m_occurrences.find_iterator(f);
it->m_value++;
occurrences_map::iterator it = m_occurrences.find_iterator(f);
it->m_value++;
}
j = to_app(cur)->get_num_args();
while (j)
@ -84,16 +84,16 @@ bool quasi_macros::is_unique(func_decl * f) const {
return m_occurrences.find(f) == 1;
}
struct var_dep_proc {
struct var_dep_proc {
bit_vector m_bitset;
public:
var_dep_proc(quantifier * q) { m_bitset.resize(q->get_num_decls(), false); }
void operator()(var * n) { m_bitset.set(n->get_idx(), true); }
void operator()(quantifier * n) {}
void operator()(app * n) {}
bool all_used(void) {
bool all_used(void) {
for (unsigned i = 0; i < m_bitset.size() ; i++)
if (!m_bitset.get(i))
if (!m_bitset.get(i))
return false;
return true;
}
@ -101,7 +101,7 @@ public:
bool quasi_macros::fully_depends_on(app * a, quantifier * q) const {
// CMW: This checks whether all variables in q are used _somewhere_ deep down in the children of a
/* var_dep_proc proc(q);
for_each_expr(proc, a);
return proc.all_used(); */
@ -116,14 +116,14 @@ bool quasi_macros::fully_depends_on(app * a, quantifier * q) const {
}
for (unsigned i = 0; i < bitset.size() ; i++) {
if (!bitset.get(i))
if (!bitset.get(i))
return false;
}
return true;
}
bool quasi_macros::depends_on(expr * e, func_decl * f) const {
bool quasi_macros::depends_on(expr * e, func_decl * f) const {
ptr_vector<expr> todo;
expr_mark visited;
todo.push_back(e);
@ -133,12 +133,12 @@ bool quasi_macros::depends_on(expr * e, func_decl * f) const {
if (visited.is_marked(cur))
continue;
if (is_app(cur)) {
app * a = to_app(cur);
if (a->get_decl() == f)
if (a->get_decl() == f)
return true;
unsigned j = a->get_num_args();
while (j>0)
todo.push_back(a->get_arg(--j));
@ -151,7 +151,7 @@ bool quasi_macros::depends_on(expr * e, func_decl * f) const {
bool quasi_macros::is_quasi_macro(expr * e, app_ref & a, expr_ref & t) const {
// Our definition of a quasi-macro:
// Forall X. f[X] = T[X], where f[X] is a term starting with symbol f, f is uninterpreted,
// Forall X. f[X] = T[X], where f[X] is a term starting with symbol f, f is uninterpreted,
// 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;);
@ -165,14 +165,14 @@ bool quasi_macros::is_quasi_macro(expr * e, app_ref & a, expr_ref & t) const {
if (is_non_ground_uninterp(lhs) && is_unique(to_app(lhs)->get_decl()) &&
!depends_on(rhs, to_app(lhs)->get_decl()) && fully_depends_on(to_app(lhs), q)) {
a = to_app(lhs);
t = rhs;
t = rhs;
return true;
} else if (is_non_ground_uninterp(rhs) && is_unique(to_app(rhs)->get_decl()) &&
!depends_on(lhs, to_app(rhs)->get_decl()) && fully_depends_on(to_app(rhs), q)) {
!depends_on(lhs, to_app(rhs)->get_decl()) && fully_depends_on(to_app(rhs), q)) {
a = to_app(rhs);
t = lhs;
t = lhs;
return true;
}
}
} else if (m_manager.is_not(qe) && is_non_ground_uninterp(to_app(qe)->get_arg(0)) &&
is_unique(to_app(to_app(qe)->get_arg(0))->get_decl())) { // this is like f(...) = false
a = to_app(to_app(qe)->get_arg(0));
@ -189,7 +189,7 @@ bool quasi_macros::is_quasi_macro(expr * e, app_ref & a, expr_ref & t) const {
}
void quasi_macros::quasi_macro_to_macro(quantifier * q, app * a, expr * t, quantifier_ref & macro) {
m_new_var_names.reset();
m_new_var_names.reset();
m_new_vars.reset();
m_new_qsorts.reset();
m_new_eqs.reset();
@ -197,19 +197,19 @@ void quasi_macros::quasi_macro_to_macro(quantifier * q, app * a, expr * t, quant
func_decl * f = a->get_decl();
// CMW: we rely on the fact that all variables in q appear at least once as
// a direct argument of `a'.
// a direct argument of `a'.
bit_vector v_seen;
v_seen.resize(q->get_num_decls(), false);
v_seen.resize(q->get_num_decls(), false);
for (unsigned i = 0 ; i < a->get_num_args() ; i++) {
if (!is_var(a->get_arg(i)) ||
if (!is_var(a->get_arg(i)) ||
v_seen.get(to_var(a->get_arg(i))->get_idx())) {
unsigned inx = m_new_var_names.size();
m_new_name.str("");
m_new_name << "X" << inx;
m_new_var_names.push_back(symbol(m_new_name.str().c_str()));
m_new_var_names.push_back(symbol(m_new_name.str().c_str()));
m_new_qsorts.push_back(f->get_domain()[i]);
m_new_vars.push_back(m_manager.mk_var(inx + q->get_num_decls(), f->get_domain()[i]));
m_new_eqs.push_back(m_manager.mk_eq(m_new_vars.back(), a->get_arg(i)));
} else {
@ -228,13 +228,13 @@ void quasi_macros::quasi_macro_to_macro(quantifier * q, app * a, expr * t, quant
new_var_names_rev.push_back(m_new_var_names.get(i));
new_qsorts_rev.push_back(m_new_qsorts.get(i));
}
// We want to keep all the old variables [already reversed]
for (unsigned i = 0 ; i < q->get_num_decls() ; i++) {
new_var_names_rev.push_back(q->get_decl_name(i));
new_qsorts_rev.push_back(q->get_decl_sort(i));
}
// Macro := Forall m_new_vars . appl = ITE( m_new_eqs, t, f_else)
app_ref appl(m_manager);
@ -251,21 +251,59 @@ 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(true, new_var_names_rev.size(),
new_qsorts_rev.c_ptr(), new_var_names_rev.c_ptr(), eq);
}
bool quasi_macros::find_macros(unsigned n, expr * const * exprs) {
TRACE("quasi_macros", tout << "Finding quasi-macros in: " << std::endl;
for (unsigned i = 0 ; i < n ; i++)
for (unsigned i = 0 ; i < n ; i++)
tout << i << ": " << mk_pp(exprs[i], m_manager) << std::endl; );
bool res = false;
m_occurrences.reset();
// Find out how many non-ground appearences for each uninterpreted function there are
for (unsigned i = 0 ; i < n ; i++)
find_occurrences(exprs[i]);
TRACE("quasi_macros",
tout << "Occurrences: " << std::endl;
for (auto & kd : m_occurrences)
tout << kd.m_key->get_name() << ": " << kd.m_value << std::endl; );
// Find all macros
for (unsigned i = 0 ; i < n ; i++) {
app_ref a(m_manager);
expr_ref t(m_manager);
if (is_quasi_macro(exprs[i], a, t)) {
quantifier_ref macro(m_manager);
quasi_macro_to_macro(to_quantifier(exprs[i]), a, t, macro);
TRACE("quasi_macros", tout << "Found quasi macro: " << mk_pp(exprs[i], m_manager) << std::endl;
tout << "Macro: " << mk_pp(macro, m_manager) << std::endl; );
proof * pr = 0;
if (m_manager.proofs_enabled())
pr = m_manager.mk_def_axiom(macro);
expr_dependency * dep = 0;
if (m_macro_manager.insert(a->get_decl(), macro, pr, dep))
res = true;
}
}
return res;
}
bool quasi_macros::find_macros(unsigned n, justified_expr const * exprs) {
TRACE("quasi_macros", tout << "Finding quasi-macros in: " << std::endl;
for (unsigned i = 0 ; i < n ; i++)
tout << i << ": " << mk_pp(exprs[i].get_fml(), m_manager) << std::endl; );
bool res = false;
m_occurrences.reset();
// Find out how many non-ground appearences for each uninterpreted function there are
for ( unsigned i = 0 ; i < n ; i++ )
find_occurrences(exprs[i]);
find_occurrences(exprs[i].get_fml());
TRACE("quasi_macros", tout << "Occurrences: " << std::endl;
for (occurrences_map::iterator it = m_occurrences.begin();
@ -277,10 +315,10 @@ bool quasi_macros::find_macros(unsigned n, expr * const * exprs) {
for ( unsigned i = 0 ; i < n ; i++ ) {
app_ref a(m_manager);
expr_ref t(m_manager);
if (is_quasi_macro(exprs[i], a, t)) {
if (is_quasi_macro(exprs[i].get_fml(), a, t)) {
quantifier_ref macro(m_manager);
quasi_macro_to_macro(to_quantifier(exprs[i]), a, t, macro);
TRACE("quasi_macros", tout << "Found quasi macro: " << mk_pp(exprs[i], m_manager) << std::endl;
quasi_macro_to_macro(to_quantifier(exprs[i].get_fml()), a, t, macro);
TRACE("quasi_macros", tout << "Found quasi macro: " << mk_pp(exprs[i].get_fml(), m_manager) << std::endl;
tout << "Macro: " << mk_pp(macro, m_manager) << std::endl; );
proof * pr = 0;
if (m_manager.proofs_enabled())
@ -293,28 +331,57 @@ bool quasi_macros::find_macros(unsigned n, expr * const * exprs) {
return res;
}
void quasi_macros::apply_macros(unsigned n, expr * const * exprs, proof * const * prs, expr_ref_vector & new_exprs, proof_ref_vector & new_prs) {
void quasi_macros::apply_macros(unsigned n, expr * const * exprs, proof * const * prs, expr_dependency * const* deps, expr_ref_vector & new_exprs, proof_ref_vector & new_prs, expr_dependency_ref_vector& new_deps) {
for ( unsigned i = 0 ; i < n ; i++ ) {
expr_ref r(m_manager), rs(m_manager);
proof_ref pr(m_manager), ps(m_manager);
expr_dependency_ref dep(m_manager);
proof * p = m_manager.proofs_enabled() ? prs[i] : 0;
m_macro_manager.expand_macros(exprs[i], p, r, pr);
m_simplifier(r, rs, ps);
new_exprs.push_back(rs);
m_macro_manager.expand_macros(exprs[i], p, deps[i], r, pr, dep);
m_rewriter(r);
new_exprs.push_back(r);
new_prs.push_back(ps);
new_deps.push_back(dep);
}
}
bool quasi_macros::operator()(unsigned n, expr * const * exprs, proof * const * prs, expr_ref_vector & new_exprs, proof_ref_vector & new_prs) {
bool quasi_macros::operator()(unsigned n, expr * const * exprs, proof * const * prs, expr_dependency * const * deps, expr_ref_vector & new_exprs, proof_ref_vector & new_prs, expr_dependency_ref_vector & new_deps) {
if (find_macros(n, exprs)) {
apply_macros(n, exprs, prs, new_exprs, new_prs);
apply_macros(n, exprs, prs, deps, new_exprs, new_prs, new_deps);
return true;
}
else {
// just copy them over
for ( unsigned i = 0 ; i < n ; i++ ) {
new_exprs.push_back(exprs[i]);
if (m_manager.proofs_enabled())
new_prs.push_back(prs[i]);
}
return false;
}
}
void quasi_macros::apply_macros(unsigned n, justified_expr const* fmls, vector<justified_expr>& new_fmls) {
for ( unsigned i = 0 ; i < n ; i++ ) {
expr_ref r(m_manager), rs(m_manager);
proof_ref pr(m_manager), ps(m_manager);
proof * p = m_manager.proofs_enabled() ? fmls[i].get_proof() : 0;
expr_dependency_ref dep(m_manager);
m_macro_manager.expand_macros(fmls[i].get_fml(), p, 0, r, pr, dep);
m_rewriter(r);
new_fmls.push_back(justified_expr(m_manager, r, pr));
}
}
bool quasi_macros::operator()(unsigned n, justified_expr const* fmls, vector<justified_expr>& new_fmls) {
if (find_macros(n, fmls)) {
apply_macros(n, fmls, new_fmls);
return true;
} else {
// just copy them over
for ( unsigned i = 0 ; i < n ; i++ ) {
new_exprs.push_back(exprs[i]);
if (m_manager.proofs_enabled())
new_prs.push_back(prs[i]);
new_fmls.push_back(fmls[i]);
}
return false;
}

View file

@ -20,9 +20,9 @@ Revision History:
#define QUASI_MACROS_H_
#include<sstream>
#include"macro_manager.h"
#include"basic_simplifier_plugin.h"
#include"simplifier.h"
#include "ast/justified_expr.h"
#include "ast/macros/macro_manager.h"
#include "ast/rewriter/th_rewriter.h"
/**
\brief Finds quasi macros and applies them.
@ -32,38 +32,44 @@ class quasi_macros {
ast_manager & m_manager;
macro_manager & m_macro_manager;
simplifier & m_simplifier;
th_rewriter m_rewriter;
occurrences_map m_occurrences;
ptr_vector<expr> m_todo;
ptr_vector<expr> m_todo;
vector<symbol> m_new_var_names;
expr_ref_vector m_new_vars;
expr_ref_vector m_new_eqs;
sort_ref_vector m_new_qsorts;
std::stringstream m_new_name;
std::stringstream m_new_name;
expr_mark m_visited_once;
expr_mark m_visited_more;
bool is_unique(func_decl * f) const;
bool is_non_ground_uninterp(expr const * e) const;
bool fully_depends_on(app * a, quantifier * q) const;
bool fully_depends_on(app * a, quantifier * q) const;
bool depends_on(expr * e, func_decl * f) const;
bool is_quasi_macro(expr * e, app_ref & a, expr_ref &v) const;
bool is_quasi_macro(expr * e, app_ref & a, expr_ref &v) const;
void quasi_macro_to_macro(quantifier * q, app * a, expr * t, quantifier_ref & macro);
void find_occurrences(expr * e);
bool find_macros(unsigned n, expr * const * exprs);
void apply_macros(unsigned n, expr * const * exprs, proof * const * prs, expr_ref_vector & new_exprs, proof_ref_vector & new_prs);
bool find_macros(unsigned n, justified_expr const* expr);
void apply_macros(unsigned n, expr * const * exprs, proof * const * prs, expr_dependency * const* deps,
expr_ref_vector & new_exprs, proof_ref_vector & new_prs, expr_dependency_ref_vector& new_deps);
void apply_macros(unsigned n, justified_expr const* fmls, vector<justified_expr>& new_fmls);
public:
quasi_macros(ast_manager & m, macro_manager & mm, simplifier & s);
quasi_macros(ast_manager & m, macro_manager & mm);
~quasi_macros();
/**
\brief Find pure function macros and apply them.
*/
bool operator()(unsigned n, expr * const * exprs, proof * const * prs, expr_ref_vector & new_exprs, proof_ref_vector & new_prs);
// bool operator()(unsigned n, expr * const * exprs, proof * const * prs, expr_ref_vector & new_exprs, proof_ref_vector & new_prs);
bool operator()(unsigned n, justified_expr const* fmls, vector<justified_expr>& new_fmls);
bool operator()(unsigned n, expr * const * exprs, proof * const * prs, expr_dependency * const * deps, expr_ref_vector & new_exprs, proof_ref_vector & new_prs, expr_dependency_ref_vector & new_deps);
};
#endif

View file

@ -16,12 +16,12 @@ Author:
Revision History:
--*/
#include"defined_names.h"
#include"obj_hashtable.h"
#include"used_vars.h"
#include"var_subst.h"
#include"ast_smt2_pp.h"
#include"ast_pp.h"
#include "ast/normal_forms/defined_names.h"
#include "util/obj_hashtable.h"
#include "ast/used_vars.h"
#include "ast/rewriter/var_subst.h"
#include "ast/ast_smt2_pp.h"
#include "ast/ast_pp.h"
struct defined_names::impl {
typedef obj_map<expr, app *> expr2name;

View file

@ -20,7 +20,7 @@ Revision History:
#ifndef DEFINED_NAMES_H_
#define DEFINED_NAMES_H_
#include"ast.h"
#include "ast/ast.h"
/**
\brief Mapping from expressions to skolem functions that are used to name them.

View file

@ -16,9 +16,9 @@ Author:
Notes:
--*/
#include"name_exprs.h"
#include"rewriter_def.h"
#include"ast_smt2_pp.h"
#include "ast/normal_forms/name_exprs.h"
#include "ast/rewriter/rewriter_def.h"
#include "ast/ast_smt2_pp.h"
class name_exprs_core : public name_exprs {
struct cfg : public default_rewriter_cfg {

View file

@ -19,8 +19,8 @@ Notes:
#ifndef NAME_EXPRS_H_
#define NAME_EXPRS_H_
#include"ast.h"
#include"defined_names.h"
#include "ast/ast.h"
#include "ast/normal_forms/defined_names.h"
class expr_predicate {
public:

View file

@ -17,18 +17,18 @@ Notes:
Major revision on 2011-10-06
--*/
#include"nnf.h"
#include"nnf_params.hpp"
#include"warning.h"
#include"used_vars.h"
#include"well_sorted.h"
#include"var_subst.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"name_exprs.h"
#include"act_cache.h"
#include"cooperate.h"
#include "ast/normal_forms/name_exprs.h"
#include "ast/act_cache.h"
#include "util/cooperate.h"
#include"ast_smt2_pp.h"
#include "ast/ast_smt2_pp.h"
/**
\brief NNF translation mode. The cheapest mode is NNF_SKOLEM, and

View file

@ -20,9 +20,9 @@ Notes:
#ifndef NNF_H_
#define NNF_H_
#include"ast.h"
#include"params.h"
#include"defined_names.h"
#include "ast/ast.h"
#include "util/params.h"
#include "ast/normal_forms/defined_names.h"
class nnf {
struct imp;

View file

@ -16,10 +16,10 @@ Author:
Notes:
--*/
#include"pull_quant.h"
#include"var_subst.h"
#include"rewriter_def.h"
#include"ast_pp.h"
#include "ast/normal_forms/pull_quant.h"
#include "ast/rewriter/var_subst.h"
#include "ast/rewriter/rewriter_def.h"
#include "ast/ast_pp.h"
struct pull_quant::imp {

View file

@ -19,7 +19,7 @@ Notes:
#ifndef PULL_QUANT_H_
#define PULL_QUANT_H_
#include"ast.h"
#include "ast/ast.h"
/**
\brief Pull nested quantifiers in a formula.

View file

@ -17,7 +17,7 @@ Revision History:
--*/
#include"num_occurs.h"
#include "ast/num_occurs.h"
void num_occurs::process(expr * t, expr_fast_mark1 & visited) {
ptr_buffer<expr, 128> stack;

View file

@ -19,8 +19,8 @@ Revision History:
#ifndef NUM_OCCURS_H_
#define NUM_OCCURS_H_
#include"ast.h"
#include"obj_hashtable.h"
#include "ast/ast.h"
#include "util/obj_hashtable.h"
/**
\brief Functor for computing the number of occurrences of each sub-expression in a expression F.

View file

@ -16,9 +16,9 @@ Author:
Revision History:
--*/
#include"occurs.h"
#include "ast/occurs.h"
#include"for_each_expr.h"
#include "ast/for_each_expr.h"
// -----------------------------------
//

View file

@ -29,7 +29,7 @@ z3_add_component(pattern
${CMAKE_CURRENT_BINARY_DIR}/database.h
COMPONENT_DEPENDENCIES
normal_forms
simplifier
rewriter
smt2parser
PYG_FILES
pattern_inference_params_helper.pyg

View file

@ -29,13 +29,13 @@ Notes:
--*/
#include"ast.h"
#include"expr_pattern_match.h"
#include"for_each_ast.h"
#include"ast_ll_pp.h"
#include"ast_pp.h"
#include"cmd_context.h"
#include"smt2parser.h"
#include "ast/ast.h"
#include "ast/pattern/expr_pattern_match.h"
#include "ast/for_each_ast.h"
#include "ast/ast_ll_pp.h"
#include "ast/ast_pp.h"
#include "cmd_context/cmd_context.h"
#include "parsers/smt2/smt2parser.h"
expr_pattern_match::expr_pattern_match(ast_manager & manager):
m_manager(manager), m_precompiled(manager) {

View file

@ -20,8 +20,8 @@ Notes:
#ifndef EXPR_PATTERN_MATCH_H_
#define EXPR_PATTERN_MATCH_H_
#include"ast.h"
#include"map.h"
#include "ast/ast.h"
#include "util/map.h"
class expr_pattern_match {

View file

@ -16,15 +16,17 @@ Author:
Revision History:
--*/
#include"pattern_inference.h"
#include"ast_ll_pp.h"
#include"ast_pp.h"
#include"ast_util.h"
#include"warning.h"
#include"arith_decl_plugin.h"
#include"pull_quant.h"
#include"well_sorted.h"
#include"for_each_expr.h"
#include "util/warning.h"
#include "ast/pattern/pattern_inference.h"
#include "ast/ast_ll_pp.h"
#include "ast/ast_pp.h"
#include "ast/ast_util.h"
#include "ast/arith_decl_plugin.h"
#include "ast/normal_forms/pull_quant.h"
#include "ast/well_sorted.h"
#include "ast/for_each_expr.h"
#include "ast/rewriter/rewriter_def.h"
void smaller_pattern::save(expr * p1, expr * p2) {
expr_pair e(p1, p2);
@ -54,7 +56,7 @@ bool smaller_pattern::process(expr * p1, expr * p2) {
unsigned num1 = app1->get_num_args();
if (num1 != app2->get_num_args() || app1->get_decl() != app2->get_decl())
return false;
for (unsigned i = 0; i < num1; i++)
for (unsigned i = 0; i < num1; i++)
save(app1->get_arg(i), app2->get_arg(i));
break;
}
@ -67,7 +69,7 @@ bool smaller_pattern::process(expr * p1, expr * p2) {
return false;
}
// it is a variable bound by an external quantifier
else if (p1 != p2)
else if (p1 != p2)
return false;
break;
}
@ -87,8 +89,20 @@ bool smaller_pattern::operator()(unsigned num_bindings, expr * p1, expr * p2) {
return process(p1, p2);
}
pattern_inference::pattern_inference(ast_manager & m, pattern_inference_params & params):
simplifier(m),
#ifdef _TRACE
static void dump_app_vector(std::ostream & out, ptr_vector<app> const & v, ast_manager & m) {
for (app * e : v)
out << mk_pp(e, m) << "\n";
}
#endif
#include "ast/pattern/database.h"
pattern_inference_cfg::pattern_inference_cfg(ast_manager & m, pattern_inference_params & params):
m(m),
m_params(params),
m_bfid(m.get_basic_family_id()),
m_afid(m.mk_family_id("arith")),
@ -102,10 +116,9 @@ pattern_inference::pattern_inference(ast_manager & m, pattern_inference_params &
m_database(m) {
if (params.m_pi_arith == AP_NO)
register_forbidden_family(m_afid);
enable_ac_support(false);
}
void pattern_inference::collect::operator()(expr * n, unsigned num_bindings) {
void pattern_inference_cfg::collect::operator()(expr * n, unsigned num_bindings) {
SASSERT(m_info.empty());
SASSERT(m_todo.empty());
SASSERT(m_cache.empty());
@ -125,7 +138,7 @@ void pattern_inference::collect::operator()(expr * n, unsigned num_bindings) {
reset();
}
inline void pattern_inference::collect::visit(expr * n, unsigned delta, bool & visited) {
inline void pattern_inference_cfg::collect::visit(expr * n, unsigned delta, bool & visited) {
entry e(n, delta);
if (!m_cache.contains(e)) {
m_todo.push_back(e);
@ -133,11 +146,11 @@ inline void pattern_inference::collect::visit(expr * n, unsigned delta, bool & v
}
}
bool pattern_inference::collect::visit_children(expr * n, unsigned delta) {
bool pattern_inference_cfg::collect::visit_children(expr * n, unsigned delta) {
bool visited = true;
unsigned i;
switch (n->get_kind()) {
case AST_APP:
case AST_APP:
i = to_app(n)->get_num_args();
while (i > 0) {
--i;
@ -153,13 +166,13 @@ bool pattern_inference::collect::visit_children(expr * n, unsigned delta) {
return visited;
}
inline void pattern_inference::collect::save(expr * n, unsigned delta, info * i) {
inline void pattern_inference_cfg::collect::save(expr * n, unsigned delta, info * i) {
m_cache.insert(entry(n, delta), i);
if (i != 0)
m_info.push_back(i);
}
void pattern_inference::collect::save_candidate(expr * n, unsigned delta) {
void pattern_inference_cfg::collect::save_candidate(expr * n, unsigned delta) {
switch (n->get_kind()) {
case AST_VAR: {
unsigned idx = to_var(n)->get_idx();
@ -187,14 +200,14 @@ void pattern_inference::collect::save_candidate(expr * n, unsigned delta) {
save(n, delta, 0);
return;
}
if (c->get_num_args() == 0) {
save(n, delta, alloc(info, m, n, uint_set(), 1));
return;
}
ptr_buffer<expr> buffer;
bool changed = false; // false if none of the children is mapped to a node different from itself.
bool changed = false; // false if none of the children is mapped to a node different from itself.
uint_set free_vars;
unsigned size = 1;
unsigned num = c->get_num_args();
@ -216,7 +229,7 @@ void pattern_inference::collect::save_candidate(expr * n, unsigned delta) {
if (child != child_info->m_node.get())
changed = true;
}
app * new_node = 0;
if (changed)
new_node = m.mk_app(decl, buffer.size(), buffer.c_ptr());
@ -229,11 +242,11 @@ void pattern_inference::collect::save_candidate(expr * n, unsigned delta) {
//
// Remark: The rule above has an exception. The operators (div, idiv, mod) are allowed to be
// used as patterns even when they are not nested in other terms. The motivation is that
// Z3 currently doesn't implement them (i.e., they are uninterpreted). So, some users add axioms
// Z3 currently doesn't implement them (i.e., they are uninterpreted). So, some users add axioms
// stating properties about these operators.
family_id fid = c->get_family_id();
decl_kind k = c->get_decl_kind();
if (!free_vars.empty() &&
if (!free_vars.empty() &&
(fid != m_afid || (fid == m_afid && !m_owner.m_nested_arith_only && (k == OP_DIV || k == OP_IDIV || k == OP_MOD || k == OP_REM || k == OP_MUL)))) {
TRACE("pattern_inference", tout << "potential candidate: \n" << mk_pp(new_node, m) << "\n";);
m_owner.add_candidate(new_node, free_vars, size);
@ -247,14 +260,14 @@ void pattern_inference::collect::save_candidate(expr * n, unsigned delta) {
}
void pattern_inference::collect::reset() {
void pattern_inference_cfg::collect::reset() {
m_cache.reset();
std::for_each(m_info.begin(), m_info.end(), delete_proc<info>());
m_info.reset();
SASSERT(m_todo.empty());
}
void pattern_inference::add_candidate(app * n, uint_set const & free_vars, unsigned size) {
void pattern_inference_cfg::add_candidate(app * n, uint_set const & free_vars, unsigned size) {
for (unsigned i = 0; i < m_num_no_patterns; i++) {
if (n == m_no_patterns[i])
return;
@ -271,7 +284,7 @@ void pattern_inference::add_candidate(app * n, uint_set const & free_vars, unsig
\brief Copy the non-looping patterns in m_candidates to result when m_params.m_pi_block_loop_patterns = true.
Otherwise, copy m_candidates to result.
*/
void pattern_inference::filter_looping_patterns(ptr_vector<app> & result) {
void pattern_inference_cfg::filter_looping_patterns(ptr_vector<app> & result) {
unsigned num = m_candidates.size();
for (unsigned i1 = 0; i1 < num; i1++) {
app * n1 = m_candidates.get(i1);
@ -288,7 +301,7 @@ void pattern_inference::filter_looping_patterns(ptr_vector<app> & result) {
uint_set const & s2 = e2->get_data().m_value.m_free_vars;
// Remark: the comparison operator only makes sense if both AST nodes
// contain the same number of variables.
// Example:
// Example:
// (f X Y) <: (f (g X Z W) Y)
if (s1 == s2 && m_le(m_num_bindings, n1, n2) && !m_le(m_num_bindings, n2, n1)) {
smaller = true;
@ -310,7 +323,7 @@ void pattern_inference::filter_looping_patterns(ptr_vector<app> & result) {
inline void pattern_inference::contains_subpattern::save(expr * n) {
inline void pattern_inference_cfg::contains_subpattern::save(expr * n) {
unsigned id = n->get_id();
m_already_processed.assure_domain(id);
if (!m_already_processed.contains(id)) {
@ -319,7 +332,7 @@ inline void pattern_inference::contains_subpattern::save(expr * n) {
}
}
bool pattern_inference::contains_subpattern::operator()(expr * n) {
bool pattern_inference_cfg::contains_subpattern::operator()(expr * n) {
m_already_processed.reset();
m_todo.reset();
expr2info::obj_map_entry * _e = m_owner.m_candidates_info.find_core(n);
@ -360,7 +373,7 @@ bool pattern_inference::contains_subpattern::operator()(expr * n) {
Return true if n contains a direct/indirect child that is also a
pattern, and contains the same number of free variables.
*/
inline bool pattern_inference::contains_subpattern(expr * n) {
inline bool pattern_inference_cfg::contains_subpattern(expr * n) {
return m_contains_subpattern(n);
}
@ -372,18 +385,15 @@ inline bool pattern_inference::contains_subpattern(expr * n) {
Remark: Every pattern p in patterns is also a member of
m_pattern_map.
*/
void pattern_inference::filter_bigger_patterns(ptr_vector<app> const & patterns, ptr_vector<app> & result) {
ptr_vector<app>::const_iterator it = patterns.begin();
ptr_vector<app>::const_iterator end = patterns.end();
for (; it != end; ++it) {
app * curr = *it;
void pattern_inference_cfg::filter_bigger_patterns(ptr_vector<app> const & patterns, ptr_vector<app> & result) {
for (app * curr : patterns) {
if (!contains_subpattern(curr))
result.push_back(curr);
}
}
bool pattern_inference::pattern_weight_lt::operator()(expr * n1, expr * n2) const {
bool pattern_inference_cfg::pattern_weight_lt::operator()(expr * n1, expr * n2) const {
expr2info::obj_map_entry * e1 = m_candidates_info.find_core(n1);
expr2info::obj_map_entry * e2 = m_candidates_info.find_core(n2);
SASSERT(e1 != 0);
@ -401,13 +411,10 @@ bool pattern_inference::pattern_weight_lt::operator()(expr * n1, expr * n2) cons
variables, then it is copied to remaining_candidate_patterns. The
new patterns are stored in result.
*/
void pattern_inference::candidates2unary_patterns(ptr_vector<app> const & candidate_patterns,
void pattern_inference_cfg::candidates2unary_patterns(ptr_vector<app> const & candidate_patterns,
ptr_vector<app> & remaining_candidate_patterns,
app_ref_buffer & result) {
ptr_vector<app>::const_iterator it = candidate_patterns.begin();
ptr_vector<app>::const_iterator end = candidate_patterns.end();
for (; it != end; ++it) {
app * candidate = *it;
for (app * candidate : candidate_patterns) {
expr2info::obj_map_entry * e = m_candidates_info.find_core(candidate);
info const & i = e->get_data().m_value;
if (i.m_free_vars.num_elems() == m_num_bindings) {
@ -421,12 +428,12 @@ void pattern_inference::candidates2unary_patterns(ptr_vector<app> const & candid
}
// TODO: this code is too inefficient when the number of candidate
// patterns is too big.
// patterns is too big.
// HACK: limit the number of case-splits:
#define MAX_SPLITS 32
void pattern_inference::candidates2multi_patterns(unsigned max_num_patterns,
ptr_vector<app> const & candidate_patterns,
void pattern_inference_cfg::candidates2multi_patterns(unsigned max_num_patterns,
ptr_vector<app> const & candidate_patterns,
app_ref_buffer & result) {
SASSERT(!candidate_patterns.empty());
m_pre_patterns.push_back(alloc(pre_pattern));
@ -464,31 +471,23 @@ void pattern_inference::candidates2multi_patterns(unsigned max_num_patterns,
m_pre_patterns.push_back(curr);
}
}
TRACE("pattern_inference", tout << "m_pre_patterns.size(): " << m_pre_patterns.size() <<
TRACE("pattern_inference", tout << "m_pre_patterns.size(): " << m_pre_patterns.size() <<
"\nnum_splits: " << num_splits << "\n";);
}
}
void pattern_inference::reset_pre_patterns() {
void pattern_inference_cfg::reset_pre_patterns() {
std::for_each(m_pre_patterns.begin(), m_pre_patterns.end(), delete_proc<pre_pattern>());
m_pre_patterns.reset();
}
#ifdef _TRACE
static void dump_app_vector(std::ostream & out, ptr_vector<app> const & v, ast_manager & m) {
ptr_vector<app>::const_iterator it = v.begin();
ptr_vector<app>::const_iterator end = v.end();
for (; it != end; ++it)
out << mk_pp(*it, m) << "\n";
}
#endif
bool pattern_inference::is_forbidden(app * n) const {
bool pattern_inference_cfg::is_forbidden(app * n) const {
func_decl const * decl = n->get_decl();
if (is_ground(n))
return false;
// Remark: skolem constants should not be used in patterns, since they do not
// occur outside of the quantifier. That is, Z3 will never match this kind of
// Remark: skolem constants should not be used in patterns, since they do not
// occur outside of the quantifier. That is, Z3 will never match this kind of
// pattern.
if (m_params.m_pi_avoid_skolems && decl->is_skolem()) {
CTRACE("pattern_inference_skolem", decl->is_skolem(), tout << "ignoring: " << mk_pp(n, m) << "\n";);
@ -499,14 +498,11 @@ bool pattern_inference::is_forbidden(app * n) const {
return false;
}
bool pattern_inference::has_preferred_patterns(ptr_vector<app> & candidate_patterns, app_ref_buffer & result) {
bool pattern_inference_cfg::has_preferred_patterns(ptr_vector<app> & candidate_patterns, app_ref_buffer & result) {
if (m_preferred.empty())
return false;
bool found = false;
ptr_vector<app>::const_iterator it = candidate_patterns.begin();
ptr_vector<app>::const_iterator end = candidate_patterns.end();
for (; it != end; ++it) {
app * candidate = *it;
for (app * candidate : candidate_patterns) {
if (m_preferred.contains(to_app(candidate)->get_decl())) {
expr2info::obj_map_entry * e = m_candidates_info.find_core(candidate);
info const & i = e->get_data().m_value;
@ -521,9 +517,9 @@ bool pattern_inference::has_preferred_patterns(ptr_vector<app> & candidate_patte
return found;
}
void pattern_inference::mk_patterns(unsigned num_bindings,
expr * n,
unsigned num_no_patterns,
void pattern_inference_cfg::mk_patterns(unsigned num_bindings,
expr * n,
unsigned num_no_patterns,
expr * const * no_patterns,
app_ref_buffer & result) {
m_num_bindings = num_bindings;
@ -532,7 +528,7 @@ void pattern_inference::mk_patterns(unsigned num_bindings,
m_collect(n, num_bindings);
TRACE("pattern_inference",
TRACE("pattern_inference",
tout << mk_pp(n, m);
tout << "\ncandidates:\n";
unsigned num = m_candidates.size();
@ -558,7 +554,7 @@ void pattern_inference::mk_patterns(unsigned num_bindings,
m_tmp1.reset();
candidates2unary_patterns(m_tmp2, m_tmp1, result);
unsigned num_extra_multi_patterns = m_params.m_pi_max_multi_patterns;
if (result.empty())
if (result.empty())
num_extra_multi_patterns++;
if (num_extra_multi_patterns > 0 && !m_tmp1.empty()) {
// m_pattern_weight_lt is not a total order
@ -576,75 +572,63 @@ void pattern_inference::mk_patterns(unsigned num_bindings,
m_candidates.reset();
}
#include"database.h" // defines g_pattern_database
void pattern_inference::reduce1_quantifier(quantifier * q) {
bool pattern_inference_cfg::reduce_quantifier(
quantifier * q,
expr * new_body,
expr * const *, // new_patterns
expr * const * new_no_patterns,
expr_ref & result,
proof_ref & result_pr) {
TRACE("pattern_inference", tout << "processing:\n" << mk_pp(q, m) << "\n";);
if (!q->is_forall()) {
simplifier::reduce1_quantifier(q);
return;
return false;
}
int weight = q->get_weight();
if (m_params.m_pi_use_database) {
m_database.initialize(g_pattern_database);
app_ref_vector new_patterns(m);
m_database.initialize(g_pattern_database);
unsigned new_weight;
if (m_database.match_quantifier(q, new_patterns, new_weight)) {
#ifdef Z3DEBUG
for (unsigned i = 0; i < new_patterns.size(); i++) { SASSERT(is_well_sorted(m, new_patterns.get(i))); }
#endif
DEBUG_CODE(for (unsigned i = 0; i < new_patterns.size(); i++) { SASSERT(is_well_sorted(m, new_patterns.get(i))); });
quantifier_ref new_q(m);
if (q->get_num_patterns() > 0) {
// just update the weight...
TRACE("pattern_inference", tout << "updating weight to: " << new_weight << "\n" << mk_pp(q, m) << "\n";);
new_q = m.update_quantifier_weight(q, new_weight);
result = m.update_quantifier_weight(q, new_weight);
}
else {
quantifier_ref tmp(m);
tmp = m.update_quantifier(q, new_patterns.size(), (expr**) new_patterns.c_ptr(), q->get_expr());
new_q = m.update_quantifier_weight(tmp, new_weight);
tmp = m.update_quantifier(q, new_patterns.size(), (expr**) new_patterns.c_ptr(), q->get_expr());
result = m.update_quantifier_weight(tmp, new_weight);
TRACE("pattern_inference", tout << "found patterns in database, weight: " << new_weight << "\n" << mk_pp(new_q, m) << "\n";);
}
proof * pr = 0;
if (m.fine_grain_proofs())
pr = m.mk_rewrite(q, new_q);
cache_result(q, new_q, pr);
return;
result_pr = m.mk_rewrite(q, new_q);
return true;
}
}
if (q->get_num_patterns() > 0) {
simplifier::reduce1_quantifier(q);
return;
return false;
}
if (m_params.m_pi_nopat_weight >= 0)
weight = m_params.m_pi_nopat_weight;
SASSERT(q->get_num_patterns() == 0);
expr * new_body;
proof * new_body_pr;
get_cached(q->get_expr(), new_body, new_body_pr);
ptr_buffer<expr> new_no_patterns;
unsigned num_no_patterns = q->get_num_no_patterns();
for (unsigned i = 0; i < num_no_patterns; i++) {
expr * new_pattern;
proof * new_pattern_pr;
get_cached(q->get_no_pattern(i), new_pattern, new_pattern_pr);
new_no_patterns.push_back(new_pattern);
}
app_ref_buffer new_patterns(m);
if (m_params.m_pi_arith == AP_CONSERVATIVE)
m_forbidden.push_back(m_afid);
mk_patterns(q->get_num_decls(), new_body, new_no_patterns.size(), new_no_patterns.c_ptr(), new_patterns);
if (new_patterns.empty() && !new_no_patterns.empty()) {
app_ref_buffer new_patterns(m);
unsigned num_no_patterns = q->get_num_no_patterns();
mk_patterns(q->get_num_decls(), new_body, num_no_patterns, new_no_patterns, new_patterns);
if (new_patterns.empty() && num_no_patterns > 0) {
if (new_patterns.empty()) {
mk_patterns(q->get_num_decls(), new_body, 0, 0, new_patterns);
if (m_params.m_pi_warnings && !new_patterns.empty()) {
@ -652,65 +636,61 @@ void pattern_inference::reduce1_quantifier(quantifier * q) {
}
}
}
if (m_params.m_pi_arith == AP_CONSERVATIVE) {
m_forbidden.pop_back();
if (new_patterns.empty()) {
flet<bool> l1(m_block_loop_patterns, false); // allow looping patterns
mk_patterns(q->get_num_decls(), new_body, new_no_patterns.size(), new_no_patterns.c_ptr(), new_patterns);
mk_patterns(q->get_num_decls(), new_body, num_no_patterns, new_no_patterns, new_patterns);
if (!new_patterns.empty()) {
weight = std::max(weight, static_cast<int>(m_params.m_pi_arith_weight));
if (m_params.m_pi_warnings) {
warning_msg("using arith. in pattern (quantifier id: %s), the weight was increased to %d (this value can be modified using PI_ARITH_WEIGHT=<val>).",
warning_msg("using arith. in pattern (quantifier id: %s), the weight was increased to %d (this value can be modified using PI_ARITH_WEIGHT=<val>).",
q->get_qid().str().c_str(), weight);
}
}
}
}
if (m_params.m_pi_arith != AP_NO && new_patterns.empty()) {
if (new_patterns.empty()) {
flet<bool> l1(m_nested_arith_only, false); // try to find a non-nested arith pattern
flet<bool> l2(m_block_loop_patterns, false); // allow looping patterns
mk_patterns(q->get_num_decls(), new_body, new_no_patterns.size(), new_no_patterns.c_ptr(), new_patterns);
mk_patterns(q->get_num_decls(), new_body, num_no_patterns, new_no_patterns, new_patterns);
if (!new_patterns.empty()) {
weight = std::max(weight, static_cast<int>(m_params.m_pi_non_nested_arith_weight));
if (m_params.m_pi_warnings) {
warning_msg("using non nested arith. pattern (quantifier id: %s), the weight was increased to %d (this value can be modified using PI_NON_NESTED_ARITH_WEIGHT=<val>).",
q->get_qid().str().c_str(), weight);
warning_msg("using non nested arith. pattern (quantifier id: %s), the weight was increased to %d (this value can be modified using PI_NON_NESTED_ARITH_WEIGHT=<val>).",
q->get_qid().str().c_str(), weight);
}
// verbose_stream() << mk_pp(q, m) << "\n";
}
}
}
quantifier_ref new_q(m);
new_q = m.update_quantifier(q, new_patterns.size(), (expr**) new_patterns.c_ptr(), new_body);
quantifier_ref new_q(m.update_quantifier(q, new_patterns.size(), (expr**) new_patterns.c_ptr(), new_body), m);
if (weight != q->get_weight())
new_q = m.update_quantifier_weight(new_q, weight);
proof_ref pr(m);
if (m.fine_grain_proofs()) {
if (new_body_pr == 0)
new_body_pr = m.mk_reflexivity(new_body);
pr = m.mk_quant_intro(q, new_q, new_body_pr);
if (m.fine_grain_proofs()) {
proof* new_body_pr = m.mk_reflexivity(new_body);
result_pr = m.mk_quant_intro(q, new_q, new_body_pr);
}
if (new_patterns.empty() && m_params.m_pi_pull_quantifiers) {
pull_quant pull(m);
expr_ref new_expr(m);
proof_ref new_pr(m);
pull(new_q, new_expr, new_pr);
quantifier * new_new_q = to_quantifier(new_expr);
if (new_new_q != new_q) {
mk_patterns(new_new_q->get_num_decls(), new_new_q->get_expr(), 0, 0, new_patterns);
quantifier * result2 = to_quantifier(new_expr);
if (result2 != new_q) {
mk_patterns(result2->get_num_decls(), result2->get_expr(), 0, 0, new_patterns);
if (!new_patterns.empty()) {
if (m_params.m_pi_warnings) {
warning_msg("pulled nested quantifier to be able to find an useable pattern (quantifier id: %s)", q->get_qid().str().c_str());
}
new_q = m.update_quantifier(new_new_q, new_patterns.size(), (expr**) new_patterns.c_ptr(), new_new_q->get_expr());
new_q = m.update_quantifier(result2, new_patterns.size(), (expr**) new_patterns.c_ptr(), result2->get_expr());
if (m.fine_grain_proofs()) {
pr = m.mk_transitivity(pr, new_pr);
pr = m.mk_transitivity(pr, m.mk_quant_intro(new_new_q, 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_reflexivity(new_q->get_expr())));
}
TRACE("pattern_inference", tout << "pulled quantifier:\n" << mk_pp(new_q, m) << "\n";);
}
@ -725,22 +705,21 @@ void pattern_inference::reduce1_quantifier(quantifier * q) {
}
if (new_patterns.empty() && new_body == q->get_expr()) {
cache_result(q, q, 0);
return;
return false;
}
cache_result(q, new_q, pr);
result = new_q;
IF_VERBOSE(10,
verbose_stream() << "(smt.inferred-patterns :qid " << q->get_qid() << "\n";
for (unsigned i = 0; i < new_patterns.size(); i++)
verbose_stream() << " " << mk_ismt2_pp(new_patterns[i], m, 2) << "\n";
verbose_stream() << ")\n"; );
return true;
}
#if 0
// unused
static void dump_expr_vector(std::ostream & out, ptr_vector<expr> const & v, ast_manager & m) {
ptr_vector<expr>::const_iterator it = v.begin();
ptr_vector<expr>::const_iterator end = v.end();
for (; it != end; ++it)
out << mk_pp(*it, m) << "\n";
}
#endif
pattern_inference_rw::pattern_inference_rw(ast_manager& m, pattern_inference_params & params):
rewriter_tpl<pattern_inference_cfg>(m, m.proofs_enabled(), m_cfg),
m_cfg(m, params)
{}

View file

@ -19,16 +19,16 @@ Revision History:
#ifndef PATTERN_INFERENCE_H_
#define PATTERN_INFERENCE_H_
#include"ast.h"
#include"simplifier.h"
#include"pattern_inference_params.h"
#include"vector.h"
#include"uint_set.h"
#include"nat_set.h"
#include"obj_hashtable.h"
#include"obj_pair_hashtable.h"
#include"map.h"
#include"expr_pattern_match.h"
#include "ast/ast.h"
#include "ast/rewriter/rewriter.h"
#include "ast/pattern/pattern_inference_params.h"
#include "util/vector.h"
#include "util/uint_set.h"
#include "util/nat_set.h"
#include "util/obj_hashtable.h"
#include "util/obj_pair_hashtable.h"
#include "util/map.h"
#include "ast/pattern/expr_pattern_match.h"
/**
\brief A pattern p_1 is smaller than a pattern p_2 iff
@ -60,7 +60,8 @@ public:
bool operator()(unsigned num_bindings, expr * p1, expr * p2);
};
class pattern_inference : public simplifier {
class pattern_inference_cfg : public default_rewriter_cfg {
ast_manager& m;
pattern_inference_params & m_params;
family_id m_bfid;
family_id m_afid;
@ -88,7 +89,7 @@ class pattern_inference : public simplifier {
typedef obj_map<expr, info> expr2info;
expr2info m_candidates_info; // candidate -> set of free vars + size
expr2info m_candidates_info; // candidate -> set of free vars + size
app_ref_vector m_candidates;
ptr_vector<app> m_tmp1;
@ -136,7 +137,7 @@ class pattern_inference : public simplifier {
};
ast_manager & m;
pattern_inference & m_owner;
pattern_inference_cfg & m_owner;
family_id m_afid;
unsigned m_num_bindings;
typedef map<entry, info *, obj_hash<entry>, default_eq<entry> > cache;
@ -150,7 +151,7 @@ class pattern_inference : public simplifier {
void save_candidate(expr * n, unsigned delta);
void reset();
public:
collect(ast_manager & m, pattern_inference & o):m(m), m_owner(o), m_afid(m.mk_family_id("arith")) {}
collect(ast_manager & m, pattern_inference_cfg & o):m(m), m_owner(o), m_afid(m.mk_family_id("arith")) {}
void operator()(expr * n, unsigned num_bindings);
};
@ -165,12 +166,12 @@ class pattern_inference : public simplifier {
void filter_bigger_patterns(ptr_vector<app> const & patterns, ptr_vector<app> & result);
class contains_subpattern {
pattern_inference & m_owner;
pattern_inference_cfg & m_owner;
nat_set m_already_processed;
ptr_vector<expr> m_todo;
void save(expr * n);
public:
contains_subpattern(pattern_inference & owner):
contains_subpattern(pattern_inference_cfg & owner):
m_owner(owner) {}
bool operator()(expr * n);
};
@ -214,10 +215,8 @@ class pattern_inference : public simplifier {
expr * const * no_patterns, // IN patterns that should not be used.
app_ref_buffer & result); // OUT result
virtual void reduce1_quantifier(quantifier * q);
public:
pattern_inference(ast_manager & m, pattern_inference_params & params);
pattern_inference_cfg(ast_manager & m, pattern_inference_params & params);
void register_forbidden_family(family_id fid) {
SASSERT(fid != m_bfid);
@ -232,6 +231,13 @@ public:
m_preferred.insert(f);
}
bool reduce_quantifier(quantifier * old_q,
expr * new_body,
expr * const * new_patterns,
expr * const * new_no_patterns,
expr_ref & result,
proof_ref & result_pr);
void register_preferred(unsigned num, func_decl * const * fs) { for (unsigned i = 0; i < num; i++) register_preferred(fs[i]); }
bool is_forbidden(func_decl const * decl) const {
@ -244,5 +250,11 @@ public:
bool is_forbidden(app * n) const;
};
class pattern_inference_rw : public rewriter_tpl<pattern_inference_cfg> {
pattern_inference_cfg m_cfg;
public:
pattern_inference_rw(ast_manager& m, pattern_inference_params & params);
};
#endif /* PATTERN_INFERENCE_H_ */

View file

@ -16,8 +16,8 @@ Author:
Revision History:
--*/
#include"pattern_inference_params.h"
#include"pattern_inference_params_helper.hpp"
#include "ast/pattern/pattern_inference_params.h"
#include "ast/pattern/pattern_inference_params_helper.hpp"
void pattern_inference_params::updt_params(params_ref const & _p) {
pattern_inference_params_helper p(_p);

View file

@ -19,7 +19,7 @@ Revision History:
#ifndef PATTERN_INFERENCE_PARAMS_H_
#define PATTERN_INFERENCE_PARAMS_H_
#include"params.h"
#include "util/params.h"
enum arith_pattern_inference_kind {
AP_NO, // do not infer patterns with arithmetic terms

View file

@ -17,8 +17,8 @@ Revision History:
--*/
#include "pb_decl_plugin.h"
#include "ast_util.h"
#include "ast/pb_decl_plugin.h"
#include "ast/ast_util.h"
pb_decl_plugin::pb_decl_plugin():
m_at_most_sym("at-most"),

View file

@ -27,7 +27,7 @@ hence:
#ifndef PB_DECL_PLUGIN_H_
#define PB_DECL_PLUGIN_H_
#include"ast.h"
#include "ast/ast.h"
enum pb_op_kind {
OP_AT_MOST_K, // at most K Booleans are true.

View file

@ -16,8 +16,8 @@ Author:
Revision History:
--*/
#include"pp.h"
#include"pp_params.hpp"
#include "ast/pp.h"
#include "ast/pp_params.hpp"
using namespace format_ns;
static std::pair<unsigned, bool> space_upto_line_break(ast_manager & m, format * f) {

Some files were not shown because too many files have changed in this diff Show more