3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-07-29 23:43:15 +00:00

Reorganizing code. Added script for generating VS project files

Signed-off-by: Leonardo de Moura <leonardo@microsoft.com>
This commit is contained in:
Leonardo de Moura 2012-10-20 15:16:37 -07:00
parent 2c464d413d
commit 8a6997960a
68 changed files with 167 additions and 170 deletions

View file

@ -0,0 +1,586 @@
/*++
Copyright (c) 2006 Microsoft Corporation
Module Name:
arith_decl_plugin.cpp
Abstract:
<abstract>
Author:
Leonardo de Moura (leonardo) 2008-01-09
Revision History:
--*/
#include"arith_decl_plugin.h"
#include"warning.h"
#include"algebraic_numbers.h"
#include"id_gen.h"
#include"ast_smt2_pp.h"
struct arith_decl_plugin::algebraic_numbers_wrapper {
unsynch_mpq_manager m_qmanager;
algebraic_numbers::manager m_amanager;
id_gen m_id_gen;
scoped_anum_vector m_nums;
algebraic_numbers_wrapper():
m_amanager(m_qmanager),
m_nums(m_amanager) {
}
~algebraic_numbers_wrapper() {
}
unsigned mk_id(algebraic_numbers::anum const & val) {
SASSERT(!m_amanager.is_rational(val));
// TODO: avoid linear scan. Use hashtable based on the floor of val
unsigned sz = m_nums.size();
for (unsigned i = 0; i < sz; i++) {
algebraic_numbers::anum const & other = m_nums.get(i);
if (m_amanager.eq(val, other))
return i;
}
unsigned new_id = m_id_gen.mk();
m_nums.reserve(new_id+1);
m_amanager.set(m_nums[new_id], val);
TRACE("algebraic2expr", tout << "mk_id -> " << new_id << "\n"; m_amanager.display(tout, val); tout << "\n";);
return new_id;
}
void recycle_id(unsigned idx) {
SASSERT(idx < m_nums.size());
SASSERT(!m_amanager.is_zero(m_nums[idx]));
TRACE("algebraic2expr", tout << "recycling: " << idx << "\n";);
m_id_gen.recycle(idx);
m_amanager.del(m_nums[idx]);
}
algebraic_numbers::anum const & idx2anum(unsigned idx) {
return m_nums[idx];
}
algebraic_numbers::anum const & to_anum(func_decl * f) {
SASSERT(f->get_decl_kind() == OP_IRRATIONAL_ALGEBRAIC_NUM);
return idx2anum(f->get_parameter(0).get_ext_id());
}
};
arith_decl_plugin::algebraic_numbers_wrapper & arith_decl_plugin::aw() {
if (m_aw == 0)
m_aw = alloc(algebraic_numbers_wrapper);
return *m_aw;
}
algebraic_numbers::manager & arith_decl_plugin::am() {
return aw().m_amanager;
}
app * arith_decl_plugin::mk_numeral(algebraic_numbers::anum const & val, bool is_int) {
if (am().is_rational(val)) {
rational rval;
am().to_rational(val, rval);
return mk_numeral(rval, is_int);
}
else {
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());
func_decl * decl = m_manager->mk_const_decl(m_rootv_sym, m_real_decl, func_decl_info(m_family_id, OP_IRRATIONAL_ALGEBRAIC_NUM, 1, &p));
return m_manager->mk_const(decl);
}
}
app * arith_decl_plugin::mk_numeral(sexpr const * p, unsigned i) {
scoped_anum r(am());
am().mk_root(p, i, r);
return mk_numeral(r, false);
}
void arith_decl_plugin::del(parameter const & p) {
SASSERT(p.is_external());
if (m_aw != 0) {
aw().recycle_id(p.get_ext_id());
}
}
parameter arith_decl_plugin::translate(parameter const & p, decl_plugin & target) {
SASSERT(p.is_external());
arith_decl_plugin & _target = static_cast<arith_decl_plugin&>(target);
return parameter(_target.aw().mk_id(aw().idx2anum(p.get_ext_id())), true);
}
void arith_decl_plugin::set_cancel(bool f) {
if (m_aw)
m_aw->m_amanager.set_cancel(f);
}
void arith_decl_plugin::set_manager(ast_manager * m, family_id id) {
decl_plugin::set_manager(m, id);
m_real_decl = m->mk_sort(symbol("Real"), sort_info(id, REAL_SORT));
m->inc_ref(m_real_decl);
sort * r = m_real_decl;
m_int_decl = m->mk_sort(symbol("Int"), sort_info(id, INT_SORT));
m->inc_ref(m_int_decl);
sort * i = m_int_decl;
sort * b = m->mk_bool_sort();
#define MK_PRED(FIELD, NAME, KIND, SORT) { \
func_decl_info info(id, KIND); \
info.set_chainable(true); \
FIELD = m->mk_func_decl(symbol(NAME), SORT, SORT, b, info); \
m->inc_ref(FIELD); \
}
MK_PRED(m_r_le_decl, "<=", OP_LE, r);
MK_PRED(m_r_ge_decl, ">=", OP_GE, r);
MK_PRED(m_r_lt_decl, "<", OP_LT, r);
MK_PRED(m_r_gt_decl, ">", OP_GT, r);
MK_PRED(m_i_le_decl, "<=", OP_LE, i);
MK_PRED(m_i_ge_decl, ">=", OP_GE, i);
MK_PRED(m_i_lt_decl, "<", OP_LT, i);
MK_PRED(m_i_gt_decl, ">", OP_GT, i);
#define MK_AC_OP(FIELD, NAME, KIND, SORT) { \
func_decl_info info(id, KIND); \
info.set_associative(); \
info.set_flat_associative(); \
info.set_commutative(); \
FIELD = m->mk_func_decl(symbol(NAME), SORT, SORT, SORT, info); \
m->inc_ref(FIELD); \
}
#define MK_OP(FIELD, NAME, KIND, SORT) \
FIELD = m->mk_func_decl(symbol(NAME), SORT, SORT, SORT, func_decl_info(id, KIND)); \
m->inc_ref(FIELD)
#define MK_UNARY(FIELD, NAME, KIND, SORT) \
FIELD = m->mk_func_decl(symbol(NAME), SORT, SORT, func_decl_info(id, KIND)); \
m->inc_ref(FIELD)
MK_AC_OP(m_r_add_decl, "+", OP_ADD, r);
MK_OP(m_r_sub_decl, "-", OP_SUB, r);
MK_AC_OP(m_r_mul_decl, "*", OP_MUL, r);
MK_OP(m_r_div_decl, "/", OP_DIV, r);
MK_UNARY(m_r_uminus_decl, "-", OP_UMINUS, r);
MK_AC_OP(m_i_add_decl, "+", OP_ADD, i);
MK_OP(m_i_sub_decl, "-", OP_SUB, i);
MK_AC_OP(m_i_mul_decl, "*", OP_MUL, i);
MK_OP(m_i_div_decl, "div", OP_IDIV, i);
MK_OP(m_i_rem_decl, "rem", OP_REM, i);
MK_OP(m_i_mod_decl, "mod", OP_MOD, i);
MK_UNARY(m_i_uminus_decl, "-", OP_UMINUS, i);
m_to_real_decl = m->mk_func_decl(symbol("to_real"), i, r, func_decl_info(id, OP_TO_REAL));
m->inc_ref(m_to_real_decl);
m_to_int_decl = m->mk_func_decl(symbol("to_int"), r, i, func_decl_info(id, OP_TO_INT));
m->inc_ref(m_to_int_decl);
m_is_int_decl = m->mk_func_decl(symbol("is_int"), r, m->mk_bool_sort(), func_decl_info(id, OP_IS_INT));
m->inc_ref(m_is_int_decl);
MK_OP(m_r_power_decl, "^", OP_POWER, r);
MK_OP(m_i_power_decl, "^", OP_POWER, i);
MK_UNARY(m_sin_decl, "sin", OP_SIN, r);
MK_UNARY(m_cos_decl, "cos", OP_COS, r);
MK_UNARY(m_tan_decl, "tan", OP_TAN, r);
MK_UNARY(m_asin_decl, "asin", OP_ASIN, r);
MK_UNARY(m_acos_decl, "acos", OP_ACOS, r);
MK_UNARY(m_atan_decl, "atan", OP_ATAN, r);
MK_UNARY(m_sinh_decl, "sinh", OP_SINH, r);
MK_UNARY(m_cosh_decl, "cosh", OP_COSH, r);
MK_UNARY(m_tanh_decl, "tanh", OP_TANH, r);
MK_UNARY(m_asinh_decl, "asinh", OP_ASINH, r);
MK_UNARY(m_acosh_decl, "acosh", OP_ACOSH, r);
MK_UNARY(m_atanh_decl, "atanh", OP_ATANH, r);
func_decl * pi_decl = m->mk_const_decl(symbol("pi"), r, func_decl_info(id, OP_PI));
m_pi = m->mk_const(pi_decl);
m->inc_ref(m_pi);
func_decl * e_decl = m->mk_const_decl(symbol("euler"), r, func_decl_info(id, OP_E));
m_e = m->mk_const(e_decl);
m->inc_ref(m_e);
}
arith_decl_plugin::arith_decl_plugin():
m_aw(0),
m_intv_sym("Int"),
m_realv_sym("Real"),
m_rootv_sym("RootObject"),
m_real_decl(0),
m_int_decl(0),
m_r_le_decl(0),
m_r_ge_decl(0),
m_r_lt_decl(0),
m_r_gt_decl(0),
m_r_add_decl(0),
m_r_sub_decl(0),
m_r_uminus_decl(0),
m_r_mul_decl(0),
m_r_div_decl(0),
m_i_le_decl(0),
m_i_ge_decl(0),
m_i_lt_decl(0),
m_i_gt_decl(0),
m_i_add_decl(0),
m_i_sub_decl(0),
m_i_uminus_decl(0),
m_i_mul_decl(0),
m_i_div_decl(0),
m_i_mod_decl(0),
m_i_rem_decl(0),
m_to_real_decl(0),
m_to_int_decl(0),
m_is_int_decl(0),
m_r_power_decl(0),
m_i_power_decl(0),
m_sin_decl(0),
m_cos_decl(0),
m_tan_decl(0),
m_asin_decl(0),
m_acos_decl(0),
m_atan_decl(0),
m_sinh_decl(0),
m_cosh_decl(0),
m_tanh_decl(0),
m_asinh_decl(0),
m_acosh_decl(0),
m_atanh_decl(0),
m_pi(0),
m_e(0) {
}
arith_decl_plugin::~arith_decl_plugin() {
dealloc(m_aw);
}
void arith_decl_plugin::finalize() {
#define DEC_REF(decl) if (decl) { m_manager->dec_ref(decl); } ((void) 0)
DEC_REF(m_real_decl);
DEC_REF(m_int_decl);
DEC_REF(m_r_le_decl);
DEC_REF(m_r_ge_decl);
DEC_REF(m_r_lt_decl);
DEC_REF(m_r_gt_decl);
DEC_REF(m_r_add_decl);
DEC_REF(m_r_sub_decl);
DEC_REF(m_r_uminus_decl);
DEC_REF(m_r_mul_decl);
DEC_REF(m_r_div_decl);
DEC_REF(m_i_le_decl);
DEC_REF(m_i_ge_decl);
DEC_REF(m_i_lt_decl);
DEC_REF(m_i_gt_decl);
DEC_REF(m_i_add_decl);
DEC_REF(m_i_sub_decl);
DEC_REF(m_i_uminus_decl);
DEC_REF(m_i_mul_decl);
DEC_REF(m_i_div_decl);
DEC_REF(m_i_mod_decl);
DEC_REF(m_i_rem_decl);
DEC_REF(m_to_real_decl);
DEC_REF(m_to_int_decl);
DEC_REF(m_is_int_decl);
DEC_REF(m_i_power_decl);
DEC_REF(m_r_power_decl);
DEC_REF(m_sin_decl);
DEC_REF(m_cos_decl);
DEC_REF(m_tan_decl);
DEC_REF(m_asin_decl);
DEC_REF(m_acos_decl);
DEC_REF(m_atan_decl);
DEC_REF(m_sinh_decl);
DEC_REF(m_cosh_decl);
DEC_REF(m_tanh_decl);
DEC_REF(m_asinh_decl);
DEC_REF(m_acosh_decl);
DEC_REF(m_atanh_decl);
DEC_REF(m_pi);
DEC_REF(m_e);
m_manager->dec_array_ref(m_small_ints.size(), m_small_ints.c_ptr());
m_manager->dec_array_ref(m_small_reals.size(), m_small_reals.c_ptr());
}
sort * arith_decl_plugin::mk_sort(decl_kind k, unsigned num_parameters, parameter const * parameters) {
switch (k) {
case REAL_SORT: return m_real_decl;
case INT_SORT: return m_int_decl;
default: return 0;
}
}
inline func_decl * arith_decl_plugin::mk_func_decl(decl_kind k, bool is_real) {
switch (k) {
case OP_LE: return is_real ? m_r_le_decl : m_i_le_decl;
case OP_GE: return is_real ? m_r_ge_decl : m_i_ge_decl;
case OP_LT: return is_real ? m_r_lt_decl : m_i_lt_decl;
case OP_GT: return is_real ? m_r_gt_decl : m_i_gt_decl;
case OP_ADD: return is_real ? m_r_add_decl : m_i_add_decl;
case OP_SUB: return is_real ? m_r_sub_decl : m_i_sub_decl;
case OP_UMINUS: return is_real ? m_r_uminus_decl : m_i_uminus_decl;
case OP_MUL: return is_real ? m_r_mul_decl : m_i_mul_decl;
case OP_DIV: return m_r_div_decl;
case OP_IDIV: return m_i_div_decl;
case OP_REM: return m_i_rem_decl;
case OP_MOD: return m_i_mod_decl;
case OP_TO_REAL: return m_to_real_decl;
case OP_TO_INT: return m_to_int_decl;
case OP_IS_INT: return m_is_int_decl;
case OP_POWER: return is_real ? m_r_power_decl : m_i_power_decl;
case OP_SIN: return m_sin_decl;
case OP_COS: return m_cos_decl;
case OP_TAN: return m_tan_decl;
case OP_ASIN: return m_asin_decl;
case OP_ACOS: return m_acos_decl;
case OP_ATAN: return m_atan_decl;
case OP_SINH: return m_sinh_decl;
case OP_COSH: return m_cosh_decl;
case OP_TANH: return m_tanh_decl;
case OP_ASINH: return m_asinh_decl;
case OP_ACOSH: return m_acosh_decl;
case OP_ATANH: return m_atanh_decl;
case OP_PI: return m_pi->get_decl();
case OP_E: return m_e->get_decl();
default: return 0;
}
}
inline decl_kind arith_decl_plugin::fix_kind(decl_kind k, unsigned arity) {
if (k == OP_SUB && arity == 1) {
return OP_UMINUS;
}
return k;
}
#define MAX_SMALL_NUM_TO_CACHE 16
app * arith_decl_plugin::mk_numeral(rational const & val, bool is_int) {
if (is_int && !val.is_int()) {
m_manager->raise_exception("invalid rational value passed as an integer");
}
if (val.is_unsigned()) {
unsigned u_val = val.get_unsigned();
if (u_val < MAX_SMALL_NUM_TO_CACHE) {
if (is_int) {
app * r = m_small_ints.get(u_val, 0);
if (r == 0) {
parameter p[2] = { parameter(val), parameter(1) };
r = m_manager->mk_const(m_manager->mk_const_decl(m_intv_sym, m_int_decl, func_decl_info(m_family_id, OP_NUM, 2, p)));
m_manager->inc_ref(r);
m_small_ints.setx(u_val, r, 0);
}
return r;
}
else {
app * r = m_small_reals.get(u_val, 0);
if (r == 0) {
parameter p[2] = { parameter(val), parameter(0) };
r = m_manager->mk_const(m_manager->mk_const_decl(m_realv_sym, m_real_decl, func_decl_info(m_family_id, OP_NUM, 2, p)));
m_manager->inc_ref(r);
m_small_reals.setx(u_val, r, 0);
}
return r;
}
}
}
parameter p[2] = { parameter(val), parameter(static_cast<int>(is_int)) };
func_decl * decl;
if (is_int)
decl = m_manager->mk_const_decl(m_intv_sym, m_int_decl, func_decl_info(m_family_id, OP_NUM, 2, p));
else
decl = m_manager->mk_const_decl(m_realv_sym, m_real_decl, func_decl_info(m_family_id, OP_NUM, 2, p));
return m_manager->mk_const(decl);
}
func_decl * arith_decl_plugin::mk_num_decl(unsigned num_parameters, parameter const * parameters, unsigned arity) {
if (!(num_parameters == 2 && arity == 0 && parameters[0].is_rational() && parameters[1].is_int())) {
m_manager->raise_exception("invalid numeral declaration");
return 0;
}
if (parameters[1].get_int() != 0)
return m_manager->mk_const_decl(m_intv_sym, m_int_decl, func_decl_info(m_family_id, OP_NUM, num_parameters, parameters));
else
return m_manager->mk_const_decl(m_realv_sym, m_real_decl, func_decl_info(m_family_id, OP_NUM, num_parameters, parameters));
}
static bool use_coercion(decl_kind k) {
return k == OP_ADD || k == OP_SUB || k == OP_MUL || k == OP_POWER || k == OP_LE || k == OP_GE || k == OP_LT || k == OP_GT || k == OP_UMINUS;
}
static bool has_real_arg(unsigned arity, sort * const * domain, sort * real_sort) {
for (unsigned i = 0; i < arity; i++)
if (domain[i] == real_sort)
return true;
return false;
}
static bool has_real_arg(ast_manager * m, unsigned num_args, expr * const * args, sort * real_sort) {
for (unsigned i = 0; i < num_args; i++)
if (m->get_sort(args[i]) == real_sort)
return true;
return false;
}
func_decl * arith_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters,
unsigned arity, sort * const * domain, sort * range) {
if (k == OP_NUM)
return mk_num_decl(num_parameters, parameters, arity);
if (arity == 0 && k != OP_PI && k != OP_E) {
m_manager->raise_exception("no arguments supplied to arithmetical operator");
return 0;
}
if (m_manager->int_real_coercions() && use_coercion(k)) {
return mk_func_decl(fix_kind(k, arity), has_real_arg(arity, domain, m_real_decl));
}
else {
bool is_real = arity > 0 && domain[0] == m_real_decl;
return mk_func_decl(fix_kind(k, arity), is_real);
}
}
func_decl * arith_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters,
unsigned num_args, expr * const * args, sort * range) {
if (k == OP_NUM)
return mk_num_decl(num_parameters, parameters, num_args);
if (num_args == 0 && k != OP_PI && k != OP_E) {
m_manager->raise_exception("no arguments supplied to arithmetical operator");
return 0;
}
if (m_manager->int_real_coercions() && use_coercion(k)) {
return mk_func_decl(fix_kind(k, num_args), has_real_arg(m_manager, num_args, args, m_real_decl));
}
else {
bool is_real = num_args > 0 && m_manager->get_sort(args[0]) == m_real_decl;
return mk_func_decl(fix_kind(k, num_args), is_real);
}
}
void arith_decl_plugin::get_sort_names(svector<builtin_name>& sort_names, symbol const & logic) {
// TODO: only define Int and Real in the right logics
sort_names.push_back(builtin_name("Int", INT_SORT));
sort_names.push_back(builtin_name("Real", REAL_SORT));
}
void arith_decl_plugin::get_op_names(svector<builtin_name>& op_names, symbol const & logic) {
op_names.push_back(builtin_name("<=",OP_LE));
op_names.push_back(builtin_name(">=",OP_GE));
op_names.push_back(builtin_name("<",OP_LT));
op_names.push_back(builtin_name(">",OP_GT));
op_names.push_back(builtin_name("+",OP_ADD));
op_names.push_back(builtin_name("-",OP_SUB));
op_names.push_back(builtin_name("~",OP_UMINUS));
op_names.push_back(builtin_name("*",OP_MUL));
op_names.push_back(builtin_name("/",OP_DIV));
op_names.push_back(builtin_name("div",OP_IDIV));
op_names.push_back(builtin_name("rem",OP_REM));
op_names.push_back(builtin_name("mod",OP_MOD));
op_names.push_back(builtin_name("to_real",OP_TO_REAL));
op_names.push_back(builtin_name("to_int",OP_TO_INT));
op_names.push_back(builtin_name("is_int",OP_IS_INT));
if (logic == symbol::null) {
op_names.push_back(builtin_name("^", OP_POWER));
op_names.push_back(builtin_name("sin", OP_SIN));
op_names.push_back(builtin_name("cos", OP_COS));
op_names.push_back(builtin_name("tan", OP_TAN));
op_names.push_back(builtin_name("asin", OP_ASIN));
op_names.push_back(builtin_name("acos", OP_ACOS));
op_names.push_back(builtin_name("atan", OP_ATAN));
op_names.push_back(builtin_name("sinh", OP_SINH));
op_names.push_back(builtin_name("cosh", OP_COSH));
op_names.push_back(builtin_name("tanh", OP_TANH));
op_names.push_back(builtin_name("asinh", OP_ASINH));
op_names.push_back(builtin_name("acosh", OP_ACOSH));
op_names.push_back(builtin_name("atanh", OP_ATANH));
op_names.push_back(builtin_name("pi", OP_PI));
op_names.push_back(builtin_name("euler", OP_E));
}
}
bool arith_decl_plugin::is_value(app* e) const {
return is_app_of(e, m_family_id, OP_NUM);
}
bool arith_decl_plugin::are_distinct(app* a, app* b) const {
TRACE("are_distinct_bug", tout << mk_ismt2_pp(a, *m_manager) << "\n" << mk_ismt2_pp(b, *m_manager) << "\n";);
if (decl_plugin::are_distinct(a,b)) {
return true;
}
#define is_non_zero(e) is_app_of(e,m_family_id, OP_NUM) && !to_app(e)->get_decl()->get_parameter(0).get_rational().is_zero()
if (is_app_of(a, m_family_id, OP_ADD) &&
a->get_num_args() == 2 &&
to_app(a)->get_arg(0) == b &&
is_non_zero(to_app(a)->get_arg(1))) {
return true;
}
if (is_app_of(a, m_family_id, OP_ADD) &&
a->get_num_args() == 2 &&
to_app(a)->get_arg(1) == b &&
is_non_zero(to_app(a)->get_arg(0))) {
return true;
}
if (is_app_of(b, m_family_id, OP_ADD) &&
b->get_num_args() == 2 &&
to_app(b)->get_arg(1) == a &&
is_non_zero(to_app(b)->get_arg(0))) {
return true;
}
if (is_app_of(b, m_family_id, OP_ADD) &&
b->get_num_args() == 2 &&
to_app(b)->get_arg(0) == a &&
is_non_zero(to_app(b)->get_arg(1))) {
return true;
}
return false;
}
expr * arith_decl_plugin::get_some_value(sort * s) {
SASSERT(s == m_int_decl || s == m_real_decl);
return mk_numeral(rational(0), s == m_int_decl);
}
arith_util::arith_util(ast_manager & m):
m_manager(m),
m_afid(m.get_family_id("arith")),
m_plugin(0) {
}
void arith_util::init_plugin() {
SASSERT(m_plugin == 0);
m_plugin = static_cast<arith_decl_plugin*>(m_manager.get_plugin(m_afid));
}
bool arith_util::is_numeral(expr const * n, rational & val, bool & is_int) const {
if (!is_app_of(n, m_afid, OP_NUM))
return false;
func_decl * decl = to_app(n)->get_decl();
val = decl->get_parameter(0).get_rational();
is_int = decl->get_parameter(1).get_int() != 0;
return true;
}
bool arith_util::is_irrational_algebraic_numeral(expr const * n, algebraic_numbers::anum & val) {
if (!is_app_of(n, m_afid, OP_IRRATIONAL_ALGEBRAIC_NUM))
return false;
am().set(val, to_irrational_algebraic_numeral(n));
return true;
}
algebraic_numbers::anum const & arith_util::to_irrational_algebraic_numeral(expr const * n) {
SASSERT(is_irrational_algebraic_numeral(n));
return plugin().aw().to_anum(to_app(n)->get_decl());
}

348
src/ast/arith_decl_plugin.h Normal file
View file

@ -0,0 +1,348 @@
/*++
Copyright (c) 2006 Microsoft Corporation
Module Name:
arith_decl_plugin.h
Abstract:
<abstract>
Author:
Leonardo de Moura (leonardo) 2008-01-09
Revision History:
--*/
#ifndef _ARITH_DECL_PLUGIN_H_
#define _ARITH_DECL_PLUGIN_H_
#include"ast.h"
class sexpr;
namespace algebraic_numbers {
class anum;
class manager;
};
enum arith_sort_kind {
REAL_SORT,
INT_SORT
};
enum arith_op_kind {
OP_NUM, // rational & integers
OP_IRRATIONAL_ALGEBRAIC_NUM, // irrationals that are roots of polynomials with integer coefficients
OP_LE,
OP_GE,
OP_LT,
OP_GT,
OP_ADD,
OP_SUB,
OP_UMINUS,
OP_MUL,
OP_DIV,
OP_IDIV,
OP_REM,
OP_MOD,
OP_TO_REAL,
OP_TO_INT,
OP_IS_INT,
OP_POWER,
// hyperbolic and trigonometric functions
OP_SIN,
OP_COS,
OP_TAN,
OP_ASIN,
OP_ACOS,
OP_ATAN,
OP_SINH,
OP_COSH,
OP_TANH,
OP_ASINH,
OP_ACOSH,
OP_ATANH,
// constants
OP_PI,
OP_E,
LAST_ARITH_OP
};
class arith_util;
class arith_decl_plugin : public decl_plugin {
protected:
struct algebraic_numbers_wrapper;
algebraic_numbers_wrapper * m_aw;
symbol m_intv_sym;
symbol m_realv_sym;
symbol m_rootv_sym;
sort * m_real_decl;
sort * m_int_decl;
func_decl * m_r_le_decl;
func_decl * m_r_ge_decl;
func_decl * m_r_lt_decl;
func_decl * m_r_gt_decl;
func_decl * m_r_add_decl;
func_decl * m_r_sub_decl;
func_decl * m_r_uminus_decl;
func_decl * m_r_mul_decl;
func_decl * m_r_div_decl;
func_decl * m_i_le_decl;
func_decl * m_i_ge_decl;
func_decl * m_i_lt_decl;
func_decl * m_i_gt_decl;
func_decl * m_i_add_decl;
func_decl * m_i_sub_decl;
func_decl * m_i_uminus_decl;
func_decl * m_i_mul_decl;
func_decl * m_i_div_decl;
func_decl * m_i_mod_decl;
func_decl * m_i_rem_decl;
func_decl * m_to_real_decl;
func_decl * m_to_int_decl;
func_decl * m_is_int_decl;
func_decl * m_r_power_decl;
func_decl * m_i_power_decl;
func_decl * m_sin_decl;
func_decl * m_cos_decl;
func_decl * m_tan_decl;
func_decl * m_asin_decl;
func_decl * m_acos_decl;
func_decl * m_atan_decl;
func_decl * m_sinh_decl;
func_decl * m_cosh_decl;
func_decl * m_tanh_decl;
func_decl * m_asinh_decl;
func_decl * m_acosh_decl;
func_decl * m_atanh_decl;
app * m_pi;
app * m_e;
ptr_vector<app> m_small_ints;
ptr_vector<app> m_small_reals;
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);
func_decl * mk_num_decl(unsigned num_parameters, parameter const * parameters, unsigned arity);
public:
arith_decl_plugin();
virtual ~arith_decl_plugin();
virtual void finalize();
algebraic_numbers::manager & am();
algebraic_numbers_wrapper & aw();
virtual void del(parameter const & p);
virtual parameter translate(parameter const & p, decl_plugin & target);
virtual decl_plugin * mk_fresh() {
return alloc(arith_decl_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 func_decl * mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters,
unsigned num_args, expr * const * args, sort * range);
virtual bool is_value(app* e) const;
virtual bool are_distinct(app* a, app* b) const;
virtual void get_op_names(svector<builtin_name> & op_names, symbol const & logic);
virtual void get_sort_names(svector<builtin_name> & sort_names, symbol const & logic);
app * mk_numeral(rational const & n, bool is_int);
app * mk_numeral(algebraic_numbers::anum const & val, bool is_int);
// Create a (real) numeral that is the i-th root of the polynomial encoded using the given sexpr.
app * mk_numeral(sexpr const * p, unsigned i);
app * mk_pi() const { return m_pi; }
app * mk_e() const { return m_e; }
virtual expr * get_some_value(sort * s);
void set_cancel(bool f);
};
class arith_util {
ast_manager & m_manager;
family_id m_afid;
arith_decl_plugin * m_plugin;
void init_plugin();
arith_decl_plugin & plugin() const {
if (!m_plugin) const_cast<arith_util*>(this)->init_plugin();
SASSERT(m_plugin != 0);
return *m_plugin;
}
public:
arith_util(ast_manager & m);
ast_manager & get_manager() const { return m_manager; }
family_id get_family_id() const { return m_afid; }
algebraic_numbers::manager & am() {
return plugin().am();
}
bool is_arith_expr(expr const * n) const { return is_app(n) && to_app(n)->get_family_id() == m_afid; }
bool is_numeral(expr const * n, rational & val, bool & is_int) const;
bool is_numeral(expr const * n, rational & val) const { bool is_int; return is_numeral(n, val, is_int); }
bool is_numeral(expr const * n) const { return is_app_of(n, m_afid, OP_NUM); }
bool is_irrational_algebraic_numeral(expr const * n) const { return is_app_of(n, m_afid, OP_IRRATIONAL_ALGEBRAIC_NUM); }
bool is_irrational_algebraic_numeral(expr const * n, algebraic_numbers::anum & val);
algebraic_numbers::anum const & to_irrational_algebraic_numeral(expr const * n);
bool is_zero(expr const * n) const { rational val; return is_numeral(n, val) && val.is_zero(); }
bool is_minus_one(expr * n) const { rational tmp; return is_numeral(n, tmp) && tmp.is_minus_one(); }
// return true if \c n is a term of the form (* -1 r)
bool is_times_minus_one(expr * n, expr * & r) const {
if (is_mul(n) && to_app(n)->get_num_args() == 2 && is_minus_one(to_app(n)->get_arg(0))) {
r = to_app(n)->get_arg(1);
return true;
}
return false;
}
bool is_le(expr const * n) const { return is_app_of(n, m_afid, OP_LE); }
bool is_ge(expr const * n) const { return is_app_of(n, m_afid, OP_GE); }
bool is_lt(expr const * n) const { return is_app_of(n, m_afid, OP_LT); }
bool is_gt(expr const * n) const { return is_app_of(n, m_afid, OP_GT); }
bool is_add(expr const * n) const { return is_app_of(n, m_afid, OP_ADD); }
bool is_sub(expr const * n) const { return is_app_of(n, m_afid, OP_SUB); }
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_idiv(expr const * n) const { return is_app_of(n, m_afid, OP_IDIV); }
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); }
bool is_to_int(expr const * n) const { return is_app_of(n, m_afid, OP_TO_INT); }
bool is_is_int(expr const * n) const { return is_app_of(n, m_afid, OP_IS_INT); }
bool is_power(expr const * n) const { return is_app_of(n, m_afid, OP_POWER); }
bool is_int(sort const * s) const { return is_sort_of(s, m_afid, INT_SORT); }
bool is_int(expr const * n) const { return is_int(m_manager.get_sort(n)); }
bool is_real(sort const * s) const { return is_sort_of(s, m_afid, REAL_SORT); }
bool is_real(expr const * n) const { return is_real(m_manager.get_sort(n)); }
bool is_int_real(sort const * s) const { return s->get_family_id() == m_afid; }
bool is_int_real(expr const * n) const { return is_int_real(m_manager.get_sort(n)); }
MATCH_UNARY(is_uminus);
MATCH_BINARY(is_sub);
MATCH_BINARY(is_add);
MATCH_BINARY(is_mul);
MATCH_BINARY(is_le);
MATCH_BINARY(is_ge);
MATCH_BINARY(is_lt);
MATCH_BINARY(is_gt);
MATCH_BINARY(is_mod);
MATCH_BINARY(is_rem);
MATCH_BINARY(is_div);
MATCH_BINARY(is_idiv);
sort * mk_int() { return m_manager.mk_sort(m_afid, INT_SORT); }
sort * mk_real() { return m_manager.mk_sort(m_afid, REAL_SORT); }
app * mk_numeral(rational const & val, bool is_int) const {
return plugin().mk_numeral(val, is_int);
}
app * mk_numeral(rational const & val, sort const * s) const {
SASSERT(is_int(s) || is_real(s));
return mk_numeral(val, is_int(s));
}
app * mk_numeral(algebraic_numbers::anum const & val, bool is_int) {
return plugin().mk_numeral(val, is_int);
}
app * mk_numeral(sexpr const * p, unsigned i) {
return plugin().mk_numeral(p, i);
}
app * mk_le(expr * arg1, expr * arg2) const { return m_manager.mk_app(m_afid, OP_LE, arg1, arg2); }
app * mk_ge(expr * arg1, expr * arg2) const { return m_manager.mk_app(m_afid, OP_GE, arg1, arg2); }
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_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_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); }
app * mk_mod(expr * arg1, expr * arg2) { return m_manager.mk_app(m_afid, OP_MOD, arg1, arg2); }
app * mk_to_real(expr * arg1) { return m_manager.mk_app(m_afid, OP_TO_REAL, arg1); }
app * mk_to_int(expr * arg1) { return m_manager.mk_app(m_afid, OP_TO_INT, arg1); }
app * mk_is_int(expr * arg1) { return m_manager.mk_app(m_afid, OP_IS_INT, arg1); }
app * mk_power(expr* arg1, expr* arg2) { return m_manager.mk_app(m_afid, OP_POWER, arg1, arg2); }
app * mk_sin(expr * arg) { return m_manager.mk_app(m_afid, OP_SIN, arg); }
app * mk_cos(expr * arg) { return m_manager.mk_app(m_afid, OP_COS, arg); }
app * mk_tan(expr * arg) { return m_manager.mk_app(m_afid, OP_TAN, arg); }
app * mk_asin(expr * arg) { return m_manager.mk_app(m_afid, OP_ASIN, arg); }
app * mk_acos(expr * arg) { return m_manager.mk_app(m_afid, OP_ACOS, arg); }
app * mk_atan(expr * arg) { return m_manager.mk_app(m_afid, OP_ATAN, arg); }
app * mk_sinh(expr * arg) { return m_manager.mk_app(m_afid, OP_SINH, arg); }
app * mk_cosh(expr * arg) { return m_manager.mk_app(m_afid, OP_COSH, arg); }
app * mk_tanh(expr * arg) { return m_manager.mk_app(m_afid, OP_TANH, arg); }
app * mk_asinh(expr * arg) { return m_manager.mk_app(m_afid, OP_ASINH, arg); }
app * mk_acosh(expr * arg) { return m_manager.mk_app(m_afid, OP_ACOSH, arg); }
app * mk_atanh(expr * arg) { return m_manager.mk_app(m_afid, OP_ATANH, arg); }
bool is_pi(expr * arg) { return is_app_of(arg, m_afid, OP_PI); }
bool is_e(expr * arg) { return is_app_of(arg, m_afid, OP_E); }
app * mk_pi() { return plugin().mk_pi(); }
app * mk_e() { return plugin().mk_e(); }
/**
\brief Return the equality (= lhs rhs), but it makes sure that
if one of the arguments is a numeral, then it will be in the right-hand-side;
if none of them are numerals, then the left-hand-side has a smaller id than the right hand side.
*/
app * mk_eq(expr * lhs, expr * rhs) {
if (is_numeral(lhs) || (!is_numeral(rhs) && lhs->get_id() > rhs->get_id()))
std::swap(lhs, rhs);
if (lhs == rhs)
return m_manager.mk_true();
if (is_numeral(lhs) && is_numeral(rhs)) {
SASSERT(lhs != rhs);
return m_manager.mk_false();
}
return m_manager.mk_eq(lhs, rhs);
}
void set_cancel(bool f) {
plugin().set_cancel(f);
}
};
#endif /* _ARITH_DECL_PLUGIN_H_ */

View file

