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

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,493 @@
/*++
Copyright (c) 2011 Microsoft Corporation
Module Name:
algebraic_numbers.h
Abstract:
Real Algebraic Numbers
Author:
Leonardo (leonardo) 2011-11-22
Notes:
--*/
#ifndef _ALGEBRAIC_NUMBERS_H_
#define _ALGEBRAIC_NUMBERS_H_
#include"rational.h"
#include"mpq.h"
#include"polynomial.h"
#include"z3_exception.h"
#include"scoped_numeral.h"
#include"scoped_numeral_vector.h"
#include"tptr.h"
#include"statistics.h"
#include"params.h"
class small_object_allocator;
class mpbq_manager;
class mpbq;
namespace algebraic_numbers {
class anum;
class manager;
class algebraic_exception : public default_exception {
public:
algebraic_exception(char const * msg):default_exception(msg) {}
};
class manager {
public:
struct imp;
private:
imp * m_imp;
small_object_allocator * m_allocator;
bool m_own_allocator;
public:
static bool precise() { return true; }
static bool field() { return true; }
typedef anum numeral;
typedef svector<numeral> numeral_vector;
typedef _scoped_numeral<manager> scoped_numeral;
typedef _scoped_numeral_vector<manager> scoped_numeral_vector;
manager(unsynch_mpq_manager & m, params_ref const & p = params_ref(), small_object_allocator * a = 0);
~manager();
static void get_param_descrs(param_descrs & r);
static void collect_param_descrs(param_descrs & r) { get_param_descrs(r); }
void set_cancel(bool f);
void updt_params(params_ref const & p);
unsynch_mpq_manager & qm() const;
mpbq_manager & bqm() const;
void del(numeral & a);
/**
\brief a <- 0
*/
void reset(numeral & a);
/**
\brief Return true if a is zero.
*/
bool is_zero(numeral const & a);
/**
\brief Return true if a is positive.
*/
bool is_pos(numeral const & a);
/**
\brief Return true if a is negative.
*/
bool is_neg(numeral const & a);
/**
\brief Return true if a is a rational number.
*/
bool is_rational(numeral const & a);
/**
\brief Return true if a is an integer.
*/
bool is_int(numeral const & a);
/**
\brief Degree of the algebraic number.
That is, degree of the polynomial that is used to encode \c a.
*/
unsigned degree(numeral const & a);
/**
\brief Convert a into a rational number.
\pre is_rational(a)
*/
void to_rational(numeral const & a, mpq & r);
/**
\brief Convert a into a rational number.
\pre is_rational(a)
*/
void to_rational(numeral const & a, rational & r);
/**
\brief a <- n
*/
void set(numeral & a, int n);
void set(numeral & a, mpz const & n);
void set(numeral & a, mpq const & n);
void set(numeral & a, numeral const & n);
void swap(numeral & a, numeral & b);
/**
\brief Store in b an integer value smaller than 'a'.
Remark: this is not the floor, but b <= floor(a)
*/
void int_lt(numeral const & a, numeral & b);
/**
\brief Store in b an integer value bigger than 'a'
Remark: this is not the ceil, but b >= ceil(a)
*/
void int_gt(numeral const & a, numeral & b);
/**
\brief Store in result a value in the interval (prev, next)
\pre lt(pre,v next)
*/
void select(numeral const & prev, numeral const & curr, numeral & result);
/**
\brief Isolate the roots of (an univariate polynomial) p, and store them as algebraic numbers in \c root.
That is, p is in Z[x].
*/
void isolate_roots(polynomial_ref const & p, numeral_vector & roots);
/**
\brief Isolate the roots of a multivariate polynomial p such that all but one variable of p is fixed by x2v, and
store them as algebraic numbers in \c root.
That is, we are viewing p as a polynomial in Z[y_1, ..., y_n][x]:
q_n(y_1, ..., y_n)x^n + ... + q_1(y_1, ..., y_n)*x + q_0
And we are returning the roots of
q_n(x2v(y_1), ..., x2v(y_n))x^n + ... + q_1(x2v(y_1), ..., x2v(y_n))*x + q_0
*/
void isolate_roots(polynomial_ref const & p, polynomial::var2anum const & x2v, numeral_vector & roots);
/**
\brief Isolate the roots of the given polynomial, and compute its sign between them.
*/
void isolate_roots(polynomial_ref const & p, polynomial::var2anum const & x2v, numeral_vector & roots, svector<int> & signs);
/**
\brief Store in r the i-th root of p.
This method throws an exception if p does not have at least i roots.
This method is not really used in the nonlinear procedure.
It is mainly used for debugging purposes, and creating regression tests
\pre i > 0
*/
void mk_root(polynomial_ref const & p, unsigned i, numeral & r);
/**
\brief Store in r the i-th root of p.
This method throws an exception if the s-expression p does not represent
an univariate polynomial, of if p does not have at least i roots.
This method is not really used in the nonlinear procedure.
It is mainly used for debugging purposes, and "reading" root objects in the SMT 2.0 front-end.
\pre i > 0
*/
void mk_root(sexpr const * p, unsigned i, numeral & r);
/**
\brief Return a^{1/k}
Throws an exception if the result is not a real.
That is, (a is negative and k is even) or (k is zero).
*/
void root(numeral const & a, unsigned k, numeral & b);
/**
\brief Return a^k
Throws an exception if 0^0.
*/
void power(numeral const & a, unsigned k, numeral & b);
/**
\brief c <- a + b
*/
void add(numeral const & a, numeral const & b, numeral & c);
void add(numeral const & a, mpz const & b, numeral & c);
/**
\brief c <- a - b
*/
void sub(numeral const & a, numeral const & b, numeral & c);
/**
\brief c <- a * b
*/
void mul(numeral const & a, numeral const & b, numeral & c);
/**
\brief a <- -a
*/
void neg(numeral & a);
/**
\brief a <- 1/a if a != 0
*/
void inv(numeral & a);
/**
\brief c <- a/b if b != 0
*/
void div(numeral const & a, numeral const & b, numeral & c);
/**
Return -1 if a < b
Return 0 if a == b
Return 1 if a > b
*/
int compare(numeral const & a, numeral const & b);
/**
\brief a == b
*/
bool eq(numeral const & a, numeral const & b);
bool eq(numeral const & a, mpq const & b);
bool eq(numeral const & a, mpz const & b);
/**
\brief a != b
*/
bool neq(numeral const & a, numeral const & b) { return !eq(a, b); }
bool neq(numeral const & a, mpq const & b) { return !eq(a, b); }
bool neq(numeral const & a, mpz const & b) { return !eq(a, b); }
/**
\brief a < b
*/
bool lt(numeral const & a, numeral const & b);
bool lt(numeral const & a, mpq const & b);
bool lt(numeral const & a, mpz const & b);
/**
\brief a > b
*/
bool gt(numeral const & a, numeral const & b) { return lt(b, a); }
bool gt(numeral const & a, mpq const & b);
bool gt(numeral const & a, mpz const & b);
/**
\brief a <= b
*/
bool le(numeral const & a, numeral const & b) { return !gt(a, b); }
bool le(numeral const & a, mpq const & b) { return !gt(a, b); }
bool le(numeral const & a, mpz const & b) { return !gt(a, b); }
/**
\brief a >= b
*/
bool ge(numeral const & a, numeral const & b) { return !lt(a, b); }
bool ge(numeral const & a, mpq const & b) { return !lt(a, b); }
bool ge(numeral const & a, mpz const & b) { return !lt(a, b); }
/**
\brief Evaluate the sign of a multivariate polynomial p(x_1, ..., x_n)
at assignment x2v: [x_1 -> alpha_1, ..., x_n -> alpha_n].
\remark forall variable x in p, we have that x2v.contains(x) is true
Return negative number if p(alpha_1, ..., alpha_n) < 0
Return 0 if p(alpha_1, ..., alpha_n) == 0
Return positive number if p(alpha_1, ..., alpha_n) > 0
*/
int eval_sign_at(polynomial_ref const & p, polynomial::var2anum const & x2v);
void get_polynomial(numeral const & a, svector<mpz> & r);
// Procedures for getting lower and upper bounds for irrational numbers
void get_lower(numeral const & a, mpbq & l);
void get_lower(numeral const & a, mpq & l);
void get_lower(numeral const & a, rational & l);
void get_lower(numeral const & a, mpq & l, unsigned precision);
void get_lower(numeral const & a, rational & l, unsigned precision);
void get_upper(numeral const & a, mpbq & u);
void get_upper(numeral const & a, mpq & u);
void get_upper(numeral const & a, rational & u);
void get_upper(numeral const & a, mpq & l, unsigned precision);
void get_upper(numeral const & a, rational & l, unsigned precision);
/**
\brief Display algebraic number as a rational if is_rational(n)
Otherwise, display it as an interval.
*/
void display_interval(std::ostream & out, numeral const & a) const;
/**
\brief Display algebraic number in decimal notation.
A question mark is added based on the precision requested.
*/
void display_decimal(std::ostream & out, numeral const & a, unsigned precision = 10) const;
/**
\brief Display algebraic number as a root object: (p, i)
That is, 'a' is the i-th root of p.
*/
void display_root(std::ostream & out, numeral const & a) const;
/**
\brief Display algebraic number as a root object in SMT 2.0 style: (root-obj p i)
That is, 'a' is the i-th root of p.
*/
void display_root_smt2(std::ostream & out, numeral const & a) const;
/**
\brief Display algebraic number in Mathematica format.
*/
void display_mathematica(std::ostream & out, numeral const & a) const;
void display(std::ostream & out, numeral const & a) { return display_decimal(out, a); }
void reset_statistics();
void collect_statistics(statistics & st) const;
};
struct basic_cell;
struct algebraic_cell;
enum anum_kind { BASIC = 0, ROOT };
class anum {
friend struct manager::imp;
friend class manager;
void * m_cell;
anum(basic_cell * cell):m_cell(TAG(void*, cell, BASIC)) {}
anum(algebraic_cell * cell):m_cell(TAG(void*, cell, ROOT)) {}
bool is_basic() const { return GET_TAG(m_cell) == BASIC; }
basic_cell * to_basic() const { SASSERT(is_basic()); return UNTAG(basic_cell*, m_cell); }
algebraic_cell * to_algebraic() const { SASSERT(!is_basic()); return UNTAG(algebraic_cell*, m_cell); }
public:
anum():m_cell(0) {}
};
};
typedef algebraic_numbers::manager anum_manager;
typedef algebraic_numbers::manager::numeral anum;
typedef algebraic_numbers::manager::numeral_vector anum_vector;
typedef algebraic_numbers::manager::scoped_numeral scoped_anum;
typedef algebraic_numbers::manager::scoped_numeral_vector scoped_anum_vector;
#define AN_MK_COMPARISON_CORE(EXTERNAL, INTERNAL, TYPE) \
inline bool EXTERNAL(scoped_anum const & a, TYPE const & b) { \
anum_manager & m = a.m(); \
scoped_anum _b(m); \
m.set(_b, b); \
return m.INTERNAL(a, _b); \
}
#define AN_MK_COMPARISON(EXTERNAL, INTERNAL) \
AN_MK_COMPARISON_CORE(EXTERNAL, INTERNAL, int) \
AN_MK_COMPARISON_CORE(EXTERNAL, INTERNAL, mpz) \
AN_MK_COMPARISON_CORE(EXTERNAL, INTERNAL, mpq)
AN_MK_COMPARISON(operator==, eq);
AN_MK_COMPARISON(operator!=, neq);
AN_MK_COMPARISON(operator<, lt);
AN_MK_COMPARISON(operator<=, le);
AN_MK_COMPARISON(operator>, gt);
AN_MK_COMPARISON(operator>=, ge);
#undef AN_MK_COMPARISON
#undef AN_MK_COMPARISON_CORE
#define AN_MK_BINARY_CORE(EXTERNAL, INTERNAL, TYPE) \
inline scoped_anum EXTERNAL(scoped_anum const & a, TYPE const & b) { \
anum_manager & m = a.m(); \
scoped_anum _b(m); \
m.set(_b, b); \
scoped_anum r(m); \
m.INTERNAL(a, _b, r); \
return r; \
}
#define AN_MK_BINARY(EXTERNAL, INTERNAL) \
AN_MK_BINARY_CORE(EXTERNAL, INTERNAL, int) \
AN_MK_BINARY_CORE(EXTERNAL, INTERNAL, mpz) \
AN_MK_BINARY_CORE(EXTERNAL, INTERNAL, mpq)
AN_MK_BINARY(operator+, add)
AN_MK_BINARY(operator-, sub)
AN_MK_BINARY(operator*, mul)
AN_MK_BINARY(operator/, div)
#undef AN_MK_BINARY
#undef AN_MK_BINARY_CORE
inline scoped_anum root(scoped_anum const & a, unsigned k) {
scoped_anum r(a.m());
a.m().root(a, k, r);
return r;
}
inline scoped_anum power(scoped_anum const & a, unsigned k) {
scoped_anum r(a.m());
a.m().power(a, k, r);
return r;
}
inline scoped_anum operator^(scoped_anum const & a, unsigned k) {
return power(a, k);
}
inline bool is_int(scoped_anum const & a) {
return a.m().is_int(a);
}
inline bool is_rational(scoped_anum const & a) {
return a.m().is_rational(a);
}
struct root_obj_pp {
anum_manager & m;
anum const & n;
root_obj_pp(anum_manager & _m, anum const & _n):m(_m), n(_n) {}
root_obj_pp(scoped_anum const & _n):m(_n.m()), n(_n.get()) {}
};
inline std::ostream & operator<<(std::ostream & out, root_obj_pp const & n) {
n.m.display_root(out, n.n);
return out;
}
struct decimal_pp {
anum_manager & m;
anum const & n;
unsigned prec;
decimal_pp(anum_manager & _m, anum const & _n, unsigned p):m(_m), n(_n), prec(p) {}
decimal_pp(scoped_anum const & _n, unsigned p):m(_n.m()), n(_n.get()), prec(p) {}
};
inline std::ostream & operator<<(std::ostream & out, decimal_pp const & n) {
n.m.display_decimal(out, n.n, n.prec);
return out;
}
struct interval_pp {
anum_manager & m;
anum const & n;
interval_pp(anum_manager & _m, anum const & _n):m(_m), n(_n) {}
interval_pp(scoped_anum const & _n):m(_n.m()), n(_n.get()) {}
};
inline std::ostream & operator<<(std::ostream & out, interval_pp const & n) {
n.m.display_interval(out, n.n);
return out;
}
#endif

View file

@ -0,0 +1,152 @@
/*++
Copyright (c) 2012 Microsoft Corporation
Module Name:
linear_eq_solver.h
Abstract:
Simple equational solver template for any number field.
No special optimization, just the basics for solving small systems.
It is a solver target to dense system of equations.
Main client: Sparse Modular GCD algorithm.
Author:
Leonardo (leonardo) 2012-01-22
Notes:
--*/
#ifndef _LINEAR_EQ_SOLVER_H_
#define _LINEAR_EQ_SOLVER_H_
template<typename numeral_manager>
class linear_eq_solver {
typedef typename numeral_manager::numeral numeral;
numeral_manager & m;
unsigned n; // number of variables
vector<svector<numeral> > A;
svector<numeral> b;
public:
linear_eq_solver(numeral_manager & _m):m(_m), n(0) { SASSERT(m.field()); }
~linear_eq_solver() { flush(); }
void flush() {
SASSERT(b.size() == A.size());
unsigned sz = A.size();
for (unsigned i = 0; i < sz; i++) {
svector<numeral> & as = A[i];
m.del(b[i]);
SASSERT(as.size() == n);
for (unsigned j = 0; j < n; j++)
m.del(as[j]);
}
A.reset();
b.reset();
n = 0;
}
void resize(unsigned _n) {
if (n != _n) {
flush();
n = _n;
for (unsigned i = 0; i < n; i++) {
A.push_back(svector<numeral>());
svector<numeral> & as = A.back();
for (unsigned j = 0; j < n; j++) {
as.push_back(numeral());
}
b.push_back(numeral());
}
}
}
void reset() {
for (unsigned i = 0; i < n; i++) {
svector<numeral> & A_i = A[i];
for (unsigned j = 0; j < n; j++) {
m.set(A_i[j], 0);
}
m.set(b[i], 0);
}
}
// Set row i with _as[0]*x_0 + ... + _as[n-1]*x_{n-1} = b
void add(unsigned i, numeral const * _as, numeral const & _b) {
SASSERT(i < n);
m.set(b[i], _b);
svector<numeral> & A_i = A[i];
for (unsigned j = 0; j < n; j++) {
m.set(A_i[j], _as[j]);
}
}
// Return true if the system of equations has a solution.
// Return false if the matrix is singular
bool solve(numeral * xs) {
for (unsigned k = 0; k < n; k++) {
TRACE("linear_eq_solver", tout << "iteration " << k << "\n"; display(tout););
// find pivot
unsigned i = k;
for (; i < n; i++) {
if (!m.is_zero(A[i][k]))
break;
}
if (i == n)
return false; // matrix is singular
A[k].swap(A[i]); // swap rows
svector<numeral> & A_k = A[k];
numeral & A_k_k = A_k[k];
SASSERT(!m.is_zero(A_k_k));
// normalize row
for (unsigned i = k+1; i < n; i++)
m.div(A_k[i], A_k_k, A_k[i]);
m.div(b[k], A_k_k, b[k]);
m.set(A_k_k, 1);
// check if first k-1 positions are zero
DEBUG_CODE({ for (unsigned i = 0; i < k; i++) { SASSERT(m.is_zero(A_k[i])); } });
// for all rows below pivot
for (unsigned i = k+1; i < n; i++) {
svector<numeral> & A_i = A[i];
numeral & A_i_k = A_i[k];
for (unsigned j = k+1; j < n; j++) {
m.submul(A_i[j], A_i_k, A_k[j], A_i[j]);
}
m.submul(b[i], A_i_k, b[k], b[i]);
m.set(A_i_k, 0);
}
}
unsigned k = n;
while (k > 0) {
--k;
TRACE("linear_eq_solver", tout << "iteration " << k << "\n"; display(tout););
SASSERT(m.is_one(A[k][k]));
// save result
m.set(xs[k], b[k]);
// back substitute
unsigned i = k;
while (i > 0) {
--i;
m.submul(b[i], A[i][k], b[k], b[i]);
m.set(A[i][k], 0);
}
}
return true;
}
void display(std::ostream & out) const {
for (unsigned i = 0; i < A.size(); i++) {
SASSERT(A[i].size() == n);
for (unsigned j = 0; j < n; j++) {
m.display(out, A[i][j]);
out << " ";
}
m.display(out, b[i]); out << "\n";
}
}
};
#endif

File diff suppressed because it is too large Load diff