@ -0,0 +1,570 @@
/*++
Copyright (c) 2006 Microsoft Corporation
Module Name:
array_decl_plugin.cpp
Abstract:
<abstract>
Author:
Leonardo de Moura (leonardo) 2008-01-09
Revision History:
--*/
#include<sstream>
#include"array_decl_plugin.h"
#include"warning.h"
#include"ast_pp.h"
#include"ast_ll_pp.h"
array_decl_plugin::array_decl_plugin():
m_store_sym("store"),
m_select_sym("select"),
m_const_sym("const"),
m_default_sym("default"),
m_map_sym("map"),
m_set_union_sym("union"),
m_set_intersect_sym("intersect"),
m_set_difference_sym("difference"),
m_set_complement_sym("complement"),
m_set_subset_sym("subset"),
m_array_ext_sym("array-ext"),
m_as_array_sym("as-array") {
}
#define ARRAY_SORT_STR "Array"
sort * array_decl_plugin::mk_sort(decl_kind k, unsigned num_parameters, parameter const * parameters) {
SASSERT(k == ARRAY_SORT);
if (num_parameters < 2) {
m_manager->raise_exception("invalid array sort definition, invalid number of parameters");
return 0;
}
for (unsigned i = 0; i < num_parameters; i++) {
if (!parameters[i].is_ast() || !is_sort(parameters[i].get_ast())) {
m_manager->raise_exception("invalid array sort definition, parameter is not a sort");
return 0;
}
}
sort * range = to_sort(parameters[num_parameters - 1].get_ast());
TRACE("array_decl_plugin_bug", tout << mk_pp(range, *m_manager) << "\n";);
if (!range->is_infinite() && !range->is_very_big() && (1 == range->get_num_elements().size())) {
return m_manager->mk_sort(symbol(ARRAY_SORT_STR), sort_info(m_family_id, ARRAY_SORT, 1,
num_parameters, parameters));
}
bool is_infinite = false;
bool is_very_big = false;
for (unsigned i = 0; i < num_parameters; i++) {
sort * s = to_sort(parameters[i].get_ast());
if (s->is_infinite()) {
is_infinite = true;
}
if (s->is_very_big()) {
is_very_big = true;
}
}
if (is_infinite) {
return m_manager->mk_sort(symbol(ARRAY_SORT_STR), sort_info(m_family_id, ARRAY_SORT, num_parameters, parameters));
}
else if (is_very_big) {
return m_manager->mk_sort(symbol(ARRAY_SORT_STR), sort_info(m_family_id, ARRAY_SORT, sort_size::mk_very_big(),
num_parameters, parameters));
}
else {
rational domain_sz(1);
rational num_elements;
for (unsigned i = 0; i < num_parameters - 1; i++) {
domain_sz *= rational(to_sort(parameters[i].get_ast())->get_num_elements().size(),rational::ui64());
}
if (domain_sz <= rational(128)) {
num_elements = rational(range->get_num_elements().size(),rational::ui64());
num_elements = power(num_elements, static_cast<int>(domain_sz.get_int64()));
}
if (domain_sz > rational(128) || !num_elements.is_uint64()) {
// too many elements...
return m_manager->mk_sort(symbol(ARRAY_SORT_STR),
sort_info(m_family_id,
ARRAY_SORT,
sort_size::mk_very_big(),
num_parameters,
parameters));
}
else {
return m_manager->mk_sort(symbol(ARRAY_SORT_STR), sort_info(m_family_id, ARRAY_SORT, num_elements.get_uint64(),
num_parameters, parameters));
}
}
}
bool array_decl_plugin::is_array_sort(sort* s) const {
return m_family_id == s->get_family_id() && s->get_decl_kind() == ARRAY_SORT;
}
func_decl * array_decl_plugin::mk_const(sort * s, unsigned arity, sort * const * domain) {
if (arity != 1) {
m_manager->raise_exception("invalid const array definition, invalid domain size");
return 0;
}
unsigned num_parameters = s->get_num_parameters();
if (num_parameters == 0) {
m_manager->raise_exception("parameter mismatch");
return 0;
}
// TBD check that range sort corresponds to last parameter.
parameter param(s);
func_decl_info info(m_family_id, OP_CONST_ARRAY, 1, &param);
info.m_private_parameters = true;
return m_manager->mk_func_decl(m_const_sym, arity, domain, s, info);
}
func_decl * array_decl_plugin::mk_map(func_decl* f, unsigned arity, sort* const* domain) {
if (arity != f->get_arity()) {
std::ostringstream buffer;
buffer << "map expects to take as many arguments as the function being mapped, "
<< "it was given " << arity << " but expects " << f->get_arity();
m_manager->raise_exception(buffer.str().c_str());
return 0;
}
if (arity == 0) {
m_manager->raise_exception("don't use map on constants");
return 0;
}
//
// check that each domain[i] is an array sort
// with the same domains and same ranges.
// and that the ranges coincide with the domain of f.
//
unsigned dom_arity = get_array_arity(domain[0]);
for (unsigned i = 0; i < arity; ++i) {
if (!is_array_sort(domain[i])) {
std::ostringstream buffer;
buffer << "map expects an array sort as argument at position " << i;
m_manager->raise_exception(buffer.str().c_str());
return 0;
}
if (get_array_arity(domain[i]) != dom_arity) {
std::ostringstream buffer;
buffer << "map expects all arguments to have the same array domain, "
<< "this is not the case for argument " << i;
m_manager->raise_exception(buffer.str().c_str());
return 0;
}
for (unsigned j = 0; j < dom_arity; ++j) {
if (get_array_domain(domain[i],j) != get_array_domain(domain[0],j)) {
std::ostringstream buffer;
buffer << "map expects all arguments to have the same array domain, "
<< "this is not the case for argument " << i;
m_manager->raise_exception(buffer.str().c_str());
return 0;
}
}
if (get_array_range(domain[i]) != f->get_domain(i)) {
std::ostringstream buffer;
buffer << "map expects the argument at position " << i
<< " to have the array range the same as the function";
m_manager->raise_exception(buffer.str().c_str());
return 0;
}
}
vector<parameter> parameters;
for (unsigned i = 0; i < dom_arity; ++i) {
parameters.push_back(domain[0]->get_parameter(i));
}
parameters.push_back(parameter(f->get_range()));
sort* range = mk_sort(ARRAY_SORT, parameters.size(), parameters.c_ptr());
parameter param(f);
func_decl_info info(m_family_id, OP_ARRAY_MAP, 1, &param);
//
// left_associative, right_associative, commutative are inherited.
// m_injective is inherited, since:
// forall x . g(f(x)) = x implies forall X . map(g)(map(f)(X)) = X
// since map(g)(map(f)(X))[i] = g(f(X[i])) = X[i]
//
info.set_right_associative(f->is_right_associative());
info.set_left_associative(f->is_left_associative());
info.set_commutative(f->is_commutative());
info.set_injective(f->is_injective());
return m_manager->mk_func_decl(m_map_sym, arity, domain, range, info);
}
func_decl * array_decl_plugin::mk_default(unsigned domain_size, sort * const * domain) {
if (domain_size != 1) {
m_manager->raise_exception("invalid default array definition, invalid domain size");
return 0;
}
// check that domain[0] is an array sort.
unsigned num_parameters = domain[0]->get_num_parameters();
if (num_parameters <= 1) {
m_manager->raise_exception("parameter mismatch. There should be more than one parameter to defaults");
return 0;
}
parameter param(domain[0]->get_parameter(num_parameters-1));
if (!param.is_ast() || !is_sort(param.get_ast())) {
m_manager->raise_exception("last parameter should be a sort");
return 0;
}
sort * s = to_sort(param.get_ast());
return m_manager->mk_func_decl(m_default_sym, domain_size, domain, s,
func_decl_info(m_family_id, OP_ARRAY_DEFAULT));
}
func_decl* array_decl_plugin::mk_select(unsigned arity, sort * const * domain) {
if (arity <= 1) {
m_manager->raise_exception("select takes at least two arguments");
return 0;
}
sort * s = domain[0];
unsigned num_parameters = s->get_num_parameters();
parameter const* parameters = s->get_parameters();
if (num_parameters != arity) {
m_manager->raise_exception("select requires as many arguments as the size of the domain");
return 0;
}
ptr_buffer<sort> new_domain; // we need this because of coercions.
new_domain.push_back(s);
for (unsigned i = 0; i + 1 < num_parameters; ++i) {
if (!parameters[i].is_ast() ||
!is_sort(parameters[i].get_ast()) ||
!m_manager->compatible_sorts(domain[i+1], to_sort(parameters[i].get_ast()))) {
m_manager->raise_exception("domain sort and parameter do not match");
UNREACHABLE();
return 0;
}
new_domain.push_back(to_sort(parameters[i].get_ast()));
}
SASSERT(new_domain.size() == arity);
return m_manager->mk_func_decl(m_select_sym, arity, new_domain.c_ptr(), get_array_range(domain[0]),
func_decl_info(m_family_id, OP_SELECT));
}
func_decl * array_decl_plugin::mk_store(unsigned arity, sort * const * domain) {
if (arity < 3) {
m_manager->raise_exception("store takes at least 3 arguments");
return 0;
}
sort * s = domain[0];
unsigned num_parameters = s->get_num_parameters();
parameter const * parameters = s->get_parameters();
if (!is_array_sort(s)) {
m_manager->raise_exception("store expects the first argument sort to be an array");
UNREACHABLE();
return 0;
}
if (arity != num_parameters+1) {
std::ostringstream buffer;
buffer << "store expects the first argument to be an array taking " << num_parameters+1
<< ", instead it was passed " << (arity - 1) << "arguments";
m_manager->raise_exception(buffer.str().c_str());
UNREACHABLE();
return 0;
}
ptr_buffer<sort> new_domain; // we need this because of coercions.
new_domain.push_back(s);
for (unsigned i = 0; i < num_parameters; ++i) {
if (!parameters[i].is_ast() || !is_sort(parameters[i].get_ast())) {
m_manager->raise_exception("expecting sort parameter");
return 0;
}
if (!m_manager->compatible_sorts(to_sort(parameters[i].get_ast()), domain[i+1])) {
m_manager->raise_exception("domain sort and parameter do not match");
UNREACHABLE();
return 0;
}
new_domain.push_back(to_sort(parameters[i].get_ast()));
}
SASSERT(new_domain.size() == arity);
return m_manager->mk_func_decl(m_store_sym, arity, new_domain.c_ptr(), domain[0],
func_decl_info(m_family_id, OP_STORE));
}
func_decl * array_decl_plugin::mk_array_ext_skolem(unsigned arity, sort * const * domain, unsigned i) {
if (arity != 2 || domain[0] != domain[1]) {
UNREACHABLE();
return 0;
}
sort * s = domain[0];
unsigned num_parameters = s->get_num_parameters();
if (num_parameters == 0 || i >= num_parameters - 1) {
UNREACHABLE();
return 0;
}
sort * r = to_sort(s->get_parameter(i).get_ast());
parameter param(s);
return m_manager->mk_func_decl(m_array_ext_sym, arity, domain, r, func_decl_info(m_family_id, OP_ARRAY_EXT_SKOLEM, 1, &param));
}
bool array_decl_plugin::check_set_arguments(unsigned arity, sort * const * domain) {
for (unsigned i = 0; i < arity; ++i) {
if (domain[i] != domain[0]) {
std::ostringstream buffer;
buffer << "arguments " << 1 << " and " << (i+1) << " have different sorts";
m_manager->raise_exception(buffer.str().c_str());
return false;
}
if (domain[i]->get_family_id() != m_family_id) {
std::ostringstream buffer;
buffer << "argument " << (i+1) << " is not of array sort";
m_manager->raise_exception(buffer.str().c_str());
return false;
}
}
if (arity > 0) {
unsigned num_params = domain[0]->get_num_parameters();
parameter const* params = domain[0]->get_parameters();
if (1 >= num_params) {
m_manager->raise_exception("expecting 2 or more parameters");
UNREACHABLE();
return false;
}
if (!params[num_params-1].is_ast()) {
m_manager->raise_exception("expecting term parameters");
UNREACHABLE();
return false;
}
if (!is_sort(params[num_params-1].get_ast()) || !m_manager->is_bool(to_sort(params[num_params-1].get_ast()))) {
m_manager->raise_exception("expecting boolean range");
UNREACHABLE();
return false;
}
}
return true;
}
func_decl * array_decl_plugin::mk_set_union(unsigned arity, sort * const * domain) {
if (arity == 0) {
m_manager->raise_exception("union takes at least one argument");
return 0;
}
sort * s = domain[0];
if (!check_set_arguments(arity, domain)) {
return 0;
}
parameter param(s);
func_decl_info info(m_family_id, OP_SET_UNION, 1, &param);
info.set_associative();
info.set_commutative();
info.set_idempotent();
sort* domain2[2] = { domain[0], domain[0] };
return m_manager->mk_func_decl(m_set_union_sym, 2, domain2, domain[0], info);
}
func_decl * array_decl_plugin::mk_set_intersect(unsigned arity, sort * const * domain) {
if (arity == 0) {
m_manager->raise_exception("intersection takes at least one argument");
return 0;
}
if (!check_set_arguments(arity, domain)) {
return 0;
}
func_decl_info info(m_family_id, OP_SET_INTERSECT);
info.set_associative();
info.set_commutative();
info.set_idempotent();
sort* domain2[2] = { domain[0], domain[0] };
return m_manager->mk_func_decl(m_set_intersect_sym, 2, domain2, domain[0], info);
}
func_decl * array_decl_plugin::mk_set_difference(unsigned arity, sort * const * domain) {
if (arity != 2) {
m_manager->raise_exception("set difference takes precisely two arguments");
return 0;
}
if (!check_set_arguments(arity, domain)) {
return 0;
}
return m_manager->mk_func_decl(m_set_difference_sym, arity, domain, domain[0],
func_decl_info(m_family_id, OP_SET_DIFFERENCE));
}
func_decl * array_decl_plugin::mk_set_complement(unsigned arity, sort * const * domain) {
if (arity != 1) {
m_manager->raise_exception("set complement takes one argument");
return 0;
}
if (!check_set_arguments(arity, domain)) {
return 0;
}
return m_manager->mk_func_decl(m_set_complement_sym, arity, domain, domain[0],
func_decl_info(m_family_id, OP_SET_COMPLEMENT));
}
func_decl * array_decl_plugin::mk_set_subset(unsigned arity, sort * const * domain) {
if (arity != 2) {
m_manager->raise_exception("subset takes two arguments");
return 0;
}
if (!check_set_arguments(arity, domain)) {
return 0;
}
sort * bool_sort = m_manager->mk_bool_sort();
return m_manager->mk_func_decl(m_set_subset_sym, arity, domain, bool_sort,
func_decl_info(m_family_id, OP_SET_SUBSET));
}
func_decl * array_decl_plugin::mk_as_array(func_decl * f) {
vector<parameter> parameters;
for (unsigned i = 0; i < f->get_arity(); i++) {
parameters.push_back(parameter(f->get_domain(i)));
}
parameters.push_back(parameter(f->get_range()));
sort * s = mk_sort(ARRAY_SORT, parameters.size(), parameters.c_ptr());
parameter param(f);
func_decl_info info(m_family_id, OP_AS_ARRAY, 1, &param);
return m_manager->mk_const_decl(m_as_array_sym, s, info);
}
func_decl * array_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters,
unsigned arity, sort * const * domain, sort * range) {
switch (k) {
case OP_SELECT:
return mk_select(arity, domain);
case OP_STORE:
return mk_store(arity, domain);
case OP_CONST_ARRAY: {
if (num_parameters == 1 && parameters[0].is_ast() && is_sort(parameters[0].get_ast())) {
sort * s = to_sort(parameters[0].get_ast());
return mk_const(s, arity, domain);
}
else if (range != 0) {
return mk_const(range, arity, domain);
}
else {
m_manager->raise_exception("array operation requires one sort parameter (the array sort)");
UNREACHABLE();
return 0;
}
}
case OP_ARRAY_MAP: {
if (num_parameters != 1 || !parameters[0].is_ast() || !is_func_decl(parameters[0].get_ast())) {
m_manager->raise_exception("array operation requires one function declaration parameter (the function to be mapped)");
UNREACHABLE();
return 0;
}
func_decl * f = to_func_decl(parameters[0].get_ast());
return mk_map(f, arity, domain);
}
case OP_ARRAY_EXT_SKOLEM:
if (num_parameters != 1 || !parameters[0].is_int()) {
UNREACHABLE();
return 0;
}
return mk_array_ext_skolem(arity, domain, parameters[0].get_int());
case OP_ARRAY_DEFAULT:
return mk_default(arity, domain);
case OP_SET_UNION:
return mk_set_union(arity, domain);
case OP_SET_INTERSECT:
return mk_set_intersect(arity, domain);
case OP_SET_DIFFERENCE:
return mk_set_difference(arity, domain);
case OP_SET_COMPLEMENT:
return mk_set_complement(arity, domain);
case OP_SET_SUBSET:
return mk_set_subset(arity, domain);
case OP_AS_ARRAY: {
if (num_parameters != 1 ||
!parameters[0].is_ast() ||
!is_func_decl(parameters[0].get_ast()) ||
to_func_decl(parameters[0].get_ast())->get_arity() == 0) {
TRACE("array_bug",
tout << "num_parameters: " << num_parameters << std::endl;
tout << "parameter.kind: " << parameters[0].is_int() << " " << parameters[0].is_ast() << " " << parameters[0].is_symbol() << "\n";
tout << "as-array-bug: " << to_func_decl(parameters[0].get_ast())->get_name() << " " << to_func_decl(parameters[0].get_ast())->get_arity() << std::endl;);
m_manager->raise_exception("as-array takes one parameter, a function declaration with arity greater than zero");
UNREACHABLE();
return 0;
}
func_decl * f = to_func_decl(parameters[0].get_ast());
return mk_as_array(f);
}
default: return 0;
}
}
void array_decl_plugin::get_sort_names(svector<builtin_name>& sort_names, symbol const & logic) {
sort_names.push_back(builtin_name(ARRAY_SORT_STR, ARRAY_SORT));
}
void array_decl_plugin::get_op_names(svector<builtin_name>& op_names, symbol const & logic) {
op_names.push_back(builtin_name("store",OP_STORE));
op_names.push_back(builtin_name("select",OP_SELECT));
if (logic == symbol::null) {
// none of the SMT2 logics support these extensions
op_names.push_back(builtin_name("const",OP_CONST_ARRAY));
op_names.push_back(builtin_name("map",OP_ARRAY_MAP));
op_names.push_back(builtin_name("default",OP_ARRAY_DEFAULT));
op_names.push_back(builtin_name("union",OP_SET_UNION));
op_names.push_back(builtin_name("intersect",OP_SET_INTERSECT));
op_names.push_back(builtin_name("difference",OP_SET_DIFFERENCE));
op_names.push_back(builtin_name("complement",OP_SET_COMPLEMENT));
op_names.push_back(builtin_name("subset",OP_SET_SUBSET));
op_names.push_back(builtin_name("as-array", OP_AS_ARRAY));
}
}
expr * array_decl_plugin::get_some_value(sort * s) {
SASSERT(s->is_sort_of(m_family_id, ARRAY_SORT));
sort * r = to_sort(s->get_parameter(s->get_num_parameters() - 1).get_ast());
expr * v = m_manager->get_some_value(r);
parameter p(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 {
SASSERT(s->is_sort_of(m_family_id, ARRAY_SORT));
unsigned sz = get_array_arity(s);
for (unsigned i = 0; i < sz; i++) {
if (!m_manager->is_fully_interp(get_array_domain(s, i)))
return false;
}
return m_manager->is_fully_interp(get_array_range(s));
}
bool array_util::is_as_array_tree(expr * n) {
ptr_buffer<expr, 32> todo;
todo.push_back(n);
while (!todo.empty()) {
expr * curr = todo.back();
todo.pop_back();
if (is_as_array(curr))
continue;
if (m_manager.is_ite(curr)) {
todo.push_back(to_app(curr)->get_arg(1));
todo.push_back(to_app(curr)->get_arg(2));
continue;
}
return false;
}
return true;
}
sort * array_util::mk_array_sort(unsigned arity, sort* const* domain, sort* range) {
vector<parameter> params;
for (unsigned i = 0; i < arity; ++i) {
params.push_back(parameter(domain[i]));
}
params.push_back(parameter(range));
return m_manager.mk_sort(m_fid, ARRAY_SORT, params.size(), params.c_ptr());
}

170
src/ast/array_decl_plugin.h Normal file
View file

@ -0,0 +1,170 @@
/*++
Copyright (c) 2006 Microsoft Corporation
Module Name:
array_decl_plugin.h
Abstract:
<abstract>
Author:
Leonardo de Moura (leonardo) 2008-01-09.
Revision History:
--*/
#ifndef _ARRAY_DECL_PLUGIN_H_
#define _ARRAY_DECL_PLUGIN_H_
#include"ast.h"
inline sort* get_array_range(sort const * s) {
return to_sort(s->get_parameter(s->get_num_parameters() - 1).get_ast());
}
inline unsigned get_array_arity(sort const * s) {
return s->get_num_parameters() -1;
}
inline sort* get_array_domain(sort const * s, unsigned idx) {
return to_sort(s->get_parameter(idx).get_ast());
}
enum array_sort_kind {
ARRAY_SORT
};
enum array_op_kind {
OP_STORE,
OP_SELECT,
OP_CONST_ARRAY,
OP_ARRAY_EXT_SKOLEM,
OP_ARRAY_DEFAULT,
OP_ARRAY_MAP,
OP_SET_UNION,
OP_SET_INTERSECT,
OP_SET_DIFFERENCE,
OP_SET_COMPLEMENT,
OP_SET_SUBSET,
OP_AS_ARRAY, // used for model construction
LAST_ARRAY_OP
};
class array_decl_plugin : public decl_plugin {
symbol m_store_sym;
symbol m_select_sym;
symbol m_const_sym;
symbol m_default_sym;
symbol m_map_sym;
symbol m_set_union_sym;
symbol m_set_intersect_sym;
symbol m_set_difference_sym;
symbol m_set_complement_sym;
symbol m_set_subset_sym;
symbol m_array_ext_sym;
symbol m_as_array_sym;
bool check_set_arguments(unsigned arity, sort * const * domain);
func_decl * mk_const(sort* ty, unsigned arity, sort * const * domain);
func_decl * mk_map(func_decl* f, unsigned arity, sort* const* domain);
func_decl * mk_default(unsigned arity, sort* const* domain);
func_decl * mk_select(unsigned arity, sort * const * domain);
func_decl * mk_store(unsigned arity, sort * const * domain);
func_decl * mk_array_ext_skolem(unsigned arity, sort * const * domain, unsigned i);
func_decl * mk_set_union(unsigned arity, sort * const * domain);
func_decl * mk_set_intersect(unsigned arity, sort * const * domain);
func_decl * mk_set_difference(unsigned arity, sort * const * domain);
func_decl * mk_set_complement(unsigned arity, sort * const * domain);
func_decl * mk_set_subset(unsigned arity, sort * const * domain);
func_decl * mk_as_array(func_decl * f);
bool is_array_sort(sort* s) const;
public:
array_decl_plugin();
virtual ~array_decl_plugin() {}
virtual decl_plugin * mk_fresh() {
return alloc(array_decl_plugin);
}
//
// Contract for sort:
// parameters[0] - 1st dimension
// ...
// parameters[n-1] - nth dimension
// parameters[n] - range
//
virtual sort * mk_sort(decl_kind k, unsigned num_parameters, parameter const * parameters);
//
// Contract for func_decl:
// parameters[0] - array sort
// Contract for others:
// no parameters
virtual func_decl * mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters,
unsigned arity, sort * const * domain, sort * range);
virtual void get_op_names(svector<builtin_name> & op_names, symbol const & logic);
virtual void get_sort_names(svector<builtin_name> & sort_names, symbol const & logic);
virtual expr * get_some_value(sort * s);
virtual bool is_fully_interp(sort const * s) const;
};
class array_util {
ast_manager & m_manager;
family_id m_fid;
public:
array_util(ast_manager& m): m_manager(m), m_fid(m.get_family_id("array")) {}
ast_manager & get_manager() const { return m_manager; }
family_id get_family_id() const { return m_fid; }
bool is_array(sort* s) const { return is_sort_of(s, m_fid, ARRAY_SORT);}
bool is_array(expr* n) const { return is_array(m_manager.get_sort(n)); }
bool is_select(expr* n) const { return is_app_of(n, m_fid, OP_SELECT); }
bool is_store(expr* n) const { return is_app_of(n, m_fid, OP_STORE); }
bool is_const(expr* n) const { return is_app_of(n, m_fid, OP_CONST_ARRAY); }
bool is_map(expr* n) const { return is_app_of(n, m_fid, OP_ARRAY_MAP); }
bool is_as_array(expr * n) const { return is_app_of(n, m_fid, OP_AS_ARRAY); }
bool is_as_array_tree(expr * n);
func_decl * get_as_array_func_decl(app * n) const { SASSERT(is_as_array(n)); return to_func_decl(n->get_decl()->get_parameter(0).get_ast()); }
app * mk_map(func_decl * f, unsigned num_args, expr * const * args) {
parameter p(f);
return m_manager.mk_app(m_fid, OP_ARRAY_MAP, 1, &p, num_args, args);
}
app * mk_const_array(sort * s, expr * v) {
parameter param(s);
return m_manager.mk_app(m_fid, OP_CONST_ARRAY, 1, &param, 1, &v);
}
app * mk_empty_set(sort * s) {
return mk_const_array(s, m_manager.mk_false());
}
app * mk_full_set(sort * s) {
return mk_const_array(s, m_manager.mk_true());
}
sort * mk_array_sort(sort* dom, sort* range) { return mk_array_sort(1, &dom, range); }
sort * mk_array_sort(unsigned arity, sort* const* domain, sort* range);
};
#endif /* _ARRAY_DECL_PLUGIN_H_ */

3057
src/ast/ast.cpp Normal file

File diff suppressed because it is too large Load diff

2342
src/ast/ast.h Normal file

File diff suppressed because it is too large Load diff

160
src/ast/ast_list.h Normal file
View file

@ -0,0 +1,160 @@
/*++
Copyright (c) 2006 Microsoft Corporation
Module Name:
ast_list.h
Abstract:
Quick hack to have lists of ASTs.
The lists have hash-consing.
This is a substitute for the old expr_lists implemented on top of the ASTs.
The new lists live in a different manager and do not affect the ast_manager.
Author:
Leonardo de Moura (leonardo) 2011-01-06.
Revision History:
--*/
#ifndef _AST_LIST_H_
#define _AST_LIST_H_
#include"ast.h"
template<typename AST>
class ast_list_manager_tpl;
template<typename AST>
class ast_list_tpl {
public:
typedef ast_list_tpl list;
private:
unsigned m_id;
unsigned m_is_nil:1;
unsigned m_ref_count:31;
AST * m_head;
list * m_tail;
ast_list_tpl():
m_is_nil(true),
m_ref_count(0),
m_head(0),
m_tail(0) {
}
ast_list_tpl(AST * h, list * t):
m_is_nil(false),
m_ref_count(0),
m_head(h),
m_tail(t) {
}
friend class ast_list_manager_tpl<AST>;
struct hash_proc;
friend struct hash_proc;
struct hash_proc {
unsigned operator()(ast_list_tpl * l) const {
unsigned h1 = l->m_head ? l->m_head->get_id() : 5;
unsigned h2 = l->m_tail ? l->m_tail->get_id() : 7;
return hash_u_u(h1, h2);
}
};
struct eq_proc;
friend struct eq_proc;
struct eq_proc {
bool operator()(ast_list_tpl * l1, ast_list_tpl * l2) const {
return l1->m_head == l2->m_head && l1->m_tail == l2->m_tail;
}
};
typedef ptr_hashtable<list, hash_proc, eq_proc> table; // for hash consing
public:
unsigned get_id() const { return m_id; }
unsigned get_ref_count() const { return m_ref_count; }
unsigned hash() const { return m_id; }
friend inline bool is_nil(list const * l) { return l->m_is_nil == true; }
friend inline bool is_cons(list const * l) { return !is_nil(l); }
friend inline AST * head(list const * l) { SASSERT(is_cons(l)); return l->m_head; }
friend inline list * tail(list const * l) { SASSERT(is_cons(l)); return l->m_tail; }
};
template<typename AST>
class ast_list_manager_tpl {
public:
typedef ast_list_tpl<AST> list;
typedef obj_hashtable<list> list_set;
private:
typedef typename list::table table;
ast_manager & m_manager;
small_object_allocator m_allocator;
table m_table;
id_gen m_id_gen;
list m_nil;
public:
ast_list_manager_tpl(ast_manager & m):
m_manager(m),
m_nil() {
m_nil.m_id = m_id_gen.mk();
m_nil.m_ref_count = 1;
}
void inc_ref(list * l) {
if (l != 0) {
l->m_ref_count++;
}
}
void dec_ref(list * l) {
while (l != 0) {
SASSERT(l->m_ref_count > 0);
l->m_ref_count--;
if (l->m_ref_count > 0)
return;
SASSERT(l != &m_nil);
m_table.erase(l);
m_manager.dec_ref(l->m_head);
m_id_gen.recycle(l->m_id);
list * old_l = l;
l = l->m_tail;
m_allocator.deallocate(sizeof(list), old_l);
}
}
list * mk_nil() { return &m_nil; }
list * mk_cons(AST * h, list * l) {
list tmp(h, l);
list * r = 0;
if (m_table.find(&tmp, r))
return r;
r = new (m_allocator.allocate(sizeof(list))) list(h, l);
m_manager.inc_ref(h);
inc_ref(l);
r->m_id = m_id_gen.mk();
m_table.insert(r);
return r;
}
};
typedef ast_list_tpl<expr> expr_list;
typedef ast_list_manager_tpl<expr> expr_list_manager;
typedef ast_list_tpl<quantifier> quantifier_list;
typedef ast_list_manager_tpl<quantifier> quantifier_list_manager;
typedef obj_ref<expr_list, expr_list_manager> expr_list_ref;
typedef obj_ref<quantifier_list, quantifier_list_manager> quantifier_list_ref;
typedef ref_vector<expr_list, expr_list_manager> expr_list_ref_vector;
typedef ref_vector<quantifier_list, quantifier_list_manager> quantifier_list_ref_vector;
#endif

315
src/ast/ast_ll_pp.cpp Normal file
View file

@ -0,0 +1,315 @@
/*++
Copyright (c) 2006 Microsoft Corporation
Module Name:
ast_ll_pp.cpp
Abstract:
AST low level pretty printer.
Author:
Leonardo de Moura (leonardo) 2006-10-19.
Revision History:
--*/
#include<iostream>
#include"for_each_ast.h"
#include"arith_decl_plugin.h"
// #define AST_LL_PP_SHOW_FAMILY_NAME
class ll_printer {
std::ostream & m_out;
ast_manager & m_manager;
ast * m_root;
bool m_only_exprs;
bool m_compact;
arith_util m_autil;
void display_def_header(ast * n) {
if (n != m_root) {
m_out << "#" << n->get_id() << " := ";
}
}
void display_child_ref(ast * n) {
m_out << "#" << n->get_id();
}
void display_name(func_decl * decl) {
symbol n = decl->get_name();
if (decl->is_skolem() && n.is_numerical())
m_out << "z3.sk." << n.get_num();
else
m_out << n;
}
bool process_numeral(expr * n) {
rational val;
bool is_int;
if (m_autil.is_numeral(n, val, is_int)) {
m_out << val << "::" << (is_int ? "Int" : "Real");
return true;
}
return false;
}
void display_sort(sort * s) {
m_out << s->get_name();
display_params(s);
}
void display_child(ast * n) {
switch (n->get_kind()) {
case AST_SORT:
display_sort(to_sort(n));
break;
case AST_APP:
if (process_numeral(to_expr(n))) {
// skip
}
else if (to_app(n)->get_num_args() == 0) {
display_name(to_app(n)->get_decl());
display_params(to_app(n)->get_decl());
}
else {
display_child_ref(n);
}
break;
default:
display_child_ref(n);
}
}
template<typename T>
void display_children(unsigned num_children, T * const * children) {
for (unsigned i = 0; i < num_children; i++) {
if (i > 0) {
m_out << " ";
}
display_child(children[i]);
}
}
void display_params(decl * d) {
unsigned n = d->get_num_parameters();
parameter const* p = d->get_parameters();
if (n > 0 && !d->private_parameters()) {
m_out << "[";
for (unsigned i = 0; i < n; i ++) {
if (p[i].is_ast()) {
display_child(p[i].get_ast());
}
else {
m_out << p[i];
}
m_out << (i < n-1 ? ":" : "");
}
m_out << "]";
}
}
public:
ll_printer(std::ostream & out, ast_manager & m, ast * n, bool only_exprs, bool compact):
m_out(out),
m_manager(m),
m_root(n),
m_only_exprs(only_exprs),
m_compact(compact),
m_autil(m) {
}
void operator()(sort * n) {
}
void operator()(func_decl * n) {
if (m_only_exprs) {
return;
}
if (n->get_family_id() != null_family_id) {
return;
}
m_out << "decl ";
display_name(n);
m_out << " :: ";
if (n->get_arity() == 0) {
display_child(n->get_range());
}
else {
m_out << "(-> ";
display_children(n->get_arity(), n->get_domain());
m_out << " ";
display_child(n->get_range());
m_out << ")";
display_params(n);
if (n->is_associative()) {
m_out << " :assoc";
}
if (n->is_commutative()) {
m_out << " :comm";
}
if (n->is_injective()) {
m_out << " :inj";
}
}
m_out << "\n";
}
void operator()(var * n) {
display_def_header(n);
m_out << "(:var " << to_var(n)->get_idx() << " ";
display_sort(n->get_sort());
m_out << ")\n";
}
void operator()(app * n) {
if (m_autil.is_numeral(n)) {
if (!m_compact)
display_def_header(n);
if (n == m_root || !m_compact) {
process_numeral(n);
m_out << "\n";
}
}
else if (m_manager.is_proof(n)) {
display_def_header(n);
m_out << "[" << n->get_decl()->get_name();
unsigned num_params = n->get_decl()->get_num_parameters();
for (unsigned i = 0; i < num_params; ++i) {
m_out << " ";
m_out << n->get_decl()->get_parameter(i);
}
unsigned num_parents = m_manager.get_num_parents(n);
for (unsigned i = 0; i < num_parents; i++) {
m_out << " ";
display_child(m_manager.get_parent(n, i));
}
m_out << "]: ";
if (m_manager.has_fact(n)) {
// display(m_manager.get_fact(n), 6);
display_child(m_manager.get_fact(n));
}
else
m_out << "*";
m_out << "\n";
}
else if (m_compact && n->get_num_args() == 0) {
if (n == m_root) {
display_child(n);
m_out << "\n";
}
}
else {
display_def_header(n);
if (n->get_num_args() > 0)
m_out << "(";
display_name(n->get_decl());
display_params(n->get_decl());
if (n->get_num_args() > 0) {
m_out << " ";
display_children(n->get_num_args(), n->get_args());
m_out << ")";
}
#ifdef AST_LL_PP_SHOW_FAMILY_NAME
if (to_app(n)->get_family_id() != null_family_id) {
m_out << " family: " << m_manager.get_family_name(to_app(n)->get_family_id());
}
#endif
m_out << "\n";
}
}
void operator()(quantifier * n) {
display_def_header(n);
m_out << "(" << (n->is_forall() ? "forall" : "exists") << " ";
unsigned num_decls = n->get_num_decls();
m_out << "(vars ";
for (unsigned i = 0; i < num_decls; i++) {
if (i > 0) {
m_out << " ";
}
m_out << "(" << n->get_decl_name(i) << " ";
display_sort(n->get_decl_sort(i));
m_out << ")";
}
m_out << ") ";
if (n->get_num_patterns() > 0) {
m_out << "(:pat ";
display_children(n->get_num_patterns(), n->get_patterns());
m_out << ") ";
}
if (n->get_num_no_patterns() > 0) {
m_out << "(:nopat ";
display_children(n->get_num_no_patterns(), n->get_no_patterns());
m_out << ") ";
}
display_child(n->get_expr());
m_out << ")\n";
}
void display(expr * n, unsigned depth) {
if (is_var(n)) {
m_out << "(:var " << to_var(n)->get_idx() << ")";
return;
}
if (!is_app(n) || depth == 0 || to_app(n)->get_num_args() == 0) {
display_child(n);
return;
}
if (to_app(n)->get_num_args() > depth && to_app(n)->get_num_args() > 16) {
display_child(n);
return;
}
unsigned num_args = to_app(n)->get_num_args();
if (num_args > 0)
m_out << "(";
display_name(to_app(n)->get_decl());
display_params(to_app(n)->get_decl());
for (unsigned i = 0; i < num_args; i++) {
m_out << " ";
display(to_app(n)->get_arg(i), depth-1);
}
if (num_args > 0)
m_out << ")";
}
void display_bounded(ast * n, unsigned depth) {
if (is_app(n)) {
display(to_expr(n), depth);
}
else if (is_var(n)) {
m_out << "(:var " << to_var(n)->get_idx() << ")";
}
else {
m_out << "#" << n->get_id();
}
}
};
void ast_ll_pp(std::ostream & out, ast_manager & m, ast * n, bool only_exprs, bool compact) {
ll_printer p(out, m, n, only_exprs, compact);
for_each_ast(p, n, true);
}
void ast_ll_pp(std::ostream & out, ast_manager & m, ast * n, ast_mark & visited, bool only_exprs, bool compact) {
ll_printer p(out, m, n, only_exprs, compact);
for_each_ast(p, visited, n, true);
}
void ast_def_ll_pp(std::ostream & out, ast_manager & m, ast * n, ast_mark & visited, bool only_exprs, bool compact) {
ll_printer p(out, m, 0, only_exprs, compact);
for_each_ast(p, visited, n, true);
}
void ast_ll_bounded_pp(std::ostream & out, ast_manager & m, ast * n, unsigned depth) {
ll_printer p(out, m, 0, false, true);
p.display_bounded(n, depth);
}

57
src/ast/ast_ll_pp.h Normal file
View file

@ -0,0 +1,57 @@
/*++
Copyright (c) 2006 Microsoft Corporation
Module Name:
ast_ll_pp.h
Abstract:
AST low level pretty printer.
Author:
Leonardo de Moura (leonardo) 2006-10-19.
Revision History:
--*/
#ifndef _AST_LL_PP_H_
#define _AST_LL_PP_H_
#include"ast.h"
#include<iostream>
void ast_ll_pp(std::ostream & out, ast_manager & m, ast * n, bool only_exprs=true, bool compact=true);
void ast_ll_pp(std::ostream & out, ast_manager & m, ast * n, ast_mark & visited, bool only_exprs=true, bool compact=true);
void ast_def_ll_pp(std::ostream & out, ast_manager & m, ast * n, ast_mark & visited, bool only_exprs=true, bool compact=true);
void ast_ll_bounded_pp(std::ostream & out, ast_manager & m, ast * n, unsigned depth);
struct mk_ll_pp {
ast * m_ast;
ast_manager & m_manager;
bool m_only_exprs;
bool m_compact;
mk_ll_pp(ast * a, ast_manager & m, bool only_exprs=true, bool compact=true): m_ast(a), m_manager(m), m_only_exprs(only_exprs), m_compact(compact) {}
};
inline std::ostream & operator<<(std::ostream & out, mk_ll_pp const & p) {
ast_ll_pp(out, p.m_manager, p.m_ast, p.m_only_exprs, p.m_compact);
return out;
}
struct mk_bounded_pp {
ast * m_ast;
ast_manager & m_manager;
unsigned m_depth;
mk_bounded_pp(ast * a, ast_manager & m, unsigned depth=3): m_ast(a), m_manager(m), m_depth(depth) {}
};
inline std::ostream & operator<<(std::ostream & out, mk_bounded_pp const & p) {
ast_ll_bounded_pp(out, p.m_manager, p.m_ast, p.m_depth);
return out;
}
#endif /* _AST_LL_PP_H_ */

516
src/ast/ast_pp.cpp Normal file
View file

@ -0,0 +1,516 @@
/*++
Copyright (c) 2006 Microsoft Corporation
Module Name:
ast_pp.cpp
Abstract:
Expression DAG pretty printer
Author:
Leonardo de Moura 2008-01-20.
Revision History:
--*/
#include"ast_pp.h"
#include"pp.h"
#include"obj_pair_hashtable.h"
#include"ast_ll_pp.h"
#include"arith_decl_plugin.h"
#include"bv_decl_plugin.h"
#include"datatype_decl_plugin.h"
#include"dl_decl_plugin.h"
#include"ast_list.h"
#include<sstream>
using namespace format_ns;
mk_pp::mk_pp(ast * a, ast_manager & m, pp_params const & p, unsigned indent, unsigned num_var_names, char const * const * var_names):
m_ast(a),
m_manager(m),
m_params(p),
m_indent(indent),
m_num_var_names(num_var_names),
m_var_names(var_names) {
}
mk_pp::mk_pp(ast * a, ast_manager & m, unsigned indent, unsigned num_var_names, char const * const * var_names):
m_ast(a),
m_manager(m),
m_params(get_pp_default_params()),
m_indent(indent),
m_num_var_names(num_var_names),
m_var_names(var_names) {
}
std::ostream & ast_pp(std::ostream & strm, ast * n, ast_manager & m) {
return ast_pp(strm, n, m, get_pp_default_params());
}
struct pp_cache {
typedef obj_pair_map<ast, quantifier_list, format *> cache;
ast_manager & m_manager;
cache m_cache;
pp_cache(ast_manager & m):
m_manager(m) {
}
~pp_cache() {
reset();
}
bool contains(ast * k1, quantifier_list * k2) const { return m_cache.contains(k1, k2); }
void get(ast * k1, quantifier_list * k2, format * & r) const { m_cache.find(k1, k2, r); }
void insert(ast * k1, quantifier_list * k2, format * f) {
SASSERT(!m_cache.contains(k1, k2));
fm(m_manager).inc_ref(f);
m_cache.insert(k1, k2, f);
}
void reset() {
cache::iterator it = m_cache.begin();
cache::iterator end = m_cache.end();
for (; it != end; ++it) {
format * f = (*it).get_value();
fm(m_manager).dec_ref(f);
}
m_cache.reset();
}
};
class formatter {
typedef quantifier_list_manager qlist_manager;
typedef quantifier_list_ref qlist_ref;
typedef quantifier_list_ref_vector qlist_ref_vector;
pp_params const & m_params;
ast_manager & m_manager;
qlist_manager m_qlist_manager;
pp_cache m_cache;
typedef std::pair<ast*, quantifier_list*> pp_entry;
svector<pp_entry> m_todo;
qlist_ref_vector m_qlists;
app_ref m_nil;
arith_util m_autil;
bv_util m_bvutil;
datatype_util m_datatype_util;
datalog::dl_decl_util m_dl_util;
ptr_vector<sort> m_datatypes;
app_ref_vector m_format_trail;
ast_mark m_visited_datatypes;
unsigned m_num_var_names;
char const * const * m_var_names;
struct symbol2format {
ast_manager & m_manager;
symbol2format(ast_manager & m):m_manager(m) {}
format * operator()(symbol const & s) {
std::string str = s.str();
return mk_string(m_manager, str.c_str());
}
};
format * get_cached(ast * n, quantifier_list * qlist) {
format * f = 0;
if (is_sort(n)) {
qlist = m_qlist_manager.mk_nil();
}
m_cache.get(n, qlist, f);
SASSERT(f);
return f;
}
void visit(ast * n, quantifier_list * qlist, bool & visited) {
if (is_sort(n)) {
qlist = m_qlist_manager.mk_nil();
}
if (!m_cache.contains(n, qlist)) {
m_todo.push_back(pp_entry(n, qlist));
visited = false;
}
}
bool visit_children(ast * n, quantifier_list * qlist) {
unsigned j;
bool visited = true;
switch (n->get_kind()) {
case AST_FUNC_DECL: {
func_decl* f = to_func_decl(n);
j = f->get_arity();
while (j > 0) {
--j;
visit(f->get_domain(j), qlist, visited);
}
visit(f->get_range(), qlist, visited);
j = f->get_num_parameters();
while (j > 0) {
--j;
parameter p(f->get_parameter(j));
if (p.is_ast()) {
visit(p.get_ast(), qlist, visited);
}
}
break;
}
case AST_SORT: {
sort* s = to_sort(n);
j = s->get_num_parameters();
while (j > 0) {
--j;
parameter p(s->get_parameter(j));
if (p.is_ast()) {
visit(p.get_ast(), qlist, visited);
}
}
break;
}
case AST_APP: {
app* a = to_app(n);
j = a->get_num_args();
while (j > 0) {
--j;
visit(a->get_arg(j), qlist, visited);
}
visit(a->get_decl(), qlist, visited);
break;
}
case AST_QUANTIFIER:
j = to_quantifier(n)->get_num_patterns();
qlist = m_qlist_manager.mk_cons(to_quantifier(n), qlist);
m_qlists.push_back(qlist);
while (j > 0) {
--j;
visit(to_quantifier(n)->get_pattern(j), qlist, visited);
}
j = to_quantifier(n)->get_num_no_patterns();
while (j > 0) {
--j;
visit(to_quantifier(n)->get_no_pattern(j), qlist, visited);
}
j = to_quantifier(n)->get_num_decls();
while (j > 0) {
--j;
visit(to_quantifier(n)->get_decl_sort(j), qlist, visited);
visit_sort(to_quantifier(n)->get_decl_sort(j));
}
visit(to_quantifier(n)->get_expr(), qlist, visited);
break;
default:
break;
}
return visited;
}
void reduce1(ast * n, quantifier_list * qlist) {
format * r;
switch(n->get_kind()) {
case AST_APP:
r = reduce1_app(to_app(n), qlist);
break;
case AST_VAR:
r = reduce1_var(to_var(n), qlist);
break;
case AST_QUANTIFIER:
r = reduce1_quantifier(to_quantifier(n), qlist);
break;
case AST_SORT:
r = reduce1_sort(to_sort(n), qlist);
break;
case AST_FUNC_DECL:
r = reduce1_func_decl(to_func_decl(n), qlist);
break;
}
m_cache.insert(n, qlist, r);
}
format * mk_parameter(parameter const & p, quantifier_list * qlist) {
if (p.is_int()) {
return mk_int(m_manager, p.get_int());
}
else if (p.is_symbol()) {
return mk_string(m_manager, p.get_symbol().str().c_str());
}
else if (p.is_ast()) {
ast * n = p.get_ast();
if (is_func_decl(n)) {
return mk_string(m_manager, to_func_decl(n)->get_name().str().c_str());
}
else {
return get_cached(p.get_ast(), qlist);
}
}
else if (p.is_rational()) {
return mk_string(m_manager, p.get_rational().to_string().c_str());
}
else {
return 0;
}
}
void mk_parameters(unsigned num_params, parameter const * p, quantifier_list * qlist, ptr_buffer<format> & result, bool add_separator) {
bool first = true;
for (unsigned i = 0; i < num_params; i++) {
if (!first && add_separator) {
result.push_back(mk_string(m_manager, ":"));
}
format * pp = mk_parameter(p[i], qlist);
if (pp) {
result.push_back(pp);
first = false;
}
}
}
format * mk_parameters(unsigned num_params, parameter const * p, quantifier_list * qlist) {
if (num_params == 0)
return m_nil;
ptr_buffer<format> buffer;
buffer.push_back(mk_string(m_manager, "["));
mk_parameters(num_params, p, qlist, buffer, true);
buffer.push_back(mk_string(m_manager, "]"));
return mk_compose(m_manager, buffer.size(), buffer.c_ptr());
}
void visit_sort(sort* s) {
if (m_datatype_util.is_datatype(s) &&
!m_visited_datatypes.is_marked(s)) {
m_datatypes.push_back(s);
m_visited_datatypes.mark(s, true);
}
}
format * reduce1_sort(sort * s, quantifier_list * qlist) {
if (m_datatype_util.is_datatype(s)) {
return mk_string(m_manager, s->get_name().str().c_str());
}
ptr_buffer<format> pps;
mk_parameters(s->get_num_parameters(), s->get_parameters(), qlist, pps, false);
std::string name = s->get_name().str();
if (pps.empty())
return mk_string(m_manager, name.c_str());
return mk_seq1(m_manager, pps.c_ptr(), pps.c_ptr() + pps.size(),
f2f(), name.c_str());
}
format * reduce1_func_decl(func_decl * f, quantifier_list * qlist) {
ptr_buffer<format> children;
children.push_back(mk_compose(m_manager,
mk_string(m_manager, f->get_name().str().c_str()),
mk_parameters(f->get_num_parameters(), f->get_parameters(), qlist)));
for (unsigned i = 0; i < f->get_arity(); i++)
children.push_back(get_cached(f->get_domain(i), qlist));
children.push_back(get_cached(f->get_range(), qlist));
return mk_seq1(m_manager, children.begin(), children.end(), f2f(), "define");
}
void get_children(app * n, quantifier_list * qlist, ptr_buffer<format> & result) {
for (unsigned i = 0; i < n->get_num_args(); i++)
result.push_back(get_cached(n->get_arg(i), qlist));
}
format * reduce1_app(app * n, quantifier_list * qlist) {
rational val;
bool is_int;
bool pos;
unsigned bv_size;
uint64 uval;
buffer<symbol> names;
ptr_buffer<format> children;
if (m_autil.is_numeral(n, val, is_int)) {
std::string str;
if (val.is_neg()) {
str = "(- " + (-val).to_string() + ")";
}
else {
str = val.to_string();
}
return mk_string(m_manager, str.c_str());
}
else if (m_bvutil.is_numeral(n, val, bv_size)) {
std::string str = val.to_string();
return mk_compose(m_manager,
mk_string(m_manager, "bv"),
mk_string(m_manager, str.c_str()),
mk_compose(m_manager, mk_string(m_manager, "["), mk_unsigned(m_manager, bv_size), mk_string(m_manager, "]")));
}
else if (m_dl_util.is_finite_sort(n) &&
m_dl_util.is_numeral_ext(n, uval)) {
return mk_string(m_manager, rational(uval,rational::ui64()).to_string().c_str());
}
else if (m_manager.is_label(n, pos, names)) {
get_children(n, qlist, children);
symbol2format f(m_manager);
format * lbl = names.size() > 1 ? mk_seq5(m_manager, names.begin(), names.end(), f) : f(names[0]);
format * args[2] = { lbl, children[0] };
format ** begin = args;
return mk_seq1(m_manager, begin, begin+2, f2f(), pos ? "lblpos" : "lblneg");
}
else if (m_manager.is_pattern(n)) {
get_children(n, qlist, children);
return mk_seq5(m_manager, children.begin(), children.end(), f2f(), "{", "}");
}
else if (m_manager.is_proof(n)) {
get_children(n, qlist, children);
return mk_seq2(m_manager, children.begin(), children.end(), f2f(), n->get_decl()->get_name().str().c_str(),
FORMAT_DEFAULT_INDENT, "[", "]");
}
else if (m_params.m_pp_fixed_indent || (n->get_decl()->get_num_parameters() > 0 && !n->get_decl()->private_parameters())) {
format * head = mk_compose(m_manager,
mk_string(m_manager, n->get_decl()->get_name().str().c_str()),
mk_parameters(n->get_decl()->get_num_parameters(), n->get_decl()->get_parameters(), qlist));
if (n->get_num_args() == 0)
return head;
children.push_back(head);
get_children(n, qlist, children);
return mk_seq4(m_manager, children.begin(), children.end(), f2f());
}
else if (n->get_num_args() == 0)
return mk_string(m_manager, n->get_decl()->get_name().str().c_str());
else {
get_children(n, qlist, children);
return mk_seq1(m_manager, children.begin(), children.end(), f2f(), n->get_decl()->get_name().str().c_str());
}
}
format * reduce1_var(var * v, quantifier_list * qlist) {
unsigned idx = v->get_idx();
unsigned i = idx;
while (!is_nil(qlist)) {
quantifier * q = head(qlist);
if (i < q->get_num_decls())
return mk_string(m_manager, q->get_decl_name(q->get_num_decls() - i - 1).str().c_str());
i -= q->get_num_decls();
qlist = tail(qlist);
}
if (i < m_num_var_names) {
return mk_string(m_manager, m_var_names[m_num_var_names - i - 1]);
}
else {
return mk_compose(m_manager, mk_string(m_manager, "#"), mk_unsigned(m_manager, idx));
}
}
format * reduce1_quantifier(quantifier * q, quantifier_list * qlist) {
qlist = m_qlist_manager.mk_cons(q, qlist);
ptr_buffer<format> buffer;
unsigned num = q->get_num_decls();
for (unsigned j = 0; j < num; j++) {
format * d[2];
d[0] = mk_string(m_manager, q->get_decl_name(j).str().c_str());
d[1] = get_cached(q->get_decl_sort(j), qlist);
format ** it = d;
buffer.push_back(mk_seq5(m_manager, it, it+2, f2f()));
}
buffer.push_back(get_cached(q->get_expr(), qlist));
num = q->get_num_patterns();
char const * pat = ":pat ";
unsigned pat_indent = static_cast<unsigned>(strlen(pat));
for (unsigned i = 0; i < num; i++)
buffer.push_back(mk_compose(m_manager, mk_string(m_manager, pat), mk_indent(m_manager, pat_indent, get_cached(q->get_pattern(i), qlist))));
num = q->get_num_no_patterns();
for (unsigned i = 0; i < num; i++)
buffer.push_back(mk_compose(m_manager, mk_string(m_manager, ":nopat {"), get_cached(q->get_no_pattern(i), qlist), mk_string(m_manager, "}")));
if (q->get_qid() != symbol::null)
buffer.push_back(mk_compose(m_manager, mk_string(m_manager, ":qid {"), mk_string(m_manager, q->get_qid().str().c_str()), mk_string(m_manager, "}")));
return mk_seq3(m_manager, buffer.begin(), buffer.end(), f2f(), q->is_forall() ? "forall" : "exists",
q->get_num_decls());
}
public:
formatter(ast_manager & m, pp_params const & p, unsigned num_var_names, char const * const * var_names):
m_params(p),
m_manager(m),
m_qlist_manager(m),
m_cache(m),
m_qlists(m_qlist_manager),
m_nil(mk_nil(m), fm(m)),
m_autil(m),
m_bvutil(m),
m_datatype_util(m),
m_dl_util(m),
m_format_trail(fm(m)),
m_num_var_names(num_var_names),
m_var_names(var_names) {
}
~formatter() {
}
format * operator()(ast * n) {
m_todo.push_back(pp_entry(n, m_qlist_manager.mk_nil()));
while (!m_todo.empty()) {
pp_entry k = m_todo.back();
if (m_cache.contains(k.first, k.second))
m_todo.pop_back();
else if (visit_children(k.first, k.second)) {
m_todo.pop_back();
reduce1(k.first, k.second);
}
}
format* f1 = get_cached(n, m_qlist_manager.mk_nil());
if (m_datatypes.empty()) {
return f1;
}
ptr_buffer<format> formats;
formats.push_back(f1);
for (unsigned i = 0; i < m_datatypes.size(); ++i) {
sort* s = m_datatypes[i];
std::ostringstream buffer;
m_datatype_util.display_datatype(s, buffer);
format* f2 = mk_string(m_manager, buffer.str().c_str());
formats.push_back(mk_line_break(m_manager));
formats.push_back(f2);
}
f1 = mk_compose(m_manager, formats.size(), formats.c_ptr());
//
// Ensure that reference count is live.
//
m_format_trail.push_back(f1);
return f1;
}
};
std::ostream & ast_pp(std::ostream & out, ast * n, ast_manager & m, pp_params const & p, unsigned indent,
unsigned num_vars, char const * const * names) {
formatter f(m, p, num_vars, names);
app_ref fmt(fm(m));
fmt = f(n);
if (indent > 0)
fmt = format_ns::mk_indent(m, indent, fmt);
pp(out, fmt, m, p);
return out;
}
std::string & ast_pp(std::string & out, ast * n, ast_manager & m, pp_params const & p, unsigned indent) {
std::ostringstream buffer;
buffer << mk_pp(n, m, p, indent);
out += buffer.str();
return out;
}
std::string ast_pp(ast * n, ast_manager & m, pp_params const & p, unsigned indent) {
std::string out;
return ast_pp(out, n, m, p, indent);
}
std::string & ast_pp(std::string & out, ast * n, ast_manager & m) {
return ast_pp(out, n, m, get_pp_default_params());
}
std::string ast_pp(ast * n, ast_manager & m) {
return ast_pp(n, m, get_pp_default_params());
}

53
src/ast/ast_pp.h Normal file
View file

@ -0,0 +1,53 @@
/*++
Copyright (c) 2006 Microsoft Corporation
Module Name:
ast_pp.h
Abstract:
Pretty printer
Author:
Leonardo de Moura 2008-01-20.
Revision History:
--*/
#ifndef _AST_PP_H_
#define _AST_PP_H_
#include"ast.h"
#include"pp_params.h"
std::ostream & ast_pp(std::ostream & strm, ast * n, ast_manager & m, pp_params const & p, unsigned indent = 0,
unsigned num_vars = 0, char const * const * names = 0);
std::ostream & ast_pp(std::ostream & strm, ast * n, ast_manager & m);
std::string & ast_pp(std::string & s, ast * n, ast_manager & m, pp_params const & p, unsigned indent = 0);
std::string ast_pp(ast * n, ast_manager & m, pp_params const & p, unsigned indent = 0);
std::string & ast_pp(std::string & s, ast * n, ast_manager & m);
std::string ast_pp(ast * n, ast_manager & m);
struct mk_pp {
ast * m_ast;
ast_manager & m_manager;
pp_params const & m_params;
unsigned m_indent;
unsigned m_num_var_names;
char const * const * m_var_names;
mk_pp(ast * a, ast_manager & m, pp_params const & p, unsigned indent = 0, unsigned num_var_names = 0, char const * const * var_names = 0);
mk_pp(ast * a, ast_manager & m, unsigned indent = 0, unsigned num_var_names = 0, char const * const * var_names = 0);
};
inline std::ostream& operator<<(std::ostream& out, const mk_pp & p) {
return ast_pp(out, p.m_ast, p.m_manager, p.m_params, p.m_indent, p.m_num_var_names, p.m_var_names);
}
inline std::string& operator+=(std::string& out, const mk_pp & p) {
return ast_pp(out, p.m_ast, p.m_manager, p.m_params, p.m_indent);
}
#endif

1140
src/ast/ast_smt2_pp.cpp Normal file

File diff suppressed because it is too large Load diff

116
src/ast/ast_smt2_pp.h Normal file
View file

@ -0,0 +1,116 @@
/*++
Copyright (c) 2011 Microsoft Corporation
Module Name:
ast_smt2_pp.cpp
Abstract:
Pretty printer of AST formulas using SMT2 format.
This printer is more expensive than the one in ast_smt_pp.h,
but is supposed to generated a "prettier" and SMT2 compliant output.
Author:
Leonardo de Moura (leonardo)
Revision History:
--*/
#ifndef _AST_SMT2_PP_H_
#define _AST_SMT2_PP_H_
#include"format.h"
#include"pp_params.h"
#include"arith_decl_plugin.h"
#include"bv_decl_plugin.h"
#include"array_decl_plugin.h"
#include"float_decl_plugin.h"
#include"dl_decl_plugin.h"
bool is_smt2_simple_symbol_char(char c);
bool is_smt2_quoted_symbol(char const * s);
bool is_smt2_quoted_symbol(symbol const & s);
std::string mk_smt2_quoted_symbol(symbol const & s);
class smt2_pp_environment {
protected:
format_ns::format * mk_neg(format_ns::format * f) const;
format_ns::format * mk_float(rational const & val) const;
bool is_indexed_fdecl(func_decl * f) const;
format_ns::format * pp_fdecl_params(format_ns::format * fname, func_decl * f);
bool is_sort_param(func_decl * f) const;
format_ns::format * pp_as(format_ns::format * fname, sort * s);
format_ns::format * pp_signature(format_ns::format * f_name, func_decl * f);
public:
virtual ~smt2_pp_environment() {}
virtual ast_manager & get_manager() const = 0;
virtual arith_util & get_autil() = 0;
virtual bv_util & get_bvutil() = 0;
virtual array_util & get_arutil() = 0;
virtual float_util & get_futil() = 0;
virtual datalog::dl_decl_util& get_dlutil() = 0;
virtual bool uses(symbol const & s) const = 0;
virtual format_ns::format * pp_fdecl(func_decl * f, unsigned & len);
virtual format_ns::format * pp_bv_literal(app * t, bool use_bv_lits, bool bv_neg);
virtual format_ns::format * pp_arith_literal(app * t, bool decimal, unsigned prec);
virtual format_ns::format * pp_float_literal(app * t);
virtual format_ns::format * pp_datalog_literal(app * t);
virtual format_ns::format * pp_sort(sort * s);
virtual format_ns::format * pp_fdecl_ref(func_decl * f);
format_ns::format * pp_fdecl_name(symbol const & fname, unsigned & len) const;
format_ns::format * pp_fdecl_name(func_decl * f, unsigned & len) const;
};
/**
\brief Simple environment that ignores name clashes.
Useful for debugging code.
*/
class smt2_pp_environment_dbg : public smt2_pp_environment {
ast_manager & m_manager;
arith_util m_autil;
bv_util m_bvutil;
array_util m_arutil;
float_util m_futil;
datalog::dl_decl_util m_dlutil;
public:
smt2_pp_environment_dbg(ast_manager & m):m_manager(m), m_autil(m), m_bvutil(m), m_arutil(m), m_futil(m), m_dlutil(m) {}
virtual ast_manager & get_manager() const { return m_manager; }
virtual arith_util & get_autil() { return m_autil; }
virtual bv_util & get_bvutil() { return m_bvutil; }
virtual array_util & get_arutil() { return m_arutil; }
virtual float_util & get_futil() { return m_futil; }
virtual datalog::dl_decl_util& get_dlutil() { return m_dlutil; }
virtual bool uses(symbol const & s) const { return false; }
};
void mk_smt2_format(expr * n, smt2_pp_environment & env, pp_params const & p,
unsigned num_vars, char const * var_prefix,
format_ns::format_ref & r, sbuffer<symbol> & var_names);
void mk_smt2_format(sort * s, smt2_pp_environment & env, pp_params const & p, format_ns::format_ref & r);
void mk_smt2_format(func_decl * f, smt2_pp_environment & env, pp_params const & p, format_ns::format_ref & r);
std::ostream & ast_smt2_pp(std::ostream & out, expr * n, smt2_pp_environment & env, pp_params const & p, unsigned indent = 0,
unsigned num_vars = 0, char const * var_prefix = 0);
std::ostream & ast_smt2_pp(std::ostream & out, sort * s, smt2_pp_environment & env, pp_params const & p, unsigned indent = 0);
std::ostream & ast_smt2_pp(std::ostream & out, func_decl * f, smt2_pp_environment & env, pp_params const & p, unsigned indent = 0);
/**
\brief Internal wrapper (for debugging purposes only)
*/
struct mk_ismt2_pp {
ast * m_ast;
ast_manager & m_manager;
pp_params const & m_params;
unsigned m_indent;
unsigned m_num_vars;
char const * m_var_prefix;
mk_ismt2_pp(ast * t, ast_manager & m, pp_params const & p, unsigned indent = 0, unsigned num_vars = 0, char const * var_prefix = 0);
mk_ismt2_pp(ast * t, ast_manager & m, unsigned indent = 0, unsigned num_vars = 0, char const * var_prefix = 0);
};
std::ostream& operator<<(std::ostream& out, mk_ismt2_pp const & p);
#endif

140
src/ast/ast_util.cpp Normal file
View file

@ -0,0 +1,140 @@
#include "ast_util.h"
app * mk_list_assoc_app(ast_manager & m, func_decl * f, unsigned num_args, expr * const * args) {
SASSERT(f->is_associative());
SASSERT(num_args >= 2);
if (num_args > 2) {
unsigned j = num_args - 1;
app * r = m.mk_app(f, args[j-1], args[j]);
-- j;
while (j > 0) {
--j;
r = m.mk_app(f, args[j], r);
}
return r;
}
else {
SASSERT(num_args == 2);
return m.mk_app(f, args[0], args[1]);
}
}
app * mk_list_assoc_app(ast_manager & m, family_id fid, decl_kind k, unsigned num_args, expr * const * args) {
func_decl * decl = m.mk_func_decl(fid, k, 0, 0, num_args, args, 0);
SASSERT(decl != 0);
SASSERT(decl->is_associative());
return mk_list_assoc_app(m, decl, num_args, args);
}
bool is_well_formed_vars(ptr_vector<sort>& bound, expr* e) {
ptr_vector<expr> todo;
ast_mark mark;
todo.push_back(e);
while (!todo.empty()) {
expr* e = todo.back();
todo.pop_back();
if (mark.is_marked(e)) {
continue;
}
mark.mark(e, true);
if (is_quantifier(e)) {
quantifier* q = to_quantifier(e);
unsigned depth = q->get_num_decls();
bound.append(depth, q->get_decl_sorts());
if (!is_well_formed_vars(bound, q->get_expr())) {
return false;
}
bound.resize(bound.size()-depth);
}
else if (is_app(e)) {
app* a = to_app(e);
for (unsigned i = 0; i < a->get_num_args(); ++i) {
todo.push_back(a->get_arg(i));
}
}
else if (is_var(e)) {
var* v = to_var(e);
unsigned index = v->get_idx();
sort* s = v->get_sort();
SASSERT(index < bound.size());
index = bound.size()-1-index;
if (!bound[index]) {
bound[index] = s;
}
if (bound[index] != s) {
return false;
}
}
else {
UNREACHABLE();
}
}
return true;
}
bool is_atom(ast_manager & m, expr * n) {
if (is_quantifier(n) || !m.is_bool(n))
return false;
if (is_var(n))
return true;
SASSERT(is_app(n));
if (to_app(n)->get_family_id() != m.get_basic_family_id()) {
return true;
}
// the other operators of the basic family are not considered atomic: distinct, ite, and, or, iff, xor, not, implies.
return (m.is_eq(n) && !m.is_bool(to_app(n)->get_arg(0))) || m.is_true(n) || m.is_false(n);
}
bool is_literal(ast_manager & m, expr * n) {
return
is_atom(m, n) ||
(m.is_not(n) && is_atom(m, to_app(n)->get_arg(0)));
}
void get_literal_atom_sign(ast_manager & m, expr * n, expr * & atom, bool & sign) {
SASSERT(is_literal(m, n));
if (is_atom(m, n)) {
atom = n;
sign = false;
}
else {
SASSERT(m.is_not(n));
atom = to_app(n)->get_arg(0);
sign = true;
}
}
bool is_clause(ast_manager & m, expr * n) {
if (is_literal(m, n))
return true;
if (m.is_or(n)) {
unsigned num_args = to_app(n)->get_num_args();
for (unsigned i = 0; i < num_args; i++) {
if (!is_literal(m, to_app(n)->get_arg(i)))
return false;
}
return true;
}
return false;
}
unsigned get_clause_num_literals(ast_manager & m, expr * cls) {
SASSERT(is_clause(m, cls));
if (is_literal(m, cls))
return 1;
SASSERT(m.is_or(cls));
return to_app(cls)->get_num_args();
}
expr * get_clause_literal(ast_manager & m, expr * cls, unsigned idx) {
SASSERT(is_clause(m, cls));
SASSERT(idx < get_clause_num_literals(m, cls));
if (is_literal(m, cls)) {
SASSERT(idx == 0);
return cls;
}
SASSERT(m.is_or(cls));
return to_app(cls)->get_arg(idx);
}

99
src/ast/ast_util.h Normal file
View file

@ -0,0 +1,99 @@
/*++
Copyright (c) 2006 Microsoft Corporation
Module Name:
ast_util.h
Abstract:
Helper functions
Author:
Leonardo de Moura (leonardo) 2007-06-08.
Revision History:
--*/
#ifndef _AST_UTIL_H_
#define _AST_UTIL_H_
#include"ast.h"
#include"obj_hashtable.h"
template<typename C>
void remove_duplicates(C & v) {
expr_fast_mark1 visited;
if (!v.empty()) {
unsigned sz = v.size();
unsigned j = 0;
for (unsigned i = 0; i < sz; i++) {
typename C::data curr = v.get(i);
if (!visited.is_marked(curr)) {
visited.mark(curr);
if (i != j)
v.set(j, curr);
j++;
}
}
v.shrink(j);
}
}
app * mk_list_assoc_app(ast_manager & m, func_decl * f, unsigned num_args, expr * const * args);
app * mk_list_assoc_app(ast_manager & m, family_id fid, decl_kind k, unsigned num_args, expr * const * args);
bool is_well_formed_vars(ptr_vector<sort>& bound, expr* n);
inline bool args_are_vars(app const * n) {
unsigned sz = n->get_num_args();
for (unsigned i = 0; i < sz; i++) {
if (!is_var(n->get_arg(i)))
return false;
}
return true;
}
inline bool depth_leq_one(app * n) {
unsigned sz = n->get_num_args();
for (unsigned i = 0; i < sz; i++) {
expr * arg = n->get_arg(i);
if (is_app(arg) && to_app(arg)->get_num_args() > 0)
return false;
}
return true;
}
template<typename AST>
void dec_ref(ast_manager & m, obj_hashtable<AST> & s) {
typename obj_hashtable<AST>::iterator it = s.begin();
typename obj_hashtable<AST>::iterator end = s.end();
for (;it != end; ++it) {
m.dec_ref(*it);
}
}
template<typename AST>
void inc_ref(ast_manager & m, obj_hashtable<AST> & s) {
typename obj_hashtable<AST>::iterator it = s.begin();
typename obj_hashtable<AST>::iterator end = s.end();
for (;it != end; ++it) {
m.inc_ref(*it);
}
}
// -----------------------------------
//
// Clauses (as ASTs) support
//
// -----------------------------------
bool is_atom(ast_manager & m, expr * n);
bool is_literal(ast_manager & m, expr * n);
void get_literal_atom_sign(ast_manager & m, expr * n, expr * & atom, bool & sign);
bool is_clause(ast_manager & m, expr * n);
unsigned get_clause_num_literals(ast_manager & m, expr * cls);
expr * get_clause_literal(ast_manager & m, expr * cls, unsigned idx);
#endif /* _AST_UTIL_H_ */

840
src/ast/bv_decl_plugin.cpp Normal file
View file

@ -0,0 +1,840 @@
/*++
Copyright (c) 2006 Microsoft Corporation
Module Name:
bv_decl_plugin.cpp
Abstract:
<abstract>
Author:
Leonardo de Moura (leonardo) 2008-01-09.
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"
bv_decl_plugin::bv_decl_plugin():
m_bv_sym("bv"),
m_concat_sym("concat"),
m_sign_extend_sym("sign_extend"),
m_zero_extend_sym("zero_extend"),
m_extract_sym("extract"),
m_rotate_left_sym("rotate_left"),
m_rotate_right_sym("rotate_right"),
m_repeat_sym("repeat"),
m_bit2bool_sym("bit2bool"),
m_mkbv_sym("mkbv"),
m_bit0(0),
m_bit1(0),
m_carry(0),
m_xor3(0),
m_int_sort(0) {
}
void bv_decl_plugin::mk_table_upto(unsigned n) {
if (m_powers.empty()) {
m_powers.push_back(rational(1));
}
unsigned sz = m_powers.size();
rational curr = m_powers[sz - 1];
rational two(2);
for (unsigned i = sz; i <= n; i++) {
curr *= two;
m_powers.push_back(curr);
}
}
rational bv_decl_plugin::power_of_two(unsigned n) const {
if (n >= m_powers.size()) {
const_cast<bv_decl_plugin*>(this)->mk_table_upto(n + 1);
}
return m_powers[n];
}
void bv_decl_plugin::set_manager(ast_manager * m, family_id id) {
decl_plugin::set_manager(m, id);
for (unsigned i = 1; i <= 64; i++) {
mk_bv_sort(i);
}
m_bit0 = m->mk_const_decl(symbol("bit0"), get_bv_sort(1), func_decl_info(m_family_id, OP_BIT0));
m_bit1 = m->mk_const_decl(symbol("bit1"), get_bv_sort(1), func_decl_info(m_family_id, OP_BIT1));
m->inc_ref(m_bit0);
m->inc_ref(m_bit1);
sort * b = m->mk_bool_sort();
sort * d[3] = {b, b, b};
m_carry = m_manager->mk_func_decl(symbol("carry"), 3, d, b, func_decl_info(m_family_id, OP_CARRY));
m_manager->inc_ref(m_carry);
m_xor3 = m_manager->mk_func_decl(symbol("xor3"), 3, d, b, func_decl_info(m_family_id, OP_XOR3));
m_manager->inc_ref(m_xor3);
m_int_sort = m_manager->mk_sort(m_manager->get_family_id("arith"), INT_SORT);
SASSERT(m_int_sort != 0); // arith_decl_plugin must be installed before bv_decl_plugin.
m_manager->inc_ref(m_int_sort);
}
void bv_decl_plugin::finalize() {
#define DEC_REF(FIELD) dec_range_ref(FIELD.begin(), FIELD.end(), *m_manager)
if (m_bit0) { m_manager->dec_ref(m_bit0); }
if (m_bit1) { m_manager->dec_ref(m_bit1); }
if (m_carry) { m_manager->dec_ref(m_carry); }
if (m_xor3) { m_manager->dec_ref(m_xor3); }
if (m_int_sort) { m_manager->dec_ref(m_int_sort); }
DEC_REF(m_bv_sorts);
DEC_REF(m_bv_neg);
DEC_REF(m_bv_add);
DEC_REF(m_bv_sub);
DEC_REF(m_bv_mul);
DEC_REF(m_bv_sdiv);
DEC_REF(m_bv_udiv);
DEC_REF(m_bv_srem);
DEC_REF(m_bv_urem);
DEC_REF(m_bv_smod);
DEC_REF(m_bv_sdiv0);
DEC_REF(m_bv_udiv0);
DEC_REF(m_bv_srem0);
DEC_REF(m_bv_urem0);
DEC_REF(m_bv_smod0);
DEC_REF(m_bv_sdiv_i);
DEC_REF(m_bv_udiv_i);
DEC_REF(m_bv_srem_i);
DEC_REF(m_bv_urem_i);
DEC_REF(m_bv_smod_i);
DEC_REF(m_bv_uleq);
DEC_REF(m_bv_sleq);
DEC_REF(m_bv_ugeq);
DEC_REF(m_bv_sgeq);
DEC_REF(m_bv_ult);
DEC_REF(m_bv_slt);
DEC_REF(m_bv_ugt);
DEC_REF(m_bv_sgt);
DEC_REF(m_bv_and);
DEC_REF(m_bv_or);
DEC_REF(m_bv_not);
DEC_REF(m_bv_xor);
DEC_REF(m_bv_nand);
DEC_REF(m_bv_nor);
DEC_REF(m_bv_xnor);
DEC_REF(m_bv_redor);
DEC_REF(m_bv_redand);
DEC_REF(m_bv_comp);
DEC_REF(m_bv_mul_ovfl);
DEC_REF(m_bv_smul_ovfl);
DEC_REF(m_bv_smul_udfl);
DEC_REF(m_bv_shl);
DEC_REF(m_bv_lshr);
DEC_REF(m_bv_ashr);
DEC_REF(m_ext_rotate_left);
DEC_REF(m_ext_rotate_right);
DEC_REF(m_int2bv);
DEC_REF(m_bv2int);
vector<ptr_vector<func_decl> >::iterator it = m_bit2bool.begin();
vector<ptr_vector<func_decl> >::iterator end = m_bit2bool.end();
for (; it != end; ++it) {
ptr_vector<func_decl> & ds = *it;
DEC_REF(ds);
}
DEC_REF(m_mkbv);
}
void bv_decl_plugin::mk_bv_sort(unsigned bv_size) {
force_ptr_array_size(m_bv_sorts, bv_size + 1);
if (m_bv_sorts[bv_size] == 0) {
parameter p(bv_size);
sort_size sz;
if (sort_size::is_very_big_base2(bv_size)) {
sz = sort_size::mk_very_big();
}
else {
sz = sort_size(power_of_two(bv_size));
}
m_bv_sorts[bv_size] = m_manager->mk_sort(symbol("bv"), sort_info(m_family_id, BV_SORT, sz, 1, &p));
m_manager->inc_ref(m_bv_sorts[bv_size]);
}
}
inline sort * bv_decl_plugin::get_bv_sort(unsigned bv_size) {
if (bv_size < (1 << 12)) {
mk_bv_sort(bv_size);
return m_bv_sorts[bv_size];
}
parameter p(bv_size);
sort_size sz(sort_size::mk_very_big());
return m_manager->mk_sort(symbol("bv"), sort_info(m_family_id, BV_SORT, sz, 1, &p));
}
sort * bv_decl_plugin::mk_sort(decl_kind k, unsigned num_parameters, parameter const * parameters) {
if (!(num_parameters == 1 && parameters[0].is_int())) {
m_manager->raise_exception("expecting one integer parameter to bit-vector sort");
}
unsigned bv_size = parameters[0].get_int();
mk_bv_sort(bv_size);
return m_bv_sorts[bv_size];
}
func_decl * bv_decl_plugin::mk_binary(ptr_vector<func_decl> & decls, decl_kind k,
char const * name, unsigned bv_size, bool ac, bool idempotent) {
force_ptr_array_size(decls, bv_size + 1);
if (decls[bv_size] == 0) {
sort * s = get_bv_sort(bv_size);
func_decl_info info(m_family_id, k);
info.set_associative(ac);
info.set_flat_associative(ac);
info.set_commutative(ac);
info.set_idempotent(idempotent);
decls[bv_size] = m_manager->mk_func_decl(symbol(name), s, s, s, info);
m_manager->inc_ref(decls[bv_size]);
}
return decls[bv_size];
}
func_decl * bv_decl_plugin::mk_unary(ptr_vector<func_decl> & decls, decl_kind k, char const * name, unsigned bv_size) {
force_ptr_array_size(decls, bv_size + 1);
if (decls[bv_size] == 0) {
sort * s = get_bv_sort(bv_size);
decls[bv_size] = m_manager->mk_func_decl(symbol(name), s, s, func_decl_info(m_family_id, k));
m_manager->inc_ref(decls[bv_size]);
}
return decls[bv_size];
}
func_decl * bv_decl_plugin::mk_int2bv(unsigned bv_size, unsigned num_parameters, parameter const * parameters,
unsigned arity, sort * const * domain) {
force_ptr_array_size(m_int2bv, bv_size + 1);
if (arity != 1) {
m_manager->raise_exception("expecting one argument to int2bv");
return 0;
}
if (m_int2bv[bv_size] == 0) {
sort * s = get_bv_sort(bv_size);
m_int2bv[bv_size] = m_manager->mk_func_decl(symbol("int2bv"), domain[0], s,
func_decl_info(m_family_id, OP_INT2BV, num_parameters, parameters));
m_manager->inc_ref(m_int2bv[bv_size]);
}
return m_int2bv[bv_size];
}
func_decl * bv_decl_plugin::mk_bv2int(unsigned bv_size, unsigned num_parameters, parameter const * parameters,
unsigned arity, sort * const * domain) {
force_ptr_array_size(m_bv2int, bv_size + 1);
if (arity != 1) {
m_manager->raise_exception("expecting one argument to bv2int");
return 0;
}
if (m_bv2int[bv_size] == 0) {
m_bv2int[bv_size] = m_manager->mk_func_decl(symbol("bv2int"), domain[0], m_int_sort,
func_decl_info(m_family_id, OP_BV2INT));
m_manager->inc_ref(m_bv2int[bv_size]);
}
return m_bv2int[bv_size];
}
func_decl * bv_decl_plugin::mk_pred(ptr_vector<func_decl> & decls, decl_kind k, char const * name, unsigned bv_size) {
force_ptr_array_size(decls, bv_size + 1);
if (decls[bv_size] == 0) {
sort * s = get_bv_sort(bv_size);
decls[bv_size] = m_manager->mk_func_decl(symbol(name), s, s, m_manager->mk_bool_sort(), func_decl_info(m_family_id, k));
m_manager->inc_ref(decls[bv_size]);
}
return decls[bv_size];
}
func_decl * bv_decl_plugin::mk_reduction(ptr_vector<func_decl> & decls, decl_kind k, char const * name, unsigned bv_size) {
force_ptr_array_size(decls, bv_size + 1);
if (decls[bv_size] == 0) {
sort * d = get_bv_sort(bv_size);
sort * r = get_bv_sort(1);
decls[bv_size] = m_manager->mk_func_decl(symbol(name), d, r, func_decl_info(m_family_id, k));
m_manager->inc_ref(decls[bv_size]);
}
return decls[bv_size];
}
func_decl * bv_decl_plugin::mk_comp(unsigned bv_size) {
force_ptr_array_size(m_bv_comp, bv_size + 1);
if (m_bv_comp[bv_size] == 0) {
sort * d = get_bv_sort(bv_size);
sort * r = get_bv_sort(1);
func_decl_info info(m_family_id, OP_BCOMP);
info.set_commutative();
m_bv_comp[bv_size] = m_manager->mk_func_decl(symbol("bvcomp"), d, d, r, info);
m_manager->inc_ref(m_bv_comp[bv_size]);
}
return m_bv_comp[bv_size];
}
func_decl * bv_decl_plugin::mk_func_decl(decl_kind k, unsigned bv_size) {
switch (k) {
case OP_BNEG: return mk_unary(m_bv_neg, k, "bvneg", bv_size);
case OP_BADD: return mk_binary(m_bv_add, k, "bvadd", bv_size, true);
case OP_BSUB: return mk_binary(m_bv_sub, k, "bvsub", bv_size, false);
case OP_BMUL: return mk_binary(m_bv_mul, k, "bvmul", bv_size, true);
case OP_BSDIV: return mk_binary(m_bv_sdiv, k, "bvsdiv", bv_size, false);
case OP_BUDIV: return mk_binary(m_bv_udiv, k, "bvudiv", bv_size, false);
case OP_BSREM: return mk_binary(m_bv_srem, k, "bvsrem", bv_size, false);
case OP_BUREM: return mk_binary(m_bv_urem, k, "bvurem", bv_size, false);
case OP_BSMOD: return mk_binary(m_bv_smod, k, "bvsmod", bv_size, false);
case OP_BSDIV0: return mk_unary(m_bv_sdiv0, k, "bvsdiv0", bv_size);
case OP_BUDIV0: return mk_unary(m_bv_udiv0, k, "bvudiv0", bv_size);
case OP_BSREM0: return mk_unary(m_bv_srem0, k, "bvsrem0", bv_size);
case OP_BUREM0: return mk_unary(m_bv_urem0, k, "bvurem0", bv_size);
case OP_BSMOD0: return mk_unary(m_bv_smod0, k, "bvsmod0", bv_size);
case OP_BSDIV_I: return mk_binary(m_bv_sdiv_i, k, "bvsdiv_i", bv_size, false);
case OP_BUDIV_I: return mk_binary(m_bv_udiv_i, k, "bvudiv_i", bv_size, false);
case OP_BSREM_I: return mk_binary(m_bv_srem_i, k, "bvsrem_i", bv_size, false);
case OP_BUREM_I: return mk_binary(m_bv_urem_i, k, "bvurem_i", bv_size, false);
case OP_BSMOD_I: return mk_binary(m_bv_smod_i, k, "bvsmod_i", bv_size, false);
case OP_ULEQ: return mk_pred(m_bv_uleq, k, "bvule", bv_size);
case OP_SLEQ: return mk_pred(m_bv_sleq, k, "bvsle", bv_size);
case OP_UGEQ: return mk_pred(m_bv_ugeq, k, "bvuge", bv_size);
case OP_SGEQ: return mk_pred(m_bv_sgeq, k, "bvsge", bv_size);
case OP_ULT: return mk_pred(m_bv_ult, k, "bvult", bv_size);
case OP_SLT: return mk_pred(m_bv_slt, k, "bvslt", bv_size);
case OP_UGT: return mk_pred(m_bv_ugt, k, "bvugt", bv_size);
case OP_SGT: return mk_pred(m_bv_sgt, k, "bvsgt", bv_size);
case OP_BAND: return mk_binary(m_bv_and, k, "bvand", bv_size, true, true);
case OP_BOR: return mk_binary(m_bv_or, k, "bvor", bv_size, true, true);
case OP_BNOT: return mk_unary(m_bv_not, k, "bvnot", bv_size);
case OP_BXOR: return mk_binary(m_bv_xor, k, "bvxor", bv_size, true);
case OP_BNAND: return mk_binary(m_bv_nand, k, "bvnand", bv_size, false);
case OP_BNOR: return mk_binary(m_bv_nor, k, "bvnor", bv_size, false);
case OP_BXNOR: return mk_binary(m_bv_xnor, k, "bvxnor", bv_size, false);
case OP_BREDOR: return mk_reduction(m_bv_redor, k, "bvredor", bv_size);
case OP_BREDAND: return mk_reduction(m_bv_redand, k, "bvredand", bv_size);
case OP_BCOMP: return mk_comp(bv_size);
case OP_BUMUL_NO_OVFL: return mk_pred(m_bv_mul_ovfl, k, "bvumul_noovfl", bv_size);
case OP_BSMUL_NO_OVFL: return mk_pred(m_bv_smul_ovfl, k, "bvsmul_noovfl", bv_size);
case OP_BSMUL_NO_UDFL: return mk_pred(m_bv_smul_udfl, k, "bvsmul_noudfl", bv_size);
case OP_BSHL: return mk_binary(m_bv_shl, k, "bvshl", bv_size, false);
case OP_BLSHR: return mk_binary(m_bv_lshr, k, "bvlshr", bv_size, false);
case OP_BASHR: return mk_binary(m_bv_ashr, k, "bvashr", bv_size, false);
case OP_EXT_ROTATE_LEFT: return mk_binary(m_ext_rotate_left, k, "ext_rotate_left", bv_size, false);
case OP_EXT_ROTATE_RIGHT: return mk_binary(m_ext_rotate_right, k, "ext_rotate_right", bv_size, false);
default: return 0;
}
}
inline bool bv_decl_plugin::get_bv_size(sort * s, int & result) {
if (s->get_family_id() == m_family_id && s->get_decl_kind() == BV_SORT) {
result = s->get_parameter(0).get_int();
return true;
}
return false;
}
inline bool bv_decl_plugin::get_bv_size(expr * t, int & result) {
return get_bv_size(m_manager->get_sort(t), result);
}
bool bv_decl_plugin::get_concat_size(unsigned arity, sort * const * domain, int & result) {
result = 0;
for (unsigned i = 0; i < arity; i++) {
int sz;
if (!get_bv_size(domain[i], sz)) {
return false;
}
result += sz;
}
return true;
}
bool bv_decl_plugin::get_extend_size(unsigned num_parameters, parameter const * parameters,
unsigned arity, sort * const * domain, int & result) {
int arg_sz;
if (arity != 1 || num_parameters != 1 || !parameters[0].is_int() || !get_bv_size(domain[0], arg_sz)) {
return false;
}
result = arg_sz + parameters[0].get_int();
return true;
}
bool bv_decl_plugin::get_extract_size(unsigned num_parameters, parameter const * parameters,
unsigned arity, sort * const * domain, int & result) {
int arg_sz;
if (arity != 1 ||
!get_bv_size(domain[0], arg_sz) ||
num_parameters != 2 ||
!parameters[0].is_int() ||
!parameters[1].is_int() ||
parameters[1].get_int() > parameters[0].get_int() ||
parameters[0].get_int() >= arg_sz) {
return false;
}
result = parameters[0].get_int() - parameters[1].get_int() + 1;
return true;
}
bool bv_decl_plugin::get_int2bv_size(unsigned num_parameters, parameter const * parameters, int & result) {
if (num_parameters != 1) {
m_manager->raise_exception("int2bv expects one parameter");
return false;
}
parameter p(parameters[0]);
if (p.is_int()) {
result = p.get_int();
return true;
}
if (!p.is_ast() || !is_expr(p.get_ast())) {
m_manager->raise_exception("int2bv expects one integer parameter");
return false;
}
return get_bv_size(to_expr(p.get_ast()), result);
}
func_decl * bv_decl_plugin::mk_num_decl(unsigned num_parameters, parameter const * parameters, unsigned arity) {
if (!(num_parameters == 2 && arity == 0 && parameters[0].is_rational() && parameters[1].is_int())) {
m_manager->raise_exception("invalid bit-vector numeral declaration");
return 0;
}
unsigned bv_size = parameters[1].get_int();
// TODO: sign an error if the parameters[0] is out of range, that is, it is a value not in [0, 2^{bv_size})
// This cannot be enforced now, since some Z3 modules try to generate these invalid numerals.
// After SMT-COMP, I should find all offending modules.
// For now, I will just simplify the numeral here.
parameter p0(mod(parameters[0].get_rational(), power_of_two(bv_size)));
parameter ps[2] = { p0, parameters[1] };
sort * bv = get_bv_sort(bv_size);
return m_manager->mk_const_decl(m_bv_sym, bv, func_decl_info(m_family_id, OP_BV_NUM, num_parameters, ps));
}
func_decl * bv_decl_plugin::mk_bit2bool(unsigned bv_size, unsigned num_parameters, parameter const * parameters,
unsigned arity, sort * const * domain) {
if (!(num_parameters == 1 && parameters[0].is_int() && arity == 1 && parameters[0].get_int() < static_cast<int>(bv_size))) {
m_manager->raise_exception("invalid bit2bool declaration");
return 0;
}
unsigned idx = parameters[0].get_int();
m_bit2bool.reserve(bv_size+1);
ptr_vector<func_decl> & v = m_bit2bool[bv_size];
v.reserve(bv_size, 0);
if (v[idx] == 0) {
v[idx] = m_manager->mk_func_decl(m_bit2bool_sym, domain[0], m_manager->mk_bool_sort(),
func_decl_info(m_family_id, OP_BIT2BOOL, num_parameters, parameters));
m_manager->inc_ref(v[idx]);
}
return v[idx];
}
func_decl * bv_decl_plugin::mk_mkbv(unsigned arity, sort * const * domain) {
for (unsigned i = 0; i < arity; i++) {
if (!m_manager->is_bool(domain[i])) {
m_manager->raise_exception("invalid mkbv operator");
return 0;
}
}
unsigned bv_size = arity;
m_mkbv.reserve(bv_size+1);
if (m_mkbv[bv_size] == 0) {
m_mkbv[bv_size] = m_manager->mk_func_decl(m_mkbv_sym, arity, domain, get_bv_sort(bv_size), func_decl_info(m_family_id, OP_MKBV));
m_manager->inc_ref(m_mkbv[bv_size]);
}
return m_mkbv[bv_size];
}
func_decl * bv_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters,
unsigned arity, sort * const * domain, sort * range) {
int bv_size;
if (k == OP_INT2BV && get_int2bv_size(num_parameters, parameters, bv_size)) {
// bv_size is filled in.
}
else if (k == OP_BV_NUM) {
return mk_num_decl(num_parameters, parameters, arity);
}
else if (k == OP_BIT0) {
return m_bit0;
}
else if (k == OP_BIT1) {
return m_bit1;
}
else if (k == OP_CARRY) {
return m_carry;
}
else if (k == OP_XOR3) {
return m_xor3;
}
else if (k == OP_MKBV) {
return mk_mkbv(arity, domain);
}
else if (arity == 0) {
m_manager->raise_exception("no arguments supplied to bit-vector operator");
return 0;
}
else if (!get_bv_size(domain[0], bv_size)) {
m_manager->raise_exception("could not extract bit-vector size");
return 0;
}
func_decl * r = mk_func_decl(k, bv_size);
if (r != 0) {
if (arity != r->get_arity()) {
m_manager->raise_exception("declared arity mismatches supplied arity");
return 0;
}
for (unsigned i = 0; i < arity; ++i) {
if (domain[i] != r->get_domain(i)) {
m_manager->raise_exception("declared sorts do not match supplied sorts");
return 0;
}
}
return r;
}
int r_size;
switch (k) {
case OP_BIT2BOOL:
return mk_bit2bool(bv_size, num_parameters, parameters, arity, domain);
case OP_INT2BV:
return mk_int2bv(bv_size, num_parameters, parameters, arity, domain);
case OP_BV2INT:
return mk_bv2int(bv_size, num_parameters, parameters, arity, domain);
case OP_CONCAT:
if (!get_concat_size(arity, domain, r_size))
m_manager->raise_exception("invalid concat application");
return m_manager->mk_func_decl(m_concat_sym, arity, domain, get_bv_sort(r_size),
func_decl_info(m_family_id, k));
case OP_SIGN_EXT:
if (!get_extend_size(num_parameters, parameters, arity, domain, r_size))
m_manager->raise_exception("invalid sign_extend application");
return m_manager->mk_func_decl(m_sign_extend_sym, arity, domain, get_bv_sort(r_size),
func_decl_info(m_family_id, k, num_parameters, parameters));
case OP_ZERO_EXT:
if (!get_extend_size(num_parameters, parameters, arity, domain, r_size))
m_manager->raise_exception("invalid zero_extend application");
return m_manager->mk_func_decl(m_zero_extend_sym, arity, domain, get_bv_sort(r_size),
func_decl_info(m_family_id, k, num_parameters, parameters));
case OP_EXTRACT:
if (!get_extract_size(num_parameters, parameters, arity, domain, r_size))
m_manager->raise_exception("invalid extract application");
return m_manager->mk_func_decl(m_extract_sym, arity, domain, get_bv_sort(r_size),
func_decl_info(m_family_id, k, num_parameters, parameters));
case OP_ROTATE_LEFT:
if (arity != 1)
m_manager->raise_exception("rotate left expects one argument");
return m_manager->mk_func_decl(m_rotate_left_sym, arity, domain, domain[0],
func_decl_info(m_family_id, k, num_parameters, parameters));
case OP_ROTATE_RIGHT:
if (arity != 1)
m_manager->raise_exception("rotate right expects one argument");
return m_manager->mk_func_decl(m_rotate_right_sym, arity, domain, domain[0],
func_decl_info(m_family_id, k, num_parameters, parameters));
case OP_REPEAT:
if (arity != 1)
m_manager->raise_exception("repeat expects one argument");
if (num_parameters != 1 || !parameters[0].is_int() || parameters[0].get_int() == 0)
m_manager->raise_exception("repeat expects one nonzero integer parameter");
if (!get_bv_size(domain[0], bv_size))
m_manager->raise_exception("repeat expects an argument with bit-vector sort");
return m_manager->mk_func_decl(m_repeat_sym, arity, domain, get_bv_sort(bv_size * parameters[0].get_int()),
func_decl_info(m_family_id, k, num_parameters, parameters));
default:
return 0;
}
}
func_decl * bv_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters,
unsigned num_args, expr * const * args, sort * range) {
int bv_size;
if (k == OP_INT2BV && get_int2bv_size(num_parameters, parameters, bv_size)) {
// bv_size is filled in.
}
else if (k == OP_BV_NUM) {
return mk_num_decl(num_parameters, parameters, num_args);
}
else if (k == OP_BIT0) {
return m_bit0;
}
else if (k == OP_BIT1) {
return m_bit1;
}
else if (k == OP_CARRY) {
return m_carry;
}
else if (k == OP_XOR3) {
return m_xor3;
}
else if (k == OP_MKBV) {
return decl_plugin::mk_func_decl(k, num_parameters, parameters, num_args, args, range);
}
else if (num_args == 0 || !get_bv_size(args[0], bv_size)) {
m_manager->raise_exception("operator is applied to arguments of the wrong sort");
return 0;
}
func_decl * r = mk_func_decl(k, bv_size);
if (r != 0) {
return r;
}
return decl_plugin::mk_func_decl(k, num_parameters, parameters, num_args, args, range);
}
bool bv_decl_plugin::is_value(app* e) const {
return is_app_of(e, m_family_id, OP_BV_NUM);
}
void bv_decl_plugin::get_offset_term(app * a, expr * & t, rational & offset) const {
family_id fid = get_family_id();
if (a->get_num_args() == 2 && is_app_of(a, fid, OP_BADD) && is_app_of(a->get_arg(0), fid, OP_BV_NUM)) {
unsigned sz;
func_decl * decl = to_app(a->get_arg(0))->get_decl();
offset = decl->get_parameter(0).get_rational();
sz = decl->get_parameter(1).get_int();
t = a->get_arg(1);
offset = mod(offset, power_of_two(sz));
}
else {
t = a;
offset = rational(0);
}
}
bool bv_decl_plugin::are_distinct(app * a, app * b) const {
#if 1
// Check for a + k1 != a + k2 when k1 != k2
rational a_offset;
expr * a_term;
rational b_offset;
expr * b_term;
get_offset_term(a, a_term, a_offset);
get_offset_term(b, b_term, b_offset);
TRACE("bv_are_distinct",
tout << mk_ismt2_pp(a, *m_manager) << "\n" << mk_ismt2_pp(b, *m_manager) << "\n";
tout << "---->\n";
tout << "a: " << a_offset << " + " << mk_ismt2_pp(a_term, *m_manager) << "\n";
tout << "b: " << b_offset << " + " << mk_ismt2_pp(b_term, *m_manager) << "\n";);
if (a_term == b_term && a_offset != b_offset)
return true;
#endif
return decl_plugin::are_distinct(a, b);
}
void bv_decl_plugin::get_sort_names(svector<builtin_name> & sort_names, symbol const & logic) {
if (logic == symbol::null)
sort_names.push_back(builtin_name("bv", BV_SORT));
sort_names.push_back(builtin_name("BitVec", BV_SORT));
}
void bv_decl_plugin::get_op_names(svector<builtin_name> & op_names, symbol const & logic) {
op_names.push_back(builtin_name("bit1",OP_BIT1));
op_names.push_back(builtin_name("bit0",OP_BIT0));
op_names.push_back(builtin_name("bvneg",OP_BNEG));
op_names.push_back(builtin_name("bvadd",OP_BADD));
op_names.push_back(builtin_name("bvsub",OP_BSUB));
op_names.push_back(builtin_name("bvmul",OP_BMUL));
op_names.push_back(builtin_name("bvsdiv",OP_BSDIV));
op_names.push_back(builtin_name("bvudiv",OP_BUDIV));
op_names.push_back(builtin_name("bvsrem",OP_BSREM));
op_names.push_back(builtin_name("bvurem",OP_BUREM));
op_names.push_back(builtin_name("bvsmod",OP_BSMOD));
op_names.push_back(builtin_name("bvule",OP_ULEQ));
op_names.push_back(builtin_name("bvsle",OP_SLEQ));
op_names.push_back(builtin_name("bvuge",OP_UGEQ));
op_names.push_back(builtin_name("bvsge",OP_SGEQ));
op_names.push_back(builtin_name("bvult",OP_ULT));
op_names.push_back(builtin_name("bvslt",OP_SLT));
op_names.push_back(builtin_name("bvugt",OP_UGT));
op_names.push_back(builtin_name("bvsgt",OP_SGT));
op_names.push_back(builtin_name("bvand",OP_BAND));
op_names.push_back(builtin_name("bvor",OP_BOR));
op_names.push_back(builtin_name("bvnot",OP_BNOT));
op_names.push_back(builtin_name("bvxor",OP_BXOR));
op_names.push_back(builtin_name("bvnand",OP_BNAND));
op_names.push_back(builtin_name("bvnor",OP_BNOR));
op_names.push_back(builtin_name("bvxnor",OP_BXNOR));
op_names.push_back(builtin_name("concat",OP_CONCAT));
op_names.push_back(builtin_name("sign_extend",OP_SIGN_EXT));
op_names.push_back(builtin_name("zero_extend",OP_ZERO_EXT));
op_names.push_back(builtin_name("extract",OP_EXTRACT));
op_names.push_back(builtin_name("repeat",OP_REPEAT));
op_names.push_back(builtin_name("bvredor",OP_BREDOR));
op_names.push_back(builtin_name("bvredand",OP_BREDAND));
op_names.push_back(builtin_name("bvcomp",OP_BCOMP));
op_names.push_back(builtin_name("bvshl",OP_BSHL));
op_names.push_back(builtin_name("bvlshr",OP_BLSHR));
op_names.push_back(builtin_name("bvashr",OP_BASHR));
op_names.push_back(builtin_name("rotate_left",OP_ROTATE_LEFT));
op_names.push_back(builtin_name("rotate_right",OP_ROTATE_RIGHT));
if (logic == symbol::null) {
op_names.push_back(builtin_name("bvumul_noovfl",OP_BUMUL_NO_OVFL));
op_names.push_back(builtin_name("bvsmul_noovfl",OP_BSMUL_NO_OVFL));
op_names.push_back(builtin_name("bvsmul_noudfl",OP_BSMUL_NO_UDFL));
op_names.push_back(builtin_name("bvsdiv0", OP_BSDIV0));
op_names.push_back(builtin_name("bvudiv0", OP_BUDIV0));
op_names.push_back(builtin_name("bvsrem0", OP_BSREM0));
op_names.push_back(builtin_name("bvurem0", OP_BUREM0));
op_names.push_back(builtin_name("bvsmod0", OP_BSMOD0));
op_names.push_back(builtin_name("bvsdiv_i", OP_BSDIV_I));
op_names.push_back(builtin_name("bvudiv_i", OP_BUDIV_I));
op_names.push_back(builtin_name("bvsrem_i", OP_BSREM_I));
op_names.push_back(builtin_name("bvurem_i", OP_BUREM_I));
op_names.push_back(builtin_name("bvumod_i", OP_BSMOD_I));
op_names.push_back(builtin_name("ext_rotate_left",OP_EXT_ROTATE_LEFT));
op_names.push_back(builtin_name("ext_rotate_right",OP_EXT_ROTATE_RIGHT));
op_names.push_back(builtin_name("int2bv",OP_INT2BV));
op_names.push_back(builtin_name("bv2int",OP_BV2INT));
op_names.push_back(builtin_name("mkbv",OP_MKBV));
}
}
expr * bv_decl_plugin::get_some_value(sort * s) {
SASSERT(s->is_sort_of(m_family_id, BV_SORT));
unsigned bv_size = s->get_parameter(0).get_int();
parameter p[2] = { parameter(rational(0)), parameter(static_cast<int>(bv_size)) };
return m_manager->mk_app(m_family_id, OP_BV_NUM, 2, p, 0, 0);
}
bv_util::bv_util(ast_manager & m):
m_manager(m) {
SASSERT(m.has_plugin(symbol("bv")));
m_plugin = static_cast<bv_decl_plugin*>(m.get_plugin(m.get_family_id("bv")));
}
rational bv_util::norm(rational const & val, unsigned bv_size, bool is_signed) const {
rational r = mod(val, power_of_two(bv_size));
SASSERT(!r.is_neg());
if (is_signed) {
if (r >= power_of_two(bv_size - 1)) {
r -= power_of_two(bv_size);
}
if (r < -power_of_two(bv_size - 1)) {
r += power_of_two(bv_size);
}
}
return r;
}
bool bv_util::has_sign_bit(rational const & n, unsigned bv_size) const {
SASSERT(bv_size > 0);
rational m = norm(n, bv_size, false);
rational p = power_of_two(bv_size - 1);
return m >= p;
}
bool bv_util::is_bv_sort(sort const * s) const {
return (s->get_family_id() == get_fid() && s->get_decl_kind() == BV_SORT && s->get_num_parameters() == 1);
}
app * bv_util::mk_numeral(rational const & val, sort* s) {
if (!is_bv_sort(s)) {
return 0;
}
unsigned bv_size = get_bv_size(s);
return mk_numeral(val, bv_size);
}
app * bv_util::mk_numeral(rational const & val, unsigned bv_size) {
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);
}
bool bv_util::is_numeral(expr const * n, rational & val, unsigned & bv_size) const {
if (!is_app_of(n, get_fid(), OP_BV_NUM)) {
return false;
}
func_decl * decl = to_app(n)->get_decl();
val = decl->get_parameter(0).get_rational();
bv_size = decl->get_parameter(1).get_int();
return true;
}
bool bv_util::is_allone(expr const * e) const {
rational r;
unsigned bv_size;
if (!is_numeral(e, r, bv_size)) {
return false;
}
bool result = (r == power_of_two(bv_size) - rational(1));
TRACE("is_allone", tout << r << " " << result << "\n";);
return result;
}
bool bv_util::is_zero(expr const * n) const {
if (!is_app_of(n, get_fid(), OP_BV_NUM)) {
return false;
}
func_decl * decl = to_app(n)->get_decl();
return decl->get_parameter(0).get_rational().is_zero();
}
sort * bv_util::mk_sort(unsigned bv_size) {
parameter p[1] = { parameter(bv_size) };
return m_manager.mk_sort(get_fid(), BV_SORT, 1, p);
}
bool bv_util::mult_inverse(rational const & n, unsigned bv_size, rational & result) {
if (n.is_one()) {
result = n;
return true;
}
if (!mod(n, rational(2)).is_one()) {
return false;
}
rational g;
rational x;
rational y;
g = gcd(n, power_of_two(bv_size), x, y);
if (x.is_neg()) {
x = mod(x, power_of_two(bv_size));
}
SASSERT(x.is_pos());
SASSERT(mod(x * n, power_of_two(bv_size)).is_one());
result = x;
return true;
}
app * bv_util::mk_bv2int(expr* e) {
sort* s = m_manager.mk_sort(m_manager.get_family_id("arith"), INT_SORT);
parameter p(s);
return m_manager.mk_app(get_fid(), OP_BV2INT, 1, &p, 1, &e);
}

405
src/ast/bv_decl_plugin.h Normal file
View file

@ -0,0 +1,405 @@
/*++
Copyright (c) 2006 Microsoft Corporation
Module Name:
bv_decl_plugin.h
Abstract:
<abstract>
Author:
Leonardo de Moura (leonardo) 2008-01-09.
Revision History:
--*/
#ifndef _BV_DECL_PLUGIN_H_
#define _BV_DECL_PLUGIN_H_
#include"ast.h"
enum bv_sort_kind {
BV_SORT
};
enum bv_op_kind {
OP_BV_NUM,
OP_BIT1,
OP_BIT0,
OP_BNEG,
OP_BADD,
OP_BSUB,
OP_BMUL,
OP_BSDIV,
OP_BUDIV,
OP_BSREM,
OP_BUREM,
OP_BSMOD,
// special functions to record the division by 0 cases
// these are internal functions
OP_BSDIV0,
OP_BUDIV0,
OP_BSREM0,
OP_BUREM0,
OP_BSMOD0,
// special functions where division by 0 has a fixed interpretation.
OP_BSDIV_I,
OP_BUDIV_I,
OP_BSREM_I,
OP_BUREM_I,
OP_BSMOD_I,
OP_ULEQ,
OP_SLEQ,
OP_UGEQ,
OP_SGEQ,
OP_ULT,
OP_SLT,
OP_UGT,
OP_SGT,
OP_BAND,
OP_BOR,
OP_BNOT,
OP_BXOR,
OP_BNAND,
OP_BNOR,
OP_BXNOR,
OP_CONCAT,
OP_SIGN_EXT,
OP_ZERO_EXT,
OP_EXTRACT,
OP_REPEAT,
OP_BREDOR,
OP_BREDAND,
OP_BCOMP,
OP_BSHL,
OP_BLSHR,
OP_BASHR,
OP_ROTATE_LEFT,
OP_ROTATE_RIGHT,
OP_EXT_ROTATE_LEFT,
OP_EXT_ROTATE_RIGHT,
OP_BUMUL_NO_OVFL, // no unsigned multiplication overflow predicate
OP_BSMUL_NO_OVFL, // no signed multiplication overflow predicate
OP_BSMUL_NO_UDFL, // no signed multiplication underflow predicate
OP_BIT2BOOL, // predicate
OP_MKBV, // bools to bv
OP_INT2BV,
OP_BV2INT,
OP_CARRY,
OP_XOR3,
LAST_BV_OP
};
// Assume k is a "div" operator. It returns the div0 uninterpreted function that
// models the value of "div" it is underspecified (i.e., when the denominator is zero).
inline bv_op_kind get_div0_op(bv_op_kind k) {
switch (k) {
case OP_BSDIV: return OP_BSDIV0;
case OP_BUDIV: return OP_BUDIV0;
case OP_BSREM: return OP_BSREM0;
case OP_BUREM: return OP_BUREM0;
case OP_BSMOD: return OP_BSMOD0;
default: UNREACHABLE(); return LAST_BV_OP;
}
}
// Assume decl is the declaration of a "div" operator. It returns the div0 declaration that
// models the value of "div" it is underspecified (i.e., when the denominator is zero).
inline func_decl * get_div0_decl(ast_manager & m, func_decl * decl) {
return m.mk_func_decl(decl->get_family_id(), get_div0_op(static_cast<bv_op_kind>(decl->get_decl_kind())),
0, 0, 1, decl->get_domain());
}
class bv_decl_plugin : public decl_plugin {
protected:
vector<rational> m_powers;
void mk_table_upto(unsigned n);
symbol m_bv_sym;
symbol m_concat_sym;
symbol m_sign_extend_sym;
symbol m_zero_extend_sym;
symbol m_extract_sym;
symbol m_rotate_left_sym;
symbol m_rotate_right_sym;
symbol m_repeat_sym;
symbol m_bit2bool_sym;
symbol m_mkbv_sym;
func_decl * m_bit0;
func_decl * m_bit1;
func_decl * m_carry;
func_decl * m_xor3;
ptr_vector<sort> m_bv_sorts;
sort * m_int_sort;
ptr_vector<func_decl> m_bv_neg;
ptr_vector<func_decl> m_bv_add;
ptr_vector<func_decl> m_bv_sub;
ptr_vector<func_decl> m_bv_mul;
ptr_vector<func_decl> m_bv_sdiv;
ptr_vector<func_decl> m_bv_udiv;
ptr_vector<func_decl> m_bv_srem;
ptr_vector<func_decl> m_bv_urem;
ptr_vector<func_decl> m_bv_smod;
ptr_vector<func_decl> m_bv_sdiv0;
ptr_vector<func_decl> m_bv_udiv0;
ptr_vector<func_decl> m_bv_srem0;
ptr_vector<func_decl> m_bv_urem0;
ptr_vector<func_decl> m_bv_smod0;
ptr_vector<func_decl> m_bv_sdiv_i;
ptr_vector<func_decl> m_bv_udiv_i;
ptr_vector<func_decl> m_bv_srem_i;
ptr_vector<func_decl> m_bv_urem_i;
ptr_vector<func_decl> m_bv_smod_i;
ptr_vector<func_decl> m_bv_uleq;
ptr_vector<func_decl> m_bv_sleq;
ptr_vector<func_decl> m_bv_ugeq;
ptr_vector<func_decl> m_bv_sgeq;
ptr_vector<func_decl> m_bv_ult;
ptr_vector<func_decl> m_bv_slt;
ptr_vector<func_decl> m_bv_ugt;
ptr_vector<func_decl> m_bv_sgt;
ptr_vector<func_decl> m_bv_and;
ptr_vector<func_decl> m_bv_or;
ptr_vector<func_decl> m_bv_not;
ptr_vector<func_decl> m_bv_xor;
ptr_vector<func_decl> m_bv_nand;
ptr_vector<func_decl> m_bv_nor;
ptr_vector<func_decl> m_bv_xnor;
ptr_vector<func_decl> m_bv_redor;
ptr_vector<func_decl> m_bv_redand;
ptr_vector<func_decl> m_bv_comp;
ptr_vector<func_decl> m_bv_mul_ovfl;
ptr_vector<func_decl> m_bv_smul_ovfl;
ptr_vector<func_decl> m_bv_smul_udfl;
ptr_vector<func_decl> m_bv_shl;
ptr_vector<func_decl> m_bv_lshr;
ptr_vector<func_decl> m_bv_ashr;
ptr_vector<func_decl> m_ext_rotate_left;
ptr_vector<func_decl> m_ext_rotate_right;
ptr_vector<func_decl> m_bv2int;
ptr_vector<func_decl> m_int2bv;
vector<ptr_vector<func_decl> > m_bit2bool;
ptr_vector<func_decl> m_mkbv;
virtual void set_manager(ast_manager * m, family_id id);
void mk_bv_sort(unsigned bv_size);
sort * get_bv_sort(unsigned bv_size);
func_decl * mk_func_decl(decl_kind k, unsigned bv_size);
func_decl * mk_binary(ptr_vector<func_decl> & decls, decl_kind k,
char const * name, unsigned bv_size, bool ac, bool idempotent = false);
func_decl * mk_unary(ptr_vector<func_decl> & decls, decl_kind k, char const * name, unsigned bv_size);
func_decl * mk_pred(ptr_vector<func_decl> & decls, decl_kind k,
char const * name, unsigned bv_size);
func_decl * mk_reduction(ptr_vector<func_decl> & decls, decl_kind k, char const * name, unsigned bv_size);
func_decl * mk_comp(unsigned bv_size);
bool get_bv_size(sort * t, int & result);
bool get_bv_size(expr * t, int & result);
bool get_concat_size(unsigned arity, sort * const * domain, int & result);
bool get_extend_size(unsigned num_parameters, parameter const * parameters,
unsigned arity, sort * const * domain, int & result);
bool get_extract_size(unsigned num_parameters, parameter const * parameters,
unsigned arity, sort * const * domain, int & result);
func_decl * mk_bv2int(unsigned bv_size, unsigned num_parameters, parameter const * parameters,
unsigned arity, sort * const * domain);
func_decl * mk_int2bv(unsigned bv_size, unsigned num_parameters, parameter const * parameters,
unsigned arity, sort * const * domain);
func_decl * mk_bit2bool(unsigned bv_size, unsigned num_parameters, parameter const * parameters,
unsigned arity, sort * const * domain);
func_decl * mk_mkbv(unsigned arity, sort * const * domain);
bool get_int2bv_size(unsigned num_parameters, parameter const * parameters, int & result);
func_decl * mk_num_decl(unsigned num_parameters, parameter const * parameters, unsigned arity);
void get_offset_term(app * a, expr * & t, rational & offset) const;
public:
bv_decl_plugin();
rational power_of_two(unsigned n) const;
virtual ~bv_decl_plugin() {}
virtual void finalize();
virtual decl_plugin * mk_fresh() { return alloc(bv_decl_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 func_decl * mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters,
unsigned num_args, expr * const * args, sort * range);
virtual bool is_value(app* e) const;
virtual void get_op_names(svector<builtin_name> & op_names, symbol const & logic);
virtual void get_sort_names(svector<builtin_name> & sort_names, symbol const & logic);
virtual bool are_distinct(app* a, app* b) const;
virtual expr * get_some_value(sort * s);
};
class bv_util {
ast_manager & m_manager;
bv_decl_plugin * m_plugin;
public:
bv_util(ast_manager & m);
ast_manager & get_manager() const { return m_manager; }
family_id get_fid() const { return m_plugin->get_family_id(); }
family_id get_family_id() const { return get_fid(); }
rational power_of_two(unsigned n) const { return m_plugin->power_of_two(n); }
rational norm(rational const & val, unsigned bv_size, bool is_signed) const ;
rational norm(rational const & val, unsigned bv_size) const { return norm(val, bv_size, false); }
bool has_sign_bit(rational const & n, unsigned bv_size) const;
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); }
sort * mk_sort(unsigned bv_size);
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;
bool is_zero(expr const * e) const;
bool is_bv_sort(sort const * s) const;
bool is_bv(expr const* e) const {
return is_bv_sort(m_manager.get_sort(e));
}
unsigned get_bv_size(sort const * s) const {
SASSERT(is_bv_sort(s));
return static_cast<unsigned>(s->get_parameter(0).get_int());
}
unsigned get_bv_size(expr const * n) const { return get_bv_size(m_manager.get_sort(n)); }
app * mk_ule(expr * arg1, expr * arg2) { return m_manager.mk_app(get_fid(), OP_ULEQ, arg1, arg2); }
app * mk_sle(expr * arg1, expr * arg2) { return m_manager.mk_app(get_fid(), OP_SLEQ, arg1, arg2); }
app * mk_extract(unsigned high, unsigned low, expr * n) {
parameter params[2] = { parameter(high), parameter(low) };
return m_manager.mk_app(get_fid(), OP_EXTRACT, 2, params, 1, &n);
}
app * mk_concat(unsigned num, expr * const * args) { return m_manager.mk_app(get_fid(), OP_CONCAT, num, args); }
app * mk_concat(expr * arg1, expr * arg2) { expr * args[2] = { arg1, arg2 }; return mk_concat(2, args); }
app * mk_bv_or(unsigned num, expr * const * args) { return m_manager.mk_app(get_fid(), OP_BOR, num, args); }
app * mk_bv_not(expr * arg) { return m_manager.mk_app(get_fid(), OP_BNOT, arg); }
app * mk_bv_xor(unsigned num, expr * const * args) { return m_manager.mk_app(get_fid(), OP_BXOR, num, args); }
app * mk_bv_neg(expr * arg) { return m_manager.mk_app(get_fid(), OP_BNEG, arg); }
app * mk_bv_urem(expr * arg1, expr * arg2) { return m_manager.mk_app(get_fid(), OP_BUREM, arg1, arg2); }
app * mk_bv_srem(expr * arg1, expr * arg2) { return m_manager.mk_app(get_fid(), OP_BSREM, arg1, arg2); }
app * mk_bv_add(expr * arg1, expr * arg2) { return m_manager.mk_app(get_fid(), OP_BADD, arg1, arg2); }
app * mk_bv_sub(expr * arg1, expr * arg2) { return m_manager.mk_app(get_fid(), OP_BSUB, arg1, arg2); }
app * mk_bv_mul(expr * arg1, expr * arg2) { return m_manager.mk_app(get_fid(), OP_BMUL, arg1, arg2); }
app * mk_zero_extend(unsigned n, expr* e) {
parameter p(n);
return m_manager.mk_app(get_fid(), OP_ZERO_EXT, 1, &p, 1, &e);
}
app * mk_sign_extend(unsigned n, expr* e) {
parameter p(n);
return m_manager.mk_app(get_fid(), OP_SIGN_EXT, 1, &p, 1, &e);
}
app * mk_bv_shl(expr* arg1, expr* arg2) { return m_manager.mk_app(get_fid(), OP_BSHL, arg1, arg2); }
app * mk_bv_ashr(expr* arg1, expr* arg2) { return m_manager.mk_app(get_fid(), OP_BASHR, arg1, arg2); }
app * mk_bv_lshr(expr* arg1, expr* arg2) { return m_manager.mk_app(get_fid(), OP_BLSHR, arg1, arg2); }
app * mk_bv2int(expr* e);
app * mk_bvsmul_no_ovfl(expr* m, expr* n) { return m_manager.mk_app(get_fid(), OP_BSMUL_NO_OVFL, n, m); }
app * mk_bvsmul_no_udfl(expr* m, expr* n) { return m_manager.mk_app(get_fid(), OP_BSMUL_NO_UDFL, n, m); }
app * mk_bvumul_no_ovfl(expr* m, expr* n) { return m_manager.mk_app(get_fid(), OP_BUMUL_NO_OVFL, n, m); }
app * mk_bv(unsigned n, expr* const* es) { return m_manager.mk_app(get_fid(), OP_MKBV, n, es); }
bool is_concat(expr const * e) const { return is_app_of(e, get_fid(), OP_CONCAT); }
bool is_extract(func_decl const * f) const { return is_decl_of(f, get_fid(), OP_EXTRACT); }
bool is_extract(expr const * e) const { return is_app_of(e, get_fid(), OP_EXTRACT); }
unsigned get_extract_high(func_decl const * f) const { return f->get_parameter(0).get_int(); }
unsigned get_extract_low(func_decl const * f) const { return f->get_parameter(1).get_int(); }
unsigned get_extract_high(expr const * n) { SASSERT(is_extract(n)); return get_extract_high(to_app(n)->get_decl()); }
unsigned get_extract_low(expr const * n) { SASSERT(is_extract(n)); return get_extract_low(to_app(n)->get_decl()); }
bool is_extract(expr const* e, unsigned& low, unsigned& high, expr*& b) {
if (!is_extract(e)) return false;
low = get_extract_low(e);
high = get_extract_high(e);
b = to_app(e)->get_arg(0);
return true;
}
bool is_bv2int(expr const* e, expr*& r) {
if (!is_bv2int(e)) return false;
r = to_app(e)->get_arg(0);
return true;
}
bool is_bv_add(expr const * e) const { return is_app_of(e, get_fid(), OP_BADD); }
bool is_bv_sub(expr const * e) const { return is_app_of(e, get_fid(), OP_BSUB); }
bool is_bv_mul(expr const * e) const { return is_app_of(e, get_fid(), OP_BMUL); }
bool is_bv_neg(expr const * e) const { return is_app_of(e, get_fid(), OP_BNEG); }
bool is_bv_sdiv(expr const * e) const { return is_app_of(e, get_fid(), OP_BSDIV); }
bool is_bv_udiv(expr const * e) const { return is_app_of(e, get_fid(), OP_BUDIV); }
bool is_bv_srem(expr const * e) const { return is_app_of(e, get_fid(), OP_BSREM); }
bool is_bv_urem(expr const * e) const { return is_app_of(e, get_fid(), OP_BUREM); }
bool is_bv_smod(expr const * e) const { return is_app_of(e, get_fid(), OP_BSMOD); }
bool is_bv_and(expr const * e) const { return is_app_of(e, get_fid(), OP_BAND); }
bool is_bv_or(expr const * e) const { return is_app_of(e, get_fid(), OP_BOR); }
bool is_bv_xor(expr const * e) const { return is_app_of(e, get_fid(), OP_BXOR); }
bool is_bv_nand(expr const * e) const { return is_app_of(e, get_fid(), OP_BNAND); }
bool is_bv_nor(expr const * e) const { return is_app_of(e, get_fid(), OP_BNOR); }
bool is_bv_not(expr const * e) const { return is_app_of(e, get_fid(), OP_BNOT); }
bool is_bv_ule(expr const * e) const { return is_app_of(e, get_fid(), OP_ULEQ); }
bool is_bv_sle(expr const * e) const { return is_app_of(e, get_fid(), OP_SLEQ); }
bool is_bit2bool(expr const * e) const { return is_app_of(e, get_fid(), OP_BIT2BOOL); }
bool is_bv2int(expr const* e) const { return is_app_of(e, get_fid(), OP_BV2INT); }
bool is_int2bv(expr const* e) const { return is_app_of(e, get_fid(), OP_INT2BV); }
bool is_mkbv(expr const * e) const { return is_app_of(e, get_fid(), OP_MKBV); }
bool is_bv_ashr(expr const * e) const { return is_app_of(e, get_fid(), OP_BASHR); }
bool is_bv_lshr(expr const * e) const { return is_app_of(e, get_fid(), OP_BLSHR); }
bool is_bv_shl(expr const * e) const { return is_app_of(e, get_fid(), OP_BSHL); }
bool is_sign_ext(expr const * e) const { return is_app_of(e, get_fid(), OP_SIGN_EXT); }
MATCH_BINARY(is_bv_add);
MATCH_BINARY(is_bv_mul);
MATCH_BINARY(is_bv_sle);
MATCH_BINARY(is_bv_ule);
MATCH_BINARY(is_bv_shl);
bool mult_inverse(rational const & n, unsigned bv_size, rational & result);
};
#endif /* _BV_DECL_PLUGIN_H_ */

View file

@ -0,0 +1,944 @@
/*++
Copyright (c) 2006 Microsoft Corporation
Module Name:
datatype_decl_plugin.cpp
Abstract:
<abstract>
Author:
Leonardo de Moura (leonardo) 2008-01-10.
Revision History:
--*/
#include"datatype_decl_plugin.h"
#include"warning.h"
#include"ast_smt2_pp.h"
/**
\brief Auxiliary class used to declare inductive datatypes.
*/
class accessor_decl {
symbol m_name;
type_ref m_type;
public:
accessor_decl(const symbol & n, type_ref r):m_name(n), m_type(r) {}
symbol const & get_name() const { return m_name; }
type_ref const & get_type() const { return m_type; }
};
accessor_decl * mk_accessor_decl(symbol const & n, type_ref const & t) {
return alloc(accessor_decl, n, t);
}
void del_accessor_decl(accessor_decl * d) {
dealloc(d);
}
void del_accessor_decls(unsigned num, accessor_decl * const * as) {
for (unsigned i = 0; i < num; i++)
del_accessor_decl(as[i]);
}
/**
\brief Auxiliary class used to declare inductive datatypes.
*/
class constructor_decl {
symbol m_name;
symbol m_recogniser_name;
ptr_vector<accessor_decl> m_accessors;
public:
constructor_decl(const symbol & n, const symbol & r, unsigned num_accessors, accessor_decl * const * accessors):
m_name(n), m_recogniser_name(r), m_accessors(num_accessors, accessors) {}
~constructor_decl() {
std::for_each(m_accessors.begin(), m_accessors.end(), delete_proc<accessor_decl>());
}
symbol const & get_name() const { return m_name; }
symbol const & get_recognizer_name() const { return m_recogniser_name; }
ptr_vector<accessor_decl> const & get_accessors() const { return m_accessors; }
};
constructor_decl * mk_constructor_decl(symbol const & n, symbol const & r, unsigned num_accessors, accessor_decl * const * accessors) {
return alloc(constructor_decl, n, r, num_accessors, accessors);
}
void del_constructor_decl(constructor_decl * d) {
dealloc(d);
}
void del_constructor_decls(unsigned num, constructor_decl * const * cs) {
for (unsigned i = 0; i < num; i++)
del_constructor_decl(cs[i]);
}
/**
\brief Auxiliary class used to declare inductive datatypes.
*/
class datatype_decl {
symbol m_name;
ptr_vector<constructor_decl> m_constructors;
public:
datatype_decl(const symbol & n, unsigned num_constructors, constructor_decl * const * constructors):
m_name(n), m_constructors(num_constructors, constructors) {}
~datatype_decl() {
std::for_each(m_constructors.begin(), m_constructors.end(), delete_proc<constructor_decl>());
}
symbol const & get_name() const { return m_name; }
ptr_vector<constructor_decl> const & get_constructors() const { return m_constructors; }
};
datatype_decl * mk_datatype_decl(symbol const & n, unsigned num_constructors, constructor_decl * const * cs) {
return alloc(datatype_decl, n, num_constructors, cs);
}
void del_datatype_decl(datatype_decl * d) {
dealloc(d);
}
void del_datatype_decls(unsigned num, datatype_decl * const * ds) {
for (unsigned i = 0; i < num; i++)
del_datatype_decl(ds[i]);
}
typedef buffer<bool, false, 256> bool_buffer;
struct invalid_datatype {};
static parameter const & read(unsigned num_parameters, parameter const * parameters, unsigned idx, bool_buffer & read_pos) {
if (idx >= num_parameters) {
throw invalid_datatype();
}
if (idx >= read_pos.size()) {
read_pos.resize(idx+1, false);
}
read_pos[idx] = true;
return parameters[idx];
}
static int read_int(unsigned num_parameters, parameter const * parameters, unsigned idx, bool_buffer & read_pos) {
const parameter & r = read(num_parameters, parameters, idx, read_pos);
if (!r.is_int()) {
throw invalid_datatype();
}
return r.get_int();
}
static symbol read_symbol(unsigned num_parameters, parameter const * parameters, unsigned idx, bool_buffer & read_pos) {
parameter const & r = read(num_parameters, parameters, idx, read_pos);
if (!r.is_symbol()) {
throw invalid_datatype();
}
return r.get_symbol();
}
enum status {
WHITE,
GRAY,
BLACK
};
/**
\brief Return true if the inductive datatype is recursive.
Pre-condition: The given argument constains the parameters of an inductive datatype.
*/
static bool is_recursive_datatype(parameter const * parameters) {
unsigned num_types = parameters[0].get_int();
unsigned tid = parameters[1].get_int();
buffer<status> already_found(num_types, WHITE);
buffer<unsigned> todo;
todo.push_back(tid);
while (!todo.empty()) {
unsigned tid = todo.back();
if (already_found[tid] == BLACK) {
todo.pop_back();
continue;
}
already_found[tid] = GRAY;
unsigned o = parameters[2 + 2*tid + 1].get_int(); // constructor offset
unsigned num_constructors = parameters[o].get_int();
bool can_process = true;
for (unsigned s = 1; s <= num_constructors; s++) {
unsigned k_i = parameters[o + s].get_int();
unsigned num_accessors = parameters[k_i + 2].get_int();
for (unsigned r = 0; r < num_accessors; r++) {
parameter const & a_type = parameters[k_i + 4 + 2*r];
if (a_type.is_int()) {
unsigned tid_prime = a_type.get_int();
switch (already_found[tid_prime]) {
case WHITE:
todo.push_back(tid_prime);
can_process = false;
break;
case GRAY:
// type is recursive
return true;
case BLACK:
break;
}
}
}
}
if (can_process) {
already_found[tid] = BLACK;
todo.pop_back();
}
}
return false;
}
/**
\brief Return the size of the inductive datatype.
Pre-condition: The given argument constains the parameters of an inductive datatype.
*/
static sort_size get_datatype_size(parameter const * parameters) {
unsigned num_types = parameters[0].get_int();
unsigned tid = parameters[1].get_int();
buffer<sort_size> szs(num_types, sort_size());
buffer<status> already_found(num_types, WHITE);
buffer<unsigned> todo;
todo.push_back(tid);
while (!todo.empty()) {
unsigned tid = todo.back();
if (already_found[tid] == BLACK) {
todo.pop_back();
continue;
}
already_found[tid] = GRAY;
unsigned o = parameters[2 + 2*tid + 1].get_int(); // constructor offset
unsigned num_constructors = parameters[o].get_int();
bool is_very_big = false;
bool can_process = true;
for (unsigned s = 1; s <= num_constructors; s++) {
unsigned k_i = parameters[o+s].get_int();
unsigned num_accessors = parameters[k_i+2].get_int();
for (unsigned r = 0; r < num_accessors; r++) {
parameter const & a_type = parameters[k_i+4 + 2*r];
if (a_type.is_int()) {
int tid_prime = a_type.get_int();
switch (already_found[tid_prime]) {
case WHITE:
todo.push_back(tid_prime);
can_process = false;
break;
case GRAY:
// type is recursive
return sort_size();
case BLACK:
break;
}
}
else {
SASSERT(a_type.is_ast());
sort * ty = to_sort(a_type.get_ast());
if (ty->is_infinite()) {
// type is infinite
return sort_size();
}
else if (ty->is_very_big()) {
is_very_big = true;
}
}
}
}
if (can_process) {
todo.pop_back();
already_found[tid] = BLACK;
if (is_very_big) {
szs[tid] = sort_size::mk_very_big();
}
else {
// the type is not infinite nor the number of elements is infinite...
// computing the number of elements
rational num;
for (unsigned s = 1; s <= num_constructors; s++) {
unsigned k_i = parameters[o+s].get_int();
unsigned num_accessors = parameters[k_i+2].get_int();
rational c_num(1);
for (unsigned r = 0; r < num_accessors; r++) {
parameter const & a_type = parameters[k_i+4 + 2*r];
if (a_type.is_int()) {
int tid_prime = a_type.get_int();
SASSERT(!szs[tid_prime].is_infinite() && !szs[tid_prime].is_very_big());
c_num *= rational(szs[tid_prime].size(),rational::ui64());
}
else {
SASSERT(a_type.is_ast());
sort * ty = to_sort(a_type.get_ast());
SASSERT(!ty->is_infinite() && !ty->is_very_big());
c_num *= rational(ty->get_num_elements().size(), rational::ui64());
}
}
num += c_num;
}
szs[tid] = sort_size(num);
}
}
}
return szs[tid];
}
/**
\brief Return true if the inductive datatype is well-founded.
Pre-condition: The given argument constains the parameters of an inductive datatype.
*/
static bool is_well_founded(parameter const * parameters) {
unsigned num_types = parameters[0].get_int();
buffer<bool> well_founded(num_types, false);
unsigned num_well_founded = 0;
bool changed;
do {
changed = false;
for (unsigned tid = 0; tid < num_types; tid++) {
if (!well_founded[tid]) {
unsigned o = parameters[2 + 2*tid + 1].get_int(); // constructor offset
unsigned num_constructors = parameters[o].get_int();
for (unsigned s = 1; s <= num_constructors; s++) {
unsigned k_i = parameters[o + s].get_int();
unsigned num_accessors = parameters[k_i + 2].get_int();
unsigned r = 0;
for (; r < num_accessors; r++) {
parameter const & a_type = parameters[k_i + 4 + 2*r];
if (a_type.is_int() && !well_founded[a_type.get_int()]) {
break;
}
}
if (r == num_accessors) {
changed = true;
well_founded[tid] = true;
num_well_founded++;
break;
}
}
}
}
} while(changed && num_well_founded < num_types);
unsigned tid = parameters[1].get_int();
return well_founded[tid];
}
datatype_decl_plugin::~datatype_decl_plugin() {
SASSERT(m_util.get() == 0);
}
void datatype_decl_plugin::finalize() {
m_util = 0; // force deletion
}
datatype_util & datatype_decl_plugin::get_util() const {
SASSERT(m_manager);
if (m_util.get() == 0) {
m_util = alloc(datatype_util, *m_manager);
}
return *(m_util.get());
}
sort * datatype_decl_plugin::mk_sort(decl_kind k, unsigned num_parameters, parameter const * parameters) {
try {
if (k != DATATYPE_SORT) {
throw invalid_datatype();
}
buffer<bool, false, 256> found;
unsigned num_types = read_int(num_parameters, parameters, 0, found);
if (num_types == 0) {
throw invalid_datatype();
}
unsigned tid = read_int(num_parameters, parameters, 1, found);
for (unsigned j = 0; j < num_types; j++) {
read_symbol(num_parameters, parameters, 2 + 2*j, found); // type name
unsigned o = read_int(num_parameters, parameters, 2 + 2*j + 1, found);
unsigned num_constructors = read_int(num_parameters, parameters, o, found);
if (num_constructors == 0) {
throw invalid_datatype();
}
for (unsigned s = 1; s <= num_constructors; s++) {
unsigned k_i = read_int(num_parameters, parameters, o + s, found);
read_symbol(num_parameters, parameters, k_i, found); // constructor name
read_symbol(num_parameters, parameters, k_i + 1, found); // recognizer name
unsigned num_accessors = read_int(num_parameters, parameters, k_i + 2, found);
unsigned first_accessor = k_i+3;
for (unsigned r = 0; r < num_accessors; r++) {
read_symbol(num_parameters, parameters, first_accessor + 2*r, found); // accessor name
parameter const & a_type = read(num_parameters, parameters, first_accessor + 2*r + 1, found); // accessort type
if (!a_type.is_int() && !a_type.is_ast()) {
throw invalid_datatype();
if (a_type.is_ast() && !is_sort(a_type.get_ast())) {
throw invalid_datatype();
}
}
}
}
}
// check if there is no garbage
if (found.size() != num_parameters || std::find(found.begin(), found.end(), false) != found.end()) {
throw invalid_datatype();
}
if (!is_well_founded(parameters)) {
m_manager->raise_exception("datatype is not well-founded");
return 0;
}
// compute datatype size
sort_size ts = get_datatype_size(parameters);
symbol const & tname = parameters[2+2*tid].get_symbol();
return m_manager->mk_sort(tname,
sort_info(m_family_id, k, ts, num_parameters, parameters, true));
}
catch (invalid_datatype) {
m_manager->raise_exception("invalid datatype");
return 0;
}
}
static sort * get_other_datatype(ast_manager & m, family_id datatype_fid, sort * source_datatype, unsigned tid) {
SASSERT(source_datatype->get_family_id() == datatype_fid);
SASSERT(source_datatype->get_decl_kind() == DATATYPE_SORT);
if (tid == static_cast<unsigned>(source_datatype->get_parameter(1).get_int())) {
return source_datatype;
}
buffer<parameter> p;
unsigned n = source_datatype->get_num_parameters();
for (unsigned i = 0; i < n; i++) {
p.push_back(source_datatype->get_parameter(i));
}
p[1] = parameter(tid);
return m.mk_sort(datatype_fid, DATATYPE_SORT, n, p.c_ptr());
}
static sort * get_type(ast_manager & m, family_id datatype_fid, sort * source_datatype, parameter const & p) {
SASSERT(p.is_ast() || p.is_int());
if (p.is_ast()) {
return to_sort(p.get_ast());
}
else {
return get_other_datatype(m, datatype_fid, source_datatype, p.get_int());
}
}
func_decl * datatype_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters,
unsigned arity, sort * const * domain, sort * range) {
if (num_parameters < 2 || !parameters[0].is_ast() || !is_sort(parameters[0].get_ast())) {
m_manager->raise_exception("invalid parameters for datatype operator");
return 0;
}
sort * datatype = to_sort(parameters[0].get_ast());
if (datatype->get_family_id() != m_family_id ||
datatype->get_decl_kind() != DATATYPE_SORT) {
m_manager->raise_exception("invalid parameters for datatype operator");
return 0;
}
for (unsigned i = 1; i < num_parameters; i++) {
if (!parameters[i].is_int()) {
m_manager->raise_exception("invalid parameters for datatype operator");
return 0;
}
}
unsigned c_idx = parameters[1].get_int();
unsigned tid = datatype->get_parameter(1).get_int();
unsigned o = datatype->get_parameter(2 + 2 * tid + 1).get_int();
unsigned num_constructors = datatype->get_parameter(o).get_int();
if (c_idx >= num_constructors) {
m_manager->raise_exception("invalid parameters for datatype operator");
return 0;
}
unsigned k_i = datatype->get_parameter(o + 1 + c_idx).get_int();
switch (k) {
case OP_DT_CONSTRUCTOR:
if (num_parameters != 2) {
m_manager->raise_exception("invalid parameters for datatype constructor");
return 0;
}
else {
symbol c_name = datatype->get_parameter(k_i).get_symbol();
unsigned num_accessors = datatype->get_parameter(k_i + 2).get_int();
if (num_accessors != arity) {
m_manager->raise_exception("invalid domain size for datatype constructor");
return 0;
}
//
// the reference count to domain could be 0.
// we need to ensure that creating a temporary
// copy of the same type causes a free.
//
sort_ref_vector domain_check(*m_manager);
for (unsigned r = 0; r < num_accessors; r++) {
sort_ref ty(*m_manager);
ty = get_type(*m_manager, m_family_id, datatype, datatype->get_parameter(k_i + 4 + 2*r));
domain_check.push_back(ty);
if (ty != domain[r]) {
m_manager->raise_exception("invalid domain for datatype constructor");
return 0;
}
}
func_decl_info info(m_family_id, k, num_parameters, parameters);
info.m_private_parameters = true;
SASSERT(info.private_parameters());
return m_manager->mk_func_decl(c_name, arity, domain, datatype, info);
}
case OP_DT_RECOGNISER:
if (num_parameters != 2 || arity != 1 || domain[0] != datatype) {
m_manager->raise_exception("invalid parameters for datatype recogniser");
return 0;
}
else {
symbol r_name = datatype->get_parameter(k_i + 1).get_symbol();
sort * b = m_manager->mk_bool_sort();
func_decl_info info(m_family_id, k, num_parameters, parameters);
info.m_private_parameters = true;
SASSERT(info.private_parameters());
return m_manager->mk_func_decl(r_name, arity, domain, b, info);
}
case OP_DT_ACCESSOR:
if (num_parameters != 3 || arity != 1 || domain[0] != datatype) {
m_manager->raise_exception("invalid parameters for datatype accessor");
return 0;
}
else {
unsigned a_idx = parameters[2].get_int();
unsigned num_accessors = datatype->get_parameter(k_i + 2).get_int();
if (a_idx >= num_accessors) {
m_manager->raise_exception("invalid datatype accessor");
return 0;
}
symbol a_name = datatype->get_parameter(k_i + 3 + 2*a_idx).get_symbol();
sort * a_type = get_type(*m_manager, m_family_id, datatype, datatype->get_parameter(k_i + 4 + 2*a_idx));
func_decl_info info(m_family_id, k, num_parameters, parameters);
info.m_private_parameters = true;
SASSERT(info.private_parameters());
return m_manager->mk_func_decl(a_name, arity, domain, a_type, info);
}
break;
default:
m_manager->raise_exception("invalid datatype operator kind");
return 0;
}
}
bool datatype_decl_plugin::mk_datatypes(unsigned num_datatypes, datatype_decl * const * datatypes, sort_ref_vector & new_types) {
buffer<parameter> p;
p.push_back(parameter(num_datatypes));
p.push_back(parameter(-1));
for (unsigned i = 0; i < num_datatypes; i++) {
p.push_back(parameter(datatypes[i]->get_name()));
p.push_back(parameter(-1)); // offset is unknown at this point
}
for (unsigned i = 0; i < num_datatypes; i++) {
p[3+2*i] = parameter(p.size()); // save offset to constructor table
ptr_vector<constructor_decl> const & constructors = datatypes[i]->get_constructors();
unsigned num_constructors = constructors.size();
p.push_back(parameter(num_constructors));
for (unsigned j = 0; j < num_constructors; j++) {
p.push_back(parameter(-1)); // offset is unknown at this point
}
}
for (unsigned i = 0; i < num_datatypes; i++) {
unsigned o = p[3+2*i].get_int();
ptr_vector<constructor_decl> const & constructors = datatypes[i]->get_constructors();
unsigned num_constructors = constructors.size();
for (unsigned j = 0; j < num_constructors; j++) {
p[o+1+j] = parameter(p.size()); // save offset to constructor definition
constructor_decl * c = constructors[j];
p.push_back(parameter(c->get_name()));
p.push_back(parameter(c->get_recognizer_name()));
ptr_vector<accessor_decl> const & accessors = c->get_accessors();
unsigned num_accessors = accessors.size();
p.push_back(parameter(num_accessors));
for (unsigned k = 0; k < num_accessors; k++) {
accessor_decl * a = accessors[k];
p.push_back(parameter(a->get_name()));
type_ref const & ty = a->get_type();
if (ty.is_idx()) {
if (static_cast<unsigned>(ty.get_idx()) >= num_datatypes) {
TRACE("datatype", tout << "Index out of bounds: " << ty.get_idx() << "\n";);
return false;
}
p.push_back(parameter(ty.get_idx()));
}
else {
p.push_back(parameter(ty.get_sort()));
}
}
}
}
for (unsigned i = 0; i < num_datatypes; i++) {
p[1] = parameter(i);
TRACE("datatype", tout << "new datatype parameters:\n";
for (unsigned j = 0; j < p.size(); j++) {
tout << "p[" << j << "] -> " << p[j] << "\n";
});
sort * ty = mk_sort(DATATYPE_SORT, p.size(), p.c_ptr());
if (ty == 0) {
TRACE("datatype", tout << "Failed to create datatype sort from parameters\n";);
return false;
}
new_types.push_back(ty);
}
return true;
}
expr * datatype_decl_plugin::get_some_value(sort * s) {
SASSERT(s->is_sort_of(m_family_id, DATATYPE_SORT));
datatype_util & util = get_util();
func_decl * c = util.get_non_rec_constructor(s);
ptr_buffer<expr> args;
for (unsigned i = 0; i < c->get_arity(); i++) {
args.push_back(m_manager->get_some_value(c->get_domain(i)));
}
return m_manager->mk_app(c, args.size(), args.c_ptr());
}
bool datatype_decl_plugin::is_fully_interp(sort const * s) const {
SASSERT(s->is_sort_of(m_family_id, DATATYPE_SORT));
parameter const * parameters = s->get_parameters();
unsigned num_types = parameters[0].get_int();
for (unsigned tid = 0; tid < num_types; tid++) {
unsigned o = parameters[2 + 2*tid + 1].get_int(); // constructor offset
unsigned num_constructors = parameters[o].get_int();
for (unsigned s = 1; s <= num_constructors; s++) {
unsigned k_i = parameters[o + s].get_int();
unsigned num_accessors = parameters[k_i + 2].get_int();
unsigned r = 0;
for (; r < num_accessors; r++) {
parameter const & a_type = parameters[k_i + 4 + 2*r];
if (a_type.is_int())
continue;
SASSERT(a_type.is_ast());
sort * arg_s = to_sort(a_type.get_ast());
if (!m_manager->is_fully_interp(arg_s))
return false;
}
}
}
return true;
}
bool datatype_decl_plugin::is_value_visit(expr * arg, ptr_buffer<app> & todo) const {
if (!is_app(arg))
return false;
family_id fid = to_app(arg)->get_family_id();
if (fid == m_family_id) {
if (!get_util().is_constructor(to_app(arg)))
return false;
if (to_app(arg)->get_num_args() == 0)
return true;
todo.push_back(to_app(arg));
return true;
}
else {
return m_manager->is_value(arg);
}
}
bool datatype_decl_plugin::is_value(app * e) const {
TRACE("dt_is_value", tout << "checking\n" << mk_ismt2_pp(e, *m_manager) << "\n";);
if (!get_util().is_constructor(e))
return false;
if (e->get_num_args() == 0)
return true;
// REMARK: if the following check is too expensive, we should
// cache the values in the datatype_decl_plugin.
ptr_buffer<app> todo;
// potentially expensive check for common sub-expressions.
for (unsigned i = 0; i < e->get_num_args(); i++) {
if (!is_value_visit(e->get_arg(i), todo)) {
TRACE("dt_is_value", tout << "not-value:\n" << mk_ismt2_pp(e->get_arg(i), *m_manager) << "\n";);
return false;
}
}
while (!todo.empty()) {
app * curr = todo.back();
SASSERT(get_util().is_constructor(curr));
todo.pop_back();
for (unsigned i = 0; i < curr->get_num_args(); i++) {
if (!is_value_visit(curr->get_arg(i), todo)) {
TRACE("dt_is_value", tout << "not-value:\n" << mk_ismt2_pp(curr->get_arg(i), *m_manager) << "\n";);
return false;
}
}
}
return true;
}
datatype_util::datatype_util(ast_manager & m):
m_manager(m),
m_family_id(m.get_family_id("datatype")),
m_asts(m) {
}
datatype_util::~datatype_util() {
std::for_each(m_vectors.begin(), m_vectors.end(), delete_proc<ptr_vector<func_decl> >());
}
func_decl * datatype_util::get_constructor(sort * ty, unsigned c_id) {
unsigned tid = ty->get_parameter(1).get_int();
unsigned o = ty->get_parameter(3 + 2*tid).get_int();
unsigned k_i = ty->get_parameter(o + c_id + 1).get_int();
unsigned num_accessors = ty->get_parameter(k_i + 2).get_int();
parameter p[2] = { parameter(ty), parameter(c_id) };
ptr_buffer<sort> domain;
for (unsigned r = 0; r < num_accessors; r++) {
domain.push_back(get_type(m_manager, m_family_id, ty, ty->get_parameter(k_i + 4 + 2*r)));
}
func_decl * d = m_manager.mk_func_decl(m_family_id, OP_DT_CONSTRUCTOR, 2, p, domain.size(), domain.c_ptr());
SASSERT(d);
return d;
}
ptr_vector<func_decl> const * datatype_util::get_datatype_constructors(sort * ty) {
SASSERT(is_datatype(ty));
ptr_vector<func_decl> * r = 0;
if (m_datatype2constructors.find(ty, r))
return r;
r = alloc(ptr_vector<func_decl>);
m_asts.push_back(ty);
m_vectors.push_back(r);
m_datatype2constructors.insert(ty, r);
unsigned tid = ty->get_parameter(1).get_int();
unsigned o = ty->get_parameter(3 + 2*tid).get_int();
unsigned num_constructors = ty->get_parameter(o).get_int();
for (unsigned c_id = 0; c_id < num_constructors; c_id++) {
func_decl * c = get_constructor(ty, c_id);
m_asts.push_back(c);
r->push_back(c);
}
return r;
}
/**
\brief Return a constructor mk(T_1, ... T_n)
where each T_i is not a datatype or it is a datatype that contains
a constructor that will not contain directly or indirectly an element of the given sort.
*/
func_decl * datatype_util::get_non_rec_constructor(sort * ty) {
SASSERT(is_datatype(ty));
func_decl * r = 0;
if (m_datatype2nonrec_constructor.find(ty, r))
return r;
r = 0;
ptr_vector<sort> forbidden_set;
forbidden_set.push_back(ty);
r = get_non_rec_constructor_core(ty, forbidden_set);
SASSERT(forbidden_set.back() == ty);
SASSERT(r);
m_asts.push_back(ty);
m_asts.push_back(r);
m_datatype2nonrec_constructor.insert(ty, r);
return r;
}
/**
\brief Return a constructor mk(T_1, ..., T_n) where
each T_i is not a datatype or it is a datatype t not in forbidden_set,
and get_non_rec_constructor_core(T_i, forbidden_set union { T_i })
*/
func_decl * datatype_util::get_non_rec_constructor_core(sort * ty, ptr_vector<sort> & forbidden_set) {
// We must select a constructor c(T_1, ..., T_n):T such that
// 1) T_i's are not recursive
// If there is no such constructor, then we select one that
// 2) each type T_i is not recursive or contains a constructor that does not depend on T
ptr_vector<func_decl> const * constructors = get_datatype_constructors(ty);
ptr_vector<func_decl>::const_iterator it = constructors->begin();
ptr_vector<func_decl>::const_iterator end = constructors->end();
// step 1)
for (; it != end; ++it) {
func_decl * c = *it;
unsigned num_args = c->get_arity();
unsigned i = 0;
for (; i < num_args; i++) {
sort * T_i = c->get_domain(i);
if (is_datatype(T_i))
break;
}
if (i == num_args)
return c;
}
// step 2)
it = constructors->begin();
for (; it != end; ++it) {
func_decl * c = *it;
TRACE("datatype_util_bug", tout << "non_rec_constructor c: " << c->get_name() << "\n";);
unsigned num_args = c->get_arity();
unsigned i = 0;
for (; i < num_args; i++) {
sort * T_i = c->get_domain(i);
TRACE("datatype_util_bug", tout << "c: " << c->get_name() << " i: " << i << " T_i: " << T_i->get_name() << "\n";);
if (!is_datatype(T_i)) {
TRACE("datatype_util_bug", tout << "T_i is not a datatype\n";);
continue;
}
if (std::find(forbidden_set.begin(), forbidden_set.end(), T_i) != forbidden_set.end()) {
TRACE("datatype_util_bug", tout << "T_i is in forbidden_set\n";);
break;
}
forbidden_set.push_back(T_i);
func_decl * nested_c = get_non_rec_constructor_core(T_i, forbidden_set);
SASSERT(forbidden_set.back() == T_i);
forbidden_set.pop_back();
TRACE("datatype_util_bug", tout << "nested_c: " << nested_c->get_name() << "\n";);
if (nested_c == 0)
break;
}
if (i == num_args)
return c;
}
return 0;
}
func_decl * datatype_util::get_constructor_recognizer(func_decl * constructor) {
SASSERT(is_constructor(constructor));
func_decl * d = 0;
if (m_constructor2recognizer.find(constructor, d))
return d;
sort * datatype = constructor->get_range();
d = m_manager.mk_func_decl(m_family_id, OP_DT_RECOGNISER, 2, constructor->get_parameters(), 1, &datatype);
SASSERT(d);
m_asts.push_back(constructor);
m_asts.push_back(d);
m_constructor2recognizer.insert(constructor, d);
return d;
}
ptr_vector<func_decl> const * datatype_util::get_constructor_accessors(func_decl * constructor) {
SASSERT(is_constructor(constructor));
ptr_vector<func_decl> * res = 0;
if (m_constructor2accessors.find(constructor, res))
return res;
res = alloc(ptr_vector<func_decl>);
m_asts.push_back(constructor);
m_vectors.push_back(res);
m_constructor2accessors.insert(constructor, res);
unsigned c_id = constructor->get_parameter(1).get_int();
sort * datatype = constructor->get_range();
unsigned tid = datatype->get_parameter(1).get_int();
unsigned o = datatype->get_parameter(3 + 2*tid).get_int();
unsigned k_i = datatype->get_parameter(o + c_id + 1).get_int();
unsigned num_accessors = datatype->get_parameter(k_i+2).get_int();
parameter p[3] = { parameter(datatype), parameter(c_id), parameter(-1) };
for (unsigned r = 0; r < num_accessors; r++) {
p[2] = parameter(r);
func_decl * d = m_manager.mk_func_decl(m_family_id, OP_DT_ACCESSOR, 3, p, 1, &datatype);
SASSERT(d);
m_asts.push_back(d);
res->push_back(d);
}
return res;
}
func_decl * datatype_util::get_accessor_constructor(func_decl * accessor) {
SASSERT(is_accessor(accessor));
func_decl * r = 0;
if (m_accessor2constructor.find(accessor, r))
return r;
sort * datatype = to_sort(accessor->get_parameter(0).get_ast());
unsigned c_id = accessor->get_parameter(1).get_int();
r = get_constructor(datatype, c_id);
m_accessor2constructor.insert(accessor, r);
m_asts.push_back(accessor);
m_asts.push_back(r);
return r;
}
func_decl * datatype_util::get_recognizer_constructor(func_decl * recognizer) {
SASSERT(is_recognizer(recognizer));
func_decl * r = 0;
if (m_recognizer2constructor.find(recognizer, r))
return r;
sort * datatype = to_sort(recognizer->get_parameter(0).get_ast());
unsigned c_id = recognizer->get_parameter(1).get_int();
r = get_constructor(datatype, c_id);
m_recognizer2constructor.insert(recognizer, r);
m_asts.push_back(recognizer);
m_asts.push_back(r);
return r;
}
bool datatype_util::is_recursive(sort * ty) {
SASSERT(is_datatype(ty));
bool r = false;
if (m_is_recursive.find(ty, r))
return r;
r = is_recursive_datatype(ty->get_parameters());
m_is_recursive.insert(ty, r);
m_asts.push_back(ty);
return r;
}
void datatype_util::reset() {
m_datatype2constructors.reset();
m_datatype2nonrec_constructor.reset();
m_constructor2accessors.reset();
m_constructor2recognizer.reset();
m_recognizer2constructor.reset();
m_accessor2constructor.reset();
m_is_recursive.reset();
std::for_each(m_vectors.begin(), m_vectors.end(), delete_proc<ptr_vector<func_decl> >());
m_vectors.reset();
m_asts.reset();
}
/**
\brief Two datatype sorts s1 and s2 are siblings if they were
defined together in the same mutually recursive definition.
*/
bool datatype_util::are_siblings(sort * s1, sort * s2) {
SASSERT(is_datatype(s1));
SASSERT(is_datatype(s2));
if (s1 == s2)
return true;
if (s1->get_num_parameters() != s2->get_num_parameters())
return false;
unsigned num_params = s1->get_num_parameters();
if (s1->get_parameter(0) != s2->get_parameter(0))
return false;
// position 1 contains the IDX of the datatype in a mutually recursive definition.
for (unsigned i = 2; i < num_params; i++) {
if (s1->get_parameter(i) != s2->get_parameter(i))
return false;
}
return true;
}
void datatype_util::display_datatype(sort *s0, std::ostream& strm) {
ast_mark mark;
ptr_buffer<sort> todo;
SASSERT(is_datatype(s0));
strm << s0->get_name() << " where\n";
todo.push_back(s0);
mark.mark(s0, true);
while (!todo.empty()) {
sort* s = todo.back();
todo.pop_back();
strm << s->get_name() << " =\n";
ptr_vector<func_decl> const * cnstrs = get_datatype_constructors(s);
for (unsigned i = 0; i < cnstrs->size(); ++i) {
func_decl* cns = (*cnstrs)[i];
func_decl* rec = get_constructor_recognizer(cns);
strm << " " << cns->get_name() << " :: " << rec->get_name() << " :: ";
ptr_vector<func_decl> const * accs = get_constructor_accessors(cns);
for (unsigned j = 0; j < accs->size(); ++j) {
func_decl* acc = (*accs)[j];
sort* s1 = acc->get_range();
strm << "(" << acc->get_name() << ": " << s1->get_name() << ") ";
if (is_datatype(s1) && are_siblings(s1, s0) && !mark.is_marked(s1)) {
mark.mark(s1, true);
todo.push_back(s1);
}
}
strm << "\n";
}
}
}