1380
src/polynomial/polynomial.h Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,235 @@
/*++
Copyright (c) 2012 Microsoft Corporation
Module Name:
polynomial_cache.cpp
Abstract:
"Hash-consing" for polynomials
Author:
Leonardo (leonardo) 2012-01-07
Notes:
--*/
#include"polynomial_cache.h"
#include"chashtable.h"
namespace polynomial {
struct poly_hash_proc {
manager & m;
poly_hash_proc(manager & _m):m(_m) {}
unsigned operator()(polynomial const * p) const { return m.hash(p); }
};
struct poly_eq_proc {
manager & m;
poly_eq_proc(manager & _m):m(_m) {}
bool operator()(polynomial const * p1, polynomial const * p2) const { return m.eq(p1, p2); }
};
struct psc_chain_entry {
polynomial const * m_p;
polynomial const * m_q;
var m_x;
unsigned m_hash;
unsigned m_result_sz;
polynomial ** m_result;
psc_chain_entry(polynomial const * p, polynomial const * q, var x, unsigned h):
m_p(p),
m_q(q),
m_x(x),
m_hash(h),
m_result_sz(0),
m_result(0) {
}
struct hash_proc { unsigned operator()(psc_chain_entry const * entry) const { return entry->m_hash; } };
struct eq_proc {
bool operator()(psc_chain_entry const * e1, psc_chain_entry const * e2) const {
return e1->m_p == e2->m_p && e1->m_q == e2->m_q && e1->m_x == e2->m_x;
}
};
};
struct factor_entry {
polynomial const * m_p;
unsigned m_hash;
unsigned m_result_sz;
polynomial ** m_result;
factor_entry(polynomial const * p, unsigned h):
m_p(p),
m_hash(h),
m_result_sz(0),
m_result(0) {
}
struct hash_proc { unsigned operator()(factor_entry const * entry) const { return entry->m_hash; } };
struct eq_proc {
bool operator()(factor_entry const * e1, factor_entry const * e2) const {
return e1->m_p == e2->m_p;
}
};
};
typedef chashtable<polynomial*, poly_hash_proc, poly_eq_proc> polynomial_table;
typedef chashtable<psc_chain_entry*, psc_chain_entry::hash_proc, psc_chain_entry::eq_proc> psc_chain_cache;
typedef chashtable<factor_entry*, factor_entry::hash_proc, factor_entry::eq_proc> factor_cache;
struct cache::imp {
manager & m;
polynomial_table m_poly_table;
psc_chain_cache m_psc_chain_cache;
factor_cache m_factor_cache;
polynomial_ref_vector m_cached_polys;
svector<char> m_in_cache;
small_object_allocator & m_allocator;
imp(manager & _m):m(_m), m_poly_table(poly_hash_proc(m), poly_eq_proc(m)), m_cached_polys(m), m_allocator(m.allocator()) {
}
~imp() {
reset_psc_chain_cache();
reset_factor_cache();
}
void del_psc_chain_entry(psc_chain_entry * entry) {
if (entry->m_result_sz != 0)
m_allocator.deallocate(sizeof(polynomial*)*entry->m_result_sz, entry->m_result);
entry->~psc_chain_entry();
m_allocator.deallocate(sizeof(psc_chain_entry), entry);
}
void del_factor_entry(factor_entry * entry) {
if (entry->m_result_sz != 0)
m_allocator.deallocate(sizeof(polynomial*)*entry->m_result_sz, entry->m_result);
entry->~factor_entry();
m_allocator.deallocate(sizeof(factor_entry), entry);
}
void reset_psc_chain_cache() {
psc_chain_cache::iterator it = m_psc_chain_cache.begin();
psc_chain_cache::iterator end = m_psc_chain_cache.end();
for (; it != end; ++it) {
del_psc_chain_entry(*it);
}
m_psc_chain_cache.reset();
}
void reset_factor_cache() {
factor_cache::iterator it = m_factor_cache.begin();
factor_cache::iterator end = m_factor_cache.end();
for (; it != end; ++it) {
del_factor_entry(*it);
}
m_factor_cache.reset();
}
unsigned pid(polynomial * p) const { return m.id(p); }
polynomial * mk_unique(polynomial * p) {
if (m_in_cache.get(pid(p), false))
return p;
polynomial * p_prime = m_poly_table.insert_if_not_there(p);
if (p == p_prime) {
m_cached_polys.push_back(p_prime);
m_in_cache.setx(pid(p_prime), true, false);
}
return p_prime;
}
void psc_chain(polynomial * p, polynomial * q, var x, polynomial_ref_vector & S) {
p = mk_unique(p);
q = mk_unique(q);
unsigned h = hash_u_u(pid(p), pid(q));
psc_chain_entry * entry = new (m_allocator.allocate(sizeof(psc_chain_entry))) psc_chain_entry(p, q, x, h);
psc_chain_entry * old_entry = m_psc_chain_cache.insert_if_not_there(entry);
if (entry != old_entry) {
entry->~psc_chain_entry();
m_allocator.deallocate(sizeof(psc_chain_entry), entry);
S.reset();
for (unsigned i = 0; i < old_entry->m_result_sz; i++) {
S.push_back(old_entry->m_result[i]);
}
}
else {
m.psc_chain(p, q, x, S);
unsigned sz = S.size();
entry->m_result_sz = sz;
entry->m_result = static_cast<polynomial**>(m_allocator.allocate(sizeof(polynomial*)*sz));
for (unsigned i = 0; i < sz; i++) {
polynomial * h = mk_unique(S.get(i));
S.set(i, h);
entry->m_result[i] = h;
}
}
}
void factor(polynomial * p, polynomial_ref_vector & distinct_factors) {
distinct_factors.reset();
p = mk_unique(p);
unsigned h = hash_u(pid(p));
factor_entry * entry = new (m_allocator.allocate(sizeof(factor_entry))) factor_entry(p, h);
factor_entry * old_entry = m_factor_cache.insert_if_not_there(entry);
if (entry != old_entry) {
entry->~factor_entry();
m_allocator.deallocate(sizeof(factor_entry), entry);
distinct_factors.reset();
for (unsigned i = 0; i < old_entry->m_result_sz; i++) {
distinct_factors.push_back(old_entry->m_result[i]);
}
}
else {
factors fs(m);
m.factor(p, fs);
unsigned sz = fs.distinct_factors();
entry->m_result_sz = sz;
entry->m_result = static_cast<polynomial**>(m_allocator.allocate(sizeof(polynomial*)*sz));
for (unsigned i = 0; i < sz; i++) {
polynomial * h = mk_unique(fs[i]);
distinct_factors.push_back(h);
entry->m_result[i] = h;
}
}
}
};
cache::cache(manager & m) {
m_imp = alloc(imp, m);
}
cache::~cache() {
dealloc(m_imp);
}
manager & cache::m() const {
return m_imp->m;
}
polynomial * cache::mk_unique(polynomial * p) {
return m_imp->mk_unique(p);
}
void cache::psc_chain(polynomial const * p, polynomial const * q, var x, polynomial_ref_vector & S) {
m_imp->psc_chain(const_cast<polynomial*>(p), const_cast<polynomial*>(q), x, S);
}
void cache::factor(polynomial const * p, polynomial_ref_vector & distinct_factors) {
m_imp->factor(const_cast<polynomial*>(p), distinct_factors);
}
void cache::reset() {
manager & _m = m();
dealloc(m_imp);
m_imp = alloc(imp, _m);
}
};

View file

@ -0,0 +1,44 @@
/*++
Copyright (c) 2012 Microsoft Corporation
Module Name:
polynomial_cache.h
Abstract:
"Hash-consing" for polynomials
Author:
Leonardo (leonardo) 2012-01-07
Notes:
--*/
#ifndef _POLYNOMIAL_CACHE_H_
#define _POLYNOMIAL_CACHE_H_
#include"polynomial.h"
namespace polynomial {
/**
\brief Functor for creating unique polynomials and caching results of operations
*/
class cache {
struct imp;
imp * m_imp;
public:
cache(manager & m);
~cache();
manager & m() const;
manager & pm() const { return m(); }
polynomial * mk_unique(polynomial * p);
void psc_chain(polynomial const * p, polynomial const * q, var x, polynomial_ref_vector & S);
void factor(polynomial const * p, polynomial_ref_vector & distinct_factors);
void reset();
};
};
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,65 @@
/*++
Copyright (c) 2011 Microsoft Corporation
Module Name:
polynomial_factorization.h
Abstract:
Methods for factoring polynomials.
Author:
Dejan (t-dejanj) 2011-11-29
Notes:
[1] Elwyn Ralph Berlekamp. Factoring Polynomials over Finite Fields. Bell System Technical Journal,
46(8-10):18531859, 1967.
[2] Donald Ervin Knuth. The Art of Computer Programming, volume 2: Seminumerical Algorithms. Addison Wesley, third
edition, 1997.
[3] Henri Cohen. A Course in Computational Algebraic Number Theory. Springer Verlag, 1993.
--*/
#pragma once
#if 0
// Disabled for reorg
#include "polynomial.h"
#include "upolynomial.h"
#include "bit_vector.h"
#include "z3_exception.h"
namespace polynomial {
/**
\brief Something to throw when we are in trouble.
*/
class factorization_exception : public default_exception {
public:
factorization_exception(char const * msg) : default_exception(msg) {}
};
/**
\brief Factor the polynomial f from Z[x1, ..., x_n]. Returns the index of the last factor that is completely
factored. I.e., if the method returns m, then f_1, ..., f_m are true irreducible factors, and the rest might
be further reducible.
*/
unsigned factor(polynomial_ref & f, factors & factors);
/**
\brief Factor the square-free primitive polynomial f from Z[x1, ..., x_n]. Returns true if the factorization
was sucesseful, i.e. it was completed and the result is complete. Otherwise the quarantee is that the all but
the last factor are irreducible.
*/
bool factor_square_free_primitive(polynomial_ref const & f, factors & factors);
}
inline std::ostream & operator<<(std::ostream & out, polynomial::factors & factors) {
factors.display(out);
return out;
}
#endif

View file

@ -0,0 +1,72 @@
/*++
Copyright (c) 2012 Microsoft Corporation
Module Name:
polynomial_primes.h
Abstract:
Some prime numbers for modular computations.
Author:
Leonardo (leonardo) 2011-12-21
Notes:
--*/
#ifndef _POLYNOMIAL_PRIMES_H_
#define _POLYNOMIAL_PRIMES_H_
namespace polynomial {
#define NUM_SMALL_PRIMES 11
const unsigned g_small_primes[NUM_SMALL_PRIMES] = {
13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53
};
#if 0
#define NUM_BIG_PRIMES 77
const unsigned g_big_primes[NUM_BIG_PRIMES] = {
16777259, 16777289, 16777291, 16777331, 16777333, 16777337, 16777381,
16777421, 16777441, 16777447, 16777469, 16777499, 16777507, 16777531,
16777571, 16777577, 16777597, 16777601, 16777619, 16777633, 16777639,
16777643, 16777669, 16777679, 16777681, 16777699, 16777711, 16777721,
16777723, 16777729, 16777751, 16777777, 16777781, 16777807, 16777811,
16777823, 16777829, 16777837, 16777853, 16777903, 16777907, 16777949,
16777967, 16777973, 16777987, 16777991, 16778009, 16778023, 16778071,
16778077, 16778089, 16778123, 16778129, 16778137, 16778147, 16778173,
16778227, 16778231, 16778291, 16778309, 16778357, 16778383, 16778401,
16778413, 16778429, 16778441, 16778449, 16778453, 16778497, 16778521,
16778537, 16778543, 16778549, 16778561, 16778603, 16778623, 16778627
};
#else
#define NUM_BIG_PRIMES 231
const unsigned g_big_primes[NUM_BIG_PRIMES] = {
39103, 39107, 39113, 39119, 39133, 39139, 39157, 39161, 39163, 39181, 39191,
39199, 39209, 39217, 39227, 39229, 39233, 39239, 39241, 39251, 39293, 39301,
39313, 39317, 39323, 39341, 39343, 39359, 39367, 39371, 39373, 39383, 39397,
39409, 39419, 39439, 39443, 39451, 39461, 39499, 39503, 39509, 39511, 39521,
39541, 39551, 39563, 39569, 39581, 39607, 39619, 39623, 39631, 39659, 39667,
39671, 39679, 39703, 39709, 39719, 39727, 39733, 39749, 39761, 39769, 39779,
39791, 39799, 39821, 39827, 39829, 39839, 39841, 39847, 39857, 39863, 39869,
39877, 39883, 39887, 39901, 39929, 39937, 39953, 39971, 39979, 39983, 39989,
40009, 40013, 40031, 40037, 40039, 40063, 40087, 40093, 40099, 40111, 40123,
40127, 40129, 40151, 40153, 40163, 40169, 40177, 40189, 40193, 40213, 40231,
40237, 40241, 40253, 40277, 40283, 40289, 40343, 40351, 40357, 40361, 40387,
40423, 40427, 40429, 40433, 40459, 40471, 40483, 40487, 40493, 40499, 40507,
40519, 40529, 40531, 40543, 40559, 40577, 40583, 40591, 40597, 40609, 40627,
40637, 40639, 40693, 40697, 40699, 40709, 40739, 40751, 40759, 40763, 40771,
40787, 40801, 40813, 40819, 40823, 40829, 40841, 40847, 40849, 40853, 40867,
40879, 40883, 40897, 40903, 40927, 40933, 40939, 40949, 40961, 40973, 40993,
41011, 41017, 41023, 41039, 41047, 41051, 41057, 41077, 41081, 41113, 41117,
41131, 41141, 41143, 41149, 41161, 41177, 41179, 41183, 41189, 41201, 41203,
41213, 41221, 41227, 41231, 41233, 41243, 41257, 41263, 41269, 41281, 41299,
41333, 41341, 41351, 41357, 41381, 41387, 41389, 41399, 41411, 41413, 41443,
41453, 41467, 41479, 41491, 41507, 41513, 41519, 41521, 41539, 41543, 41549
};
#endif
};
#endif

View file

@ -0,0 +1,50 @@
/*++
Copyright (c) 2012 Microsoft Corporation
Module Name:
polynomial_var2value.h
Abstract:
Simple implementations of the var2value interface.
Author:
Leonardo (leonardo) 2012-01-05
Notes:
--*/
#ifndef _POLYNOMIAL_VAR2VALUE_H_
#define _POLYNOMIAL_VAR2VALUE_H_
#include"polynomial.h"
#include"scoped_numeral_vector.h"
namespace polynomial {
// default implementation used for debugging purposes
template<typename ValManager>
class simple_var2value : public var2value<ValManager, typename ValManager::numeral> {
var_vector m_xs;
_scoped_numeral_vector<ValManager> m_vs;
public:
simple_var2value(ValManager & m):m_vs(m) {}
void push_back(var x, typename ValManager::numeral const & v) { m_xs.push_back(x); m_vs.push_back(v); }
virtual ValManager & m() const { return m_vs.m(); }
virtual bool contains(var x) const { return std::find(m_xs.begin(), m_xs.end(), x) != m_xs.end(); }
virtual typename ValManager::numeral const & operator()(var x) const {
for (unsigned i = 0; i < m_xs.size(); i++)
if (m_xs[i] == x)
return m_vs[i];
UNREACHABLE();
static typename ValManager::numeral zero;
return zero;
}
};
};
#endif

View file

@ -0,0 +1,112 @@
/*++
Copyright (c) 2011 Microsoft Corporation
Module Name:
sexpr2upolynomial.cpp
Abstract:
sexpr to upolynomial converter
Author:
Leonardo (leonardo) 2011-12-28
Notes:
--*/
#include"sexpr2upolynomial.h"
#include"sexpr.h"
sexpr2upolynomial_exception::sexpr2upolynomial_exception(char const * msg, sexpr const * s):
cmd_exception(msg, s->get_line(), s->get_pos()) {
}
#define MAX_POLYNOMIAL_DEPTH 1 << 16
// Simple recursive parser
void sexpr2upolynomial(upolynomial::manager & m, sexpr const * s, upolynomial::numeral_vector & p, unsigned depth) {
if (depth > MAX_POLYNOMIAL_DEPTH)
throw sexpr2upolynomial_exception("invalid univariate polynomial, too complex", s);
if (s->is_composite()) {
unsigned num = s->get_num_children();
if (num == 0)
throw sexpr2upolynomial_exception("invalid univariate polynomial, symbol expected", s);
sexpr * h = s->get_child(0);
if (!h->is_symbol())
throw sexpr2upolynomial_exception("invalid univariate polynomial, symbol expected", s);
symbol op = h->get_symbol();
if (op == "+") {
if (num <= 1)
throw sexpr2upolynomial_exception("invalid univariate polynomial, '+' operator expects at least one argument", s);
sexpr2upolynomial(m, s->get_child(1), p, depth+1);
upolynomial::scoped_numeral_vector arg(m);
for (unsigned i = 2; i < num; i++) {
m.reset(arg);
sexpr2upolynomial(m, s->get_child(i), arg, depth+1);
m.add(arg.size(), arg.c_ptr(), p.size(), p.c_ptr(), p);
}
}
else if (op == "-") {
if (num <= 1)
throw sexpr2upolynomial_exception("invalid univariate polynomial, '-' operator expects at least one argument", s);
sexpr2upolynomial(m, s->get_child(1), p, depth+1);
if (num == 2) {
m.neg(p);
return;
}
upolynomial::scoped_numeral_vector arg(m);
for (unsigned i = 2; i < num; i++) {
m.reset(arg);
sexpr2upolynomial(m, s->get_child(i), arg, depth+1);
m.sub(p.size(), p.c_ptr(), arg.size(), arg.c_ptr(), p);
}
}
else if (op == "*") {
if (num <= 1)
throw sexpr2upolynomial_exception("invalid univariate polynomial, '*' operator expects at least one argument", s);
sexpr2upolynomial(m, s->get_child(1), p, depth+1);
upolynomial::scoped_numeral_vector arg(m);
for (unsigned i = 2; i < num; i++) {
m.reset(arg);
sexpr2upolynomial(m, s->get_child(i), arg, depth+1);
m.mul(arg.size(), arg.c_ptr(), p.size(), p.c_ptr(), p);
}
}
else if (op == "^") {
if (num != 3)
throw sexpr2upolynomial_exception("invalid univariate polynomial, '^' operator expects two arguments", s);
sexpr2upolynomial(m, s->get_child(1), p, depth+1);
sexpr * arg2 = s->get_child(2);
if (!arg2->is_numeral() || !arg2->get_numeral().is_unsigned())
throw sexpr2upolynomial_exception("invalid univariate polynomial, exponent must be an unsigned integer", arg2);
unsigned k = arg2->get_numeral().get_unsigned();
m.pw(p.size(), p.c_ptr(), k, p);
}
else {
throw sexpr2upolynomial_exception("invalid univariate polynomial, '+', '-', '^' or '*' expected", s);
}
}
else if (s->is_numeral()) {
// make constant polynomial
rational a = s->get_numeral();
if (!a.is_int())
throw sexpr2upolynomial_exception("invalid univariate polynomial, integer coefficient expected", s);
m.set(1, &a, p);
}
else if (s->is_symbol()) {
if (s->get_symbol() != "x")
throw sexpr2upolynomial_exception("invalid univariate polynomial, variable 'x' expected", s);
// make identity
rational as[2] = { rational(0), rational(1) };
m.set(2, as, p);
}
else {
throw sexpr2upolynomial_exception("invalid univariate polynomial, unexpected ", s);
}
}
void sexpr2upolynomial(upolynomial::manager & m, sexpr const * s, upolynomial::numeral_vector & p) {
sexpr2upolynomial(m, s, p, 0);
}

View file

@ -0,0 +1,33 @@
/*++
Copyright (c) 2011 Microsoft Corporation
Module Name:
sexpr2upolynomial.h
Abstract:
sexpr to upolynomial converter
Author:
Leonardo (leonardo) 2011-12-28
Notes:
--*/
#ifndef _SEXPR2UPOLYNOMIAL_H_
#define _SEXPR2UPOLYNOMIAL_H_
#include"upolynomial.h"
#include"cmd_context_types.h"
class sexpr;
class sexpr2upolynomial_exception : public cmd_exception {
public:
sexpr2upolynomial_exception(char const * msg, sexpr const * s);
};
void sexpr2upolynomial(upolynomial::manager & m, sexpr const * s, upolynomial::numeral_vector & p);
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,922 @@
/*++
Copyright (c) 2011 Microsoft Corporation
Module Name:
upolynomial.h
Abstract:
Goodies for creating and handling univariate polynomials.
A dense representation is much better for Root isolation algorithms,
encoding algebraic numbers, factorization, etc.
We also use integers as the coefficients of univariate polynomials.
Author:
Leonardo (leonardo) 2011-11-29
Notes:
--*/
#ifndef _UPOLYNOMIAL_H_
#define _UPOLYNOMIAL_H_
#include"mpzzp.h"
#include"rational.h"
#include"polynomial.h"
#include"z3_exception.h"
#include"mpbq.h"
#define FACTOR_VERBOSE_LVL 1000
namespace upolynomial {
typedef polynomial::factor_params factor_params;
// It is used only for signing cancellation.
class upolynomial_exception : public default_exception {
public:
upolynomial_exception(char const * msg):default_exception(msg) {}
};
typedef mpz numeral;
typedef mpzzp_manager numeral_manager;
typedef mpzzp_manager zp_numeral_manager;
typedef unsynch_mpz_manager z_numeral_manager;
typedef svector<numeral> numeral_vector;
class core_manager {
public:
typedef _scoped_numeral_vector<numeral_manager> scoped_numeral_vector;
typedef _scoped_numeral<numeral_manager> scoped_numeral;
/**
\brief Convenient vector of polynomials that manages its own memory and keeps the degree, of each polynomial.
Polynomial is c*f_1^k_1*...*f_n^k_n.
*/
class factors {
private:
vector<numeral_vector> m_factors;
svector<unsigned> m_degrees;
core_manager & m_upm;
numeral m_constant;
unsigned m_total_factors;
unsigned m_total_degree;
public:
factors(core_manager & upm);
~factors();
core_manager & upm() const { return m_upm; }
core_manager & pm() const { return m_upm; }
numeral_manager & nm() const;
unsigned distinct_factors() const { return m_factors.size(); }
unsigned total_factors() const { return m_total_factors; }
void clear();
void reset() { clear(); }
numeral_vector const & operator[](unsigned i) const { return m_factors[i]; }
numeral const & get_constant() const { return m_constant; }
void set_constant(numeral const & constant);
unsigned get_degree() const { return m_total_degree; }
unsigned get_degree(unsigned i) const { return m_degrees[i]; }
void set_degree(unsigned i, unsigned degree);
void push_back(numeral_vector const & p, unsigned degree);
// push p to vectors and kill it
void push_back_swap(numeral_vector & p, unsigned degree);
void swap_factor(unsigned i, numeral_vector & p);
void swap(factors & other);
void multiply(numeral_vector & out) const;
void display(std::ostream & out) const;
friend std::ostream & operator<<(std::ostream & out, factors const & fs) {
fs.display(out);
return out;
}
};
protected:
numeral_manager m_manager;
numeral_vector m_basic_tmp;
numeral_vector m_div_tmp1;
numeral_vector m_div_tmp2;
numeral_vector m_exact_div_tmp;
numeral_vector m_gcd_tmp1;
numeral_vector m_gcd_tmp2;
numeral_vector m_CRA_tmp;
#define UPOLYNOMIAL_MGCD_TMPS 6
numeral_vector m_mgcd_tmp[UPOLYNOMIAL_MGCD_TMPS];
numeral_vector m_sqf_tmp1;
numeral_vector m_sqf_tmp2;
numeral_vector m_pw_tmp;
volatile bool m_cancel;
static bool is_alias(numeral const * p, numeral_vector & buffer) { return buffer.c_ptr() != 0 && buffer.c_ptr() == p; }
void neg_core(unsigned sz1, numeral const * p1, numeral_vector & buffer);
void add_core(unsigned sz1, numeral const * p1, unsigned sz2, numeral const * p2, numeral_vector & buffer);
void sub_core(unsigned sz1, numeral const * p1, unsigned sz2, numeral const * p2, numeral_vector & buffer);
void mul_core(unsigned sz1, numeral const * p1, unsigned sz2, numeral const * p2, numeral_vector & buffer);
void flip_sign_if_lm_neg(numeral_vector & buffer);
void mod_gcd(unsigned sz_u, numeral const * u, unsigned sz_v, numeral const * v, numeral_vector & result);
void CRA_combine_images(numeral_vector const & q, numeral const & p, numeral_vector & C, numeral & bound);
public:
core_manager(z_numeral_manager & m);
~core_manager();
z_numeral_manager & zm() const { return m_manager.m(); }
numeral_manager & m() const { return const_cast<core_manager*>(this)->m_manager; }
/**
\brief Return true if Z_p[X]
*/
bool modular() const { return m().modular(); }
bool field() const { return m().field(); }
/**
\brief Return p in Z_p[X]
\pre modular
*/
numeral const & p() const { return m().p(); }
/**
\brief Set manager as Z[X]
*/
void set_z() { m().set_z(); }
/**
\brief Set manager as Z_p[X]
*/
void set_zp(numeral const & p) { m().set_zp(p); }
void set_zp(uint64 p) { m().set_zp(p); }
void checkpoint();
void set_cancel(bool f);
/**
\brief set p size to 0. That is, p is the zero polynomial after this operation.
*/
void reset(numeral_vector & p);
/**
\brief Remove zero leading coefficients.
After applying this method, we have that p is empty() or p[p.size()-1] is not zero.
*/
void trim(numeral_vector & p);
void set_size(unsigned sz, numeral_vector & buffer);
/**
\brief Return the actual degree of p.
*/
unsigned degree(numeral_vector const & p) {
unsigned sz = p.size();
return sz == 0 ? 0 : sz - 1;
}
/**
\brief Return true if p is the zero polynomial.
*/
bool is_zero(numeral_vector & p) { trim(p); return p.empty(); }
/**
\brief Return true if p is a constant polynomial
*/
bool is_const(numeral_vector & p) { trim(p); return p.size() <= 1; }
/**
\brief Copy p to buffer.
*/
void set(unsigned sz, numeral const * p, numeral_vector & buffer);
void set(numeral_vector & target, numeral_vector const & source) { set(source.size(), source.c_ptr(), target); }
/**
\brief Copy p to buffer.
Coefficients of p must be integer.
*/
void set(unsigned sz, rational const * p, numeral_vector & buffer);
/**
\brief Compute the primitive part and the content of f (pp can alias f).
*/
void get_primitive_and_content(unsigned f_sz, numeral const * f, numeral_vector & pp, numeral & cont);
void get_primitive_and_content(numeral_vector const & f, numeral_vector & pp, numeral & cont) {
get_primitive_and_content(f.size(), f.c_ptr(), pp, cont);
}
void get_primitive(numeral_vector const & f, numeral_vector & pp) {
scoped_numeral cont(m());
get_primitive_and_content(f.size(), f.c_ptr(), pp, cont);
}
/**
\brief p := -p
*/
void neg(unsigned sz, numeral * p);
void neg(numeral_vector & p) { neg(p.size(), p.c_ptr()); }
/**
\brief buffer := -p
*/
void neg(unsigned sz, numeral const * p, numeral_vector & buffer);
void neg(numeral_vector const & p, numeral_vector & p_neg) { neg(p.size(), p.c_ptr(), p_neg); }
/**
\brief buffer := p1 + p2
*/
void add(unsigned sz1, numeral const * p1, unsigned sz2, numeral const * p2, numeral_vector & buffer);
void add(numeral_vector const & a, numeral_vector const & b, numeral_vector & c) { add(a.size(), a.c_ptr(), b.size(), b.c_ptr(), c); }
/**
\brief buffer := p1 - p2
*/
void sub(unsigned sz1, numeral const * p1, unsigned sz2, numeral const * p2, numeral_vector & buffer);
void sub(numeral_vector const & a, numeral_vector const & b, numeral_vector & c) { sub(a.size(), a.c_ptr(), b.size(), b.c_ptr(), c); }
/**
\brief buffer := p1 * p2
*/
void mul(unsigned sz1, numeral const * p1, unsigned sz2, numeral const * p2, numeral_vector & buffer);
void mul(numeral_vector const & a, numeral_vector const & b, numeral_vector & c) { mul(a.size(), a.c_ptr(), b.size(), b.c_ptr(), c); }
/**
\brief r := p^k
*/
void pw(unsigned sz, numeral const * p, unsigned k, numeral_vector & r);
/**
\brief buffer := dp/dx
*/
void derivative(unsigned sz1, numeral const * p, numeral_vector & buffer);
void derivative(numeral_vector const & p, numeral_vector & d_p) { derivative(p.size(), p.c_ptr(), d_p); }
/**
\brief Divide coeffients of p by their GCD
*/
void normalize(unsigned sz, numeral * p);
/**
\brief Divide coeffients of p by their GCD
*/
void normalize(numeral_vector & p);
/**
\brief Divide the coefficients of p by b.
This method assumes that every coefficient of p is a multiple of b, and b != 0.
*/
void div(unsigned sz, numeral * p, numeral const & b);
void div(numeral_vector & p, numeral const & b) { div(p.size(), p.c_ptr(), b); }
/**
\brief Multiply the coefficients of p by b.
This method assume b != 0.
*/
void mul(unsigned sz, numeral * p, numeral const & b);
/**
\brief Multiply the coefficients of p by b.
If b == 0, it is equivalent to a reset()
*/
void mul(numeral_vector & p, numeral const & b);
/**
\brief Similar to div_rem but p1 and p2 must not be q and r.
*/
void div_rem_core(unsigned sz1, numeral const * p1, unsigned sz2, numeral const * p2, unsigned & d, numeral_vector & q, numeral_vector & r);
/**
\brief If numeral is a field, then
return q and r s.t. p1 = q*p2 + r
And degree(r) < degree(p2).
If numeral is not a field, then
return q and r s.t. (b_m)^d * p1 = q * p2 + r
where b_m is the leading coefficient of p2 and d <= sz1 - sz2 + 1
if sz1 >= sz2.
The output value d is irrelevant if numeral is a field.
*/
void div_rem(unsigned sz1, numeral const * p1, unsigned sz2, numeral const * p2, unsigned & d, numeral_vector & q, numeral_vector & r);
/**
\see div_rem
*/
void div_rem(unsigned sz1, numeral const * p1, unsigned sz2, numeral const * p2, numeral_vector & q, numeral_vector & r) {
unsigned d = 0;
div_rem(sz1, p1, sz2, p2, d, q, r);
}
void div_rem(numeral_vector const & p1, numeral_vector const & p2, numeral_vector & q, numeral_vector & r) {
div_rem(p1.size(), p1.c_ptr(), p2.size(), p2.c_ptr(), q, r);
}
/**
\see div_rem
*/
void div(unsigned sz1, numeral const * p1, unsigned sz2, numeral const * p2, numeral_vector & q);
/**
\see div_rem
*/
void rem(unsigned sz1, numeral const * p1, unsigned sz2, numeral const * p2, unsigned & d, numeral_vector & r);
/**
\see div_rem
*/
void rem(unsigned sz1, numeral const * p1, unsigned sz2, numeral const * p2, numeral_vector & r) {
unsigned d = 0;
rem(sz1, p1, sz2, p2, d, r);
}
/**
\brief Signed pseudo-remainder.
Alias for rem(sz1, p1, sz2, p2, r); neg(r);
*/
void srem(unsigned sz1, numeral const * p1, unsigned sz2, numeral const * p2, numeral_vector & r);
/**
\brief Return true if p2 divides p1.
*/
bool divides(unsigned sz1, numeral const * p1, unsigned sz2, numeral const * p2);
bool divides(numeral_vector const & p1, numeral_vector const & p2) { return divides(p1.size(), p1.c_ptr(), p2.size(), p2.c_ptr()); }
/**
\brief Return true if p2 divides p1, and store the quotient in q.
*/
bool exact_div(unsigned sz1, numeral const * p1, unsigned sz2, numeral const * p2, numeral_vector & q);
bool exact_div(numeral_vector const & p1, numeral_vector const & p2, numeral_vector & q) {
return exact_div(p1.size(), p1.c_ptr(), p2.size(), p2.c_ptr(), q);
}
/**
\brief Assuming that we can, make the polynomial monic by dividing with the leading coefficient. It
puts the leading coefficient into lc, and it's inverse into lc_inv.
*/
void mk_monic(unsigned sz, numeral * p, numeral & lc, numeral & lc_inv);
void mk_monic(unsigned sz, numeral * p, numeral & lc) { numeral lc_inv; mk_monic(sz, p, lc, lc_inv); m().del(lc_inv); }
void mk_monic(unsigned sz, numeral * p) { numeral lc, lc_inv; mk_monic(sz, p, lc, lc_inv); m().del(lc); m().del(lc_inv); }
void mk_monic(numeral_vector & p) { mk_monic(p.size(), p.c_ptr()); }
/**
\brief g := gcd(p1, p2)
If in a field the coefficients don't matter, so we also make sure that D is monic.
*/
void gcd(unsigned sz1, numeral const * p1, unsigned sz2, numeral const * p2, numeral_vector & g);
void euclid_gcd(unsigned sz1, numeral const * p1, unsigned sz2, numeral const * p2, numeral_vector & g);
void subresultant_gcd(unsigned sz1, numeral const * p1, unsigned sz2, numeral const * p2, numeral_vector & g);
void gcd(numeral_vector const & p1, numeral_vector const & p2, numeral_vector & g) {
gcd(p1.size(), p1.c_ptr(), p2.size(), p2.c_ptr(), g);
}
void subresultant_gcd(numeral_vector const & p1, numeral_vector const & p2, numeral_vector & g) {
subresultant_gcd(p1.size(), p1.c_ptr(), p2.size(), p2.c_ptr(), g);
}
/**
\brief g := square free part of p
*/
void square_free(unsigned sz, numeral const * p, numeral_vector & g);
/**
\brief Return true if p is a square-free polynomial.
*/
bool is_square_free(unsigned sz, numeral const * p);
/**
\brief Return true if p is a square-free polynomial.
*/
bool is_square_free(numeral_vector const & p) {
return is_square_free(p.size(), p.c_ptr());
}
/**
\brief Convert a multi-variate polynomial (that is) actually representing an univariate polynomial
into a vector of coefficients.
*/
template<typename polynomial_ref>
void to_numeral_vector(polynomial_ref const & p, numeral_vector & r) {
typename polynomial_ref::manager & pm = p.m();
SASSERT(pm.is_univariate(p));
polynomial_ref np(pm);
np = pm.normalize(p);
unsigned sz = pm.size(p);
unsigned deg = pm.total_degree(p);
r.reserve(deg+1);
for (unsigned i = 0; i <= deg; i++) {
m().reset(r[i]);
}
for (unsigned i = 0; i < sz; i++) {
unsigned k = pm.total_degree(pm.get_monomial(p, i));
SASSERT(k <= deg);
m().set(r[k], pm.coeff(p, i));
}
set_size(deg+1, r);
}
/**
\brief Convert a multi-variate polynomial in [x, y1, ..., yn] to a univariate polynomial in just x
by removing everything multivariate.
*/
template<typename polynomial_ref>
void to_numeral_vector(polynomial_ref const & p, polynomial::var x, numeral_vector & r) {
typename polynomial_ref::manager & pm = p.m();
polynomial_ref np(pm);
np = pm.normalize(p);
unsigned sz = pm.size(p);
unsigned deg = pm.degree(p, x);
r.reserve(deg+1);
for (unsigned i = 0; i <= deg; i++) {
m().reset(r[i]);
}
for (unsigned i = 0; i < sz; i++) {
typename polynomial::monomial * mon = pm.get_monomial(p, i);
if (pm.size(mon) == 0) {
m().set(r[0], pm.coeff(p, i));
} else if (pm.size(mon) == 1 && pm.get_var(mon, 0) == x) {
unsigned m_deg_x = pm.degree(mon, 0);
m().set(r[m_deg_x], pm.coeff(p, i));
}
}
set_size(deg+1, r);
}
/**
\brief Extended GCD
This method assumes that numeral is a field.
It determines U, V, D such that
A*U + B*V = D and D is the GCD of A and B.
Since in a field the coefficients don't matter, we also make sure that D is monic.
*/
void ext_gcd(unsigned szA, numeral const * A, unsigned szB, numeral const * B, numeral_vector & U, numeral_vector & V, numeral_vector & D);
void ext_gcd(numeral_vector const & A, numeral_vector const & B, numeral_vector & U, numeral_vector & V, numeral_vector & D) {
ext_gcd(A.size(), A.c_ptr(), B.size(), B.c_ptr(), U, V, D);
}
bool eq(unsigned sz1, numeral const * p1, unsigned sz2, numeral const * p2);
bool eq(numeral_vector const & p1, numeral_vector const & p2) { return eq(p1.size(), p1.c_ptr(), p2.size(), p2.c_ptr()); }
void display(std::ostream & out, unsigned sz, numeral const * p, char const * var_name = "x", bool use_star = false) const;
void display(std::ostream & out, numeral_vector const & p, char const * var_name = "x") const { display(out, p.size(), p.c_ptr(), var_name); }
void display_star(std::ostream & out, unsigned sz, numeral const * p) { display(out, sz, p, "x", true); }
void display_star(std::ostream & out, numeral_vector const & p) { display_star(out, p.size(), p.c_ptr()); }
void display_smt2(std::ostream & out, unsigned sz, numeral const * p, char const * var_name = "x") const;
void display_smt2(std::ostream & out, numeral_vector const & p, char const * var_name = "x") const {
return display_smt2(out, p.size(), p.c_ptr(), var_name);
}
};
class scoped_set_z {
core_manager & m;
bool m_modular;
core_manager::scoped_numeral m_p;
public:
scoped_set_z(core_manager & _m):m(_m), m_modular(m.modular()), m_p(m.m()) { m_p = m.p(); m.set_z(); }
~scoped_set_z() { if (m_modular) m.set_zp(m_p); }
};
class scoped_set_zp {
core_manager & m;
bool m_modular;
core_manager::scoped_numeral m_p;
public:
scoped_set_zp(core_manager & _m, numeral const & p):m(_m), m_modular(m.modular()), m_p(m.m()) { m_p = m.p(); m.set_zp(p); }
scoped_set_zp(core_manager & _m, uint64 p):m(_m), m_modular(m.modular()), m_p(m.m()) { m_p = m.p(); m.set_zp(p); }
~scoped_set_zp() { if (m_modular) m.set_zp(m_p); else m.set_z(); }
};
class manager;
typedef core_manager z_manager;
typedef core_manager zp_manager;
typedef z_manager::factors factors;
typedef zp_manager::factors zp_factors;
typedef svector<numeral> numeral_vector;
class scoped_numeral_vector : public _scoped_numeral_vector<numeral_manager> {
public:
scoped_numeral_vector(numeral_manager & m):_scoped_numeral_vector<numeral_manager>(m) {}
scoped_numeral_vector(manager & m);
};
class upolynomial_sequence {
numeral_vector m_seq_coeffs; // coefficients of all polynomials in the sequence
unsigned_vector m_begins; // start position (in m_seq_coeffs) of each polynomial in the sequence
unsigned_vector m_szs; // size of each polynomial in the sequence
friend class manager;
public:
/**
\brief Add a new polynomial to the sequence.
The contents of p is erased.
*/
void push(unsigned sz, numeral * p);
/**
\brief Add a new polynomial to the sequence.
The contents of p is preserved.
*/
void push(numeral_manager & m, unsigned sz, numeral const * p);
/**
\brief Return the number of polynomials in the sequence.
*/
unsigned size() const { return m_szs.size(); }
/**
\brief Return the vector of coefficients for the i-th polynomial in the sequence.
*/
numeral const * coeffs(unsigned i) const { return m_seq_coeffs.c_ptr() + m_begins[i]; }
/**
\brief Return the size of the i-th polynomial in the sequence.
*/
unsigned size(unsigned i) const { return m_szs[i]; }
};
class scoped_upolynomial_sequence : public upolynomial_sequence {
manager & m_manager;
public:
scoped_upolynomial_sequence(manager & m):m_manager(m) {}
~scoped_upolynomial_sequence();
};
class manager : public core_manager {
numeral_vector m_db_tmp;
numeral_vector m_dbab_tmp1;
numeral_vector m_dbab_tmp2;
numeral_vector m_tr_tmp;
numeral_vector m_push_tmp;
int sign_of(numeral const & c);
struct drs_frame;
void pop_top_frame(numeral_vector & p_stack, svector<drs_frame> & frame_stack);
void push_child_frames(unsigned sz, numeral const * p, numeral_vector & p_stack, svector<drs_frame> & frame_stack);
void add_isolating_interval(svector<drs_frame> const & frame_stack, mpbq_manager & bqm, mpbq_vector & lowers, mpbq_vector & uppers);
void add_root(svector<drs_frame> const & frame_stack, mpbq_manager & bqm, mpbq_vector & roots);
void drs_isolate_0_1_roots(unsigned sz, numeral const * p, mpbq_manager & bqm, mpbq_vector & roots, mpbq_vector & lowers, mpbq_vector & uppers);
void drs_isolate_roots(unsigned sz, numeral * p, numeral & U, mpbq_manager & bqm, mpbq_vector & roots, mpbq_vector & lowers, mpbq_vector & uppers);
void drs_isolate_roots(unsigned sz, numeral const * p, mpbq_manager & bqm, mpbq_vector & roots, mpbq_vector & lowers, mpbq_vector & uppers);
void sqf_nz_isolate_roots(unsigned sz, numeral const * p, mpbq_manager & bqm, mpbq_vector & roots, mpbq_vector & lowers, mpbq_vector & uppers);
void sturm_seq_core(upolynomial_sequence & seq);
enum location { PLUS_INF, MINUS_INF, ZERO, MPBQ };
template<location loc>
unsigned sign_variations_at_core(upolynomial_sequence const & seq, mpbq const & b);
void flip_sign(factors & r);
void flip_factor_sign_if_lm_neg(numeral_vector & p, factors & r, unsigned k);
void factor_2_sqf_pp(numeral_vector & p, factors & r, unsigned k);
bool factor_sqf_pp(numeral_vector & p, factors & r, unsigned k, factor_params const & params);
bool factor_core(unsigned sz, numeral const * p, factors & r, factor_params const & params);
public:
manager(z_numeral_manager & m):core_manager(m) {}
~manager();
void reset(numeral_vector & p) { core_manager::reset(p); }
void reset(upolynomial_sequence & seq);
/**
\brief Return true if 0 is a root of p.
*/
bool has_zero_roots(unsigned sz, numeral const * p) { SASSERT(sz > 0); return m().is_zero(p[0]); }
/**
\brief Store in buffer a polynomial that has the same roots of p but the zero roots.
We have that:
forall u, p(u) = 0 and u != 0 implies buffer(u) = 0
forall u, buffer(u) = 0 implies p(u) = 0
This method assumes p is not the zero polynomial
*/
void remove_zero_roots(unsigned sz, numeral const * p, numeral_vector & buffer);
/**
\brief Return true if 1/2 is a root of p.
*/
bool has_one_half_root(unsigned sz, numeral const * p);
/**
\brief Store in buffer a polynomial that has the same roots of p, but a 1/2 root is removed.
This method assumes that 1/2 is a root of p.
*/
void remove_one_half_root(unsigned sz, numeral const * p, numeral_vector & buffer);
/**
\brief Return the number of sign changes in the coefficients of p.
Zero coefficients are ignored.
*/
unsigned sign_changes(unsigned sz, numeral const * p);
/**
\brief Return the descartes bound for the number of roots of p in the interval (0, +oo)
Result:
0 - p has no roots in (0,1)
1 - p has one root in (0,1)
>1 - p has more than one root in (0,1)
*/
unsigned descartes_bound(unsigned sz, numeral const * p);
/**
\brief Return the descartes bound for the number of roots of p in the interval (0, 1)
\see descartes_bound
*/
unsigned descartes_bound_0_1(unsigned sz, numeral const * p);
/**
\brief Return the descartes bound for the number of roots of p in the interval (a, b)
\see descartes_bound
*/
unsigned descartes_bound_a_b(unsigned sz, numeral const * p, mpbq_manager & m, mpbq const & a, mpbq const & b);
/**
\brief p(x) := p(x+1)
*/
void translate(unsigned sz, numeral * p);
void translate(unsigned sz, numeral const * p, numeral_vector & buffer) { set(sz, p, buffer); translate(sz, buffer.c_ptr()); }
/**
\brief p(x) := p(x+2^k)
*/
void translate_k(unsigned sz, numeral * p, unsigned k);
void translate_k(unsigned sz, numeral const * p, unsigned k, numeral_vector & buffer) { set(sz, p, buffer); translate_k(sz, buffer.c_ptr(), k); }
/**
\brief p(x) := p(x+c)
*/
void translate_z(unsigned sz, numeral * p, numeral const & c);
void translate_z(unsigned sz, numeral const * p, numeral const & c, numeral_vector & buffer) { set(sz, p, buffer); translate_z(sz, buffer.c_ptr(), c); }
/**
\brief p(x) := p(x+b) where b = c/2^k
buffer := (2^k)^n * p(x + c/(2^k))
*/
void translate_bq(unsigned sz, numeral * p, mpbq const & b);
void translate_bq(unsigned sz, numeral const * p, mpbq const & b, numeral_vector & buffer) { set(sz, p, buffer); translate_bq(sz, buffer.c_ptr(), b); }
/**
\brief p(x) := p(x+b) where b = c/d
buffer := d^n * p(x + c/d)
*/
void translate_q(unsigned sz, numeral * p, mpq const & b);
void translate_q(unsigned sz, numeral const * p, mpq const & b, numeral_vector & buffer) { set(sz, p, buffer); translate_q(sz, buffer.c_ptr(), b); }
/**
\brief p(x) := 2^n*p(x/2) where n = sz-1
*/
void compose_2n_p_x_div_2(unsigned sz, numeral * p);
/**
\brief p(x) := (2^k)^n * p(x/(2^k))
*/
void compose_2kn_p_x_div_2k(unsigned sz, numeral * p, unsigned k);
/**
\brief p(x) := p(2^k * x)
If u is a root of old(p), then u/2^k is a root of p
*/
void compose_p_2k_x(unsigned sz, numeral * p, unsigned k);
/**
\brief p(x) := p(b * x)
If u is a root of old(p), then u/b is a root of p
*/
void compose_p_b_x(unsigned sz, numeral * p, numeral const & b);
/**
\brief p(x) := p(b * x)
If u is a root of old(p), then u/b is a root of p
Let b be of the form c/(2^k), then this operation is equivalent to:
(2^k)^n*p(c*x/(2^k))
Let old(p) be of the form:
a_n * x^n + a_{n-1}*x^{n-1} + ... + a_1 * x + a_0
Then p is of the form:
a_n * c^n * x^n + a_{n-1} * c^{n-1} * 2^k * x^{n-1} + ... + a_1 * c * (2^k)^(n-1) * x + a_0
*/
void compose_p_b_x(unsigned sz, numeral * p, mpbq const & b);
/**
\brief p(x) := p(q*x)
*/
void compose_p_q_x(unsigned sz, numeral * p, mpq const & q);
/**
\brief p(x) := a^n * p(x/a)
*/
void compose_an_p_x_div_a(unsigned sz, numeral * p, numeral const & a);
/**
\brief p(x) := p(-x)
*/
void p_minus_x(unsigned sz, numeral * p);
/**
\brief p(x) := x^n * p(1/x)
*/
void p_1_div_x(unsigned sz, numeral * p);
/**
\brief Evaluate the sign of p(b)
*/
int eval_sign_at(unsigned sz, numeral const * p, mpbq const & b);
/**
\brief Evaluate the sign of p(b)
*/
int eval_sign_at(unsigned sz, numeral const * p, mpq const & b);
/**
\brief Evaluate the sign of p(b)
*/
int eval_sign_at(unsigned sz, numeral const * p, mpz const & b);
/**
\brief Evaluate the sign of p(0)
*/
int eval_sign_at_zero(unsigned sz, numeral const * p);
/**
\brief Evaluate the sign of p(+oo)
*/
int eval_sign_at_plus_inf(unsigned sz, numeral const * p);
/**
\brief Evaluate the sign of p(-oo)
*/
int eval_sign_at_minus_inf(unsigned sz, numeral const * p);
/**
\brief Evaluate the sign variations in the polynomial sequence at -oo
*/
unsigned sign_variations_at_minus_inf(upolynomial_sequence const & seq);
/**
\brief Evaluate the sign variations in the polynomial sequence at +oo
*/
unsigned sign_variations_at_plus_inf(upolynomial_sequence const & seq);
/**
\brief Evaluate the sign variations in the polynomial sequence at 0
*/
unsigned sign_variations_at_zero(upolynomial_sequence const & seq);
/**
\brief Evaluate the sign variations in the polynomial sequence at b
*/
unsigned sign_variations_at(upolynomial_sequence const & seq, mpbq const & b);
/**
\brief Return an upper bound U for all roots of p.
U is a positive value.
We have that if u is a root of p, then |u| < U
*/
void root_upper_bound(unsigned sz, numeral const * p, numeral & U);
unsigned knuth_positive_root_upper_bound(unsigned sz, numeral const * p);
unsigned knuth_negative_root_upper_bound(unsigned sz, numeral const * p);
/**
\brief Return k s.t. for any nonzero root alpha of p(x):
|alpha| > 1/2^k
*/
unsigned nonzero_root_lower_bound(unsigned sz, numeral const * p);
/**
\brief Isolate roots of a square free polynomial p.
The result is stored in three vectors: roots, lowers and uppers.
The vector roots contains actual roots of p.
The vectors lowers and uppers have the same size, and
For all i in [0, lowers.size()), we have that there is only and only one root of p in the interval (lowers[i], uppers[i]).
Every root of p in roots or in an interval (lowers[i], uppers[i])
The total number of roots of p is roots.size() + lowers.size()
\pre p is not the zero polynomial, that is, sz > 0
*/
void sqf_isolate_roots(unsigned sz, numeral const * p, mpbq_manager & bqm, mpbq_vector & roots, mpbq_vector & lowers, mpbq_vector & uppers);
/**
\brief Isolate roots of an arbitrary polynomial p.
\see sqf_isolate_roots.
\pre p is not the zero polynomial, that is, sz > 0
*/
void isolate_roots(unsigned sz, numeral const * p, mpbq_manager & bqm, mpbq_vector & roots, mpbq_vector & lowers, mpbq_vector & uppers);
void drs_isolate_roots(unsigned sz, numeral * p, unsigned neg_k, unsigned pos_k,
mpbq_manager & bqm, mpbq_vector & roots, mpbq_vector & lowers, mpbq_vector & uppers);
void sturm_isolate_roots_core(unsigned sz, numeral * p, unsigned neg_k, unsigned pos_k,
mpbq_manager & bqm, mpbq_vector & roots, mpbq_vector & lowers, mpbq_vector & uppers);
void sturm_isolate_roots(unsigned sz, numeral const * p, mpbq_manager & bqm, mpbq_vector & roots, mpbq_vector & lowers, mpbq_vector & uppers);
/**
\brief Compute the sturm sequence for p1 and p2.
*/
void sturm_seq(unsigned sz1, numeral const * p1, unsigned sz2, numeral const * p2, upolynomial_sequence & seq);
/**
\brief Compute the sturm sequence for p and p'.
*/
void sturm_seq(unsigned sz, numeral const * p, upolynomial_sequence & seq);
/**
\brief Compute the sturm tarski sequence for p1 and p1'*p2.
*/
void sturm_tarski_seq(unsigned sz1, numeral const * p1, unsigned sz2, numeral const * p2, upolynomial_sequence & seq);
/**
\brief Compute the Fourier sequence for p.
*/
void fourier_seq(unsigned sz, numeral const * p, upolynomial_sequence & seq);
/**
\brief Convert an isolating interval into a refinable one.
See comments in upolynomial.cpp.
*/
bool isolating2refinable(unsigned sz, numeral const * p, mpbq_manager & bqm, mpbq & a, mpbq & b);
//
// Interval refinement procedures
// They all assume p is square free and (a, b) is a refinable isolating interval.
//
// Return TRUE, if interval was squeezed, and new interval is stored in (a,b).
// Return FALSE, if the actual root was found, it is stored in a.
//
// See upolynomial.cpp for additional comments
bool refine_core(unsigned sz, numeral const * p, int sign_a, mpbq_manager & bqm, mpbq & a, mpbq & b);
bool refine(unsigned sz, numeral const * p, mpbq_manager & bqm, mpbq & a, mpbq & b);
bool refine_core(unsigned sz, numeral const * p, int sign_a, mpbq_manager & bqm, mpbq & a, mpbq & b, unsigned prec_k);
bool refine(unsigned sz, numeral const * p, mpbq_manager & bqm, mpbq & a, mpbq & b, unsigned prec_k);
/////////////////////
/**
\brief Convert a isolating (refinable) rational interval into a
isolating refinable binary rational interval.
Return TRUE, if interval was found and the result is stored in (c, d).
Return FALSE, if the actual root was found, it is stored in c.
*/
bool convert_q2bq_interval(unsigned sz, numeral const * p, mpq const & a, mpq const & b, mpbq_manager & bqm, mpbq & c, mpbq & d);
/**
\brief Given a polynomial p, and a lower bound l. Return
the root id i. That is, the first root u > l is the i-th root of p.
*/
unsigned get_root_id(unsigned sz, numeral const * p, mpbq const & l);
/**
\brief Make sure that isolating interval (a, b) for p does not contain zero.
Return TRUE, if updated (a, b) does not contain zero.
Return FALSE, if zero is a root of p
*/
bool normalize_interval_core(unsigned sz, numeral const * p, int sign_a, mpbq_manager & m, mpbq & a, mpbq & b);
/**
\brief Similar to normalize_interval_core, but sign_a does not need to be provided.
*/
bool normalize_interval(unsigned sz, numeral const * p, mpbq_manager & m, mpbq & a, mpbq & b);
/**
\brief Return true if all irreducible factors were found.
That is, if the result if false, there is no guarantee that the factors in r are irreducible.
This can happen when limits (e.g., on the search space size) are set in params.
*/
bool factor(unsigned sz, numeral const * p, factors & r, factor_params const & params = factor_params());
bool factor(numeral_vector const & p, factors & r, factor_params const & params = factor_params()) { return factor(p.size(), p.c_ptr(), r, params); }
void display(std::ostream & out, unsigned sz, numeral const * p, char const * var_name = "x", bool use_star = false) const {
return core_manager::display(out, sz, p, var_name);
}
void display(std::ostream & out, numeral_vector const & p, char const * var_name = "x") const {
return core_manager::display(out, p, var_name);
}
void display(std::ostream & out, upolynomial_sequence const & seq, char const * var_name = "x") const;
};
};
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,96 @@
/*++
Copyright (c) 2011 Microsoft Corporation
Module Name:
upolynomial_factorization.h
Abstract:
Methods for factoring polynomials.
Author:
Dejan (t-dejanj) 2011-11-29
Notes:
[1] Elwyn Ralph Berlekamp. Factoring Polynomials over Finite Fields. Bell System Technical Journal,
46(8-10):18531859, 1967.
[2] Donald Ervin Knuth. The Art of Computer Programming, volume 2: Seminumerical Algorithms. Addison Wesley, third
edition, 1997.
[3] Henri Cohen. A Course in Computational Algebraic Number Theory. Springer Verlag, 1993.
--*/
#ifndef _UPOLYNOMIAL_FACTORIZATION_H_
#define _UPOLYNOMIAL_FACTORIZATION_H_
#include"upolynomial.h"
#include"polynomial.h"
#include"bit_vector.h"
#include"z3_exception.h"
namespace upolynomial {
typedef manager::scoped_numeral scoped_numeral;
/**
\breif Factor f into f = f_1^k_1 * ... * p_n^k_n, such that p_i are square-free and coprime.
*/
void zp_square_free_factor(zp_manager & zp_upm, numeral_vector const & f, zp_factors & sq_free_factors);
/**
\brief Factor the monic square-free polynomial f from Z_p[x]. Returns true if factorization was sucesseful, or false
if f is an irreducible square-free polynomial in Z_p[x].
*/
bool zp_factor_square_free(zp_manager & zp_upm, numeral_vector const & f, zp_factors & factors);
inline bool zp_factor_square_free(zp_manager & zp_upm, numeral_vector const & f, zp_factors & factors, factor_params const & params) {
return zp_factor_square_free(zp_upm, f, factors);
}
/**
\brief Factor the monic square-free polynomial f from Z_p[x] using the Berlekamp algorithm. If randomized is true
the factor splitting is done randomly [3], otherwise it is done as in the original Berlekamp [1].
*/
bool zp_factor_square_free_berlekamp(zp_manager & zp_upm, numeral_vector const & f, zp_factors & factors, bool randomized = true);
/**
\brief Factor the polynomial f from Z_p[x]. Returns true if factorization was sucesseful, or false if f is
an irreducible polynomial in Z_p[x]
*/
bool zp_factor(zp_manager & zp_upm, numeral_vector const & f, zp_factors & factors);
/**
\brief Performs a Hensel lift of A and B in Z_a to Z_b, where p is prime and and a = p^{a_k}, b = p^{b_k},
r = (a, b), with the following assumptions:
* UA + VB = 1 (mod a)
* C = AB (mod b)
* (l(A), r) = 1 (importand in order to divide by A, i.e. to invert l(A))
the output of is two polynomials A1, B1 (replacing A and B) such that A1 = A (mod b), B1 = B (mod b),
l(A1) = l(A), deg(A1) = deg(A), deg(B1) = deg(B) and C = A1 B1 (mod b*r). Such A1, B1 are unique if
r is prime. See [3] p. 138.
The method will also change the zp_manager's module from b to b*r
*/
void hensel_lift(z_manager & upm, numeral const & a, numeral const & b, numeral const & r,
numeral_vector const & U, numeral_vector const & A, numeral_vector const & V, numeral_vector const & B,
numeral_vector const & C, numeral_vector & A_lifted, numeral_vector & B_lifted);
/**
\brief Performs the Hensel lift for the (monic!) factors_p of f in Z_p to Z_{p^e}.
*/
void hensel_lift(z_manager & upm, numeral_vector const & f, zp_factors const & factors_p, unsigned e, zp_factors & factors_pe);
/**
\brief Factor the square-free polynomial f from Z[x]. Returns true if factorization was sucesseful, or false if
f is an irreducible polynomial in Z[x]. The vector of factors is cleared.
*/
bool factor_square_free(z_manager & upm, numeral_vector const & f, factors & fs, factor_params const & ps = factor_params());
/**
Similar to factor_square_free, but it is used to factor the k-th component f^k of a polynomial.
That is, the factors of f are inserted as factors of degree k into fs.
*/
bool factor_square_free(z_manager & upm, numeral_vector const & f, factors & fs, unsigned k, factor_params const & ps = factor_params());
};
#endif