View file

@ -0,0 +1,200 @@
/*++
Copyright (c) 2006 Microsoft Corporation
Module Name:
datatype_decl_plugin.h
Abstract:
<abstract>
Author:
Leonardo de Moura (leonardo) 2008-01-09.
Revision History:
--*/
#ifndef _DATATYPE_DECL_PLUGIN_H_
#define _DATATYPE_DECL_PLUGIN_H_
#include"ast.h"
#include"tptr.h"
#include"buffer.h"
#include"obj_hashtable.h"
enum datatype_sort_kind {
DATATYPE_SORT
};
enum datatype_op_kind {
OP_DT_CONSTRUCTOR,
OP_DT_RECOGNISER,
OP_DT_ACCESSOR,
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.
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.
This is a transient value, it is only used to declare a set of
recursive datatypes.
*/
class type_ref {
void * m_data;
public:
type_ref():m_data(TAG(void *, static_cast<void*>(0), 1)) {}
type_ref(int idx):m_data(BOXINT(void *, idx)) {}
type_ref(sort * s):m_data(TAG(void *, s, 1)) {}
bool is_idx() const { return GET_TAG(m_data) == 0; }
bool is_sort() const { return GET_TAG(m_data) == 1; }
sort * get_sort() const { return UNTAG(sort *, m_data); }
int get_idx() const { return UNBOXINT(m_data); }
};
class accessor_decl;
class constructor_decl;
class datatype_decl;
class datatype_util;
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);
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.
for j in 0..n-1
parameters[2 + 2*j] - (symbol) name of the type
parameters[2 + 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 ofr 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, 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;
private:
bool is_value_visit(expr * arg, ptr_buffer<app> & todo) const;
};
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;
ast_ref_vector m_asts;
ptr_vector<ptr_vector<func_decl> > m_vectors;
func_decl * get_constructor(sort * ty, unsigned c_id);
func_decl * get_non_rec_constructor_core(sort * ty, ptr_vector<sort> & forbidden_set);
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_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_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); }
ptr_vector<func_decl> const * get_datatype_constructors(sort * ty);
unsigned get_datatype_num_constructors(sort * ty) { return get_datatype_constructors(ty)->size(); }
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);
void reset();
void display_datatype(sort *s, std::ostream& strm);
};
#endif /* _DATATYPE_DECL_PLUGIN_H_ */