View file

@ -0,0 +1,420 @@
/*++
Copyright (c) 2011 Microsoft Corporation
Module Name:
upolynomial_factorization_int.h
Abstract:
(Internal) header file for univariate polynomial factorization.
This classes are exposed for debugging purposes only.
Author:
Dejan (t-dejanj) 2011-11-29
Notes:
[1] Elwyn Ralph Berlekamp. Factoring Polynomials over Finite Fields. Bell System Technical Journal,
46(8-10):18531859, 1967.
[2] Donald Ervin Knuth. The Art of Computer Programming, volume 2: Seminumerical Algorithms. Addison Wesley, third
edition, 1997.
[3] Henri Cohen. A Course in Computational Algebraic Number Theory. Springer Verlag, 1993.
--*/
#ifndef _UPOLYNOMIAL_FACTORIZATION_INT_H_
#define _UPOLYNOMIAL_FACTORIZATION_INT_H_
#include"upolynomial_factorization.h"
namespace upolynomial {
// copy p from some manager to zp_p in Z_p[x]
inline void to_zp_manager(zp_manager & zp_upm, numeral_vector & p) {
zp_numeral_manager & zp_nm(zp_upm.m());
for (unsigned i = 0; i < p.size(); ++ i) {
zp_nm.p_normalize(p[i]);
}
zp_upm.trim(p);
}
// copy p from some manager to zp_p in Z_p[x]
inline void to_zp_manager(zp_manager & zp_upm, numeral_vector const & p, numeral_vector & zp_p) {
zp_numeral_manager & zp_nm(zp_upm.m());
zp_upm.reset(zp_p);
for (unsigned i = 0; i < p.size(); ++ i) {
numeral p_i; // no need to delete, we keep it pushed in zp_p
zp_nm.set(p_i, p[i]);
zp_p.push_back(p_i);
}
zp_upm.trim(zp_p);
}
/**
\brief Contains all possible degrees of a factorization of a polynomial.
If
p = p1^{k_1} * ... * pn^{k_n} with p_i of degree d_i
then it is represents numbers of the for \sum a_i*d_i, where a_i <= k_i. Two numbers always in the set are
deg(p) and 0.
*/
class factorization_degree_set {
// the set itself, a (m_max_degree)-binary number
bit_vector m_set;
public:
factorization_degree_set() { }
factorization_degree_set(zp_factors const & factors)
{
zp_manager & upm = factors.upm();
// the set contains only {0}
m_set.push_back(true);
for (unsigned i = 0; i < factors.distinct_factors(); ++ i) {
unsigned degree = upm.degree(factors[i]);
unsigned multiplicity = factors.get_degree(i);
for (unsigned k = 0; k < multiplicity; ++ k) {
bit_vector tmp(m_set);
m_set.shift_right(degree);
m_set |= tmp;
}
}
SASSERT(in_set(0) && in_set(factors.get_degree()));
}
unsigned max_degree() const { return m_set.size() - 1; }
void swap(factorization_degree_set & other) {
m_set.swap(other.m_set);
}
bool is_trivial() const {
// check if set = {0, n}
for (int i = 1; i < (int) m_set.size() - 1; ++ i) {
if (m_set.get(i)) return false;
}
return true;
}
void remove(unsigned k) {
m_set.set(k, false);
}
bool in_set(unsigned k) const {
return m_set.get(k);
}
void intersect(const factorization_degree_set& other) {
m_set &= other.m_set;
}
void display(std::ostream & out) const {
out << "[0";
for (unsigned i = 1; i <= max_degree(); ++ i) {
if (in_set(i)) {
out << ", " << i;
}
}
out << "] represented by " << m_set;
}
};
/**
\brief A to iterate through all combinations of factors. This is only needed for the factorization, and we
always iterate through the
*/
template <typename factors_type>
class factorization_combination_iterator_base {
protected:
// total size of available factors
int m_total_size;
// maximal size of the selection
int m_max_size;
// the factors to select from
factors_type const & m_factors;
// which factors are enabled
svector<bool> m_enabled;
// the size of the current selection
int m_current_size;
// the current selection: indices at positions < m_current_size, other values are maxed out
svector<int> m_current;
/**
Assuming a valid selection m_current[0], ..., m_current[position], try to find the next option for
m_current[position], i.e. the first bigger one that's enabled.
*/
int find(int position, int upper_bound) {
int current = m_current[position] + 1;
while (current < upper_bound && !m_enabled[current]) {
current ++;
}
if (current == upper_bound) {
return -1;
} else {
return current;
}
}
public:
factorization_combination_iterator_base(factors_type const & factors)
: m_total_size(factors.distinct_factors()),
m_max_size(factors.distinct_factors()/2),
m_factors(factors)
{
SASSERT(factors.total_factors() > 1);
SASSERT(factors.total_factors() == factors.distinct_factors());
// enable all to start with
m_enabled.resize(m_factors.distinct_factors(), true);
// max out the m_current so that it always fits
m_current.resize(m_factors.distinct_factors()+1, m_factors.distinct_factors());
m_current_size = 0;
}
/**
\brief Returns the factors we are enumerating through.
*/
factors_type const & get_factors() const {
return m_factors;
}
/**
\brief Computes the next combination of factors and returns true if it exists. If remove current is true
it will eliminate the current selected elements from any future selection.
*/
bool next(bool remove_current) {
int max_upper_bound = m_factors.distinct_factors();
do {
// the index we are currently trying to fix
int current_i = m_current_size - 1;
// the value we found as plausable (-1 we didn't find anything)
int current_value = -1;
if (remove_current) {
SASSERT(m_current_size > 0);
// disable the elements of the current selection from ever appearing again
for (current_i = m_current_size - 1; current_i > 0; -- current_i) {
SASSERT(m_enabled[m_current[current_i]]);
m_enabled[m_current[current_i]] = false;
m_current[current_i] = max_upper_bound;
}
// the last one
SASSERT(m_enabled[m_current[0]]);
m_enabled[m_current[0]] = false;
// not removing current anymore
remove_current = false;
// out max size is also going down
m_total_size -= m_current_size;
m_max_size = m_total_size/2;
}
// we go back to the first one that can be increased (if removing current go all the way)
while (current_i >= 0) {
current_value = find(current_i, m_current[current_i + 1]);
if (current_value >= 0) {
// found one
m_current[current_i] = current_value;
break;
} else {
// go back some more
current_i --;
}
}
do {
if (current_value == -1) {
// we couldn't find any options, we have to increse size and start from the first one of that size
if (m_current_size >= m_max_size) {
return false;
} else {
m_current_size ++;
m_current[0] = -1;
current_i = 0;
current_value = find(current_i, max_upper_bound);
// if we didn't find any, we are done
if (current_value == -1) {
return false;
} else {
m_current[current_i] = current_value;
}
}
}
// ok we have a new selection for the current one
for (current_i ++; current_i < m_current_size; ++ current_i) {
// start from the previous one
m_current[current_i] = m_current[current_i-1];
current_value = find(current_i, max_upper_bound);
if (current_value == -1) {
// screwed, didn't find the next one, this means we need to increase the size
m_current[0] = -1;
break;
} else {
m_current[current_i] = current_value;
}
}
} while (current_value == -1);
} while (filter_current());
// found the next one, hurray
return true;
}
/**
\brief A function that returns true if the current combination should be ignored.
*/
virtual bool filter_current() const = 0;
/**
\brief Returns the size of the current selection (cardinality)
*/
unsigned left_size() const {
return m_current_size;
}
/**
\brief Returns the size of the rest of the current selection (cardinality)
*/
unsigned right_size() const {
return m_total_size - m_current_size;
}
void display(std::ostream& out) const {
out << "[ ";
for (unsigned i = 0; i < m_current.size(); ++ i) {
out << m_current[i] << " ";
}
out << "] from [ ";
for (unsigned i = 0; i < m_factors.distinct_factors(); ++ i) {
if (m_enabled[i]) {
out << i << " ";
}
}
out << "]" << std::endl;
}
};
class ufactorization_combination_iterator : public factorization_combination_iterator_base<zp_factors> {
// the degree sets to choose from
factorization_degree_set const & m_degree_set;
public:
ufactorization_combination_iterator(zp_factors const & factors, factorization_degree_set const & degree_set)
: factorization_combination_iterator_base<zp_factors>(factors),
m_degree_set(degree_set)
{}
/**
\brief Filter the ones not in the degree set.
*/
bool filter_current() const {
// select only the ones that have degrees in the degree set
if (!m_degree_set.in_set(current_degree())) {
return true;
}
return false;
}
/**
\brief Returns the degree of the current selection.
*/
unsigned current_degree() const {
unsigned degree = 0;
zp_manager & upm = m_factors.pm();
for (unsigned i = 0; i < left_size(); ++ i) {
degree += upm.degree(m_factors[m_current[i]]);
}
return degree;
}
void left(numeral_vector & out) const {
SASSERT(m_current_size > 0);
zp_manager & upm = m_factors.upm();
upm.set(m_factors[m_current[0]].size(), m_factors[m_current[0]].c_ptr(), out);
for (int i = 1; i < m_current_size; ++ i) {
upm.mul(out.size(), out.c_ptr(), m_factors[m_current[i]].size(), m_factors[m_current[i]].c_ptr(), out);
}
}
void get_left_tail_coeff(numeral const & m, numeral & out) {
zp_numeral_manager & nm = m_factors.upm().m();
nm.set(out, m);
for (int i = 0; i < m_current_size; ++ i) {
nm.mul(out, m_factors[m_current[i]][0], out);
}
}
void get_right_tail_coeff(numeral const & m, numeral & out) {
zp_numeral_manager & nm = m_factors.upm().m();
nm.set(out, m);
unsigned current = 0;
unsigned selection_i = 0;
// selection is ordered, so we just take the ones in between that are not disable
while (current < m_factors.distinct_factors()) {
if (!m_enabled[current]) {
// by skipping the disabled we never skip a selected one
current ++;
} else {
if (selection_i >= m_current.size() || (int) current < m_current[selection_i]) {
SASSERT(m_factors.get_degree(current) == 1);
nm.mul(out, m_factors[current][0], out);
current ++;
} else {
current ++;
selection_i ++;
}
}
}
}
void right(numeral_vector & out) const {
SASSERT(m_current_size > 0);
zp_manager & upm = m_factors.upm();
upm.reset(out);
unsigned current = 0;
unsigned selection_i = 0;
// selection is ordered, so we just take the ones in between that are not disable
while (current < m_factors.distinct_factors()) {
if (!m_enabled[current]) {
// by skipping the disabled we never skip a selected one
current ++;
} else {
if (selection_i >= m_current.size() || (int) current < m_current[selection_i]) {
SASSERT(m_factors.get_degree(current) == 1);
if (out.size() == 0) {
upm.set(m_factors[current].size(), m_factors[current].c_ptr(), out);
} else {
upm.mul(out.size(), out.c_ptr(), m_factors[current].size(), m_factors[current].c_ptr(), out);
}
current ++;
} else {
current ++;
selection_i ++;
}
}
}
}
};
};
#endif

View file

@ -0,0 +1,44 @@
/*++
Copyright (c) 2011 Microsoft Corporation
Module Name:
cmd_context_types.h
Abstract:
Author:
Leonardo (leonardo) 2011-04-22
Notes:
--*/
#include<iostream>
#include"cmd_context_types.h"
std::ostream & operator<<(std::ostream & out, cmd_arg_kind k) {
switch (k) {
case CPK_UINT: out << "unsigned int"; break;
case CPK_BOOL: out << "bool"; break;
case CPK_DOUBLE: out << "double"; break;
case CPK_NUMERAL: out << "rational"; break;
case CPK_DECIMAL: out << "rational"; break;
case CPK_STRING: out << "string"; break;
case CPK_OPTION_VALUE: out << "optional-value"; break;
case CPK_KEYWORD: out << "keyword"; break;
case CPK_SYMBOL: out << "symbol"; break;
case CPK_SYMBOL_LIST: out << "symbol-list"; break;
case CPK_SORT: out << "sort"; break;
case CPK_SORT_LIST: out << "sort-list"; break;
case CPK_EXPR: out << "expression"; break;
case CPK_EXPR_LIST: out << "expression-list"; break;
case CPK_FUNC_DECL: out << "declaration"; break;
case CPK_FUNC_DECL_LIST: out << "declaration-list"; break;
case CPK_SORTED_VAR: out << "sorted-variable"; break;
case CPK_SORTED_VAR_LIST: out << "sorted-variable-list"; break;
case CPK_SEXPR: out << "s-expression"; break;
default: out << "unknown"; break;
}
return out;
}

View file

@ -0,0 +1,119 @@
/*++
Copyright (c) 2011 Microsoft Corporation
Module Name:
cmd_context_types.h
Abstract:
Author:
Leonardo (leonardo) 2011-04-22
Notes:
--*/
#ifndef _CMD_CONTEXT_TYPES_H_
#define _CMD_CONTEXT_TYPES_H_
#include"symbol.h"
#include"z3_exception.h"
#include<sstream>
class rational;
class expr;
class sort;
class func_decl;
class sexpr;
class cmd_context;
enum cmd_arg_kind {
CPK_UINT, CPK_BOOL, CPK_DOUBLE, CPK_NUMERAL,
CPK_DECIMAL, CPK_STRING, CPK_OPTION_VALUE,
CPK_KEYWORD,
CPK_SYMBOL, CPK_SYMBOL_LIST,
CPK_SORT, CPK_SORT_LIST,
CPK_EXPR, CPK_EXPR_LIST,
CPK_FUNC_DECL, CPK_FUNC_DECL_LIST,
CPK_SORTED_VAR, CPK_SORTED_VAR_LIST,
CPK_SEXPR,
CPK_INVALID
};
std::ostream & operator<<(std::ostream & out, cmd_arg_kind k);
typedef cmd_arg_kind param_kind;
class cmd_exception : public default_exception {
int m_line;
int m_pos;
std::string compose(char const* msg, symbol const& s) {
std::stringstream stm;
stm << msg << s;
return stm.str();
}
public:
cmd_exception(char const * msg):default_exception(msg), m_line(-1), m_pos(-1) {}
cmd_exception(std::string const & msg):default_exception(msg.c_str()), m_line(-1), m_pos(-1) {}
cmd_exception(std::string const & msg, int line, int pos):default_exception(msg.c_str()), m_line(line), m_pos(pos) {}
cmd_exception(char const * msg, symbol const & s):
default_exception(compose(msg,s).c_str()),m_line(-1),m_pos(-1) {}
cmd_exception(char const * msg, symbol const & s, int line, int pos):
default_exception(compose(msg,s).c_str()),m_line(line),m_pos(pos) {}
bool has_pos() const { return m_line >= 0; }
int line() const { SASSERT(has_pos()); return m_line; }
int pos() const { SASSERT(has_pos()); return m_pos; }
};
class stop_parser_exception {
};
typedef std::pair<symbol, sort*> sorted_var;
// A command may have a variable number of arguments.
#define VAR_ARITY UINT_MAX
/**
\brief Command abstract class.
Commands may have variable number of argumets.
*/
class cmd {
symbol m_name;
public:
cmd(char const * n):m_name(n) {}
virtual ~cmd() {}
virtual void reset(cmd_context & ctx) {}
virtual void finalize(cmd_context & ctx) {}
virtual symbol get_name() const { return m_name; }
virtual char const * get_usage() const { return 0; }
virtual char const * get_descr(cmd_context & ctx) const { return 0; }
virtual unsigned get_arity() const { return 0; }
// command invocation
virtual void prepare(cmd_context & ctx) {}
virtual cmd_arg_kind next_arg_kind(cmd_context & ctx) const { UNREACHABLE(); return CPK_UINT; }
virtual void set_next_arg(cmd_context & ctx, unsigned val) { UNREACHABLE(); }
virtual void set_next_arg(cmd_context & ctx, bool val) { UNREACHABLE(); }
virtual void set_next_arg(cmd_context & ctx, rational const & val) { UNREACHABLE(); }
virtual void set_next_arg(cmd_context & ctx, double val) { UNREACHABLE(); }
virtual void set_next_arg(cmd_context & ctx, char const * val) { UNREACHABLE(); }
virtual void set_next_arg(cmd_context & ctx, symbol const & s) { UNREACHABLE(); }
virtual void set_next_arg(cmd_context & ctx, unsigned num, symbol const * slist) { UNREACHABLE(); }
virtual void set_next_arg(cmd_context & ctx, sort * s) { UNREACHABLE(); }
virtual void set_next_arg(cmd_context & ctx, unsigned num, sort * const * slist) { UNREACHABLE(); }
virtual void set_next_arg(cmd_context & ctx, expr * t) { UNREACHABLE(); }
virtual void set_next_arg(cmd_context & ctx, unsigned num, expr * const * tlist) { UNREACHABLE(); }
virtual void set_next_arg(cmd_context & ctx, sorted_var const & sv) { UNREACHABLE(); }
virtual void set_next_arg(cmd_context & ctx, unsigned num, sorted_var const * svlist) { UNREACHABLE(); }
virtual void set_next_arg(cmd_context & ctx, func_decl * f) { UNREACHABLE(); }
virtual void set_next_arg(cmd_context & ctx, unsigned num, func_decl * const * flist) { UNREACHABLE(); }
virtual void set_next_arg(cmd_context & ctx, sexpr * n) { UNREACHABLE(); }
virtual void failure_cleanup(cmd_context & ctx) {}
virtual void execute(cmd_context & ctx) {}
};
#endif

87
src/util/cooperate.cpp Normal file
View file