745
src/ast/dl_decl_plugin.cpp Normal file
View file

@ -0,0 +1,745 @@
/*++
Copyright (c) 2010 Microsoft Corporation
Module Name:
dl_decl_plugin.h
Abstract:
<abstract>
Author:
Nikolaj Bjorner (nbjorner) 2010-04-10
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"
namespace datalog {
dl_decl_plugin::dl_decl_plugin() :
m_store_sym("store"),
m_empty_sym("empty"),
m_is_empty_sym("is_empty"),
m_join_sym("join"),
m_union_sym("union"),
m_widen_sym("widen"),
m_project_sym("project"),
m_filter_sym("filter"),
m_negation_filter_sym("negation_filter"),
m_rename_sym("rename"),
m_complement_sym("complement"),
m_select_sym("select"),
m_clone_sym("clone"),
m_num_sym("N"),
m_lt_sym("<"),
m_le_sym("<="),
m_rule_sym("R"),
m_hyper_resolve_sym("hyper-res")
{
}
bool dl_decl_plugin::check_bounds(char const* msg, unsigned low, unsigned up, unsigned val) const {
if (low <= val && val <= up) {
return true;
}
std::ostringstream buffer;
buffer << msg << ", value is not within bound " << low << " <= " << val << " <= " << up;
m_manager->raise_exception(buffer.str().c_str());
return false;
}
bool dl_decl_plugin::check_domain(unsigned low, unsigned up, unsigned val) const {
return check_bounds("unexpected number of arguments", low, up, val);
}
bool dl_decl_plugin::check_params(unsigned low, unsigned up, unsigned val) const {
return check_bounds("unexpected number of parameters", low, up, val);
}
sort * dl_decl_plugin::mk_relation_sort( unsigned num_parameters, parameter const * parameters) {
bool is_finite = true;
rational r(1);
for (unsigned i = 0; is_finite && i < num_parameters; ++i) {
if (!parameters[i].is_ast() || !is_sort(parameters[i].get_ast())) {
m_manager->raise_exception("expecting sort parameters");
return 0;
}
sort* s = to_sort(parameters[i].get_ast());
sort_size sz1 = s->get_num_elements();
if (sz1.is_finite()) {
r *= rational(sz1.size(),rational::ui64());
}
else {
is_finite = false;
}
}
sort_size sz;
if (is_finite && r.is_uint64()) {
sz = sort_size::mk_finite(r.get_uint64());
}
else {
sz = sort_size::mk_very_big();
}
sort_info info(m_family_id, DL_RELATION_SORT, sz, num_parameters, parameters);
return m_manager->mk_sort(symbol("Table"),info);
}
sort * dl_decl_plugin::mk_finite_sort(unsigned num_params, parameter const* params) {
if (num_params != 2) {
m_manager->raise_exception("expecting two parameters");
return 0;
}
if (!params[0].is_symbol()) {
m_manager->raise_exception("expecting symbol");
return 0;
}
if (!params[1].is_rational() || !params[1].get_rational().is_uint64()) {
m_manager->raise_exception("expecting rational");
return 0;
}
sort_size sz = sort_size::mk_finite(params[1].get_rational().get_uint64());
sort_info info(m_family_id, DL_FINITE_SORT, sz, num_params, params);
return m_manager->mk_sort(params[0].get_symbol(),info);
}
sort* dl_decl_plugin::mk_rule_sort() {
sort_size sz(sort_size::mk_infinite());
sort_info info(m_family_id, DL_RULE_SORT, sz, 0, 0);
return m_manager->mk_sort(m_rule_sym, info);
}
sort * dl_decl_plugin::mk_sort(decl_kind k, unsigned num_parameters, parameter const * parameters) {
switch(k) {
case DL_RELATION_SORT:
return mk_relation_sort(num_parameters, parameters);
case DL_FINITE_SORT:
return mk_finite_sort(num_parameters, parameters);
case DL_RULE_SORT:
return mk_rule_sort();
default:
UNREACHABLE();
}
return 0;
}
bool dl_decl_plugin::is_rel_sort(sort* r) {
ptr_vector<sort> sorts;
return is_rel_sort(r, sorts);
}
bool dl_decl_plugin::is_rel_sort(sort* r, ptr_vector<sort>& sorts) {
if (!is_sort_of(r, m_family_id, DL_RELATION_SORT)) {
m_manager->raise_exception("expected relation sort");
return false;
}
unsigned n = r->get_num_parameters();
for (unsigned i = 0; i < n; ++i) {
parameter const& p = r->get_parameter(i);
if (!p.is_ast() || !is_sort(p.get_ast())) {
m_manager->raise_exception("exptected sort parameter");
return false;
}
sorts.push_back(to_sort(p.get_ast()));
}
return true;
}
bool dl_decl_plugin::is_fin_sort(sort* r) {
if (!is_sort_of(r, m_family_id, DL_FINITE_SORT)) {
m_manager->raise_exception("expected finite sort");
return false;
}
return true;
}
func_decl* dl_decl_plugin::mk_store_select(decl_kind k, unsigned arity, sort* const* domain) {
bool is_store = (k == OP_RA_STORE);
ast_manager& m = *m_manager;
symbol sym = is_store?m_store_sym:m_select_sym;
sort * r = domain[0];
if (!is_store) {
r = m.mk_bool_sort();
}
ptr_vector<sort> sorts;
if (!is_rel_sort(r, sorts)) {
return 0;
}
if (sorts.size() + 1 != arity) {
m_manager->raise_exception("wrong arity supplied to relational access");
return 0;
}
for (unsigned i = 0; i < sorts.size(); ++i) {
if (sorts[i] != domain[i+1]) {
IF_VERBOSE(0,
verbose_stream() << "Domain: " << mk_pp(domain[0], m) << "\n" <<
mk_pp(sorts[i], m) << "\n" <<
mk_pp(domain[i+1], m) << "\n";);
m_manager->raise_exception("sort miss-match for relational access");
return 0;
}
}
func_decl_info info(m_family_id, k, 0, 0);
return m.mk_func_decl(sym, arity, domain, r, info);
}
func_decl * dl_decl_plugin::mk_empty(parameter const& p) {
ast_manager& m = *m_manager;
if (!p.is_ast() || !is_sort(p.get_ast())) {
m_manager->raise_exception("expected sort parameter");
return 0;
}
sort* r = to_sort(p.get_ast());
if (!is_rel_sort(r)) {
return 0;
}
func_decl_info info(m_family_id, OP_RA_EMPTY, 1, &p);
return m.mk_func_decl(m_empty_sym, 0, (sort*const*)0, r, info);
}
func_decl* dl_decl_plugin::mk_project(unsigned num_params, parameter const* params, sort* r) {
ast_manager& m = *m_manager;
ptr_vector<sort> sorts;
vector<parameter> ps;
TRACE("dl_decl_plugin",
tout << mk_pp(r, m) << " ";
for (unsigned i = 0; i < num_params; ++i) {
tout << params[i] << " ";
}
tout << "\n";
);
if (!is_rel_sort(r, sorts)) {
return 0;
}
SASSERT(sorts.size() >= num_params);
// populate ps
unsigned j = 0, i = 0;
for (; i < num_params; ++i) {
if (!params[i].is_int()) {
m_manager->raise_exception("expecting integer parameter");
return 0;
}
unsigned k = params[i].get_int();
if (j > k) {
m_manager->raise_exception("arguments to projection should be increasing");
return 0;
}
while (j < k) {
ps.push_back(parameter(sorts[j]));
++j;
}
++j;
}
for (; j < sorts.size(); ++j) {
ps.push_back(parameter(sorts[j]));
}
SASSERT(ps.size() + num_params == sorts.size());
sort* r2 = m.mk_sort(m_family_id, DL_RELATION_SORT, ps.size(), ps.c_ptr());
func_decl_info info(m_family_id, OP_RA_PROJECT, num_params, params);
return m.mk_func_decl(m_project_sym, 1, &r, r2, info);
}
func_decl * dl_decl_plugin::mk_unionw(decl_kind k, sort* s1, sort* s2) {
ast_manager& m = *m_manager;
if (s1 != s2) {
m_manager->raise_exception("sort miss-match for arguments to union");
return 0;
}
if (!is_rel_sort(s1)) {
return 0;
}
sort* domain[2] = { s1, s2 };
func_decl_info info(m_family_id, k, 0, 0);
return m.mk_func_decl(m_union_sym, 2, domain, s1, info);
}
func_decl * dl_decl_plugin::mk_filter(parameter const& p, sort* r) {
ast_manager& m = *m_manager;
ptr_vector<sort> sorts;
if (!is_rel_sort(r, sorts)) {
return 0;
}
if (!p.is_ast() || !is_expr(p.get_ast())) {
m_manager->raise_exception("ast expression expected to filter");
}
expr* f = to_expr(p.get_ast());
// 1. f is of Boolean type.
// 2. the free variables in f correspond to column types of r.
if (!m.is_bool(f)) {
m_manager->raise_exception("filter predicate should be of Boolean type");
return 0;
}
ptr_vector<expr> todo;
todo.push_back(f);
ast_mark mark;
while (!todo.empty()) {
expr* e = todo.back();
todo.pop_back();
if (mark.is_marked(e)) {
continue;
}
mark.mark(e, true);
unsigned idx;
switch(e->get_kind()) {
case AST_VAR:
idx = to_var(e)->get_idx();
if (idx >= sorts.size()) {
m_manager->raise_exception("illegal index");
return 0;
}
if (sorts[idx] != m.get_sort(e)) {
m_manager->raise_exception("sort miss-match in filter");
return 0;
}
break;
case AST_APP:
for (unsigned i = 0; i < to_app(e)->get_num_args(); ++i) {
todo.push_back(to_app(e)->get_arg(i));
}
break;
case AST_QUANTIFIER:
m_manager->raise_exception("quantifiers are not allowed in filter expressions");
return 0;
default:
m_manager->raise_exception("unexpected filter expression kind");
return 0;
}
}
func_decl_info info(m_family_id, OP_RA_FILTER, 1, &p);
return m.mk_func_decl(m_filter_sym, 1, &r, r, info);
}
func_decl * dl_decl_plugin::mk_rename(unsigned num_params, parameter const* params, sort* r) {
ptr_vector<sort> sorts;
if (!is_rel_sort(r, sorts)) {
return 0;
}
unsigned index0;
sort* last_sort = 0;
for (unsigned i = 0; i < num_params; ++i) {
parameter const& p = params[i];
if (!p.is_int()) {
m_manager->raise_exception("expected integer parameter");
return 0;
}
unsigned j = p.get_int();
if (j >= sorts.size()) {
// We should not use ast_pp anymore on error messages.
// m_manager->raise_exception("index %d out of bound %s : %d", j, ast_pp(r, *m_manager).c_str(), sorts.size());
m_manager->raise_exception("index out of bound");
return 0;
}
if (i == 0) {
index0 = j;
last_sort = sorts[j];
}
else {
std::swap(last_sort, sorts[j]);
}
}
sorts[index0] = last_sort;
vector<parameter> params2;
for (unsigned i = 0; i < sorts.size(); ++i) {
params2.push_back(parameter(sorts[i]));
}
sort* rng = m_manager->mk_sort(m_family_id, DL_RELATION_SORT, params2.size(), params2.c_ptr());
func_decl_info info(m_family_id, OP_RA_RENAME, num_params, params);
return m_manager->mk_func_decl(m_rename_sym, 1, &r, rng, info);
}
func_decl * dl_decl_plugin::mk_join(unsigned num_params, parameter const* params, sort* r1, sort* r2) {
vector<parameter> params2;
ptr_vector<sort> sorts1, sorts2;
if (!is_rel_sort(r1, sorts1)) {
return 0;
}
if (!is_rel_sort(r2, sorts2)) {
return 0;
}
for (unsigned i = 0; i < sorts1.size(); ++i) {
params2.push_back(parameter(sorts1[i]));
}
for (unsigned i = 0; i < sorts2.size(); ++i) {
params2.push_back(parameter(sorts2[i]));
}
if (0 != num_params % 2) {
m_manager->raise_exception("expecting an even number of parameters to join");
return 0;
}
for (unsigned i = 0; i + 1 < num_params; i += 2) {
parameter const& p1 = params[i];
parameter const& p2 = params[i+1];
if (!p1.is_int() || !p2.is_int()) {
m_manager->raise_exception("encountered non-integer parameter");
return 0;
}
unsigned i1 = p1.get_int();
unsigned i2 = p2.get_int();
if (i1 >= sorts1.size() || i2 >= sorts2.size()) {
m_manager->raise_exception("index out of bounds");
return 0;
}
if (sorts1[i1] != sorts2[i2]) {
m_manager->raise_exception("sort miss-match in join");
return 0;
}
}
sort* args[2] = { r1, r2 };
sort* rng = m_manager->mk_sort(m_family_id, DL_RELATION_SORT, params2.size(), params2.c_ptr());
func_decl_info info(m_family_id, OP_RA_JOIN, num_params, params);
return m_manager->mk_func_decl(m_join_sym, 2, args, rng, info);
}
func_decl* dl_decl_plugin::mk_complement(sort* s) {
if (!is_rel_sort(s)) {
return 0;
}
func_decl_info info(m_family_id, OP_RA_COMPLEMENT, 0, 0);
return m_manager->mk_func_decl(m_complement_sym, 1, &s, s, info);
}
func_decl * dl_decl_plugin::mk_negation_filter(unsigned num_params, parameter const* params, sort* r1, sort* r2) {
ptr_vector<sort> sorts1, sorts2;
if (!is_rel_sort(r1, sorts1)) {
return 0;
}
if (!is_rel_sort(r2, sorts2)) {
return 0;
}
if (0 != num_params % 2) {
m_manager->raise_exception("expecting an even number of parameters to negation filter");
return 0;
}
for (unsigned i = 0; i + 1 < num_params; i += 2) {
parameter const& p1 = params[i];
parameter const& p2 = params[i+1];
if (!p1.is_int() || !p2.is_int()) {
m_manager->raise_exception("encountered non-integer parameter");
return 0;
}
unsigned i1 = p1.get_int();
unsigned i2 = p2.get_int();
if (i1 >= sorts1.size() || i2 >= sorts2.size()) {
m_manager->raise_exception("index out of bounds");
return 0;
}
if (sorts1[i1] != sorts2[i2]) {
m_manager->raise_exception("sort miss-match in join");
return 0;
}
}
sort* args[2] = { r1, r2 };
func_decl_info info(m_family_id, OP_RA_NEGATION_FILTER, num_params, params);
return m_manager->mk_func_decl(m_negation_filter_sym, 2, args, r1, info);
}
func_decl * dl_decl_plugin::mk_is_empty(sort* s) {
if (!is_rel_sort(s)) {
return 0;
}
func_decl_info info(m_family_id, OP_RA_IS_EMPTY, 0, 0);
sort* rng = m_manager->mk_bool_sort();
return m_manager->mk_func_decl(m_is_empty_sym, 1, &s, rng, info);
}
func_decl * dl_decl_plugin::mk_constant(parameter const* params) {
parameter const& p = params[0];
parameter const& ps = params[1];
if (!p.is_rational() || !p.get_rational().is_uint64()) {
m_manager->raise_exception("first parameter should be a rational");
return 0;
}
if (!ps.is_ast() || !is_sort(ps.get_ast()) || !is_fin_sort(to_sort(ps.get_ast()))) {
m_manager->raise_exception("second paramter should be a finite domain sort");
return 0;
}
sort* s = to_sort(ps.get_ast());
func_decl_info info(m_family_id, OP_DL_CONSTANT, 2, params);
return m_manager->mk_func_decl(m_num_sym, 0, (sort*const*)0, s, info);
}
func_decl * dl_decl_plugin::mk_compare(decl_kind k, symbol const& sym, sort *const* domain) {
if (!is_sort_of(domain[0], m_family_id, DL_FINITE_SORT)) {
m_manager->raise_exception("expecting finite domain sort");
return 0;
}
if (domain[0] != domain[1]) {
m_manager->raise_exception("expecting two identical finite domain sorts");
return 0;
}
func_decl_info info(m_family_id, k, 0, 0);
return m_manager->mk_func_decl(sym, 2, domain, m_manager->mk_bool_sort(), info);
}
func_decl * dl_decl_plugin::mk_clone(sort* s) {
if (!is_rel_sort(s)) {
return 0;
}
func_decl_info info(m_family_id, OP_RA_CLONE, 0, 0);
return m_manager->mk_func_decl(m_clone_sym, 1, &s, s, info);
}
func_decl * dl_decl_plugin::mk_func_decl(
decl_kind k, unsigned num_parameters, parameter const * parameters,
unsigned arity, sort * const * domain, sort * range) {
func_decl* result = 0;
switch(k) {
case OP_RA_STORE:
case OP_RA_SELECT:
if (!check_params(0, 0, num_parameters) ||
!check_domain(1, UINT_MAX, arity)) {
return 0;
}
result = mk_store_select(k, arity, domain);
break;
case OP_RA_EMPTY:
if (!check_params( 1, 1, num_parameters) ||
!check_domain(0, 0, arity)) {
return 0;
}
result = mk_empty(parameters[0]);
break;
case OP_RA_JOIN:
if (!check_params(0, UINT_MAX, num_parameters) ||
!check_domain(2, 2, arity)) {
return 0;
}
result = mk_join(num_parameters, parameters, domain[0], domain[1]);
break;
case OP_RA_UNION:
case OP_RA_WIDEN:
if (!check_params( 0, 0, num_parameters) ||
!check_domain(2, 2, arity)) {
return 0;
}
result = mk_unionw(k, domain[0], domain[1]);
break;
case OP_RA_PROJECT:
if (!check_params( 1, UINT_MAX, num_parameters) ||
!check_domain(1, 1, arity)) {
return 0;
}
result = mk_project(num_parameters, parameters, domain[0]);
break;
case OP_RA_FILTER:
if (!check_params( 1, 1, num_parameters) ||
!check_domain(1, 1, arity)) {
return 0;
}
result = mk_filter(parameters[0], domain[0]);
break;
case OP_RA_IS_EMPTY:
if (!check_params( 0, 0, num_parameters) ||
!check_domain(1, 1, arity)) {
return 0;
}
result = mk_is_empty(domain[0]);
break;
case OP_RA_RENAME:
if (!check_params( 2, UINT_MAX, num_parameters) ||
!check_domain(1, 1, arity)) {
return 0;
}
result = mk_rename(num_parameters, parameters, domain[0]);
break;
case OP_RA_COMPLEMENT:
if (!check_params( 0, 0, num_parameters) ||
!check_domain(1, 1, arity)) {
return 0;
}
result = mk_complement(domain[0]);
break;
case OP_RA_NEGATION_FILTER:
if (!check_params(1, UINT_MAX, num_parameters) ||
!check_domain(2, 2, arity)) {
return 0;
}
result = mk_negation_filter(num_parameters, parameters, domain[0], domain[1]);
break;
case OP_RA_CLONE:
if (!check_params(0, 0, num_parameters) || !check_domain(1, 1, arity)) {
return 0;
}
result = mk_clone(domain[0]);
break;
case OP_DL_CONSTANT:
if (!check_params( 2, 2, num_parameters) ||
!check_domain(0, 0, arity)) {
return 0;
}
result = mk_constant(parameters);
break;
case OP_DL_LT:
if (!check_params( 0, 0, num_parameters) ||
!check_domain(2, 2, arity)) {
return 0;
}
result = mk_compare(OP_DL_LT, m_lt_sym, domain);
break;
default:
m_manager->raise_exception("operator not recognized");
return 0;
}
TRACE("dl_decl_plugin", tout << mk_pp(result, *m_manager) << "\n";);
return result;
}
void dl_decl_plugin::get_op_names(svector<builtin_name> & op_names, symbol const & logic) {
}
void dl_decl_plugin::get_sort_names(svector<builtin_name> & sort_names, symbol const & logic) {
}
dl_decl_util::ast_plugin_registrator::ast_plugin_registrator(ast_manager& m)
{
// ensure required plugins are installed into the ast_manager
m.register_decl_plugins();
}
dl_decl_util::dl_decl_util(ast_manager& m):
m_plugin_registrator(m),
m(m),
m_arith(m),
m_bv(m),
m_fid(m.get_family_id(symbol("datalog_relation")))
{}
// create a constant belonging to a given finite domain.
app* dl_decl_util::mk_numeral(uint64 value, sort* s) {
if (is_finite_sort(s)) {
parameter params[2] = { parameter(rational(value, rational::ui64())), parameter(s) };
return m.mk_const(m.mk_func_decl(m_fid, OP_DL_CONSTANT, 2, params, 0, (sort*const*)0));
}
if (m_arith.is_int(s) || m_arith.is_real(s)) {
return m_arith.mk_numeral(rational(value, rational::ui64()), s);
}
if (m_bv.is_bv_sort(s)) {
return m_bv.mk_numeral(rational(value, rational::ui64()), s);
}
if (m.is_bool(s)) {
if (value == 0) {
return m.mk_false();
}
SASSERT(value == 1);
return m.mk_true();
}
m.raise_exception("unrecognized sort");
return 0;
}
bool dl_decl_util::is_numeral(expr* e, uint64& v) const {
if (is_numeral(e)) {
app* c = to_app(e);
SASSERT(c->get_decl()->get_num_parameters() == 2);
parameter const& p = c->get_decl()->get_parameter(0);
SASSERT(p.is_rational());
SASSERT(p.get_rational().is_uint64());
v = p.get_rational().get_uint64();
return true;
}
return false;
}
bool dl_decl_util::is_numeral_ext(expr* e, uint64& v) const {
if (is_numeral(e, v)) {
return true;
}
rational val;
unsigned bv_size = 0;
if (m_bv.is_numeral(e, val, bv_size) && bv_size < 64) {
SASSERT(val.is_uint64());
v = val.get_uint64();
return true;
}
if (m.is_true(e)) {
v = 1;
return true;
}
if (m.is_false(e)) {
v = 0;
return true;
}
return false;
}
bool dl_decl_util::is_numeral_ext(expr* c) const {
if (is_numeral(c)) return true;
rational val;
unsigned bv_size = 0;
if (m_arith.is_numeral(c, val) && val.is_uint64()) return true;
if (m_bv.is_numeral(c, val, bv_size) && bv_size < 64) return true;
return m.is_true(c) || m.is_false(c);
}
sort* dl_decl_util::mk_sort(const symbol& name, uint64 domain_size) {
if (domain_size == 0) {
std::stringstream sstm;
sstm << "Domain size of sort '" << name << "' may not be 0";
throw default_exception(sstm.str());
}
parameter params[2] = { parameter(name), parameter(rational(domain_size, rational::ui64())) };
return m.mk_sort(m_fid, DL_FINITE_SORT, 2, params);
}
bool dl_decl_util::try_get_size(const sort * s, uint64& size) const {
sort_size sz = s->get_info()->get_num_elements();
if (sz.is_finite()) {
size = sz.size();
return true;
}
return false;
}
app* dl_decl_util::mk_lt(expr* a, expr* b) {
expr* args[2] = { a, b };
return m.mk_app(m_fid, OP_DL_LT, 0, 0, 2, args);
}
app* dl_decl_util::mk_le(expr* a, expr* b) {
expr* args[2] = { b, a };
return m.mk_not(m.mk_app(m_fid, OP_DL_LT, 0, 0, 2, args));
}
sort* dl_decl_util::mk_rule_sort() {
return m.mk_sort(m_fid, DL_RULE_SORT);
}
app* dl_decl_util::mk_rule(symbol const& name, unsigned num_args, expr* const* args) {
ptr_buffer<sort> sorts;
for (unsigned i = 0; i < num_args; ++i) {
sorts.push_back(m.get_sort(args[i]));
}
func_decl* f = m.mk_func_decl(name, num_args, sorts.c_ptr(), mk_rule_sort());
return m.mk_app(f, num_args, args);
}
};

217
src/ast/dl_decl_plugin.h Normal file
View file

@ -0,0 +1,217 @@
/*++
Copyright (c) 2010 Microsoft Corporation
Module Name:
dl_decl_plugin.h
Abstract:
<abstract>
Author:
Nikolaj Bjorner (nbjorner) 2010-04-10
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"
namespace datalog {
enum dl_sort_kind {
DL_RELATION_SORT,
DL_FINITE_SORT,
DL_RULE_SORT
};
enum dl_op_kind {
OP_RA_STORE,
OP_RA_EMPTY,
OP_RA_IS_EMPTY,
OP_RA_JOIN,
OP_RA_UNION,
OP_RA_WIDEN,
OP_RA_PROJECT,
OP_RA_FILTER,
OP_RA_NEGATION_FILTER,
OP_RA_RENAME,
OP_RA_COMPLEMENT,
OP_RA_SELECT,
OP_RA_CLONE,
OP_DL_CONSTANT,
OP_DL_LT,
LAST_RA_OP
};
class dl_decl_plugin : public decl_plugin {
symbol m_store_sym;
symbol m_empty_sym;
symbol m_is_empty_sym;
symbol m_join_sym;
symbol m_union_sym;
symbol m_widen_sym;
symbol m_project_sym;
symbol m_filter_sym;
symbol m_negation_filter_sym;
symbol m_rename_sym;
symbol m_complement_sym;
symbol m_select_sym;
symbol m_clone_sym;
symbol m_num_sym;
symbol m_lt_sym;
symbol m_le_sym;
symbol m_rule_sym;
symbol m_hyper_resolve_sym;
bool check_bounds(char const* msg, unsigned low, unsigned up, unsigned val) const;
bool check_domain(unsigned low, unsigned up, unsigned val) const;
bool check_params(unsigned low, unsigned up, unsigned val) const;
bool is_rel_sort(sort* s);
bool is_rel_sort(sort* s, ptr_vector<sort>& sorts);
bool is_fin_sort(sort* r);
func_decl * mk_store_select(decl_kind k, unsigned arity, sort * const * domain);
func_decl * mk_empty(parameter const& p);
func_decl * mk_is_empty(sort* r);
func_decl * mk_join(unsigned num_params, parameter const* params, sort* r1, sort* r2);
func_decl * mk_unionw(decl_kind k, sort* s1, sort* s2);
func_decl * mk_project(unsigned num_params, parameter const * params, sort* r);
func_decl * mk_filter(parameter const& p, sort* r);
func_decl * mk_rename(unsigned num_params, parameter const * params, sort* r);
func_decl * mk_complement(sort* r);
func_decl * mk_negation_filter(unsigned num_params, parameter const* params, sort* r1, sort* r2);
func_decl * mk_constant(parameter const* params);
func_decl * mk_compare(decl_kind k, symbol const& sym, sort*const* domain);
func_decl * mk_clone(sort* r);
func_decl * mk_rule(unsigned arity);
func_decl * mk_hyper_res(unsigned num_params, parameter const* params, unsigned arity, sort *const* domain);
sort * mk_finite_sort(unsigned num_params, parameter const* params);
sort * mk_relation_sort(unsigned num_params, parameter const* params);
sort * mk_rule_sort();
public:
dl_decl_plugin();
virtual ~dl_decl_plugin() {}
virtual decl_plugin * mk_fresh() { return alloc(dl_decl_plugin); }
//
// Contract for sort DL_RELATION_SORT
// parameters[0] - 1st dimension
// ...
// parameters[n-1] - nth dimension
//
// Contract for sort DL_FINITE_SORT
// parameters[0] - name
// parameters[1] - uint64
//
virtual sort * mk_sort(decl_kind k, unsigned num_parameters, parameter const * parameters);
//
// Contract for func_decl:
// parameters[0] - array sort
// Contract for OP_DL_CONSTANT:
// parameters[0] - rational containing uint64 with constant value
// parameters[1] - a DL_FINITE_SORT sort of the constant
// Contract for others:
// no parameters
virtual func_decl * mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters,
unsigned arity, sort * const * domain, sort * range);
virtual void get_op_names(svector<builtin_name> & op_names, symbol const & logic);
virtual void get_sort_names(svector<builtin_name> & sort_names, symbol const & logic);
virtual bool is_value(app* e) const { return is_app_of(e, m_family_id, OP_DL_CONSTANT); }
};
class dl_decl_util {
/**
Some plugins need to be registered in the ast_manager before we
create some of the member objects (the bv_util requires bv plugin
installed).
Doing this in the constructor of the dl_decl_plugin object is too late (as
member objects are created before we get into the constructor), so we
have this auxiliary object that is the first object of the context,
so that it gets created first. It's only purpose is that in its
constructor the required plugins are added to the ast manager.
*/
class ast_plugin_registrator {
public:
ast_plugin_registrator(ast_manager& m);
};
ast_plugin_registrator m_plugin_registrator;
ast_manager& m;
arith_util m_arith;
bv_util m_bv;
family_id m_fid;
public:
dl_decl_util(ast_manager& m);
// create a constant belonging to a given finite domain.
// the options include the DL_FINITE_SORT, BV_SORT, and BOOL_SORT
app* mk_numeral(uint64 value, sort* s);
app* mk_lt(expr* a, expr* b);
app* mk_le(expr* a, expr* b);
bool is_lt(expr* a) { return is_app_of(a, m_fid, OP_DL_LT); }
bool is_numeral(expr* c) const { return is_app_of(c, m_fid, OP_DL_CONSTANT); }
bool is_numeral(expr* e, uint64& v) const;
//
// Utilities for extracting constants
// from bit-vectors and finite domains.
//
bool is_numeral_ext(expr* c, uint64& v) const;
bool is_numeral_ext(expr* c) const;
sort* mk_sort(const symbol& name, uint64 domain_size);
bool try_get_size(const sort *, uint64& size) const;
bool is_finite_sort(sort* s) const {
return is_sort_of(s, m_fid, DL_FINITE_SORT);
}
bool is_finite_sort(expr* e) const {
return is_finite_sort(m.get_sort(e));
}
bool is_rule_sort(sort* s) const {
return is_sort_of(s, m_fid, DL_RULE_SORT);
}
sort* mk_rule_sort();
app* mk_rule(symbol const& name, unsigned num_args = 0, expr* const* args = 0);
app* mk_fact(symbol const& name) { return mk_rule(name, 0, 0); }
ast_manager& get_manager() const { return m; }
family_id get_family_id() const { return m_fid; }
};
};
#endif /* _DL_DECL_PLUGIN_H_ */