@ -0,0 +1,87 @@
/*++
Copyright (c) 2011 Microsoft Corporation
Module Name:
cooperate.cpp
Abstract:
Cooperation support
Author:
Leonardo (leonardo) 2011-05-17
Notes:
--*/
#include"z3_omp.h"
#include"cooperate.h"
#include"trace.h"
#include"debug.h"
struct cooperation_lock {
omp_nest_lock_t m_lock;
char const * m_task;
volatile int m_owner_thread;
cooperation_lock() {
omp_set_nested(1);
omp_init_nest_lock(&m_lock);
m_task = 0;
m_owner_thread = -1;
}
~cooperation_lock() {
omp_destroy_nest_lock(&m_lock);
}
};
cooperation_lock g_lock;
bool cooperation_ctx::g_cooperate = false;
void cooperation_ctx::checkpoint(char const * task) {
SASSERT(cooperation_ctx::enabled());
int tid = omp_get_thread_num();
if (g_lock.m_owner_thread == tid) {
g_lock.m_owner_thread = -1;
omp_unset_nest_lock(&(g_lock.m_lock));
}
// this critical section is used to force the owner thread to give a chance to
// another thread to get the lock
#pragma omp critical (z3_cooperate)
{
omp_set_nest_lock(&(g_lock.m_lock));
TRACE("cooperate_detail", tout << task << ", tid: " << tid << "\n";);
CTRACE("cooperate", g_lock.m_task != task, tout << "moving to task: " << task << "\n";);
g_lock.m_owner_thread = tid;
}
}
cooperation_section::cooperation_section() {
SASSERT(!cooperation_ctx::enabled());
SASSERT(!omp_in_parallel());
cooperation_ctx::g_cooperate = true;
}
cooperation_section::~cooperation_section() {
SASSERT(cooperation_ctx::enabled());
cooperation_ctx::g_cooperate = false;
}
init_task::init_task(char const * task) {
SASSERT(cooperation_ctx::enabled());
SASSERT(omp_in_parallel());
cooperation_ctx::checkpoint(task);
}
init_task::~init_task() {
int tid = omp_get_thread_num();
if (g_lock.m_owner_thread == tid) {
g_lock.m_owner_thread = -1;
omp_unset_nest_lock(&(g_lock.m_lock));
}
}

50
src/util/cooperate.h Normal file
View file

@ -0,0 +1,50 @@
/*++
Copyright (c) 2011 Microsoft Corporation
Module Name:
cooperate.h
Abstract:
Cooperation support
Author:
Leonardo (leonardo) 2011-05-17
Notes:
--*/
#ifndef _COOPERATE_H_
#define _COOPERATE_H_
class cooperation_section;
class cooperation_ctx {
friend class cooperation_section;
static bool g_cooperate;
public:
static bool enabled() { return g_cooperate; }
static void checkpoint(char const * task);
};
inline void cooperate(char const * task) {
if (cooperation_ctx::enabled()) cooperation_ctx::checkpoint(task);
}
// must be declared before "#pragma parallel" to enable cooperation
class cooperation_section {
public:
cooperation_section();
~cooperation_section();
};
// must be first declaration inside "#pragma parallel for"
class init_task {
public:
init_task(char const * task);
~init_task();
};
#endif

37
src/util/error_codes.h Normal file
View file

@ -0,0 +1,37 @@
/*++
Copyright (c) 2006 Microsoft Corporation
Module Name:
error_codes.h
Abstract:
Error codes produced by Z3.
Author:
Leonardo de Moura (leonardo) 2007-09-04.
Revision History:
--*/
#ifndef _ERROR_CODES_H_
#define _ERROR_CODES_H_
#define ERR_OK 0
#define ERR_MEMOUT 101
#define ERR_TIMEOUT 102
#define ERR_PARSER 103
#define ERR_UNSOUNDNESS 104
#define ERR_INCOMPLETENESS 105
#define ERR_INI_FILE 106
#define ERR_NOT_IMPLEMENTED_YET 107
#define ERR_OPEN_FILE 108
#define ERR_CMD_LINE 109
#define ERR_INTERNAL_FATAL 110
#define ERR_TYPE_CHECK 111
#define ERR_UNKNOWN_RESULT 112
#endif /* _ERROR_CODES_H_ */

View file

@ -21,7 +21,6 @@ Revision History:
#include"mpq.h"
#include"hash.h"
#include"params.h"
typedef std::pair<mpq, mpq> mpq_inf;
@ -32,12 +31,12 @@ class mpq_inf_manager {
public:
typedef mpq_inf numeral;
mpq_inf_manager(mpq_manager<SYNCH> & _m, params_ref const & p = params_ref()):m(_m) {
updt_params(p);
mpq_inf_manager(mpq_manager<SYNCH> & _m, double inf = 0.0001):m(_m) {
set_inf(inf);
}
void updt_params(params_ref const & p) {
m_inf = p.get_double(":infinitesimal-as-double", 0.00001);
void set_inf(double inf) {
m_inf = inf;
}
enum inf_kind { NEG=-1, ZERO, POS };

716
src/util/params.cpp Normal file
View file

@ -0,0 +1,716 @@
/*++
Copyright (c) 2011 Microsoft Corporation
Module Name:
params.cpp
Abstract:
Parameters
Author:
Leonardo (leonardo) 2011-05-09
Notes:
--*/
#include"params.h"
#include"rational.h"
#include"symbol.h"
#include"dictionary.h"
struct param_descrs::imp {
typedef std::pair<param_kind, char const *> info;
dictionary<info> m_info;
svector<symbol> m_names;
void insert(symbol const & name, param_kind k, char const * descr) {
SASSERT(!name.is_numerical());
info i;
if (m_info.find(name, i)) {
SASSERT(i.first == k);
return;
}
m_info.insert(name, info(k, descr));
m_names.push_back(name);
}
void erase(symbol const & name) {
m_info.erase(name);
}
param_kind get_kind(symbol const & name) const {
info i;
if (m_info.find(name, i))
return i.first;
return CPK_INVALID;
}
unsigned size() const {
return m_names.size();
}
symbol get_param_name(unsigned idx) const {
return m_names[idx];
}
struct lt {
bool operator()(symbol const & s1, symbol const & s2) const { return strcmp(s1.bare_str(), s2.bare_str()) < 0; }
};
void display(std::ostream & out, unsigned indent) const {
svector<symbol> names;
dictionary<info>::iterator it = m_info.begin();
dictionary<info>::iterator end = m_info.end();
for (; it != end; ++it) {
names.push_back(it->m_key);
}
std::sort(names.begin(), names.end(), lt());
svector<symbol>::iterator it2 = names.begin();
svector<symbol>::iterator end2 = names.end();
for (; it2 != end2; ++it2) {
for (unsigned i = 0; i < indent; i++) out << " ";
out << *it2;
info d;
d.second = 0;
m_info.find(*it2, d);
SASSERT(d.second);
out << " (" << d.first << ") " << d.second << "\n";
}
}
};
param_descrs::param_descrs() {
m_imp = alloc(imp);
}
param_descrs::~param_descrs() {
dealloc(m_imp);
}
void param_descrs::insert(symbol const & name, param_kind k, char const * descr) {
m_imp->insert(name, k, descr);
}
void param_descrs::insert(char const * name, param_kind k, char const * descr) {
insert(symbol(name), k, descr);
}
void param_descrs::erase(symbol const & name) {
m_imp->erase(name);
}
void param_descrs::erase(char const * name) {
erase(symbol(name));
}
param_kind param_descrs::get_kind(symbol const & name) const {
return m_imp->get_kind(name);
}
param_kind param_descrs::get_kind(char const * name) const {
return get_kind(symbol(name));
}
unsigned param_descrs::size() const {
return m_imp->size();
}
symbol param_descrs::get_param_name(unsigned i) const {
return m_imp->get_param_name(i);
}
void param_descrs::display(std::ostream & out, unsigned indent) const {
return m_imp->display(out, indent);
}
void insert_max_memory(param_descrs & r) {
r.insert(":max-memory", CPK_UINT, "(default: infty) maximum amount of memory in megabytes.");
}
void insert_max_steps(param_descrs & r) {
r.insert(":max-steps", CPK_UINT, "(default: infty) maximum number of steps.");
}
void insert_produce_models(param_descrs & r) {
r.insert(":produce-models", CPK_BOOL, "(default: false) model generation.");
}
void insert_produce_proofs(param_descrs & r) {
r.insert(":produce-proofs", CPK_BOOL, "(default: false) proof generation.");
}
void insert_timeout(param_descrs & r) {
r.insert(":timeout", CPK_UINT, "(default: infty) timeout in milliseconds.");
}
class params {
friend class params_ref;
struct value {
param_kind m_kind;
union {
bool m_bool_value;
unsigned m_uint_value;
double m_double_value;
char const * m_str_value;
char const * m_sym_value;
rational * m_rat_value;
};
};
typedef std::pair<symbol, value> entry;
svector<entry> m_entries;
unsigned m_ref_count;
void del_value(entry & e);
void del_values();
public:
params():m_ref_count(0) {}
~params() {
reset();
}
void inc_ref() { m_ref_count++; }
void dec_ref() { SASSERT(m_ref_count > 0); m_ref_count--; if (m_ref_count == 0) dealloc(this); }
bool empty() const { return m_entries.empty(); }
bool contains(symbol const & k) const;
bool contains(char const * k) const;
void reset();
void reset(symbol const & k);
void reset(char const * k);
void validate(param_descrs const & p) const {
svector<params::entry>::const_iterator it = m_entries.begin();
svector<params::entry>::const_iterator end = m_entries.end();
for (; it != end; ++it) {
param_kind expected = p.get_kind(it->first);
if (expected == CPK_INVALID)
throw default_exception("unknown parameter '%s'", it->first.str().c_str());
if (it->second.m_kind != expected)
throw default_exception("parameter kind mismatch '%s'", it->first.str().c_str());
}
}
// getters
bool get_bool(symbol const & k, bool _default) const;
bool get_bool(char const * k, bool _default) const;
unsigned get_uint(symbol const & k, unsigned _default) const;
unsigned get_uint(char const * k, unsigned _default) const;
double get_double(symbol const & k, double _default) const;
double get_double(char const * k, double _default) const;
char const * get_str(symbol const & k, char const * _default) const;
char const * get_str(char const * k, char const * _default) const;
rational get_rat(symbol const & k, rational const & _default) const;
rational get_rat(char const * k, rational const & _default) const;
symbol get_sym(symbol const & k, symbol const & _default) const;
symbol get_sym(char const * k, symbol const & _default) const;
// setters
void set_bool(symbol const & k, bool v);
void set_bool(char const * k, bool v);
void set_uint(symbol const & k, unsigned v);
void set_uint(char const * k, unsigned v);
void set_double(symbol const & k, double v);
void set_double(char const * k, double v);
void set_str(symbol const & k, char const * v);
void set_str(char const * k, char const * v);
void set_rat(symbol const & k, rational const & v);
void set_rat(char const * k, rational const & v);
void set_sym(symbol const & k, symbol const & v);
void set_sym(char const * k, symbol const & v);
void display(std::ostream & out) const {
out << "(params";
svector<params::entry>::const_iterator it = m_entries.begin();
svector<params::entry>::const_iterator end = m_entries.end();
for (; it != end; ++it) {
out << " " << it->first;
switch (it->second.m_kind) {
case CPK_BOOL:
out << " " << it->second.m_bool_value;
break;
case CPK_UINT:
out << " " <<it->second.m_uint_value;
break;
case CPK_DOUBLE:
out << " " << it->second.m_double_value;
break;
case CPK_NUMERAL:
out << " " << *(it->second.m_rat_value);
break;
case CPK_SYMBOL:
out << " " << symbol::mk_symbol_from_c_ptr(it->second.m_sym_value);
break;
case CPK_STRING:
out << " " << it->second.m_str_value;
break;
default:
UNREACHABLE();
break;
}
}
out << ")";
}
};
params_ref::~params_ref() {
if (m_params)
m_params->dec_ref();
}
params_ref::params_ref(params_ref const & p):
m_params(0) {
operator=(p);
}
void params_ref::display(std::ostream & out) const {
if (m_params)
m_params->display(out);
else
out << "(params)";
}
void params_ref::validate(param_descrs const & p) const {
if (m_params)
m_params->validate(p);
}
params_ref & params_ref::operator=(params_ref const & p) {
if (p.m_params)
p.m_params->inc_ref();
if (m_params)
m_params->dec_ref();
m_params = p.m_params;
return *this;
}
void params_ref::copy(params_ref const & src) {
if (m_params == 0)
operator=(src);
else {
init();
copy_core(src.m_params);
}
}
void params_ref::copy_core(params const * src) {
if (src == 0)
return;
svector<params::entry>::const_iterator it = src->m_entries.begin();
svector<params::entry>::const_iterator end = src->m_entries.end();
for (; it != end; ++it) {
switch (it->second.m_kind) {
case CPK_BOOL:
m_params->set_bool(it->first, it->second.m_bool_value);
break;
case CPK_UINT:
m_params->set_uint(it->first, it->second.m_uint_value);
break;
case CPK_DOUBLE:
m_params->set_double(it->first, it->second.m_double_value);
break;
case CPK_NUMERAL:
m_params->set_rat(it->first, *(it->second.m_rat_value));
break;
case CPK_SYMBOL:
m_params->set_sym(it->first, symbol::mk_symbol_from_c_ptr(it->second.m_sym_value));
break;
case CPK_STRING:
m_params->set_str(it->first, it->second.m_str_value);
break;
default:
UNREACHABLE();
break;
}
}
}
void params_ref::init() {
if (!m_params) {
m_params = alloc(params);
m_params->inc_ref();
}
else if (m_params->m_ref_count > 1) {
params * old = m_params;
m_params = alloc(params);
m_params->inc_ref();
copy_core(old);
old->dec_ref();
}
SASSERT(m_params->m_ref_count == 1);
}
bool params_ref::get_bool(symbol const & k, bool _default) const { return m_params ? m_params->get_bool(k, _default) : _default; }
bool params_ref::get_bool(char const * k, bool _default) const { return m_params ? m_params->get_bool(k, _default) : _default; }
unsigned params_ref::get_uint(symbol const & k, unsigned _default) const { return m_params ? m_params->get_uint(k, _default) : _default; }
unsigned params_ref::get_uint(char const * k, unsigned _default) const { return m_params ? m_params->get_uint(k, _default) : _default; }
double params_ref::get_double(symbol const & k, double _default) const { return m_params ? m_params->get_double(k, _default) : _default; }
double params_ref::get_double(char const * k, double _default) const { return m_params ? m_params->get_double(k, _default) : _default; }
char const * params_ref::get_str(symbol const & k, char const * _default) const { return m_params ? m_params->get_str(k, _default) : _default; }
char const * params_ref::get_str(char const * k, char const * _default) const { return m_params ? m_params->get_str(k, _default) : _default; }
rational params_ref::get_rat(symbol const & k, rational const & _default) const {
return m_params ? m_params->get_rat(k, _default) : _default;
}
rational params_ref::get_rat(char const * k, rational const & _default) const {
return m_params ? m_params->get_rat(k, _default) : _default;
}
symbol params_ref::get_sym(symbol const & k, symbol const & _default) const {
return m_params ? m_params->get_sym(k, _default) : _default;
}
symbol params_ref::get_sym(char const * k, symbol const & _default) const {
return m_params ? m_params->get_sym(k, _default) : _default;
}
bool params_ref::empty() const {
if (!m_params)
return true;
return m_params->empty();
}
bool params_ref::contains(symbol const & k) const {
if (!m_params)
return false;
return m_params->contains(k);
}
bool params_ref::contains(char const * k) const {
if (!m_params)
return false;
return m_params->contains(k);
}
void params_ref::reset() {
if (m_params)
m_params->reset();
}
void params_ref::reset(symbol const & k) {
if (m_params)
m_params->reset(k);
}
void params_ref::reset(char const * k) {
if (m_params)
m_params->reset(k);
}
void params_ref::set_bool(symbol const & k, bool v) {
init();
m_params->set_bool(k, v);
}
void params_ref::set_bool(char const * k, bool v) {
init();
m_params->set_bool(k, v);
}
void params_ref::set_uint(symbol const & k, unsigned v) {
init();
m_params->set_uint(k, v);
}
void params_ref::set_uint(char const * k, unsigned v) {
init();
m_params->set_uint(k, v);
}
void params_ref::set_double(symbol const & k, double v) {
init();
m_params->set_double(k, v);
}
void params_ref::set_double(char const * k, double v) {
init();
m_params->set_double(k, v);
}
void params_ref::set_str(symbol const & k, char const * v) {
init();
m_params->set_str(k, v);
}
void params_ref::set_str(char const * k, char const * v) {
init();
m_params->set_str(k, v);
}
void params_ref::set_rat(symbol const & k, rational const & v) {
init();
m_params->set_rat(k, v);
}
void params_ref::set_rat(char const * k, rational const & v) {
init();
m_params->set_rat(k, v);
}
void params_ref::set_sym(symbol const & k, symbol const & v) {
init();
m_params->set_sym(k, v);
}
void params_ref::set_sym(char const * k, symbol const & v) {
init();
m_params->set_sym(k, v);
}
void params::del_value(entry & e) {
switch (e.second.m_kind) {
case CPK_NUMERAL:
if (e.second.m_kind == CPK_NUMERAL)
dealloc(e.second.m_rat_value);
break;
default:
return;
}
}
#define TRAVERSE_ENTRIES(CODE) { \
svector<entry>::iterator it = m_entries.begin(); \
svector<entry>::iterator end = m_entries.end(); \
for (; it != end; ++it) { \
CODE \
} \
}
#define TRAVERSE_CONST_ENTRIES(CODE) { \
svector<entry>::const_iterator it = m_entries.begin(); \
svector<entry>::const_iterator end = m_entries.end(); \
for (; it != end; ++it) { \
CODE \
} \
}
void params::del_values() {
TRAVERSE_ENTRIES(del_value(*it););
}
#define CONTAINS(k) { \
if (empty()) \
return false; \
TRAVERSE_CONST_ENTRIES(if (it->first == k) return true;); \
return false; \
}
bool params::contains(symbol const & k) const {
CONTAINS(k);
}
bool params::contains(char const * k) const {
CONTAINS(k);
}
void params::reset() {
del_values();
m_entries.finalize();
SASSERT(empty());
}
#define RESET(k) { \
if (empty()) return; \
TRAVERSE_ENTRIES(if (it->first == k) { \
svector<entry>::iterator it2 = it; \
del_value(*it2); \
++it; \
for (; it != end; ++it, ++it2) { \
*it2 = *it; \
} \
m_entries.pop_back(); \
return; \
}); \
}
void params::reset(symbol const & k) {
RESET(k);
}
void params::reset(char const * k) {
RESET(k);
}
#define GET_VALUE(MATCH_CODE, KIND) { \
if (empty()) return _default; \
TRAVERSE_CONST_ENTRIES(if (it->first == k && it->second.m_kind == KIND) { \
MATCH_CODE \
}); \
return _default; \
}
#define GET_SIMPLE_VALUE(FIELD_NAME, KIND) GET_VALUE(return it->second.FIELD_NAME;, KIND)
bool params::get_bool(symbol const & k, bool _default) const {
GET_SIMPLE_VALUE(m_bool_value, CPK_BOOL);
}
bool params::get_bool(char const * k, bool _default) const {
GET_SIMPLE_VALUE(m_bool_value, CPK_BOOL);
}
unsigned params::get_uint(symbol const & k, unsigned _default) const {
GET_SIMPLE_VALUE(m_uint_value, CPK_UINT);
}
unsigned params::get_uint(char const * k, unsigned _default) const {
GET_SIMPLE_VALUE(m_uint_value, CPK_UINT);
}
double params::get_double(symbol const & k, double _default) const {
GET_SIMPLE_VALUE(m_double_value, CPK_DOUBLE);
}
double params::get_double(char const * k, double _default) const {
GET_SIMPLE_VALUE(m_double_value, CPK_DOUBLE);
}
char const * params::get_str(symbol const & k, char const * _default) const {
GET_SIMPLE_VALUE(m_str_value, CPK_STRING);
}
char const * params::get_str(char const * k, char const * _default) const {
GET_SIMPLE_VALUE(m_str_value, CPK_STRING);
}
rational params::get_rat(symbol const & k, rational const & _default) const {
if (empty()) return _default;
TRAVERSE_CONST_ENTRIES(if (it->first == k) {
if (it->second.m_kind == CPK_NUMERAL) {
return *(it->second.m_rat_value);
}
if (it->second.m_kind == CPK_UINT) {
return rational(static_cast<int>(it->second.m_uint_value));
}
});
return _default;
}
rational params::get_rat(char const * k, rational const & _default) const {
if (empty()) return _default;
TRAVERSE_CONST_ENTRIES(if (it->first == k) {
if (it->second.m_kind == CPK_NUMERAL) {
return *(it->second.m_rat_value);
}
if (it->second.m_kind == CPK_UINT) {
return rational(static_cast<int>(it->second.m_uint_value));
}
});
return _default;
}
symbol params::get_sym(symbol const & k, symbol const & _default) const {
GET_VALUE(return symbol::mk_symbol_from_c_ptr(it->second.m_sym_value);, CPK_SYMBOL);
}
symbol params::get_sym(char const * k, symbol const & _default) const {
GET_VALUE(return symbol::mk_symbol_from_c_ptr(it->second.m_sym_value);, CPK_SYMBOL);
}
#define SET_VALUE(MATCH_CODE, ADD_CODE) { \
TRAVERSE_ENTRIES(if (it->first == k) { \
MATCH_CODE \
return; \
}); \
ADD_CODE \
}
#define SET_SIMPLE_VALUE(FIELD_NAME, KIND) SET_VALUE({ \
del_value(*it); \
it->second.m_kind = KIND; \
it->second.FIELD_NAME = v; \
}, \
{ \
entry new_entry; \
new_entry.first = symbol(k); \
new_entry.second.m_kind = KIND; \
new_entry.second.FIELD_NAME = v; \
m_entries.push_back(new_entry); \
})
// setters
void params::set_bool(symbol const & k, bool v) {
SET_SIMPLE_VALUE(m_bool_value, CPK_BOOL);
}
void params::set_bool(char const * k, bool v) {
SET_SIMPLE_VALUE(m_bool_value, CPK_BOOL);
}
void params::set_uint(symbol const & k, unsigned v) {
SET_SIMPLE_VALUE(m_uint_value, CPK_UINT);
}
void params::set_uint(char const * k, unsigned v) {
SET_SIMPLE_VALUE(m_uint_value, CPK_UINT);
}
void params::set_double(symbol const & k, double v) {
SET_SIMPLE_VALUE(m_double_value, CPK_DOUBLE);
}
void params::set_double(char const * k, double v) {
SET_SIMPLE_VALUE(m_double_value, CPK_DOUBLE);
}
void params::set_str(symbol const & k, char const * v) {
SET_SIMPLE_VALUE(m_str_value, CPK_STRING);
}
void params::set_str(char const * k, char const * v) {
SET_SIMPLE_VALUE(m_str_value, CPK_STRING);
}
#define SET_RAT_VALUE() SET_VALUE({ \
if (it->second.m_kind != CPK_NUMERAL) { \
del_value(*it); \
it->second.m_kind = CPK_NUMERAL; \
it->second.m_rat_value = alloc(rational); \
} \
*(it->second.m_rat_value) = v; \
}, \
{ \
entry new_entry; \
new_entry.first = symbol(k); \
new_entry.second.m_kind = CPK_NUMERAL; \
new_entry.second.m_rat_value = alloc(rational); \
*(new_entry.second.m_rat_value) = v; \
m_entries.push_back(new_entry); \
})
void params::set_rat(symbol const & k, rational const & v) {
SET_RAT_VALUE();
}
void params::set_rat(char const * k, rational const & v) {
SET_RAT_VALUE();
}
#define SET_SYM_VALUE() SET_VALUE({ \
del_value(*it); \
it->second.m_kind = CPK_SYMBOL; \
it->second.m_sym_value = v.bare_str(); \
}, \
{ \
entry new_entry; \
new_entry.first = symbol(k); \
new_entry.second.m_kind = CPK_SYMBOL; \
new_entry.second.m_sym_value = v.bare_str(); \
m_entries.push_back(new_entry); \
})
void params::set_sym(symbol const & k, symbol const & v) {
SET_SYM_VALUE();
}
void params::set_sym(char const * k, symbol const & v) {
SET_SYM_VALUE();
}