View file

@ -0,0 +1,545 @@
/*++
Copyright (c) 2012 Microsoft Corporation
Module Name:
float_decl_plugin.cpp
Abstract:
Floating point decl plugin
Author:
Leonardo de Moura (leonardo) 2012-01-15.
Revision History:
--*/
#include"float_decl_plugin.h"
#include"arith_decl_plugin.h"
#include"bv_decl_plugin.h"
float_decl_plugin::float_decl_plugin():
m_values(m_fm),
m_value_table(mpf_hash_proc(m_values), mpf_eq_proc(m_values)) {
m_real_sort = 0;
m_int_sort = 0;
m_bv_plugin = 0;
}
void float_decl_plugin::set_manager(ast_manager * m, family_id id) {
decl_plugin::set_manager(m, id);
family_id aid = m_manager->get_family_id("arith");
m_real_sort = m_manager->mk_sort(aid, REAL_SORT);
SASSERT(m_real_sort != 0); // arith_decl_plugin must be installed before float_decl_plugin.
m_manager->inc_ref(m_real_sort);
m_int_sort = m_manager->mk_sort(aid, INT_SORT);
SASSERT(m_int_sort != 0); // arith_decl_plugin must be installed before float_decl_plugin.
m_manager->inc_ref(m_int_sort);
if (m_manager->has_plugin(symbol("bv"))) {
// bv plugin is optional, so m_bv_plugin may be 0
m_bv_fid = m_manager->get_family_id("bv");
m_bv_plugin = static_cast<bv_decl_plugin*>(m_manager->get_plugin(m_bv_fid));
}
}
float_decl_plugin::~float_decl_plugin() {
}
unsigned float_decl_plugin::mk_id(mpf const & v) {
unsigned new_id = m_id_gen.mk();
m_values.reserve(new_id+1);
m_fm.set(m_values[new_id], v);
unsigned old_id = m_value_table.insert_if_not_there(new_id);
if (old_id != new_id) {
m_id_gen.recycle(new_id);
m_fm.del(m_values[new_id]);
}
return old_id;
}
void float_decl_plugin::recycled_id(unsigned id) {
SASSERT(m_value_table.contains(id));
m_value_table.erase(id);
m_id_gen.recycle(id);
m_fm.del(m_values[id]);
}
func_decl * float_decl_plugin::mk_value_decl(mpf const & v) {
parameter p(mk_id(v), true);
SASSERT(p.is_external());
sort * s = mk_float_sort(v.get_ebits(), v.get_sbits());
return m_manager->mk_const_decl(symbol("float"), s, func_decl_info(m_family_id, OP_FLOAT_VALUE, 1, &p));
}
app * float_decl_plugin::mk_value(mpf const & v) {
return m_manager->mk_const(mk_value_decl(v));
}
bool float_decl_plugin::is_value(expr * n, mpf & val) {
if (is_app_of(n, m_family_id, OP_FLOAT_VALUE)) {
m_fm.set(val, m_values[to_app(n)->get_decl()->get_parameter(0).get_ext_id()]);
return true;
}
return false;
}
bool float_decl_plugin::is_rm(expr * n, mpf_rounding_mode & val) {
if (is_app_of(n, m_family_id, OP_RM_NEAREST_TIES_TO_AWAY)) {
val = MPF_ROUND_NEAREST_TAWAY;
return true;
}
else if (is_app_of(n, m_family_id, OP_RM_NEAREST_TIES_TO_EVEN)) {
val = MPF_ROUND_NEAREST_TEVEN;
return true;
}
else if (is_app_of(n, m_family_id, OP_RM_TOWARD_NEGATIVE)) {
val = MPF_ROUND_TOWARD_NEGATIVE;
return true;
}
else if (is_app_of(n, m_family_id, OP_RM_TOWARD_POSITIVE)) {
val = MPF_ROUND_TOWARD_POSITIVE;
return true;
}
else if (is_app_of(n, m_family_id, OP_RM_TOWARD_ZERO)) {
val = MPF_ROUND_TOWARD_ZERO;
return true;
}
return 0;
}
void float_decl_plugin::del(parameter const & p) {
SASSERT(p.is_external());
recycled_id(p.get_ext_id());
}
parameter float_decl_plugin::translate(parameter const & p, decl_plugin & target) {
SASSERT(p.is_external());
float_decl_plugin & _target = static_cast<float_decl_plugin&>(target);
return parameter(_target.mk_id(m_values[p.get_ext_id()]), true);
}
void float_decl_plugin::finalize() {
if (m_real_sort) { m_manager->dec_ref(m_real_sort); }
if (m_int_sort) { m_manager->dec_ref(m_int_sort); }
}
decl_plugin * float_decl_plugin::mk_fresh() {
return alloc(float_decl_plugin);
}
sort * float_decl_plugin::mk_float_sort(unsigned ebits, unsigned sbits) {
parameter p1(ebits), p2(sbits);
parameter ps[2] = { p1, p2 };
sort_size sz;
sz = sort_size::mk_very_big(); // TODO: refine
return m_manager->mk_sort(symbol("FP"), sort_info(m_family_id, FLOAT_SORT, sz, 2, ps));
}
sort * float_decl_plugin::mk_rm_sort() {
return m_manager->mk_sort(symbol("RoundingMode"), sort_info(m_family_id, ROUNDING_MODE_SORT));
}
sort * float_decl_plugin::mk_sort(decl_kind k, unsigned num_parameters, parameter const * parameters) {
switch (k) {
case FLOAT_SORT:
if (!(num_parameters == 2 && parameters[0].is_int() && parameters[1].is_int())) {
m_manager->raise_exception("expecting two integer parameters to floating point sort");
}
return mk_float_sort(parameters[0].get_int(), parameters[1].get_int());
case ROUNDING_MODE_SORT:
return mk_rm_sort();
default:
m_manager->raise_exception("unknown floating point theory sort");
return 0;
}
}
func_decl * float_decl_plugin::mk_rm_const_decl(decl_kind k, unsigned num_parameters, parameter const * parameters,
unsigned arity, sort * const * domain, sort * range) {
if (num_parameters != 0)
m_manager->raise_exception("rounding mode constant does not have parameters");
if (arity != 0)
m_manager->raise_exception("rounding mode is a constant");
sort * s = mk_rm_sort();
func_decl_info finfo(m_family_id, k);
switch (k) {
case OP_RM_NEAREST_TIES_TO_EVEN:
return m_manager->mk_const_decl(symbol("roundNearestTiesToEven"), s, finfo);
case OP_RM_NEAREST_TIES_TO_AWAY:
return m_manager->mk_const_decl(symbol("roundNearestTiesToAway"), s, finfo);
case OP_RM_TOWARD_POSITIVE:
return m_manager->mk_const_decl(symbol("roundTowardPositive"), s, finfo);
case OP_RM_TOWARD_NEGATIVE:
return m_manager->mk_const_decl(symbol("roundTowardNegative"), s, finfo);
case OP_RM_TOWARD_ZERO:
return m_manager->mk_const_decl(symbol("roundTowardZero"), s, finfo);
default:
UNREACHABLE();
return 0;
}
}
func_decl * float_decl_plugin::mk_float_const_decl(decl_kind k, unsigned num_parameters, parameter const * parameters,
unsigned arity, sort * const * domain, sort * range) {
sort * s;
if (num_parameters == 1 && parameters[0].is_ast() && is_sort(parameters[0].get_ast()) && is_float_sort(to_sort(parameters[0].get_ast()))) {
s = to_sort(parameters[0].get_ast());
}
else if (range != 0 && is_float_sort(range)) {
s = range;
}
else {
m_manager->raise_exception("sort of floating point constant was not specified");
}
SASSERT(is_sort_of(s, m_family_id, FLOAT_SORT));
unsigned ebits = s->get_parameter(0).get_int();
unsigned sbits = s->get_parameter(1).get_int();
scoped_mpf val(m_fm);
if (k == OP_FLOAT_NAN) {
m_fm.mk_nan(ebits, sbits, val);
SASSERT(m_fm.is_nan(val));
}
else if (k == OP_FLOAT_MINUS_INF) {
m_fm.mk_ninf(ebits, sbits, val);
}
else {
SASSERT(k == OP_FLOAT_PLUS_INF);
m_fm.mk_pinf(ebits, sbits, val);
}
return mk_value_decl(val);
}
func_decl * float_decl_plugin::mk_bin_rel_decl(decl_kind k, unsigned num_parameters, parameter const * parameters,
unsigned arity, sort * const * domain, sort * range) {
if (arity != 2)
m_manager->raise_exception("invalid number of arguments to floating point relation");
if (domain[0] != domain[1] || !is_float_sort(domain[0]))
m_manager->raise_exception("sort mismatch");
symbol name;
switch (k) {
case OP_FLOAT_EQ: name = "=="; break;
case OP_FLOAT_LT: name = "<"; break;
case OP_FLOAT_GT: name = ">"; break;
case OP_FLOAT_LE: name = "<="; break;
case OP_FLOAT_GE: name = ">="; break;
default:
UNREACHABLE();
break;
}
func_decl_info finfo(m_family_id, k);
finfo.set_chainable(true);
return m_manager->mk_func_decl(name, arity, domain, m_manager->mk_bool_sort(), finfo);
}
func_decl * float_decl_plugin::mk_unary_rel_decl(decl_kind k, unsigned num_parameters, parameter const * parameters,
unsigned arity, sort * const * domain, sort * range) {
if (arity != 1)
m_manager->raise_exception("invalid number of arguments to floating point relation");
if (!is_float_sort(domain[0]))
m_manager->raise_exception("sort mismatch");
symbol name;
switch (k) {
case OP_FLOAT_IS_ZERO: name = "isZero"; break;
case OP_FLOAT_IS_NZERO: name = "isNZero"; break;
case OP_FLOAT_IS_PZERO: name = "isPZero"; break;
case OP_FLOAT_IS_SIGN_MINUS: name = "isSignMinus"; break;
default:
UNREACHABLE();
break;
}
return m_manager->mk_func_decl(name, arity, domain, m_manager->mk_bool_sort(), func_decl_info(m_family_id, k));
}
func_decl * float_decl_plugin::mk_unary_decl(decl_kind k, unsigned num_parameters, parameter const * parameters,
unsigned arity, sort * const * domain, sort * range) {
if (arity != 1)
m_manager->raise_exception("invalid number of arguments to floating point operator");
if (!is_float_sort(domain[0]))
m_manager->raise_exception("sort mismatch");
symbol name;
switch (k) {
case OP_FLOAT_ABS: name = "abs"; break;
case OP_FLOAT_UMINUS: name = "-"; break;
default:
UNREACHABLE();
break;
}
return m_manager->mk_func_decl(name, arity, domain, domain[0], func_decl_info(m_family_id, k));
}
func_decl * float_decl_plugin::mk_binary_decl(decl_kind k, unsigned num_parameters, parameter const * parameters,
unsigned arity, sort * const * domain, sort * range) {
if (arity != 2)
m_manager->raise_exception("invalid number of arguments to floating point operator");
if (domain[0] != domain[1] || !is_float_sort(domain[0]))
m_manager->raise_exception("sort mismatch");
symbol name;
switch (k) {
case OP_FLOAT_REM: name = "remainder"; break;
case OP_FLOAT_MIN: name = "min"; break;
case OP_FLOAT_MAX: name = "max"; break;
default:
UNREACHABLE();
break;
}
return m_manager->mk_func_decl(name, arity, domain, domain[0], func_decl_info(m_family_id, k));
}
func_decl * float_decl_plugin::mk_rm_binary_decl(decl_kind k, unsigned num_parameters, parameter const * parameters,
unsigned arity, sort * const * domain, sort * range) {
if (arity != 3)
m_manager->raise_exception("invalid number of arguments to floating point operator");
if (!is_rm_sort(domain[0]) || domain[1] != domain[2] || !is_float_sort(domain[1]))
m_manager->raise_exception("sort mismatch");
symbol name;
switch (k) {
case OP_FLOAT_ADD: name = "+"; break;
case OP_FLOAT_SUB: name = "-"; break;
case OP_FLOAT_MUL: name = "*"; break;
case OP_FLOAT_DIV: name = "/"; break;
default:
UNREACHABLE();
break;
}
return m_manager->mk_func_decl(name, arity, domain, domain[1], func_decl_info(m_family_id, k));
}
func_decl * float_decl_plugin::mk_rm_unary_decl(decl_kind k, unsigned num_parameters, parameter const * parameters,
unsigned arity, sort * const * domain, sort * range) {
if (arity != 2)
m_manager->raise_exception("invalid number of arguments to floating point operator");
if (!is_rm_sort(domain[0]) || !is_float_sort(domain[1]))
m_manager->raise_exception("sort mismatch");
symbol name;
switch (k) {
case OP_FLOAT_SQRT: name = "squareRoot"; break;
case OP_FLOAT_ROUND_TO_INTEGRAL: name = "roundToIntegral"; break;
default:
UNREACHABLE();
break;
}
return m_manager->mk_func_decl(name, arity, domain, domain[1], func_decl_info(m_family_id, k));
}
func_decl * float_decl_plugin::mk_fused_ma(decl_kind k, unsigned num_parameters, parameter const * parameters,
unsigned arity, sort * const * domain, sort * range) {
if (arity != 4)
m_manager->raise_exception("invalid number of arguments to fused_ma operator");
if (!is_rm_sort(domain[0]) || domain[1] != domain[2] || domain[1] != domain[3] || !is_float_sort(domain[1]))
m_manager->raise_exception("sort mismatch");
symbol name("fusedMA");
return m_manager->mk_func_decl(name, arity, domain, domain[1], func_decl_info(m_family_id, k));
}
func_decl * float_decl_plugin::mk_to_float(decl_kind k, unsigned num_parameters, parameter const * parameters,
unsigned arity, sort * const * domain, sort * range) {
if (m_bv_plugin && arity == 3 &&
is_sort_of(domain[0], m_bv_fid, BV_SORT) &&
is_sort_of(domain[1], m_bv_fid, BV_SORT) &&
is_sort_of(domain[2], m_bv_fid, BV_SORT)) {
// When the bv_decl_plugin is installed, then we know how to convert 3 bit-vectors into a float!
sort * fp = mk_float_sort(domain[2]->get_parameter(0).get_int(), domain[1]->get_parameter(0).get_int()+1);
symbol name("asFloat");
return m_manager->mk_func_decl(name, arity, domain, fp, func_decl_info(m_family_id, k, num_parameters, parameters));
}
else {
// .. Otherwise we only know how to convert rationals/reals.
if (!(num_parameters == 2 && parameters[0].is_int() && parameters[1].is_int()))
m_manager->raise_exception("expecting two integer parameters to asFloat");
if (arity != 2 && arity != 3)
m_manager->raise_exception("invalid number of arguments to asFloat operator");
if (!is_rm_sort(domain[0]) || domain[1] != m_real_sort)
m_manager->raise_exception("sort mismatch");
if (arity == 2) {
sort * fp = mk_float_sort(parameters[0].get_int(), parameters[1].get_int());
symbol name("asFloat");
return m_manager->mk_func_decl(name, arity, domain, fp, func_decl_info(m_family_id, k, num_parameters, parameters));
}
else {
if (domain[2] != m_int_sort)
m_manager->raise_exception("sort mismatch");
sort * fp = mk_float_sort(parameters[0].get_int(), parameters[1].get_int());
symbol name("asFloat");
return m_manager->mk_func_decl(name, arity, domain, fp, func_decl_info(m_family_id, k, num_parameters, parameters));
}
}
}
func_decl * float_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters,
unsigned arity, sort * const * domain, sort * range) {
switch (k) {
case OP_TO_FLOAT:
return mk_to_float(k, num_parameters, parameters, arity, domain, range);
case OP_FLOAT_MINUS_INF:
case OP_FLOAT_PLUS_INF:
case OP_FLOAT_NAN:
return mk_float_const_decl(k, num_parameters, parameters, arity, domain, range);
case OP_RM_NEAREST_TIES_TO_EVEN:
case OP_RM_NEAREST_TIES_TO_AWAY:
case OP_RM_TOWARD_POSITIVE:
case OP_RM_TOWARD_NEGATIVE:
case OP_RM_TOWARD_ZERO:
return mk_rm_const_decl(k, num_parameters, parameters, arity, domain, range);
case OP_FLOAT_EQ:
case OP_FLOAT_LT:
case OP_FLOAT_GT:
case OP_FLOAT_LE:
case OP_FLOAT_GE:
return mk_bin_rel_decl(k, num_parameters, parameters, arity, domain, range);
case OP_FLOAT_IS_ZERO:
case OP_FLOAT_IS_NZERO:
case OP_FLOAT_IS_PZERO:
case OP_FLOAT_IS_SIGN_MINUS:
return mk_unary_rel_decl(k, num_parameters, parameters, arity, domain, range);
case OP_FLOAT_ABS:
case OP_FLOAT_UMINUS:
return mk_unary_decl(k, num_parameters, parameters, arity, domain, range);
case OP_FLOAT_REM:
case OP_FLOAT_MIN:
case OP_FLOAT_MAX:
return mk_binary_decl(k, num_parameters, parameters, arity, domain, range);
case OP_FLOAT_ADD:
case OP_FLOAT_MUL:
case OP_FLOAT_DIV:
return mk_rm_binary_decl(k, num_parameters, parameters, arity, domain, range);
case OP_FLOAT_SUB:
if (arity == 1)
return mk_unary_decl(OP_FLOAT_UMINUS, num_parameters, parameters, arity, domain, range);
else
return mk_rm_binary_decl(k, num_parameters, parameters, arity, domain, range);
case OP_FLOAT_SQRT:
case OP_FLOAT_ROUND_TO_INTEGRAL:
return mk_rm_unary_decl(k, num_parameters, parameters, arity, domain, range);
case OP_FLOAT_FUSED_MA:
return mk_fused_ma(k, num_parameters, parameters, arity, domain, range);
default:
m_manager->raise_exception("unsupported floating point operator");
return 0;
}
}
void float_decl_plugin::get_op_names(svector<builtin_name> & op_names, symbol const & logic) {
op_names.push_back(builtin_name("plusInfinity", OP_FLOAT_PLUS_INF));
op_names.push_back(builtin_name("minusInfinity", OP_FLOAT_MINUS_INF));
op_names.push_back(builtin_name("NaN", OP_FLOAT_NAN));
op_names.push_back(builtin_name("roundNearestTiesToEven", OP_RM_NEAREST_TIES_TO_EVEN));
op_names.push_back(builtin_name("roundNearestTiesToAway", OP_RM_NEAREST_TIES_TO_AWAY));
op_names.push_back(builtin_name("roundTowardPositive", OP_RM_TOWARD_POSITIVE));
op_names.push_back(builtin_name("roundTowardNegative", OP_RM_TOWARD_NEGATIVE));
op_names.push_back(builtin_name("roundTowardZero", OP_RM_TOWARD_ZERO));
op_names.push_back(builtin_name("+", OP_FLOAT_ADD));
op_names.push_back(builtin_name("-", OP_FLOAT_SUB));
op_names.push_back(builtin_name("/", OP_FLOAT_DIV));
op_names.push_back(builtin_name("*", OP_FLOAT_MUL));
op_names.push_back(builtin_name("abs", OP_FLOAT_ABS));
op_names.push_back(builtin_name("remainder", OP_FLOAT_REM));
op_names.push_back(builtin_name("fusedMA", OP_FLOAT_FUSED_MA));
op_names.push_back(builtin_name("squareRoot", OP_FLOAT_SQRT));
op_names.push_back(builtin_name("roundToIntegral", OP_FLOAT_ROUND_TO_INTEGRAL));
op_names.push_back(builtin_name("==", OP_FLOAT_EQ));
op_names.push_back(builtin_name("<", OP_FLOAT_LT));
op_names.push_back(builtin_name(">", OP_FLOAT_GT));
op_names.push_back(builtin_name("<=", OP_FLOAT_LE));
op_names.push_back(builtin_name(">=", OP_FLOAT_GE));
op_names.push_back(builtin_name("isZero", OP_FLOAT_IS_ZERO));
op_names.push_back(builtin_name("isNZero", OP_FLOAT_IS_NZERO));
op_names.push_back(builtin_name("isPZero", OP_FLOAT_IS_PZERO));
op_names.push_back(builtin_name("isSignMinus", OP_FLOAT_IS_SIGN_MINUS));
op_names.push_back(builtin_name("min", OP_FLOAT_MIN));
op_names.push_back(builtin_name("max", OP_FLOAT_MAX));
op_names.push_back(builtin_name("asFloat", OP_TO_FLOAT));
}
void float_decl_plugin::get_sort_names(svector<builtin_name> & sort_names, symbol const & logic) {
sort_names.push_back(builtin_name("FP", FLOAT_SORT));
sort_names.push_back(builtin_name("RoundingMode", ROUNDING_MODE_SORT));
}
bool float_decl_plugin::is_value(app * e) const {
if (e->get_family_id() != m_family_id)
return false;
switch (e->get_decl_kind()) {
case OP_RM_NEAREST_TIES_TO_EVEN:
case OP_RM_NEAREST_TIES_TO_AWAY:
case OP_RM_TOWARD_POSITIVE:
case OP_RM_TOWARD_NEGATIVE:
case OP_RM_TOWARD_ZERO:
case OP_FLOAT_VALUE:
return true;
case OP_TO_FLOAT:
return m_manager->is_value(e->get_arg(0));
default:
return false;
}
}
float_util::float_util(ast_manager & m):
m_manager(m),
m_fid(m.get_family_id("float")),
m_a_util(m) {
m_plugin = static_cast<float_decl_plugin*>(m.get_plugin(m_fid));
}
float_util::~float_util() {
}
sort * float_util::mk_float_sort(unsigned ebits, unsigned sbits) {
parameter ps[2] = { parameter(ebits), parameter(sbits) };
return m().mk_sort(m_fid, FLOAT_SORT, 2, ps);
}
unsigned float_util::get_ebits(sort * s) {
SASSERT(is_float(s));
return static_cast<unsigned>(s->get_parameter(0).get_int());
}
unsigned float_util::get_sbits(sort * s) {
SASSERT(is_float(s));
return static_cast<unsigned>(s->get_parameter(1).get_int());
}
app * float_util::mk_nan(unsigned ebits, unsigned sbits) {
scoped_mpf v(fm());
fm().mk_nan(ebits, sbits, v);
return mk_value(v);
}
app * float_util::mk_plus_inf(unsigned ebits, unsigned sbits) {
scoped_mpf v(fm());
fm().mk_pinf(ebits, sbits, v);
return mk_value(v);
}
app * float_util::mk_minus_inf(unsigned ebits, unsigned sbits) {
scoped_mpf v(fm());
fm().mk_ninf(ebits, sbits, v);
return mk_value(v);
}
app * float_util::mk_pzero(unsigned ebits, unsigned sbits) {
scoped_mpf v(fm());
fm().mk_pzero(ebits, sbits, v);
return mk_value(v);
}
app * float_util::mk_nzero(unsigned ebits, unsigned sbits) {
scoped_mpf v(fm());
fm().mk_nzero(ebits, sbits, v);
return mk_value(v);
}

243
src/ast/float_decl_plugin.h Normal file
View file

@ -0,0 +1,243 @@
/*++
Copyright (c) 2012 Microsoft Corporation
Module Name:
float_decl_plugin.h
Abstract:
Floating point decl plugin
Author:
Leonardo de Moura (leonardo) 2012-01-15.
Revision History:
--*/
#ifndef _FLOAT_DECL_PLUGIN_H_
#define _FLOAT_DECL_PLUGIN_H_
#include"ast.h"
#include"id_gen.h"
#include"arith_decl_plugin.h"
#include"bv_decl_plugin.h"
#include"mpf.h"
enum float_sort_kind {
FLOAT_SORT,
ROUNDING_MODE_SORT
};
enum float_op_kind {
OP_RM_NEAREST_TIES_TO_EVEN,
OP_RM_NEAREST_TIES_TO_AWAY,
OP_RM_TOWARD_POSITIVE,
OP_RM_TOWARD_NEGATIVE,
OP_RM_TOWARD_ZERO,
OP_FLOAT_VALUE,
OP_FLOAT_PLUS_INF,
OP_FLOAT_MINUS_INF,
OP_FLOAT_NAN,
OP_FLOAT_ADD,
OP_FLOAT_SUB,
OP_FLOAT_UMINUS,
OP_FLOAT_MUL,
OP_FLOAT_DIV,
OP_FLOAT_REM,
OP_FLOAT_ABS,
OP_FLOAT_MIN,
OP_FLOAT_MAX,
OP_FLOAT_FUSED_MA, // x*y + z
OP_FLOAT_SQRT,
OP_FLOAT_ROUND_TO_INTEGRAL,
OP_FLOAT_EQ,
OP_FLOAT_LT,
OP_FLOAT_GT,
OP_FLOAT_LE,
OP_FLOAT_GE,
OP_FLOAT_IS_ZERO,
OP_FLOAT_IS_NZERO,
OP_FLOAT_IS_PZERO,
OP_FLOAT_IS_SIGN_MINUS,
OP_TO_FLOAT,
LAST_FLOAT_OP
};
class float_decl_plugin : public decl_plugin {
struct mpf_hash_proc {
scoped_mpf_vector const & m_values;
mpf_hash_proc(scoped_mpf_vector const & values):m_values(values) {}
unsigned operator()(unsigned id) const { return m_values.m().hash(m_values[id]); }
};
struct mpf_eq_proc {
scoped_mpf_vector const & m_values;
mpf_eq_proc(scoped_mpf_vector const & values):m_values(values) {}
bool operator()(unsigned id1, unsigned id2) const { return m_values.m().eq_core(m_values[id1], m_values[id2]); }
};
typedef chashtable<unsigned, mpf_hash_proc, mpf_eq_proc> value_table;
mpf_manager m_fm;
id_gen m_id_gen;
scoped_mpf_vector m_values;
value_table m_value_table;
sort * m_real_sort;
sort * m_int_sort;
family_id m_bv_fid;
bv_decl_plugin * m_bv_plugin;
sort * mk_float_sort(unsigned ebits, unsigned sbits);
sort * mk_rm_sort();
func_decl * mk_rm_const_decl(decl_kind k, unsigned num_parameters, parameter const * parameters,
unsigned arity, sort * const * domain, sort * range);
func_decl * mk_float_const_decl(decl_kind k, unsigned num_parameters, parameter const * parameters,
unsigned arity, sort * const * domain, sort * range);
func_decl * mk_bin_rel_decl(decl_kind k, unsigned num_parameters, parameter const * parameters,
unsigned arity, sort * const * domain, sort * range);
func_decl * mk_unary_rel_decl(decl_kind k, unsigned num_parameters, parameter const * parameters,
unsigned arity, sort * const * domain, sort * range);
func_decl * mk_unary_decl(decl_kind k, unsigned num_parameters, parameter const * parameters,
unsigned arity, sort * const * domain, sort * range);
func_decl * mk_binary_decl(decl_kind k, unsigned num_parameters, parameter const * parameters,
unsigned arity, sort * const * domain, sort * range);
func_decl * mk_rm_binary_decl(decl_kind k, unsigned num_parameters, parameter const * parameters,
unsigned arity, sort * const * domain, sort * range);
func_decl * mk_rm_unary_decl(decl_kind k, unsigned num_parameters, parameter const * parameters,
unsigned arity, sort * const * domain, sort * range);
func_decl * mk_fused_ma(decl_kind k, unsigned num_parameters, parameter const * parameters,
unsigned arity, sort * const * domain, sort * range);
func_decl * mk_to_float(decl_kind k, unsigned num_parameters, parameter const * parameters,
unsigned arity, sort * const * domain, sort * range);
virtual void set_manager(ast_manager * m, family_id id);
unsigned mk_id(mpf const & v);
void recycled_id(unsigned id);
public:
float_decl_plugin();
bool is_float_sort(sort * s) const { return is_sort_of(s, m_family_id, FLOAT_SORT); }
bool is_rm_sort(sort * s) const { return is_sort_of(s, m_family_id, ROUNDING_MODE_SORT); }
virtual ~float_decl_plugin();
virtual void finalize();
virtual decl_plugin * mk_fresh();
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 void get_op_names(svector<builtin_name> & op_names, symbol const & logic);
virtual void get_sort_names(svector<builtin_name> & sort_names, symbol const & logic);
virtual bool is_value(app* e) const;
mpf_manager & fm() { return m_fm; }
func_decl * mk_value_decl(mpf const & v);
app * mk_value(mpf const & v);
bool is_value(expr * n) { return is_app_of(n, m_family_id, OP_FLOAT_VALUE); }
bool is_value(expr * n, mpf & val);
bool is_rm(expr * n, mpf_rounding_mode & val);
mpf const & get_value(unsigned id) const {
SASSERT(m_value_table.contains(id));
return m_values[id];
}
virtual void del(parameter const & p);
virtual parameter translate(parameter const & p, decl_plugin & target);
};
class float_util {
ast_manager & m_manager;
float_decl_plugin * m_plugin;
family_id m_fid;
arith_util m_a_util;
public:
float_util(ast_manager & m);
~float_util();
ast_manager & m() const { return m_manager; }
mpf_manager & fm() const { return m_plugin->fm(); }
family_id get_fid() const { return m_fid; }
family_id get_family_id() const { return m_fid; }
arith_util & au() { return m_a_util; }
sort * mk_float_sort(unsigned ebits, unsigned sbits);
sort * mk_rm_sort() { return m().mk_sort(m_fid, ROUNDING_MODE_SORT); }
bool is_float(sort * s) { return is_sort_of(s, m_fid, FLOAT_SORT); }
bool is_rm(sort * s) { return is_sort_of(s, m_fid, ROUNDING_MODE_SORT); }
unsigned get_ebits(sort * s);
unsigned get_sbits(sort * s);
app * mk_round_nearest_ties_to_even() { return m().mk_const(m_fid, OP_RM_NEAREST_TIES_TO_EVEN); }
app * mk_round_nearest_ties_to_away() { return m().mk_const(m_fid, OP_RM_NEAREST_TIES_TO_AWAY); }
app * mk_round_toward_positive() { return m().mk_const(m_fid, OP_RM_TOWARD_POSITIVE); }
app * mk_round_toward_negative() { return m().mk_const(m_fid, OP_RM_TOWARD_NEGATIVE); }
app * mk_round_toward_zero() { return m().mk_const(m_fid, OP_RM_TOWARD_ZERO); }
app * mk_nan(unsigned ebits, unsigned sbits);
app * mk_plus_inf(unsigned ebits, unsigned sbits);
app * mk_minus_inf(unsigned ebits, unsigned sbits);
app * mk_nan(sort * s) { return mk_nan(get_ebits(s), get_sbits(s)); }
app * mk_plus_inf(sort * s) { return mk_plus_inf(get_ebits(s), get_sbits(s)); }
app * mk_minus_inf(sort * s) { return mk_minus_inf(get_ebits(s), get_sbits(s)); }
app * mk_value(mpf const & v) { return m_plugin->mk_value(v); }
bool is_value(expr * n) { return m_plugin->is_value(n); }
bool is_value(expr * n, mpf & v) { return m_plugin->is_value(n, v); }
bool is_rm(expr * n, mpf_rounding_mode & v) { return m_plugin->is_rm(n, v); }
app * mk_pzero(unsigned ebits, unsigned sbits);
app * mk_nzero(unsigned ebits, unsigned sbits);
app * mk_pzero(sort * s) { return mk_pzero(get_ebits(s), get_sbits(s)); }
app * mk_nzero(sort * s) { return mk_nzero(get_ebits(s), get_sbits(s)); }
bool is_nan(expr * n) { scoped_mpf v(fm()); return is_value(n, v) && fm().is_nan(v); }
bool is_plus_inf(expr * n) { scoped_mpf v(fm()); return is_value(n, v) && fm().is_pinf(v); }
bool is_minus_inf(expr * n) { scoped_mpf v(fm()); return is_value(n, v) && fm().is_ninf(v); }
bool is_zero(expr * n) { scoped_mpf v(fm()); return is_value(n, v) && fm().is_zero(v); }
bool is_pzero(expr * n) { scoped_mpf v(fm()); return is_value(n, v) && fm().is_pzero(v); }
bool is_nzero(expr * n) { scoped_mpf v(fm()); return is_value(n, v) && fm().is_nzero(v); }
bool is_to_float(expr * n) { return is_app_of(n, m_fid, OP_TO_FLOAT); }
app * mk_to_float(expr * arg1, expr * arg2) { return m().mk_app(m_fid, OP_TO_FLOAT, arg1, arg2); }
app * mk_add(expr * arg1, expr * arg2, expr * arg3) { return m().mk_app(m_fid, OP_FLOAT_ADD, arg1, arg2, arg3); }
app * mk_mul(expr * arg1, expr * arg2, expr * arg3) { return m().mk_app(m_fid, OP_FLOAT_MUL, arg1, arg2, arg3); }
app * mk_sub(expr * arg1, expr * arg2, expr * arg3) { return m().mk_app(m_fid, OP_FLOAT_SUB, arg1, arg2, arg3); }
app * mk_div(expr * arg1, expr * arg2, expr * arg3) { return m().mk_app(m_fid, OP_FLOAT_DIV, arg1, arg2, arg3); }
app * mk_uminus(expr * arg1) { return m().mk_app(m_fid, OP_FLOAT_UMINUS, arg1); }
app * mk_rem(expr * arg1, expr * arg2) { return m().mk_app(m_fid, OP_FLOAT_REM, arg1, arg2); }
app * mk_max(expr * arg1, expr * arg2) { return m().mk_app(m_fid, OP_FLOAT_MAX, arg1, arg2); }
app * mk_min(expr * arg1, expr * arg2) { return m().mk_app(m_fid, OP_FLOAT_MIN, arg1, arg2); }
app * mk_abs(expr * arg1, expr * arg2) { return m().mk_app(m_fid, OP_FLOAT_ABS, arg1, arg2); }
app * mk_sqrt(expr * arg1, expr * arg2) { return m().mk_app(m_fid, OP_FLOAT_SQRT, arg1, arg2); }
app * mk_round(expr * arg1, expr * arg2) { return m().mk_app(m_fid, OP_FLOAT_ROUND_TO_INTEGRAL, arg1, arg2); }
app * mk_fused_ma(expr * arg1, expr * arg2, expr * arg3, expr * arg4) {
expr * args[4] = { arg1, arg2, arg3, arg4 };
return m().mk_app(m_fid, OP_FLOAT_FUSED_MA, 4, args);
}
app * mk_float_eq(expr * arg1, expr * arg2) { return m().mk_app(m_fid, OP_FLOAT_EQ, arg1, arg2); }
app * mk_lt(expr * arg1, expr * arg2) { return m().mk_app(m_fid, OP_FLOAT_LT, arg1, arg2); }
app * mk_gt(expr * arg1, expr * arg2) { return m().mk_app(m_fid, OP_FLOAT_GT, arg1, arg2); }
app * mk_le(expr * arg1, expr * arg2) { return m().mk_app(m_fid, OP_FLOAT_LE, arg1, arg2); }
app * mk_ge(expr * arg1, expr * arg2) { return m().mk_app(m_fid, OP_FLOAT_GE, arg1, arg2); }
app * mk_is_zero(expr * arg1) { return m().mk_app(m_fid, OP_FLOAT_IS_ZERO, arg1); }
app * mk_is_nzero(expr * arg1) { return m().mk_app(m_fid, OP_FLOAT_IS_NZERO, arg1); }
app * mk_is_pzero(expr * arg1) { return m().mk_app(m_fid, OP_FLOAT_IS_PZERO, arg1); }
app * mk_is_sign_minus(expr * arg1) { return m().mk_app(m_fid, OP_FLOAT_IS_SIGN_MINUS, arg1); }
bool is_uminus(expr * a) { return is_app_of(a, m_fid, OP_FLOAT_UMINUS); }
};
#endif

274
src/ast/for_each_ast.h Normal file
View file

@ -0,0 +1,274 @@
/*++
Copyright (c) 2006 Microsoft Corporation
Module Name:
for_each_ast.h
Abstract:
Visitor for AST nodes
Author:
Leonardo de Moura (leonardo) 2006-10-18.
Revision History:
--*/
#ifndef _FOR_EACH_AST_H_
#define _FOR_EACH_AST_H_
#include"ast.h"
#include"trace.h"
#include"map.h"
template<typename T>
bool for_each_ast_args(ptr_vector<ast> & stack, ast_mark & visited, unsigned num_args, T * const * args) {
bool result = true;
for (unsigned i = 0; i < num_args; i++) {
T * arg = args[i];
if (!visited.is_marked(arg)) {
stack.push_back(arg);
result = false;
}
}
return result;
}
bool for_each_parameter(ptr_vector<ast> & stack, ast_mark & visited, unsigned num_args, parameter const * params);
template<typename ForEachProc>
void for_each_ast(ForEachProc & proc, ast_mark & visited, ast * n, bool visit_parameters = false) {
ptr_vector<ast> stack;
ast * curr;
stack.push_back(n);
while (!stack.empty()) {
curr = stack.back();
TRACE("for_each_ast", tout << "visiting node: " << curr->get_id() << ", kind: " << get_ast_kind_name(curr->get_kind())
<< ", stack size: " << stack.size() << "\n";);
if (visited.is_marked(curr)) {
stack.pop_back();
continue;
}
switch(curr->get_kind()) {
case AST_SORT:
if (visit_parameters &&
!for_each_parameter(stack, visited, to_sort(curr)->get_num_parameters(), to_sort(curr)->get_parameters())) {
break;
}
proc(to_sort(curr));
visited.mark(curr, true);
stack.pop_back();
break;
case AST_VAR: {
var* v = to_var(curr);
proc(v);
visited.mark(curr, true);
stack.pop_back();
break;
}
case AST_FUNC_DECL:
if (visit_parameters &&
!for_each_parameter(stack, visited, to_func_decl(curr)->get_num_parameters(), to_func_decl(curr)->get_parameters())) {
break;
}
if (!for_each_ast_args(stack,
visited,
to_func_decl(curr)->get_arity(),
to_func_decl(curr)->get_domain())) {
break;
}
if (!visited.is_marked(to_func_decl(curr)->get_range())) {
stack.push_back(to_func_decl(curr)->get_range());
break;
}
proc(to_func_decl(curr));
visited.mark(curr, true);
stack.pop_back();
break;
case AST_APP:
if (!visited.is_marked(to_app(curr)->get_decl())) {
stack.push_back(to_app(curr)->get_decl());
break;
}
if (for_each_ast_args(stack, visited, to_app(curr)->get_num_args(), to_app(curr)->get_args())) {
proc(to_app(curr));
visited.mark(curr, true);
stack.pop_back();
}
break;
case AST_QUANTIFIER:
if (!for_each_ast_args(stack, visited, to_quantifier(curr)->get_num_patterns(),
to_quantifier(curr)->get_patterns())) {
break;
}
if (!for_each_ast_args(stack, visited, to_quantifier(curr)->get_num_no_patterns(),
to_quantifier(curr)->get_no_patterns())) {
break;
}
if (!visited.is_marked(to_quantifier(curr)->get_expr())) {
stack.push_back(to_quantifier(curr)->get_expr());
break;
}
proc(to_quantifier(curr));
visited.mark(curr, true);
stack.pop_back();
break;
}
}
}
template<typename ForEachProc>
void for_each_ast(ForEachProc & proc, ast * n, bool visit_parameters = false) {
ast_mark visited;
for_each_ast(proc, visited, n, visit_parameters);
}
template<typename EscapeProc>
struct for_each_ast_proc : public EscapeProc {
void operator()(ast * n) { EscapeProc::operator()(n); }
void operator()(sort * n) { operator()(static_cast<ast *>(n)); }
void operator()(func_decl * n) { operator()(static_cast<ast *>(n)); }
void operator()(var * n) { operator()(static_cast<ast *>(n)); }
void operator()(app * n) { operator()(static_cast<ast *>(n)); }
void operator()(quantifier * n) { operator()(static_cast<ast *>(n)); }
};
unsigned get_num_nodes(ast * n);
template<class Visitor, class T, bool recurse_quantifier = true>
class recurse_ast {
template<class T2>
class mem_map : public map<ast*, T2*, obj_hash<ast>, ptr_eq<ast> > {};
public:
static T* recurse(Visitor & visit, ast * aArg) {
unsigned arity;
ast* a;
ast * const * args;
T* result;
ptr_vector<ast> stack;
mem_map<T> memoize;
ptr_vector<T> results;
stack.push_back(aArg);
while (!stack.empty()) {
a = stack.back();
results.reset();
if (memoize.find(a, result)) {
stack.pop_back();
continue;
}
switch(a->get_kind()) {
case AST_SORT:
memoize.insert(a, visit.mk_sort(to_sort(a)));
stack.pop_back();
break;
case AST_FUNC_DECL: {
arity = to_func_decl(a)->get_arity();
func_decl * func_decl_ast = to_func_decl(a);
args = (ast * const *)(func_decl_ast->get_domain());
recurse_list(stack, arity, args, &memoize, results);
if (!memoize.find(func_decl_ast->get_range(), result)) {
stack.push_back(func_decl_ast->get_range());
}
else if (results.size() == arity) {
result = visit.mk_func_decl(func_decl_ast, result, results);
memoize.insert(a, result);
stack.pop_back();
}
break;
}
case AST_APP: {
app * app = to_app(a);
arity = app->get_num_args();
args = (ast * const *)(app->get_args());
recurse_list(stack, arity, args, &memoize, results);
if (arity == results.size()) {
result = visit.mk_app(app, results);
memoize.insert(a, result);
stack.pop_back();
}
break;
}
case AST_VAR:
memoize.insert(a, visit.mk_var(to_var(a)));
stack.pop_back();
break;
case AST_QUANTIFIER: {
quantifier * quantifier_ast = to_quantifier(a);
ptr_vector<T> decl_types;
if (recurse_quantifier) {
args = (ast * const *) quantifier_ast->get_decl_sorts();
arity = quantifier_ast->get_num_decls();
ast* body = quantifier_ast->get_expr();
recurse_list(stack, arity, args, &memoize, decl_types);
if (!memoize.find(body, result)) {
stack.push_back(body);
}
else if (decl_types.size() == arity) {
result = visit.mk_quantifier(quantifier_ast, decl_types, result);
memoize.insert(a, result);
stack.pop_back();
}
}
else {
result = visit.mk_quantifier(quantifier_ast, decl_types, result);
memoize.insert(a, result);
stack.pop_back();
}
break;
}
default:
UNREACHABLE();
break;
}
}
if (!memoize.find(aArg, result)) {
UNREACHABLE();
}
return result;
}
private:
template<typename AST>
static void recurse_list(ptr_vector<ast> & stack, unsigned arity, AST * const * ast_list, mem_map<T> * memoize,
ptr_vector<T> & results) {
T * result;
for (unsigned i = 0; i < arity; ++i) {
if (memoize->find(ast_list[i], result)) {
results.push_back(result);
}
else {
stack.push_back(ast_list[i]);
}
}
}
};
#endif /* _FOR_EACH_AST_H_ */

212
src/ast/format.cpp Normal file
View file

@ -0,0 +1,212 @@
/*++
Copyright (c) 2006 Microsoft Corporation
Module Name:
format.cpp
Abstract:
<abstract>
Author:
Leonardo de Moura (leonardo) 2008-01-20.
Revision History:
--*/
#include"format.h"
#include"recurse_expr_def.h"
namespace format_ns {
class format_decl_plugin : public decl_plugin {
protected:
sort * m_format_sort;
symbol m_nil;
symbol m_string;
symbol m_indent;
symbol m_compose;
symbol m_choice;
symbol m_line_break;
symbol m_line_break_ext;
virtual void set_manager(ast_manager * m, family_id id) {
SASSERT(m->is_format_manager());
decl_plugin::set_manager(m, id);
m_format_sort = m->mk_sort(symbol("format"), sort_info(id, FORMAT_SORT));
m->inc_ref(m_format_sort);
}
public:
format_decl_plugin():
m_format_sort(0),
m_nil("nil"),
m_string("string"),
m_indent("indent"),
m_compose("compose"),
m_choice("choice"),
m_line_break("cr"),
m_line_break_ext("cr++") {
}
virtual ~format_decl_plugin() {}
virtual void finalize() {
if (m_format_sort)
m_manager->dec_ref(m_format_sort);
}
virtual decl_plugin * mk_fresh() {
return alloc(format_decl_plugin);
}
virtual sort * mk_sort(decl_kind k, unsigned num_parameters, parameter const* parameters) {
SASSERT(k == FORMAT_SORT);
return m_format_sort;
}
virtual func_decl * mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters,
unsigned arity, sort * const * domain, sort * range) {
switch (k) {
case OP_NIL:
return m_manager->mk_func_decl(m_nil, arity, domain, m_format_sort,
func_decl_info(m_family_id, OP_NIL));
case OP_STRING:
return m_manager->mk_func_decl(m_string, arity, domain, m_format_sort,
func_decl_info(m_family_id, OP_STRING, num_parameters, parameters));
case OP_INDENT:
return m_manager->mk_func_decl(m_indent, arity, domain, m_format_sort,
func_decl_info(m_family_id, OP_INDENT, num_parameters, parameters));
case OP_COMPOSE:
return m_manager->mk_func_decl(m_compose, arity, domain, m_format_sort,
func_decl_info(m_family_id, OP_COMPOSE));
case OP_CHOICE:
return m_manager->mk_func_decl(m_choice, arity, domain, m_format_sort,
func_decl_info(m_family_id, OP_CHOICE));
case OP_LINE_BREAK:
return m_manager->mk_func_decl(m_line_break, arity, domain, m_format_sort,
func_decl_info(m_family_id, OP_LINE_BREAK));
case OP_LINE_BREAK_EXT:
return m_manager->mk_func_decl(m_line_break_ext, arity, domain, m_format_sort,
func_decl_info(m_family_id, OP_LINE_BREAK_EXT, num_parameters, parameters));
default:
return 0;
}
}
};
family_id get_format_family_id(ast_manager & m) {
symbol f("format");
if (!fm(m).has_plugin(f))
fm(m).register_plugin(f, alloc(format_decl_plugin));
return fm(m).get_family_id(f);
}
static family_id fid(ast_manager & m) {
return get_format_family_id(m);
}
sort * fsort(ast_manager & m) {
return fm(m).mk_sort(fid(m), FORMAT_SORT);
}
struct flat_visitor {
ast_manager & m_manager;
family_id m_fid;
flat_visitor(ast_manager & m):
m_manager(fm(m)),
m_fid(fid(m)) {
SASSERT(m_manager.is_format_manager());
}
format * visit(var *) { UNREACHABLE(); return 0; }
format * visit(quantifier * q, format *, format * const *, format * const *) { UNREACHABLE(); return 0; }
format * visit(format * n, format * const * children) {
if (is_app_of(n, m_fid, OP_LINE_BREAK))
return mk_string(m_manager, " ");
else if (is_app_of(n, m_fid, OP_LINE_BREAK_EXT))
return mk_string(m_manager, n->get_decl()->get_parameter(0).get_symbol().bare_str());
else if (is_app_of(n, m_fid, OP_CHOICE))
return to_app(n->get_arg(0));
else
return m_manager.mk_app(n->get_decl(), n->get_num_args(), (expr *const*) children);
}
};
format * flat(ast_manager & m, format * f) {
flat_visitor v(m);
recurse_expr<format *, flat_visitor, true, true> r(v);
return r(f);
}
format * mk_string(ast_manager & m, char const * str) {
symbol s(str);
parameter p(s);
return fm(m).mk_app(fid(m), OP_STRING, 1, &p, 0, 0);
}
format * mk_int(ast_manager & m, int i) {
static char buffer[128];
#ifdef _WINDOWS
sprintf_s(buffer, ARRAYSIZE(buffer), "%d", i);
#else
sprintf(buffer, "%d", i);
#endif
return mk_string(m, buffer);
}
format * mk_unsigned(ast_manager & m, unsigned u) {
static char buffer[128];
#ifdef _WINDOWS
sprintf_s(buffer, ARRAYSIZE(buffer), "%u", u);
#else
sprintf(buffer, "%u", u);
#endif
return mk_string(m, buffer);
}
format * mk_indent(ast_manager & m, unsigned i, format * f) {
parameter p(i);
expr * e = static_cast<expr*>(f);
return fm(m).mk_app(fid(m), OP_INDENT, 1, &p, 1, &e);
}
format * mk_line_break(ast_manager & m) {
return fm(m).mk_app(fid(m), OP_LINE_BREAK);
}
format * mk_choice(ast_manager & m, format * f1, format * f2) {
return fm(m).mk_app(fid(m), OP_CHOICE, f1, f2);
}
format * mk_group(ast_manager & m, format * f) {
return mk_choice(m, flat(m, f), f);
}
format * mk_compose(ast_manager & m, unsigned num_children, format * const * children) {
return fm(m).mk_app(fid(m), OP_COMPOSE, num_children, (expr * const *) children);
}
format * mk_compose(ast_manager & m, format * f1, format * f2) {
return fm(m).mk_app(fid(m), OP_COMPOSE, f1, f2);
}
format * mk_compose(ast_manager & m, format * f1, format * f2, format * f3) {
return fm(m).mk_app(fid(m), OP_COMPOSE, f1, f2, f3);
}
format * mk_compose(ast_manager & m, format * f1, format * f2, format * f3, format * f4) {
expr * f[4] = { f1, f2, f3, f4 };
return fm(m).mk_app(fid(m), OP_COMPOSE, 4, f);
}
format * mk_nil(ast_manager & m) {
return fm(m).mk_app(fid(m), OP_NIL);
}
};

197
src/ast/format.h Normal file
View file