112
src/util/params.h Normal file
View file

@ -0,0 +1,112 @@
/*++
Copyright (c) 2011 Microsoft Corporation
Module Name:
params.h
Abstract:
Parameters.
Author:
Leonardo (leonardo) 2011-04-22
Notes:
--*/
#ifndef _PARAMS_H_
#define _PARAMS_H_
#include"cmd_context_types.h"
#include"vector.h"
typedef cmd_arg_kind param_kind;
class params;
class param_descrs;
class params_ref {
params * m_params;
void init();
void copy_core(params const * p);
public:
params_ref():m_params(0) {}
params_ref(params_ref const & p);
~params_ref();
params_ref & operator=(params_ref const & p);
// copy params from p
void copy(params_ref const & src);
void append(params_ref const & src) { copy(src); }
bool get_bool(symbol const & k, bool _default) const;
bool get_bool(char const * k, bool _default) const;
unsigned get_uint(symbol const & k, unsigned _default) const;
unsigned get_uint(char const * k, unsigned _default) const;
double get_double(symbol const & k, double _default) const;
double get_double(char const * k, double _default) const;
char const * get_str(symbol const & k, char const * _default) const;
char const * get_str(char const * k, char const * _default) const;
rational get_rat(symbol const & k, rational const & _default) const;
rational get_rat(char const * k, rational const & _default) const;
symbol get_sym(symbol const & k, symbol const & _default) const;
symbol get_sym(char const * k, symbol const & _default) const;
bool empty() const;
bool contains(symbol const & k) const;
bool contains(char const * k) const;
void reset();
void reset(symbol const & k);
void reset(char const * k);
void set_bool(symbol const & k, bool v);
void set_bool(char const * k, bool v);
void set_uint(symbol const & k, unsigned v);
void set_uint(char const * k, unsigned v);
void set_double(symbol const & k, double v);
void set_double(char const * k, double v);
void set_str(symbol const & k, char const * v);
void set_str(char const * k, char const * v);
void set_rat(symbol const & k, rational const & v);
void set_rat(char const * k, rational const & v);
void set_sym(symbol const & k, symbol const & v);
void set_sym(char const * k, symbol const & v);
void display(std::ostream & out) const;
void validate(param_descrs const & p) const;
};
inline std::ostream & operator<<(std::ostream & out, params_ref const & ref) {
ref.display(out);
return out;
}
class param_descrs {
struct imp;
imp * m_imp;
public:
param_descrs();
~param_descrs();
void insert(char const * name, param_kind k, char const * descr);
void insert(symbol const & name, param_kind k, char const * descr);
void erase(char const * name);
void erase(symbol const & name);
param_kind get_kind(char const * name) const;
param_kind get_kind(symbol const & name) const;
void display(std::ostream & out, unsigned indent = 0) const;
unsigned size() const;
symbol get_param_name(unsigned idx) const;
};
void insert_max_memory(param_descrs & r);
void insert_max_steps(param_descrs & r);
void insert_produce_models(param_descrs & r);
void insert_produce_proofs(param_descrs & r);
void insert_timeout(param_descrs & r);
#endif

871
src/util/skip_list_base.h Normal file
View file