@ -0,0 +1,197 @@
/*++
Copyright (c) 2006 Microsoft Corporation
Module Name:
format.h
Abstract:
<abstract>
Author:
Leonardo de Moura (leonardo) 2008-01-20.
Revision History:
--*/
#ifndef _FORMAT_H_
#define _FORMAT_H_
#include"ast.h"
namespace format_ns {
typedef app format;
typedef app_ref format_ref;
enum format_sort_kind {
FORMAT_SORT
};
enum format_op_kind {
OP_NIL,
OP_STRING,
OP_INDENT,
OP_COMPOSE,
OP_CHOICE,
OP_LINE_BREAK,
OP_LINE_BREAK_EXT
};
struct f2f {
format * operator()(format * f) { return f; }
};
/**
\brief Return the "format manager" associated with the given ast_manager.
*/
inline ast_manager & fm(ast_manager & m) {
return m.get_format_manager();
}
family_id get_format_family_id(ast_manager & m);
format * mk_string(ast_manager & m, char const * str);
format * mk_int(ast_manager & m, int i);
format * mk_unsigned(ast_manager & m, unsigned u);
format * mk_indent(ast_manager & m, unsigned i, format * f);
format * mk_line_break(ast_manager & m);
format * mk_group(ast_manager & m, format * f);
format * mk_compose(ast_manager & m, unsigned num_children, format * const * children);
format * mk_compose(ast_manager & m, format * f1, format * f2);
format * mk_compose(ast_manager & m, format * f1, format * f2, format * f3);
format * mk_compose(ast_manager & m, format * f1, format * f2, format * f3, format * f4);
format * mk_nil(ast_manager & m);
format * mk_choice(ast_manager & m, format * f1, format * f2);
template<typename It, typename ToDoc>
format * mk_seq(ast_manager & m, It const & begin, It const & end, ToDoc proc) {
app_ref_buffer children(fm(m));
for (It it = begin; it != end; ++it) {
format * curr = proc(*it);
if (curr->get_decl_kind() != OP_NIL) {
children.push_back(mk_line_break(m));
children.push_back(curr);
}
}
return mk_compose(m, children.size(), children.c_ptr());
}
/**
(header elem_1
elem_2
...
elem_n)
*/
template<typename It, typename ToDoc>
format * mk_seq1(ast_manager & m, It const & begin, It const & end, ToDoc proc, char const * header,
char const * lp = "(", char const * rp = ")") {
if (begin == end)
return mk_compose(m, mk_string(m, lp), mk_string(m, header), mk_string(m, rp));
unsigned indent = static_cast<unsigned>(strlen(lp) + strlen(header) + 1);
It it = begin;
format * first = proc(*it);
++it;
return mk_group(m, mk_compose(m,
mk_string(m, lp),
mk_string(m, header),
mk_indent(m, indent,
mk_compose(m,
mk_string(m, " "),
first,
mk_seq(m, it, end, proc),
mk_string(m, rp)))));
}
#define FORMAT_DEFAULT_INDENT 2
/**
(header
elem_1
...
elem_n)
*/
template<typename It, typename ToDoc>
format * mk_seq2(ast_manager & m, It const & begin, It const & end, ToDoc proc, char const * header,
unsigned indent = FORMAT_DEFAULT_INDENT, char const * lp = "(", char const * rp = ")") {
if (begin == end)
return mk_compose(m, mk_string(m, lp), mk_string(m, header), mk_string(m, rp));
return mk_group(m, mk_compose(m,
mk_indent(m, static_cast<unsigned>(strlen(lp)),
mk_compose(m, mk_string(m, lp), mk_string(m, header))),
mk_indent(m, indent,
mk_compose(m, mk_seq(m, begin, end, proc), mk_string(m, rp)))));
}
/**
(header elem_1
...
elem_i
elem_{i+1}
...
elem_n)
*/
template<typename It, typename ToDoc>
format * mk_seq3(ast_manager & m, It const & begin, It const & end, ToDoc proc, char const * header, unsigned i = 1,
unsigned indent = FORMAT_DEFAULT_INDENT, char const * lp = "(", char const * rp = ")") {
SASSERT(i >= 1);
if (begin == end)
return mk_compose(m, mk_string(m, lp), mk_string(m, header), mk_string(m, rp));
unsigned idx = 0;
It end1 = begin;
for (;end1 != end && idx < i; ++end1, ++idx)
;
It it = begin;
format * first = proc(*it);
++it;
return mk_group(m,
mk_compose(m,
mk_compose(m, mk_string(m, lp), mk_string(m, header)),
mk_group(m, mk_indent(m, static_cast<unsigned>(strlen(header) + strlen(lp) + 1),
mk_compose(m, mk_string(m, " "), first,
mk_seq(m, it, end1, proc)))),
mk_indent(m, indent, mk_seq(m, end1, end, proc)),
mk_string(m, rp)));
}
/**
(elem_1
elem_2
...
elem_n)
*/
template<typename It, typename ToDoc>
format * mk_seq4(ast_manager & m, It const & begin, It const & end, ToDoc proc, unsigned indent = FORMAT_DEFAULT_INDENT,
char const * lp = "(", char const * rp = ")") {
if (begin == end)
return mk_compose(m, mk_string(m, lp), mk_string(m, rp));
unsigned indent1 = static_cast<unsigned>(strlen(lp));
It it = begin;
format * first = proc(*it);
++it;
return mk_group(m, mk_compose(m,
mk_indent(m, indent1, mk_compose(m, mk_string(m, lp), first)),
mk_indent(m, indent, mk_compose(m,
mk_seq(m, it, end, proc),
mk_string(m, rp)))));
}
/**
(elem_1
elem_2
...
elem_n)
*/
template<typename It, typename ToDoc>
format * mk_seq5(ast_manager & m, It const & begin, It const & end, ToDoc proc,
char const * lp = "(", char const * rp = ")") {
return mk_seq4(m, begin, end, proc, static_cast<unsigned>(strlen(lp)), lp, rp);
}
};
#endif /* _FORMAT_H_ */

148
src/ast/pp.cpp Normal file
View file

@ -0,0 +1,148 @@
/*++
Copyright (c) 2006 Microsoft Corporation
Module Name:
pp.cpp
Abstract:
<abstract>
Author:
Leonardo de Moura (leonardo) 2008-01-20.
Revision History:
--*/
#include"pp.h"
using namespace format_ns;
pp_params g_pp_params;
void set_pp_default_params(pp_params const & p) {
g_pp_params = p;
}
void register_pp_params(ini_params & p) {
g_pp_params.register_params(p);
}
pp_params const & get_pp_default_params() {
return g_pp_params;
}
static std::pair<unsigned, bool> space_upto_line_break(ast_manager & m, format * f) {
unsigned r;
SASSERT(f->get_family_id() == fm(m).get_family_id("format"));
decl_kind k = f->get_decl_kind();
switch(k) {
case OP_STRING: {
size_t len = strlen(f->get_decl()->get_parameter(0).get_symbol().bare_str());
return std::make_pair(static_cast<unsigned>(len), false);
}
case OP_CHOICE:
return space_upto_line_break(m, to_app(f->get_arg(0)));
case OP_COMPOSE:
r = 0;
for (unsigned i = 0; i < f->get_num_args(); i++) {
std::pair<unsigned, bool> pair = space_upto_line_break(m, to_app(f->get_arg(i)));
r += pair.first;
if (pair.second)
return std::make_pair(r, true);
}
return std::make_pair(r, false);
case OP_INDENT:
return space_upto_line_break(m, to_app(f->get_arg(0)));
case OP_LINE_BREAK:
case OP_LINE_BREAK_EXT:
return std::make_pair(0, true);
default:
return std::make_pair(0, false);
}
}
inline bool fits(ast_manager & m, format * f, unsigned space_left) {
unsigned s = space_upto_line_break(m, f).first;
TRACE("fits", tout << "s: " << s << " space_left " << space_left << "\n";);
return s <= space_left;
}
void pp(std::ostream & out, format * f, ast_manager & m, pp_params const & p) {
unsigned pos = 0;
unsigned ribbon_pos = 0;
unsigned line = 0;
unsigned len;
unsigned i;
int space_left;
svector<std::pair<format *, unsigned> > todo;
todo.push_back(std::make_pair(f, 0));
app_ref space(mk_string(m, " "), fm(m));
while (!todo.empty()) {
if (line >= p.m_pp_max_num_lines)
return;
std::pair<format *, unsigned> pair = todo.back();
format * f = pair.first;
unsigned indent = pair.second;
todo.pop_back();
SASSERT(f->get_family_id() == fm(m).get_family_id("format"));
switch (f->get_decl_kind()) {
case OP_STRING:
if (p.m_pp_bounded && pos > p.m_pp_max_width)
break;
len = static_cast<unsigned>(strlen(f->get_decl()->get_parameter(0).get_symbol().bare_str()));
if (p.m_pp_bounded && pos + len > p.m_pp_max_width) {
out << "...";
break;
}
pos += len;
ribbon_pos += len;
out << f->get_decl()->get_parameter(0).get_symbol();
break;
case OP_INDENT:
todo.push_back(std::make_pair(to_app(f->get_arg(0)),
std::min(indent + f->get_decl()->get_parameter(0).get_int(),
p.m_pp_max_indent)));
break;
case OP_COMPOSE:
i = f->get_num_args();
while (i > 0) {
--i;
todo.push_back(std::make_pair(to_app(f->get_arg(i)), indent));
}
break;
case OP_CHOICE:
space_left = std::min(p.m_pp_max_width - pos, p.m_pp_max_ribbon - pos);
if (space_left > 0 && fits(m, to_app(f->get_arg(0)), space_left))
todo.push_back(std::make_pair(to_app(f->get_arg(0)), indent));
else
todo.push_back(std::make_pair(to_app(f->get_arg(1)), indent));
break;
case OP_LINE_BREAK:
case OP_LINE_BREAK_EXT:
if (p.m_pp_single_line) {
todo.push_back(std::make_pair(space, indent));
break;
}
pos = indent;
ribbon_pos = 0;
line++;
if (line < p.m_pp_max_num_lines) {
out << "\n";
for (unsigned i = 0; i < indent; i++)
out << " ";
}
else
out << "...\n";
break;
default:
break;
}
}
}
void pp(std::ostream & out, format_ns::format * f, ast_manager & m) {
pp(out, f, m, g_pp_params);
}

34
src/ast/pp.h Normal file
View file

@ -0,0 +1,34 @@
/*++
Copyright (c) 2006 Microsoft Corporation
Module Name:
pp.h
Abstract:
<abstract>
Author:
Leonardo de Moura (leonardo) 2008-01-20.
Revision History:
--*/
#ifndef _PP_H_
#define _PP_H_
#include"format.h"
#include"pp_params.h"
void set_pp_default_params(pp_params const & p);
void register_pp_params(ini_params & p);
pp_params const & get_pp_default_params();
void pp(std::ostream & out, format_ns::format * f, ast_manager & m, pp_params const & p);
void pp(std::ostream & out, format_ns::format * f, ast_manager & m);
#endif /* _PP_H_ */

57
src/ast/pp_params.cpp Normal file
View file

@ -0,0 +1,57 @@
/*++
Copyright (c) 2006 Microsoft Corporation
Module Name:
pp_params.cpp
Abstract:
<abstract>
Author:
Leonardo de Moura (leonardo) 2008-01-20.
Revision History:
--*/
#include"pp_params.h"
pp_params::pp_params():
m_pp_max_indent(UINT_MAX),
m_pp_max_num_lines(UINT_MAX),
m_pp_max_width(80),
m_pp_max_ribbon(80),
m_pp_max_depth(5),
m_pp_min_alias_size(10),
m_pp_decimal(false),
m_pp_decimal_precision(10),
m_pp_bv_lits(true),
m_pp_bv_neg(false),
m_pp_flat_assoc(true),
m_pp_fixed_indent(false),
m_pp_single_line(false),
m_pp_bounded(false),
m_pp_simplify_implies(false) {
}
void pp_params::register_params(ini_params & p) {
p.register_unsigned_param("PP_MAX_INDENT", m_pp_max_indent, "max. indentation in pretty printer", true);
p.register_unsigned_param("PP_MAX_NUM_LINES", m_pp_max_num_lines, "max. number of lines to be displayed in pretty printer", true);
p.register_unsigned_param("PP_MAX_WIDTH", m_pp_max_width, "max. width in pretty printer", true);
p.register_unsigned_param("PP_MAX_RIBBON", m_pp_max_ribbon, "max. ribbon (width - indentation) in pretty printer", true);
p.register_unsigned_param("PP_MAX_DEPTH", m_pp_max_depth, "max. term depth (when pretty printing SMT2 terms/formulas)", true);
p.register_unsigned_param("PP_MIN_ALIAS_SIZE", m_pp_min_alias_size, "min. size for creating an alias for a shared term (when pretty printing SMT2 terms/formulas)", true);
p.register_bool_param("PP_DECIMAL", m_pp_decimal, "pretty print real numbers using decimal notation (the output may be truncated). Z3 adds a '?' if the value is not precise", true);
p.register_unsigned_param("PP_DECIMAL_PRECISION", m_pp_decimal_precision, "maximum number of decimal places to be used when PP_DECIMAL=true", true);
p.register_bool_param("PP_BV_LITERALS", m_pp_bv_lits, "use Bit-Vector literals (e.g, #x0F and #b0101) during pretty printing", true);
p.register_bool_param("PP_BV_NEG", m_pp_bv_neg, "use bvneg when displaying Bit-Vector literals where the most significant bit is 1", true);
p.register_bool_param("PP_FLAT_ASSOC", m_pp_flat_assoc, "flat associative operators (when pretty printing SMT2 terms/formulas)", true);
p.register_bool_param("PP_FIXED_INDENT", m_pp_fixed_indent, "use a fixed indentation for applications", true);
p.register_bool_param("PP_SINGLE_LINE", m_pp_single_line, "ignore line breaks when true", true);
p.register_bool_param("PP_BOUNDED", m_pp_bounded, "ignore characters exceeding max widht", true);
p.register_bool_param("PP_SIMPLIFY_IMPLIES", m_pp_simplify_implies, "simplify nested implications for pretty printing", true);
}

46
src/ast/pp_params.h Normal file
View file

@ -0,0 +1,46 @@
/*++
Copyright (c) 2006 Microsoft Corporation
Module Name:
pp_params.h
Abstract:
<abstract>
Author:
Leonardo de Moura (leonardo) 2008-01-20.
Revision History:
--*/
#ifndef _PP_PARAMS_H_
#define _PP_PARAMS_H_
#include"ini_file.h"
struct pp_params {
unsigned m_pp_max_indent; // max. indentation
unsigned m_pp_max_num_lines; // max. num. lines
unsigned m_pp_max_width; // max. width
unsigned m_pp_max_ribbon; // max. ribbon: width - indentation
unsigned m_pp_max_depth;
unsigned m_pp_min_alias_size;
bool m_pp_decimal; // display reals using decimals
unsigned m_pp_decimal_precision; // max. number of decimal places
bool m_pp_bv_lits;
bool m_pp_bv_neg; // use bvneg to display bit-vector literals which the most significant bit is 1
bool m_pp_flat_assoc;
bool m_pp_fixed_indent;
bool m_pp_single_line; // ignore line breaks if true
bool m_pp_bounded; // ignore characters exceeding max width.
bool m_pp_simplify_implies; // simplify nested implications during pretty printing
pp_params();
void register_params(ini_params & p);
};
#endif /* _PP_PARAMS_H_ */

47
src/ast/recurse_expr.h Normal file
View file

@ -0,0 +1,47 @@
/*++
Copyright (c) 2006 Microsoft Corporation
Module Name:
recurse_expr.h
Abstract:
Traverse an expression applying a visitor.
Author:
Leonardo de Moura (leonardo) 2008-01-11.
Revision History:
--*/
#ifndef _RECURSE_EXPR_H_
#define _RECURSE_EXPR_H_
#include"ast.h"
#include"obj_hashtable.h"
template<typename T, typename Visitor, bool IgnorePatterns=false, bool CallDestructors=true>
class recurse_expr : public Visitor {
obj_map<expr, T> m_cache;
ptr_vector<expr> m_todo;
vector<T, CallDestructors> m_results1;
vector<T, CallDestructors> m_results2;
bool is_cached(expr * n) const { T c; return m_cache.find(n, c); }
T get_cached(expr * n) const { T c; m_cache.find(n, c); return c; }
void cache_result(expr * n, T c) { m_cache.insert(n, c); }
void visit(expr * n, bool & visited);
bool visit_children(expr * n);
void process(expr * n);
public:
recurse_expr(Visitor const & v = Visitor()):Visitor(v) {}
T operator()(expr * n);
void reset() { m_cache.reset(); m_todo.reset(); }
void finalize() { m_cache.finalize(); m_todo.finalize(); }
};
#endif /* _RECURSE_EXPR_H_ */

109
src/ast/recurse_expr_def.h Normal file
View file

@ -0,0 +1,109 @@
/*++
Copyright (c) 2006 Microsoft Corporation
Module Name:
recurse_expr_def.h
Abstract:
Traverse an expression applying a visitor.
Author:
Leonardo de Moura (leonardo) 2008-01-11.
Revision History:
--*/
#ifndef _RECURSE_EXPR_DEF_H_
#define _RECURSE_EXPR_DEF_H_
#include"recurse_expr.h"
template<typename T, typename Visitor, bool IgnorePatterns, bool CallDestructors>
inline void recurse_expr<T, Visitor, IgnorePatterns, CallDestructors>::visit(expr * n, bool & visited) {
if (!is_cached(n)) {
m_todo.push_back(n);
visited = false;
}
}
template<typename T, typename Visitor, bool IgnorePatterns, bool CallDestructors>
bool recurse_expr<T, Visitor, IgnorePatterns, CallDestructors>::visit_children(expr * n) {
bool visited = true;
unsigned num;
switch (n->get_kind()) {
case AST_APP:
num = to_app(n)->get_num_args();
for (unsigned j = 0; j < num; j++)
visit(to_app(n)->get_arg(j), visited);
break;
case AST_QUANTIFIER:
if (!IgnorePatterns) {
num = to_quantifier(n)->get_num_patterns();
for (unsigned j = 0; j < num; j++)
visit(to_quantifier(n)->get_pattern(j), visited);
num = to_quantifier(n)->get_num_no_patterns();
for (unsigned j = 0; j < num; j++)
visit(to_quantifier(n)->get_no_pattern(j), visited);
}
visit(to_quantifier(n)->get_expr(), visited);
break;
default:
break;
}
return visited;
}
template<typename T, typename Visitor, bool IgnorePatterns, bool CallDestructors>
void recurse_expr<T, Visitor, IgnorePatterns, CallDestructors>::process(expr * n) {
unsigned num;
switch (n->get_kind()) {
case AST_APP:
m_results1.reset();
num = to_app(n)->get_num_args();
for (unsigned j = 0; j < num; j++)
m_results1.push_back(get_cached(to_app(n)->get_arg(j)));
cache_result(n, this->Visitor::visit(to_app(n), m_results1.c_ptr()));
break;
case AST_VAR:
cache_result(n, this->Visitor::visit(to_var(n)));
break;
case AST_QUANTIFIER:
if (IgnorePatterns) {
cache_result(n, this->Visitor::visit(to_quantifier(n), get_cached(to_quantifier(n)->get_expr()), 0, 0));
}
else {
m_results1.reset();
m_results2.reset();
num = to_quantifier(n)->get_num_patterns();
for (unsigned j = 0; j < num; j++)
m_results1.push_back(get_cached(to_quantifier(n)->get_pattern(j)));
num = to_quantifier(n)->get_num_no_patterns();
for (unsigned j = 0; j < num; j++)
m_results2.push_back(get_cached(to_quantifier(n)->get_no_pattern(j)));
cache_result(n, this->Visitor::visit(to_quantifier(n), get_cached(to_quantifier(n)->get_expr()), m_results1.c_ptr(), m_results2.c_ptr()));
}
break;
default:
UNREACHABLE();
}
}
template<typename T, typename Visitor, bool IgnorePatterns, bool CallDestructors>
T recurse_expr<T, Visitor, IgnorePatterns, CallDestructors>::operator()(expr * r) {
m_todo.push_back(r);
while (!m_todo.empty()) {
expr * n = m_todo.back();
if (is_cached(n))
m_todo.pop_back();
else if (visit_children(n)) {
m_todo.pop_back();
process(n);
}
}
return get_cached(r);
}
#endif /* _RECURSE_EXPR_DEF_H_ */

265
src/ast/seq_decl_plugin.cpp Normal file
View file

@ -0,0 +1,265 @@
/*++
Copyright (c) 2011 Microsoft Corporation
Module Name:
dl_decl_plugin.h
Abstract:
<abstract>
Author:
Nikolaj Bjorner (nbjorner) 2011-14-11
Revision History:
--*/
#include "seq_decl_plugin.h"
#include "arith_decl_plugin.h"
#include "array_decl_plugin.h"
#include <sstream>
seq_decl_plugin::seq_decl_plugin(): m_init(false) {}
void seq_decl_plugin::finalize() {
for (unsigned i = 0; i < m_sigs.size(); ++i)
dealloc(m_sigs[i]);
}
bool seq_decl_plugin::is_sort_param(sort* s, unsigned& idx) {
return
s->get_name().is_numerical() &&
(idx = s->get_name().get_num(), true);
}
bool seq_decl_plugin::match(ptr_vector<sort>& binding, sort* s, sort* sP) {
if (s == sP) return true;
unsigned i;
if (is_sort_param(sP, i)) {
if (binding.size() <= i) binding.resize(i+1);
if (binding[i] && (binding[i] != s)) return false;
binding[i] = s;
return true;
}
if (s->get_family_id() == sP->get_family_id() &&
s->get_decl_kind() == sP->get_decl_kind() &&
s->get_name() == sP->get_name()) {
SASSERT(s->get_num_parameters() == sP->get_num_parameters());
for (unsigned i = 0; i < s->get_num_parameters(); ++i) {
parameter const& p = s->get_parameter(i);
if (p.is_ast() && is_sort(p.get_ast())) {
parameter const& p2 = sP->get_parameter(i);
if (!match(binding, to_sort(p.get_ast()), to_sort(p2.get_ast()))) return false;
}
}
return true;
}
else {
return false;
}
}
void seq_decl_plugin::match(psig& sig, unsigned dsz, sort *const* dom, sort* range, sort_ref& range_out) {
ptr_vector<sort> binding;
ast_manager& m = *m_manager;
if (sig.m_dom.size() != dsz) {
std::ostringstream strm;
strm << "Unexpected number of arguments to '" << sig.m_name << "' ";
strm << sig.m_dom.size() << " arguments expected " << dsz << " given";
m.raise_exception(strm.str().c_str());
}
bool is_match = true;
for (unsigned i = 0; is_match && i < dsz; ++i) {
is_match = match(binding, dom[i], sig.m_dom[i].get());
}
if (range && is_match) {
is_match = match(binding, range, sig.m_range);
}
if (!is_match) {
std::ostringstream strm;
strm << "Sort of polymorphic function '" << sig.m_name << "' ";
strm << "does not match the declared type";
m.raise_exception(strm.str().c_str());
}
if (!range && dsz == 0) {
std::ostringstream strm;
strm << "Sort of polymorphic function '" << sig.m_name << "' ";
strm << "is ambiguous. Function takes no arguments and sort of range has not been constrained";
m.raise_exception(strm.str().c_str());
}
range_out = apply_binding(binding, sig.m_range);
}
sort* seq_decl_plugin::apply_binding(ptr_vector<sort> const& binding, sort* s) {
unsigned i;
if (is_sort_param(s, i)) {
if (binding.size() <= i || !binding[i]) {
m_manager->raise_exception("Expecting type parameter to be bound");
}
return binding[i];
}
if (is_sort_of(s, m_family_id, SEQ_SORT) || is_sort_of(s, m_family_id, RE_SORT)) {
SASSERT(s->get_num_parameters() == 1);
SASSERT(s->get_parameter(0).is_ast());
SASSERT(is_sort(s->get_parameter(0).get_ast()));
sort* p = apply_binding(binding, to_sort(s->get_parameter(0).get_ast()));
parameter param(p);
return mk_sort(s->get_decl_kind(), 1, &param);
}
return s;
}
void seq_decl_plugin::init() {
if(m_init) return;
ast_manager& m = *m_manager;
m_init = true;
sort* A = m.mk_sort(symbol((unsigned)0));
sort* B = m.mk_sort(symbol((unsigned)1));
parameter paramA(A);
sort* seqA = m.mk_sort(m_family_id, SEQ_SORT, 1, &paramA);
sort* reA = m.mk_sort(m_family_id, RE_SORT, 1, &paramA);
sort* seqAseqA[2] = { seqA, seqA };
sort* seqAA[2] = { seqA, A };
sort* seqAB[2] = { seqA, B };
sort* seqAreA[2] = { seqA, reA };
sort* AseqA[2] = { A, seqA };
sort* reAreA[2] = { reA, reA };
sort* AA[2] = { A, A };
sort* seqABB[3] = { seqA, B, B };
sort* boolT = m.mk_bool_sort();
sort* intT = arith_util(m).mk_int();
sort* predA = array_util(m).mk_array_sort(A, boolT);
m_sigs.resize(LAST_SEQ_OP);
// TBD: have (par ..) construct and load parameterized signature from premable.
m_sigs[OP_SEQ_UNIT] = alloc(psig, m, "seq-unit", 1, 1, &A, seqA);
m_sigs[OP_SEQ_EMPTY] = alloc(psig, m, "seq-empty", 1, 0, 0, seqA);
m_sigs[OP_SEQ_CONCAT] = alloc(psig, m, "seq-concat", 1, 2, seqAseqA, seqA);
m_sigs[OP_SEQ_CONS] = alloc(psig, m, "seq-cons", 1, 2, AseqA, seqA);
m_sigs[OP_SEQ_REV_CONS] = alloc(psig, m, "seq-rev-cons", 1, 2, seqAA, seqA);
m_sigs[OP_SEQ_HEAD] = alloc(psig, m, "seq-head", 1, 1, &seqA, A);
m_sigs[OP_SEQ_TAIL] = alloc(psig, m, "seq-tail", 1, 1, &seqA, seqA);
m_sigs[OP_SEQ_LAST] = alloc(psig, m, "seq-last", 1, 1, &seqA, A);
m_sigs[OP_SEQ_FIRST] = alloc(psig, m, "seq-first", 1, 1, &seqA, seqA);
m_sigs[OP_SEQ_PREFIX_OF] = alloc(psig, m, "seq-prefix-of", 1, 2, seqAseqA, boolT);
m_sigs[OP_SEQ_SUFFIX_OF] = alloc(psig, m, "seq-suffix-of", 1, 2, seqAseqA, boolT);
m_sigs[OP_SEQ_SUBSEQ_OF] = alloc(psig, m, "seq-subseq-of", 1, 2, seqAseqA, boolT);
m_sigs[OP_SEQ_EXTRACT] = alloc(psig, m, "seq-extract", 2, 3, seqABB, seqA);
m_sigs[OP_SEQ_NTH] = alloc(psig, m, "seq-nth", 2, 2, seqAB, A);
m_sigs[OP_SEQ_LENGTH] = alloc(psig, m, "seq-length", 1, 1, &seqA, intT);
m_sigs[OP_RE_PLUS] = alloc(psig, m, "re-plus", 1, 1, &reA, reA);
m_sigs[OP_RE_STAR] = alloc(psig, m, "re-star", 1, 1, &reA, reA);
m_sigs[OP_RE_OPTION] = alloc(psig, m, "re-option", 1, 1, &reA, reA);
m_sigs[OP_RE_RANGE] = alloc(psig, m, "re-range", 1, 2, AA, reA);
m_sigs[OP_RE_CONCAT] = alloc(psig, m, "re-concat", 1, 2, reAreA, reA);
m_sigs[OP_RE_UNION] = alloc(psig, m, "re-union", 1, 2, reAreA, reA);
m_sigs[OP_RE_INTERSECT] = alloc(psig, m, "re-intersect", 1, 2, reAreA, reA);
m_sigs[OP_RE_DIFFERENCE] = alloc(psig, m, "re-difference", 1, 2, reAreA, reA);
m_sigs[OP_RE_COMPLEMENT] = alloc(psig, m, "re-complement", 1, 1, &reA, reA);
m_sigs[OP_RE_LOOP] = alloc(psig, m, "re-loop", 1, 1, &reA, reA);
m_sigs[OP_RE_EMPTY_SEQ] = alloc(psig, m, "re-empty-seq", 1, 0, 0, reA);
m_sigs[OP_RE_EMPTY_SET] = alloc(psig, m, "re-empty-set", 1, 0, 0, reA);
m_sigs[OP_RE_FULL_SET] = alloc(psig, m, "re-full-set", 1, 0, 0, reA);
m_sigs[OP_RE_OF_SEQ] = alloc(psig, m, "re-of-seq", 1, 1, &seqA, reA);
m_sigs[OP_RE_OF_PRED] = alloc(psig, m, "re-of-pred", 1, 1, &predA, reA);
m_sigs[OP_RE_MEMBER] = alloc(psig, m, "re-member", 1, 2, seqAreA, boolT);
}
sort * seq_decl_plugin::mk_sort(decl_kind k, unsigned num_parameters, parameter const * parameters) {
init();
ast_manager& m = *m_manager;
switch (k) {
case SEQ_SORT:
if (num_parameters != 1) {
m.raise_exception("Invalid sequence sort, expecting one parameter");
}
if (!parameters[0].is_ast() || !is_sort(parameters[0].get_ast())) {
m.raise_exception("invalid sequence sort, parameter is not a sort");
}
return m.mk_sort(symbol("Seq"), sort_info(m_family_id, SEQ_SORT, num_parameters, parameters));
case RE_SORT:
if (num_parameters != 1) {
m.raise_exception("Invalid regex sort, expecting one parameter");
}
if (!parameters[0].is_ast() || !is_sort(parameters[0].get_ast())) {
m.raise_exception("invalid regex sort, parameter is not a sort");
}
return m.mk_sort(symbol("RegEx"), sort_info(m_family_id, RE_SORT, num_parameters, parameters));
default:
UNREACHABLE();
return 0;
}
}
func_decl * seq_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters,
unsigned arity, sort * const * domain, sort * range) {
init();
ast_manager& m = *m_manager;
sort_ref rng(m);
switch(k) {
case OP_SEQ_UNIT:
case OP_SEQ_EMPTY:
case OP_SEQ_CONCAT:
case OP_SEQ_CONS:
case OP_SEQ_REV_CONS:
case OP_SEQ_HEAD:
case OP_SEQ_TAIL:
case OP_SEQ_LAST:
case OP_SEQ_FIRST:
case OP_SEQ_PREFIX_OF:
case OP_SEQ_SUFFIX_OF:
case OP_SEQ_SUBSEQ_OF:
case OP_SEQ_LENGTH:
case OP_RE_PLUS:
case OP_RE_STAR:
case OP_RE_OPTION:
case OP_RE_RANGE:
case OP_RE_CONCAT:
case OP_RE_UNION:
case OP_RE_INTERSECT:
case OP_RE_DIFFERENCE:
case OP_RE_COMPLEMENT:
case OP_RE_EMPTY_SEQ:
case OP_RE_EMPTY_SET:
case OP_RE_OF_SEQ:
case OP_RE_OF_PRED:
case OP_RE_MEMBER:
match(*m_sigs[k], arity, domain, range, rng);
return m.mk_func_decl(m_sigs[k]->m_name, arity, domain, rng, func_decl_info(m_family_id, k));
case OP_SEQ_EXTRACT:
case OP_SEQ_NTH:
// TBD check numeric arguments for being BVs or integers.
match(*m_sigs[k], arity, domain, range, rng);
return m.mk_func_decl(m_sigs[k]->m_name, arity, domain, rng, func_decl_info(m_family_id, k));
case OP_RE_LOOP:
match(*m_sigs[k], arity, domain, range, rng);
if (num_parameters != 2 || !parameters[0].is_int() || !parameters[1].is_int()) {
m.raise_exception("Expecting two numeral parameters to function re-loop");
}
return m.mk_func_decl(m_sigs[k]->m_name, arity, domain, rng, func_decl_info(m_family_id, k, num_parameters, parameters));
default:
UNREACHABLE();
return 0;
}
}
void seq_decl_plugin::get_op_names(svector<builtin_name> & op_names, symbol const & logic) {
init();
for (unsigned i = 0; i < m_sigs.size(); ++i) {
op_names.push_back(builtin_name(m_sigs[i]->m_name.str().c_str(), i));
}
}
void seq_decl_plugin::get_sort_names(svector<builtin_name> & sort_names, symbol const & logic) {
init();
sort_names.push_back(builtin_name("Seq", SEQ_SORT));
sort_names.push_back(builtin_name("RegEx", RE_SORT));
}
bool seq_decl_plugin::is_value(app* e) const {
// TBD: empty sequence is a value.
return false;
}

120
src/ast/seq_decl_plugin.h Normal file
View file

@ -0,0 +1,120 @@
/*++
Copyright (c) 2011 Microsoft Corporation
Module Name:
seq_decl_plugin.h
Abstract:
<abstract>
Author:
Nikolaj Bjorner (nbjorner) 2011-14-11
Revision History:
--*/
#ifndef _SEQ_DECL_PLUGIN_H_
#define _SEQ_DECL_PLUGIN_H_
#include "ast.h"
enum seq_sort_kind {
SEQ_SORT,
RE_SORT
};
enum seq_op_kind {
OP_SEQ_UNIT,
OP_SEQ_EMPTY,
OP_SEQ_CONCAT,
OP_SEQ_CONS,
OP_SEQ_REV_CONS,
OP_SEQ_HEAD,
OP_SEQ_TAIL,
OP_SEQ_LAST,
OP_SEQ_FIRST,
OP_SEQ_PREFIX_OF,
OP_SEQ_SUFFIX_OF,
OP_SEQ_SUBSEQ_OF,
OP_SEQ_EXTRACT,
OP_SEQ_NTH,
OP_SEQ_LENGTH,
OP_RE_PLUS,
OP_RE_STAR,
OP_RE_OPTION,
OP_RE_RANGE,
OP_RE_CONCAT,
OP_RE_UNION,
OP_RE_INTERSECT,
OP_RE_COMPLEMENT,
OP_RE_DIFFERENCE,
OP_RE_LOOP,
OP_RE_EMPTY_SET,
OP_RE_FULL_SET,
OP_RE_EMPTY_SEQ,
OP_RE_OF_SEQ,
OP_RE_OF_PRED,
OP_RE_MEMBER,
LAST_SEQ_OP
};
class seq_decl_plugin : public decl_plugin {
struct psig {
symbol m_name;
unsigned m_num_params;
sort_ref_vector m_dom;
sort_ref m_range;
psig(ast_manager& m, char const* name, unsigned n, unsigned dsz, sort* const* dom, sort* rng):
m_name(name),
m_num_params(n),
m_dom(m),
m_range(rng, m)
{
m_dom.append(dsz, dom);
}
};
ptr_vector<psig> m_sigs;
bool m_init;
void match(psig& sig, unsigned dsz, sort* const* dom, sort* range, sort_ref& rng);
bool match(ptr_vector<sort>& binding, sort* s, sort* sP);
sort* apply_binding(ptr_vector<sort> const& binding, sort* s);
bool is_sort_param(sort* s, unsigned& idx);
void init();
public:
seq_decl_plugin();
virtual ~seq_decl_plugin() {}
virtual void finalize();
virtual decl_plugin * mk_fresh() { return alloc(seq_decl_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 void get_op_names(svector<builtin_name> & op_names, symbol const & logic);
virtual void get_sort_names(svector<builtin_name> & sort_names, symbol const & logic);
virtual bool is_value(app* e) const;
};
#endif /* _SEQ_DECL_PLUGIN_H_ */

140
src/ast/shared_occs.cpp Normal file
View file

@ -0,0 +1,140 @@
/*++
Copyright (c) 2011 Microsoft Corporation
Module Name:
shared_occs.cpp
Abstract:
Functor for computing the shared subterms in a given
term.
Author:
Leonardo de Moura (leonardo) 2011-04-01.
Revision History:
--*/
#include"shared_occs.h"
#include"ast_smt2_pp.h"
#include"ref_util.h"
inline void shared_occs::insert(expr * t) {
obj_hashtable<expr>::entry * dummy;
if (m_shared.insert_if_not_there_core(t, dummy))
m.inc_ref(t);
}
void shared_occs::reset() {
dec_ref_collection_values(m, m_shared);
m_shared.reset();
}
void shared_occs::cleanup() {
reset();
m_shared.finalize();
m_stack.finalize();
}
shared_occs::~shared_occs() {
reset();
}
inline bool shared_occs::process(expr * t, shared_occs_mark & visited) {
switch (t->get_kind()) {
case AST_APP: {
unsigned num_args = to_app(t)->get_num_args();
if (t->get_ref_count() > 1 && (m_track_atomic || num_args > 0)) {
if (visited.is_marked(t)) {
insert(t);
return true;
}
visited.mark(t);
}
if (num_args == 0)
return true; // done with t
m_stack.push_back(frame(t, 0)); // need to create frame if num_args > 0
return false;
}
case AST_VAR:
if (m_track_atomic && t->get_ref_count() > 1) {
if (visited.is_marked(t))
insert(t);
else
visited.mark(t);
}
return true; // done with t
case AST_QUANTIFIER:
if (t->get_ref_count() > 1) {
if (visited.is_marked(t)) {
insert(t);
return true; // done with t
}
visited.mark(t);
}
if (!m_visit_quantifiers)
return true;
m_stack.push_back(frame(t, 0));
return false;
default:
UNREACHABLE();
return true;
}
}
void shared_occs::operator()(expr * t, shared_occs_mark & visited) {
SASSERT(m_stack.empty());
if (process(t, visited)) {
return;
}
SASSERT(!m_stack.empty());
while (!m_stack.empty()) {
start:
frame & fr = m_stack.back();
expr * curr = fr.first;
switch (curr->get_kind()) {
case AST_APP: {
unsigned num_args = to_app(curr)->get_num_args();
while (fr.second < num_args) {
expr * arg = to_app(curr)->get_arg(fr.second);
fr.second++;
if (!process(arg, visited))
goto start;
}
break;
}
case AST_QUANTIFIER: {
SASSERT(m_visit_quantifiers);
unsigned num_children = m_visit_patterns ? to_quantifier(curr)->get_num_children() : 1;
while (fr.second < num_children) {
expr * child = to_quantifier(curr)->get_child(fr.second);
fr.second++;
if (!process(child, visited))
goto start;
}
break;
}
default:
UNREACHABLE();
break;
}
m_stack.pop_back();
}
}
void shared_occs::operator()(expr * t) {
SASSERT(m_stack.empty());
shared_occs_mark visited;
reset();
operator()(t, visited);
}
void shared_occs::display(std::ostream & out, ast_manager & m) const {
iterator it = begin_shared();
iterator end = end_shared();
for (; it != end; ++it) {
out << mk_ismt2_pp(*it, m) << "\n";
}
}

81
src/ast/shared_occs.h Normal file
View file

@ -0,0 +1,81 @@
/*++
Copyright (c) 2011 Microsoft Corporation
Module Name:
shared_occs.h
Abstract:
Functor for computing the shared subterms in a given
term.
Author:
Leonardo de Moura (leonardo) 2011-04-01.
Revision History:
--*/
#ifndef _SHARED_OCCS_H_
#define _SHARED_OCCS_H_
#include"ast.h"
#include"obj_hashtable.h"
class shared_occs_mark {
ptr_buffer<ast> m_to_unmark;
public:
shared_occs_mark() {}
~shared_occs_mark() {
reset();
}
bool is_marked(ast * n) { return n->is_marked_so(); }
void reset_mark(ast * n) { n->reset_mark_so(); }
void mark(ast * n) { if (is_marked(n)) return; n->mark_so(true); m_to_unmark.push_back(n); }
void reset() {
ptr_buffer<ast>::iterator it = m_to_unmark.begin();
ptr_buffer<ast>::iterator end = m_to_unmark.end();
for (; it != end; ++it) {
reset_mark(*it);
}
m_to_unmark.reset();
}
void mark(ast * n, bool flag) { if (flag) mark(n); else reset_mark(n); }
};
/**
\brief Functor for computing the shared subterms in a given term.
*/
class shared_occs {
ast_manager & m;
bool m_track_atomic;
bool m_visit_quantifiers;
bool m_visit_patterns;
obj_hashtable<expr> m_shared;
typedef std::pair<expr*, unsigned> frame;
svector<frame> m_stack;
bool process(expr * t, shared_occs_mark & visited);
void insert(expr * t);
public:
typedef obj_hashtable<expr>::iterator iterator;
shared_occs(ast_manager & _m, bool track_atomic = false, bool visit_quantifiers = true, bool visit_patterns = false):
m(_m),
m_track_atomic(track_atomic),
m_visit_quantifiers(visit_quantifiers),
m_visit_patterns(visit_patterns) {
}
~shared_occs();
void operator()(expr * t);
void operator()(expr * t, shared_occs_mark & visited);
bool is_shared(expr * t) const { return m_shared.contains(t); }
unsigned num_shared() const { return m_shared.size(); }
iterator begin_shared() const { return m_shared.begin(); }
iterator end_shared() const { return m_shared.end(); }
void reset();
void cleanup();
void display(std::ostream & out, ast_manager & m) const;
};
#endif