@ -0,0 +1,871 @@
/*++
Copyright (c) 2006 Microsoft Corporation
Module Name:
skip_list_base.h
Abstract:
<abstract>
Author:
Leonardo de Moura (leonardo) 2010-10-01.
Revision History:
WARNING: IT IS NOT SAFE TO STORE KEYS, VALUES in the SKIP_LIST that need non-default constructors/destructors.
--*/
#ifndef _SKIP_LIST_BASE_H_
#define _SKIP_LIST_BASE_H_
#include<memory.h>
#include"util.h"
#include"memory_manager.h"
#include"small_object_allocator.h"
#include"trace.h"
#ifdef _MSC_VER
#pragma warning(disable : 4200)
#endif
/*
This file defines a base class for implementing skip-list like data-structures.
This base class is relies on a manager for providing some basic services.
The manager is a template parameter.
A Skip-list manager is responsible for:
- Providing primitives for allocating/deallocating memory
void * allocate(size_t size);
void deallocate(size_t size, void* p);
- Generating random skip-list levels efficiently
unsigned random_level(unsigned max_level);
- Call-backs that will be invoked when a reference for a "value" stored in the skip-list is incremented/decremented.
void inc_ref_eh(value const & v);
void dec_ref_eh(value const & h);
*/
/**
\brief Base class for generating random_levels.
*/
class random_level_manager {
#define SL_BITS_IN_RANDOM 16
unsigned m_random_data;
unsigned m_random_bits:16;
unsigned m_random_left:16;
unsigned random_value() {
return ((m_random_data = m_random_data * 214013L + 2531011L) >> 16) & 0xffff;
}
void init_random() {
m_random_data = 0;
m_random_bits = random_value();
m_random_left = SL_BITS_IN_RANDOM/2;
}
public:
random_level_manager() {
init_random();
}
unsigned random_level(unsigned max_level) {
unsigned level = 1;
unsigned b;
do {
b = m_random_bits&3;
if (!b)
level++;
m_random_bits >>= 2;
m_random_left--;
if (m_random_left == 0) {
m_random_bits = random_value();
m_random_left = SL_BITS_IN_RANDOM/2;
}
} while (!b);
return (level > max_level ? max_level : level);
}
};
/**
\brief Basic skip-list manager.
The class is parametrized by the Value type that is stored in the skip-list.
*/
template<typename Value>
class sl_manager_base : public random_level_manager {
typedef Value value;
small_object_allocator m_alloc;
public:
void * allocate(size_t size) {
return m_alloc.allocate(size);
}
void deallocate(size_t size, void* p) {
m_alloc.deallocate(size, p);
}
void inc_ref_eh(value const & v) {
/* do nothing */
}
void dec_ref_eh(value const & h) {
/* do nothing */
}
};
#define SL_SIZE_NUM_BITS 12
#define SL_CAPACITY_NUM_BITS SL_SIZE_NUM_BITS
#define SL_MAX_CAPACITY ((1 << SL_SIZE_NUM_BITS) - 1)
#define SL_LEVEL_NUM_BITS 8
#define SL_MAX_LEVEL ((1 << SL_LEVEL_NUM_BITS) - 1)
COMPILE_TIME_ASSERT(SL_SIZE_NUM_BITS == SL_CAPACITY_NUM_BITS);
COMPILE_TIME_ASSERT(SL_SIZE_NUM_BITS + SL_CAPACITY_NUM_BITS + SL_LEVEL_NUM_BITS == 32);
/**
\brief Base (template) class for implementing skip-list like data-structures where
entries are stored in buckets to improve cache behavior.
The Traits template parameter must provide:
- a definition for the class Traits::manager
- a definition for the class Traits::entry which provides:
- a definition for the types key and value
- the methods:
key const & begin_key() const
key const & end_key() const
value const & val() const
void set_begin_key(key const & k)
void set_end_key(key const & k)
void set_val(value const & v)
void display(ostream & out) const
- the maximal number of levels Traits::max_level
- the maximal capacity of each bucket Traits::max_capacity
- the initial capacity of the first bucket Traits::initial_capacity
- flag for reference counting support Traits::ref_count. If this flag is true
the methods inc_ref_eh and dec_ref_eh in the manager object will be invoked.
- the methods
bool lt(key const & k1, key const & k2)
bool eq(key const & k1, key const & k2)
bool val_eq(value const & v1, value const & v2)
key succ(key const & k)
key pred(key const & k)
*/
template<typename Traits>
class skip_list_base : protected Traits {
protected:
typedef typename Traits::entry entry;
public:
typedef typename Traits::manager manager;
typedef typename entry::key key;
typedef typename entry::value value;
struct bucket {
unsigned m_size:SL_SIZE_NUM_BITS; //!< number of entries stored in the bucket.
unsigned m_capacity:SL_CAPACITY_NUM_BITS; //!< capacity (number of entries) that can be stored in the bucket.
unsigned m_level:SL_LEVEL_NUM_BITS;
char m_extra[0];
static unsigned get_obj_size(unsigned num_lvls, unsigned capacity) {
return sizeof(bucket) + num_lvls*sizeof(bucket*) + capacity*sizeof(entry);
}
entry * get_entries() { return reinterpret_cast<entry*>(m_extra); }
entry const * get_entries() const { return reinterpret_cast<entry const *>(m_extra); }
bucket ** next_vect() { return reinterpret_cast<bucket**>(get_entries() + m_capacity); }
bucket * const * next_vect() const { return reinterpret_cast<bucket* const *>(get_entries() + m_capacity); }
bucket(unsigned lvl, unsigned capacity = Traits::max_capacity):
m_size(0),
m_capacity(capacity),
m_level(lvl) {
memset(next_vect(), 0, sizeof(bucket*)*lvl);
}
unsigned level() const { return m_level; }
unsigned size() const { return m_size; }
unsigned capacity() const { return m_capacity; }
bool empty() const { return size() == 0; }
void set_size(unsigned sz) { m_size = sz; }
void shrink(unsigned delta) { m_size -= delta; }
void expand(unsigned delta) { m_size += delta; }
entry & first_entry() { SASSERT(!empty()); return get_entries()[0]; }
entry & last_entry() { SASSERT(!empty()); return get_entries()[size() - 1]; }
entry const & first_entry() const { SASSERT(!empty()); return get_entries()[0]; }
entry const & last_entry() const { SASSERT(!empty()); return get_entries()[size() - 1]; }
entry const & get(unsigned idx) const { SASSERT(idx < size()); return get_entries()[idx]; }
entry & get(unsigned idx) { SASSERT(idx < size()); return get_entries()[idx]; }
void set(unsigned idx, entry const & e) { SASSERT(idx < capacity()); get_entries()[idx] = e; }
bucket * get_next(unsigned idx) const { return next_vect()[idx]; }
void set_next(unsigned idx, bucket * bt) { SASSERT(idx < level()); next_vect()[idx] = bt; }
};
// Only the header bucket has zero entries.
bucket * m_header;
bucket * first_bucket() const {
return m_header->get_next(0);
}
#ifdef Z3DEBUG
/**
\brief (debugging only) Return the predecessor bucket of the given bucket.
\pre bt != m_header, and bt is a bucket of the list.
*/
bucket * pred_bucket(bucket * bt) const {
SASSERT(bt != m_header);
bucket * curr = m_header;
while (curr->get_next(0) != bt) {
curr = curr->get_next(0);
SASSERT(curr != 0); // bt is not in the list
}
return curr;
}
#endif
bool lt(key const & k1, key const & k2) const { return Traits::lt(k1, k2); }
bool gt(key const & k1, key const & k2) const { return lt(k2, k1); }
bool geq(key const & k1, key const & k2) const { return !lt(k1, k2); }
bool leq(key const & k1, key const & k2) const { return !gt(k1, k2); }
/**
\brief Create a new bucket of the given level.
*/
static bucket * mk_bucket(manager & m, unsigned lvl, unsigned capacity = Traits::max_capacity) {
void * mem = m.allocate(bucket::get_obj_size(lvl, capacity));
return new (mem) bucket(lvl, capacity);
}
static bucket * mk_header(manager & m, unsigned lvl) {
return mk_bucket(m, lvl, 0);
}
static void inc_ref(manager & m, value const & v) {
if (Traits::ref_count)
m.inc_ref_eh(v);
}
static void dec_ref(manager & m, value const & v) {
if (Traits::ref_count)
m.dec_ref_eh(v);
}
/**
\brief Invoke dec_ref_eh for each value stored in the bucket.
*/
static void dec_ref(manager & m, bucket * bt) {
if (Traits::ref_count) {
unsigned sz = bt->size();
for (unsigned i = 0; i < sz; i++)
m.dec_ref_eh(bt->get(i).val());
}
}
/**
\brief Deallocate the given bucket.
\remark This method invokes dec_ref_eh for each value in the bucket.
*/
template<bool DecRef>
static void deallocate_bucket(manager & m, bucket * bt) {
if (DecRef)
dec_ref(m, bt);
unsigned sz = bucket::get_obj_size(bt->level(), bt->capacity());
bt->~bucket();
m.deallocate(sz, bt);
}
/**
\brief Deallocate all buckets in the skip list.
\remark This method invokes dec_ref_eh for each value in the list.
*/
template<bool DecRef>
void deallocate_list(manager & m) {
bucket * curr = m_header;
while (curr != 0) {
bucket * old = curr;
curr = curr->get_next(0);
deallocate_bucket<DecRef>(m, old);
}
}
#ifdef Z3DEBUG
/**
\brief Check the following property
for all i \in [0, b->level()) . pred_vect[i]->get_next(i) == b
*/
bool check_pred_vect(bucket * bt, bucket * pred_vect[]) {
if (bt == 0)
return true;
for (unsigned i = 0; i < bt->level(); i++) {
SASSERT(pred_vect[i]->get_next(i) == bt);
}
return true;
}
#endif
/**
\brief Delete the given buffer and update the forward/next pointer of the buckets in pred_vect.
\remark This method invokes dec_ref_eh for each value in the bucket.
*/
void del_bucket(manager & m, bucket * bt, bucket * pred_vect[]) {
SASSERT(check_pred_vect(bt, pred_vect));
for (unsigned i = 0; i < bt->level(); i++)
pred_vect[i]->set_next(i, bt->get_next(i));
deallocate_bucket<true>(m, bt);
}
/**
\brief Update the \c pred_vect vector from levels [0, bt->level()).
That is, bt will be now the "predecessor" for these levels.
*/
static void update_predecessor_vector(bucket * pred_vect [], bucket * bt) {
unsigned lvl = bt->level();
for (unsigned i = 0; i < lvl; i++) {
pred_vect[i] = bt;
}
}
/**
\brief Similar to the previous method, but the updated vector is stored in new_pred_vect.
*/
void update_predecessor_vector(bucket * pred_vect[], bucket * bt, bucket * new_pred_vect[]) {
unsigned bt_lvl = bt->level();
for (unsigned i = 0; i < bt_lvl; i++) {
new_pred_vect[i] = bt;
}
unsigned list_lvl = level();
for (unsigned i = bt_lvl; i < list_lvl; i++) {
new_pred_vect[i] = pred_vect[i];
}
}
/**
\brief Return the list level.
*/
unsigned level() const {
return m_header->level();
}
/**
\brief Expand/Increase the number of levels in the header.
*/
void expand_header(manager & m, unsigned new_lvl) {
SASSERT(new_lvl > level());
bucket * new_header = mk_header(m, new_lvl);
// copy forward pointers of the old header.
unsigned old_lvl = level();
for (unsigned i = 0; i < old_lvl; i++)
new_header->set_next(i, m_header->get_next(i));
// update header
deallocate_bucket<false>(m, m_header);
m_header = new_header;
}
/**
\brief Increase list level to lvl if lvl > level()
*/
void update_list_level(manager & m, unsigned lvl) {
if (lvl > level()) {
expand_header(m, lvl);
}
}
/**
\brief Increase list level (and store m_header in the new levels in pred_vect) if lvl > level().
*/
void update_list_level(manager & m, unsigned lvl, bucket * pred_vect[]) {
if (lvl > level()) {
bucket * old_header = m_header;
unsigned old_lvl = m_header->level();
expand_header(m, lvl);
for (unsigned i = 0; i < old_lvl; i++) {
if (pred_vect[i] == old_header)
pred_vect[i] = m_header;
}
for (unsigned i = old_lvl; i < lvl; i++) {
pred_vect[i] = m_header;
}
SASSERT(level() == lvl);
}
}
/**
\brief Add first entry to the list.
\remark This method will invoke inc_ref_eh for e.val()
*/
void insert_first_entry(manager & m, entry const & e) {
unsigned lvl = m.random_level(Traits::max_level);
bucket * new_bucket = mk_bucket(m, lvl, Traits::initial_capacity);
update_list_level(m, lvl);
for (unsigned i = 0; i < lvl; i++) {
m_header->set_next(i, new_bucket);
}
inc_ref(m, e.val());
new_bucket->set_size(1);
new_bucket->set(0, e);
}
/**
\brief Expand the capacity of the first-bucket in a skip-list with only one bucket.
This method assumes the capacity of the first-bucket < Traits::max_capacity
*/
void expand_first_bucket(manager & m) {
bucket * f = first_bucket();
SASSERT(f != 0);
SASSERT(f->get_next(0) == 0);
SASSERT(f->capacity() < Traits::max_capacity);
unsigned old_capacity = f->capacity();
SASSERT(old_capacity > 0);
unsigned new_capacity = old_capacity * 2;
if (new_capacity > Traits::max_capacity)
new_capacity = Traits::max_capacity;
unsigned lvl = f->level();
bucket * new_f = mk_bucket(m, lvl, new_capacity);
unsigned sz = f->size();
new_f->set_size(sz);
for (unsigned i = 0; i < sz; i++)
new_f->set(i, f->get(i));
for (unsigned i = 0; i < lvl; i++)
m_header->set_next(i, new_f);
deallocate_bucket<false>(m, f);
SASSERT(first_bucket() == new_f);
}
/**
\brief Create a new bucket and divide the elements in bt between bt and the new bucket.
*/
void splice(manager & m, bucket * bt, bucket * pred_vect[]) {
SASSERT(bt->capacity() == Traits::max_capacity);
unsigned bt_lvl = bt->level();
unsigned new_bucket_lvl = m.random_level(Traits::max_level);
bucket * new_bucket = mk_bucket(m, new_bucket_lvl);
update_list_level(m, new_bucket_lvl, pred_vect);
unsigned _lvl = std::min(bt_lvl, new_bucket_lvl);
for (unsigned i = 0; i < _lvl; i++) {
new_bucket->set_next(i, bt->get_next(i));
bt->set_next(i, new_bucket);
}
for (unsigned i = bt_lvl; i < new_bucket_lvl; i++) {
new_bucket->set_next(i, pred_vect[i]->get_next(i));
pred_vect[i]->set_next(i, new_bucket);
}
unsigned old_size = bt->size();
SASSERT(old_size >= 2);
unsigned mid = old_size/2;
new_bucket->set_size(old_size - mid);
unsigned i = mid;
unsigned j = 0;
for (; i < old_size; i++, j++) {
new_bucket->set(j, bt->get(i));
}
bt->set_size(mid);
SASSERT(!bt->empty());
SASSERT(!new_bucket->empty());
}
/**
\brief Open space at position idx. The number of entries in bt is increased by one.
\remark This method will *NOT* invoke inc_ref_eh
*/
void open_space(bucket * bt, unsigned idx) {
SASSERT(bt->size() < bt->capacity());
SASSERT(idx <= bt->size());
unsigned i = bt->size();
while (i > idx) {
bt->set(i, bt->get(i-1));
i--;
}
bt->expand(1);
}
/**
\brief Open two spaces at position idx. The number of entries in bt is increased by one.
\remark This method will *NOT* invoke inc_ref_eh
*/
void open_2spaces(bucket * bt, unsigned idx) {
SASSERT(bt->size() < bt->capacity() - 1);
SASSERT(idx <= bt->size());
unsigned i = bt->size() + 1;
unsigned end = idx + 1;
while (i > end) {
bt->set(i, bt->get(i-2));
i--;
}
bt->expand(2);
}
/**
\brief Delete entry at position idx.
\remark This method will invoke dec_ref_eh for the value stored in entry at position idx.
*/
void del_entry(manager & m, bucket * bt, unsigned idx) {
SASSERT(!bt->empty());
SASSERT(idx < bt->size());
dec_ref(m, bt->get(idx).val());
unsigned sz = bt->size();
for (unsigned i = idx; i < sz - 1; i++) {
bt->set(i, bt->get(i+1));
}
bt->shrink(1);
}
/**
\brief Create a copy of the skip list.
\remark This method will invoke inc_ref_eh for all values copied.
*/
void clone_core(manager & m, skip_list_base * new_list) const {
bucket * pred_vect[Traits::max_level];
unsigned lvl = level();
new_list->update_list_level(m, lvl);
bucket * new_header = new_list->m_header;
for (unsigned i = 0; i < lvl; i++)
pred_vect[i] = new_header;
bucket * curr = first_bucket();
while (curr != 0) {
unsigned curr_lvl = curr->level();
bucket * new_bucket = new_list->mk_bucket(m, curr_lvl, curr->capacity());
for (unsigned i = 0; i < curr_lvl; i++) {
pred_vect[i]->set_next(i, new_bucket);
pred_vect[i] = new_bucket;
}
unsigned curr_sz = curr->size();
for (unsigned i = 0; i < curr_sz; i++) {
entry const & curr_entry = curr->get(i);
inc_ref(m, curr_entry.val());
new_bucket->set(i, curr_entry);
}
new_bucket->set_size(curr_sz);
curr = curr->get_next(0);
}
}
public:
skip_list_base():
m_header(0) {
SASSERT(Traits::max_capacity >= 2);
SASSERT(Traits::initial_capacity >= 2);
SASSERT(Traits::initial_capacity <= Traits::max_capacity);
SASSERT(Traits::max_level >= 1);
SASSERT(Traits::max_capacity <= SL_MAX_CAPACITY);
SASSERT(Traits::max_level <= SL_MAX_LEVEL);
}
skip_list_base(manager & m):
m_header(0) {
SASSERT(Traits::max_capacity >= 2);
SASSERT(Traits::initial_capacity >= 2);
SASSERT(Traits::initial_capacity <= Traits::max_capacity);
SASSERT(Traits::max_level >= 1);
SASSERT(Traits::max_capacity <= SL_MAX_CAPACITY);
SASSERT(Traits::max_level <= SL_MAX_LEVEL);
init(m);
}
~skip_list_base() {
SASSERT(m_header == 0);
}
void deallocate(manager & m) {
deallocate_list<true>(m);
m_header = 0;
}
/**
\brief Deallocate the list but do not invoke dec_ref_eh.
*/
void deallocate_no_decref(manager & m) {
deallocate_list<false>(m);
m_header = 0;
}
/**
\brief Initialize a list that was created using the default constructor.
It can be used also to initialized a list deallocated using the method #deallocate.
*/
void init(manager & m) {
SASSERT(m_header == 0);
m_header = mk_header(m, 1);
}
/**
\brief Remove all elements from the skip-list.
*/
void reset(manager & m) {
deallocate_list<true>(m);
m_header = mk_header(m, 1);
}
/**
\brief Remove all elements from the skip-list without invoking dec_ref_eh.
*/
void reset_no_decref(manager & m) {
deallocate_list<false>(m);
m_header = mk_header(m, 1);
}
/**
\brief Return true if the list is empty.
*/
bool empty() const {
SASSERT(m_header != 0);
return first_bucket() == 0;
}
protected:
/**
\brief Return the position of the bucket in the skip list.
*/
unsigned get_bucket_idx(bucket const * bt) const {
bucket * curr = m_header;
unsigned pos = 0;
while (curr != 0) {
if (curr == bt)
return pos;
pos++;
curr = curr->get_next(0);
}
UNREACHABLE();
return pos;
}
/**
\brief Display the given entry.
*/
void display(std::ostream & out, entry const & e) const {
e.display(out);
}
/**
\brief Display a reference to the given bucket.
*/
void display_bucket_ref(std::ostream & out, bucket const * bt) const {
if (bt == 0)
out << "NIL";
else
out << "#" << get_bucket_idx(bt);
}
/**
\brief Display the predecessor vector.
*/
void display_predecessor_vector(std::ostream & out, bucket const * const pred_vect[]) const {
for (unsigned i = 0; i < level(); i++) {
out << i << ": ";
display_bucket_ref(out, pred_vect[i]);
if (pred_vect[i]) {
out << " -> ";
display_bucket_ref(out, pred_vect[i]->get_next(i));
}
out << "\n";
}
}
/**
\brief Display the successors of the given bucket.
*/
void display_successors(std::ostream & out, bucket const * bt) const {
out << "[";
for (unsigned i = 0; i < bt->level(); i++) {
if (i > 0) out << ", ";
display_bucket_ref(out, bt->get_next(i));
}
out << "]";
}
/**
\brief Display the given bucket.
*/
void display(std::ostream & out, bucket const * bt) const {
if (bt == 0) {
out << "NIL\n";
return;
}
out << "bucket ";
display_bucket_ref(out, bt);
out << ", capacity: " << bt->capacity() << "\n";
out << "successors: ";
display_successors(out, bt);
out << "\n";
out << "entries:\n";
for (unsigned i = 0; i < bt->size(); i++) {
display(out, bt->get(i));
out << "\n";
}
out << "----------\n";
}
public:
/**
\brief Dump the skip list for debugging purposes.
It assumes that key and value types implement operator <<.
*/
void display_physical(std::ostream & out) const {
out << "{\nskip-list level: " << m_header->level() << "\n";
bucket * curr = m_header;
while (curr != 0) {
display(out, curr);
curr = curr->get_next(0);
}
out << "}\n";
}
void display(std::ostream & out) const {
bucket * curr = m_header;
while (curr != 0) {
unsigned sz = curr->size();
for (unsigned i = 0; i < sz; i++) {
if (i > 0)
out << " ";
curr->get(i).display(out);
}
curr = curr->get_next(0);
}
}
protected:
/**
\brief Return true if bucket b2 can be reached from b1 following get_next(i) pointers
*/
bool is_reachable_at_i(bucket const * bt1, bucket const * bt2, unsigned i) const {
bucket * curr = bt1->get_next(i);
while (curr != 0) {
if (curr == bt2)
return true;
curr = curr->get_next(i);
}
return false;
}
protected:
static void display_size_info_core(std::ostream & out, unsigned cls_size) {
out << "sizeof root: " << cls_size << "\n";
out << "bucket max capacity: " << Traits::max_capacity << "\n";
out << "bucket max level: " << Traits::max_level << "\n";
out << "sizeof(bucket): " << sizeof(bucket) << " + " << sizeof(bucket*) << "*lvl + " << sizeof(entry) << "*capacity\n";
out << "sizeof(usual bucket): " << (sizeof(bucket) + sizeof(entry)*Traits::max_capacity) << " + " << sizeof(bucket*) << "*lvl\n";
out << "sizeof(max. bucket): " << (sizeof(bucket) + sizeof(entry)*Traits::max_capacity + sizeof(bucket*)*Traits::max_level) << "\n";
out << "sizeof(entry): " << sizeof(entry) << "\n";
out << "sizeof empty: " << cls_size + bucket::get_obj_size(1, 0) << "\n";;
out << "sizeof singleton: ["
<< (cls_size + bucket::get_obj_size(1, 0) + bucket::get_obj_size(1, Traits::initial_capacity)) << ", "
<< (cls_size +
bucket::get_obj_size(Traits::max_level, 0) +
bucket::get_obj_size(Traits::max_level, Traits::max_capacity)) << "]\n";
}
public:
/**
\brief Return true if skip-list has more than k buckets (not considering the header).
\remark This method is for debugging purposes.
*/
bool has_more_than_k_buckets(unsigned k) const {
bucket * curr = first_bucket();
while (curr != 0 && k > 0) {
curr = curr->get_next(0);
k--;
}
return curr != 0;
}
/**
\brief Return true if the skip-list has more than k entries.
*/
bool has_more_than_k_entries(unsigned k) const {
bucket * curr = first_bucket();
while (curr != 0 && k >= curr->size()) {
k -= curr->size();
curr = curr->get_next(0);
}
SASSERT(curr == 0 || curr->size() > k);
return curr != 0;
}
protected:
/**
\brief Return the amount of memory consumed by the list.
*/
unsigned memory_core(unsigned cls_size) const {
unsigned r = 0;
r += cls_size;
bucket * curr = m_header;
while (curr != 0) {
r += bucket::get_obj_size(curr->level(), curr->capacity());
curr = curr->get_next(0);
}
return r;
}
public:
/**
\brief Compress the buckets of the skip-list.
Make sure that all, but the last bucket, have at least \c load entries.
\remark If load > Traits::max_capacity, then it assumes load = Traits::max_capacity.
*/
void compress(manager & m, unsigned load = Traits::max_capacity/2) {
if (load > Traits::max_capacity)
load = Traits::max_capacity;
bucket * pred_vect[Traits::max_level];
update_predecessor_vector(pred_vect, m_header);
bucket * curr = first_bucket();
while (curr != 0) {
update_predecessor_vector(pred_vect, curr);
bucket * next = curr->get_next(0);
while (curr->size() < load && next != 0) {
// steal entries of the successor bucket.
unsigned deficit = load - curr->size();
unsigned next_size = next->size();
if (next_size <= deficit) {
for (unsigned i = 0, j = curr->size(); i < next_size; i++, j++) {
curr->set(j, next->get(i));
}
curr->expand(next_size);
bucket * new_next = next->get_next(0);
del_bucket(m, next, pred_vect);
next = new_next;
SASSERT(curr->size() <= load);
}
else {
for (unsigned i = 0, j = curr->size(); i < deficit; i++, j++) {
curr->set(j, next->get(i));
}
curr->expand(deficit);
for (unsigned i = deficit, j = 0; i < next_size; i++, j++) {
next->set(j, next->get(i));
}
next->set_size(next_size - deficit);
SASSERT(curr->size() == load);
}
}
curr = curr->get_next(0);
}
}
void swap(skip_list_base & other) {
bucket * tmp = m_header;
m_header = other.m_header;
other.m_header = tmp;
}
};
#endif

View file

@ -20,7 +20,7 @@ Notes:
#include"map.h"
#include"str_hashtable.h"
#include"buffer.h"
#include"ast_smt2_pp.h"
#include"smt2_util.h"
#include<iomanip>
void statistics::update(char const * key, unsigned inc) {

74
src/util/z3_exception.cpp Normal file
View file

@ -0,0 +1,74 @@
/*++
Copyright (c) 2011 Microsoft Corporation
Module Name:
z3_exception.cpp
Abstract:
Generic Z3 exception
Author:
Leonardo (leonardo) 2012-04-12
Notes:
--*/
#include<sstream>
#include<stdarg.h>
#include<sstream>
#include"z3_exception.h"
#include"warning.h"
#include"error_codes.h"
#include"debug.h"
unsigned z3_exception::error_code() const {
return ERR_OK;
}
bool z3_exception::has_error_code() const {
return error_code() != ERR_OK;
}
z3_error::z3_error(unsigned error_code):m_error_code(error_code) {
SASSERT(error_code != 0);
}
char const * z3_error::msg() const {
switch (m_error_code) {
case ERR_MEMOUT: return "out of memory";
case ERR_TIMEOUT: return "timeout";
case ERR_PARSER: return "parser error";
case ERR_UNSOUNDNESS: return "unsoundess";
case ERR_INCOMPLETENESS: return "incompleteness";
case ERR_INI_FILE: return "invalid INI file";
case ERR_NOT_IMPLEMENTED_YET: return "not implemented yet";
case ERR_OPEN_FILE: return "open file";
case ERR_CMD_LINE: return "invalid command line";
case ERR_INTERNAL_FATAL: return "internal error";
case ERR_TYPE_CHECK: return "type error";
default: return "unknown error";
}
}
unsigned z3_error::error_code() const {
return m_error_code;
}
default_exception::default_exception(char const* msg, ...) {
std::stringstream out;
va_list args;
va_start(args, msg);
format2ostream(out, msg, args);
va_end(args);
m_msg = out.str();
}
default_exception::default_exception(std::string const & msg): m_msg(msg) {
}
char const * default_exception::msg() const {
return m_msg.c_str();
}

49
src/util/z3_exception.h Normal file
View file

@ -0,0 +1,49 @@
/*++
Copyright (c) 2011 Microsoft Corporation
Module Name:
z3_exception.h
Abstract:
Generic Z3 exception
Author:
Leonardo (leonardo) 2011-04-28
Notes:
--*/
#ifndef _Z3_EXCEPTION_H_
#define _Z3_EXCEPTION_H_
#include<string>
class z3_exception {
public:
virtual ~z3_exception() {}
virtual char const * msg() const = 0;
virtual unsigned error_code() const;
bool has_error_code() const;
};
class z3_error : public z3_exception {
unsigned m_error_code;
public:
z3_error(unsigned error_code);
virtual char const * msg() const;
virtual unsigned error_code() const;
};
class default_exception : public z3_exception {
std::string m_msg;
public:
default_exception(std::string const& msg);
default_exception(char const* msg, ...);
virtual ~default_exception() {}
virtual char const * msg() const;
};
#endif

38
src/util/z3_omp.h Normal file
View file

@ -0,0 +1,38 @@
/*++
Copyright (c) 2012 Microsoft Corporation
Module Name:
z3_omp.h
Abstract:
Wrapper for OMP functions and data-structures
Author:
Leonardo (leonardo) 2012-01-05
Notes:
--*/
#ifndef _Z3_OMP_H
#define _Z3_OMP_H
#ifndef _NO_OMP_
#include"omp.h"
#else
#define omp_in_parallel() false
#define omp_set_num_threads(SZ) ((void)0)
#define omp_get_thread_num() 0
#define omp_get_num_procs() 1
#define omp_set_nested(V) ((void)0)
#define omp_init_nest_lock(L) ((void) 0)
#define omp_destroy_nest_lock(L) ((void) 0)
#define omp_set_nest_lock(L) ((void) 0)
#define omp_unset_nest_lock(L) ((void) 0)
struct omp_nest_lock_t {
};
#endif
#endif