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:
parent
2c464d413d
commit
8a6997960a
68 changed files with 167 additions and 170 deletions
586
src/ast/arith_decl_plugin.cpp
Normal file
586
src/ast/arith_decl_plugin.cpp
Normal 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
348
src/ast/arith_decl_plugin.h
Normal 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_ */
|
||||
|
570
src/ast/array_decl_plugin.cpp
Normal file
570
src/ast/array_decl_plugin.cpp
Normal 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, ¶m);
|
||||
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, ¶m);
|
||||
//
|
||||
// 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, ¶m));
|
||||
}
|
||||
|
||||
|
||||
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, ¶m);
|
||||
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, ¶m);
|
||||
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
170
src/ast/array_decl_plugin.h
Normal 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, ¶m, 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
3057
src/ast/ast.cpp
Normal file
File diff suppressed because it is too large
Load diff
2342
src/ast/ast.h
Normal file
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
160
src/ast/ast_list.h
Normal 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
315
src/ast/ast_ll_pp.cpp
Normal 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
57
src/ast/ast_ll_pp.h
Normal 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
516
src/ast/ast_pp.cpp
Normal 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
53
src/ast/ast_pp.h
Normal 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
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
116
src/ast/ast_smt2_pp.h
Normal 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
140
src/ast/ast_util.cpp
Normal 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
99
src/ast/ast_util.h
Normal 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
840
src/ast/bv_decl_plugin.cpp
Normal 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
405
src/ast/bv_decl_plugin.h
Normal 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_ */
|
||||
|
944
src/ast/datatype_decl_plugin.cpp
Normal file
944
src/ast/datatype_decl_plugin.cpp
Normal 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";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
200
src/ast/datatype_decl_plugin.h
Normal file
200
src/ast/datatype_decl_plugin.h
Normal 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
745
src/ast/dl_decl_plugin.cpp
Normal 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
217
src/ast/dl_decl_plugin.h
Normal 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_ */
|
||||
|
545
src/ast/float_decl_plugin.cpp
Normal file
545
src/ast/float_decl_plugin.cpp
Normal 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
243
src/ast/float_decl_plugin.h
Normal 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
274
src/ast/for_each_ast.h
Normal 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
212
src/ast/format.cpp
Normal 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
197
src/ast/format.h
Normal 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
148
src/ast/pp.cpp
Normal 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
34
src/ast/pp.h
Normal 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
57
src/ast/pp_params.cpp
Normal 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
46
src/ast/pp_params.h
Normal 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
47
src/ast/recurse_expr.h
Normal 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
109
src/ast/recurse_expr_def.h
Normal 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
265
src/ast/seq_decl_plugin.cpp
Normal 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, ¶m);
|
||||
}
|
||||
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, ¶mA);
|
||||
sort* reA = m.mk_sort(m_family_id, RE_SORT, 1, ¶mA);
|
||||
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
120
src/ast/seq_decl_plugin.h
Normal 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
140
src/ast/shared_occs.cpp
Normal 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
81
src/ast/shared_occs.h
Normal 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
|
3117
src/polynomial/algebraic_numbers.cpp
Normal file
3117
src/polynomial/algebraic_numbers.cpp
Normal file
File diff suppressed because it is too large
Load diff
493
src/polynomial/algebraic_numbers.h
Normal file
493
src/polynomial/algebraic_numbers.h
Normal 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
|
152
src/polynomial/linear_eq_solver.h
Normal file
152
src/polynomial/linear_eq_solver.h
Normal 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
|
7386
src/polynomial/polynomial.cpp
Normal file
7386
src/polynomial/polynomial.cpp
Normal file
File diff suppressed because it is too large
Load diff
1380
src/polynomial/polynomial.h
Normal file
1380
src/polynomial/polynomial.h
Normal file
File diff suppressed because it is too large
Load diff
235
src/polynomial/polynomial_cache.cpp
Normal file
235
src/polynomial/polynomial_cache.cpp
Normal 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);
|
||||
}
|
||||
};
|
44
src/polynomial/polynomial_cache.h
Normal file
44
src/polynomial/polynomial_cache.h
Normal 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
|
1143
src/polynomial/polynomial_factorization.cpp
Normal file
1143
src/polynomial/polynomial_factorization.cpp
Normal file
File diff suppressed because it is too large
Load diff
65
src/polynomial/polynomial_factorization.h
Normal file
65
src/polynomial/polynomial_factorization.h
Normal 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):1853–1859, 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
|
72
src/polynomial/polynomial_primes.h
Normal file
72
src/polynomial/polynomial_primes.h
Normal 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
|
50
src/polynomial/polynomial_var2value.h
Normal file
50
src/polynomial/polynomial_var2value.h
Normal 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
|
112
src/polynomial/sexpr2upolynomial.cpp
Normal file
112
src/polynomial/sexpr2upolynomial.cpp
Normal 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);
|
||||
}
|
33
src/polynomial/sexpr2upolynomial.h
Normal file
33
src/polynomial/sexpr2upolynomial.h
Normal 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
|
3131
src/polynomial/upolynomial.cpp
Normal file
3131
src/polynomial/upolynomial.cpp
Normal file
File diff suppressed because it is too large
Load diff
922
src/polynomial/upolynomial.h
Normal file
922
src/polynomial/upolynomial.h
Normal 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
|
1300
src/polynomial/upolynomial_factorization.cpp
Normal file
1300
src/polynomial/upolynomial_factorization.cpp
Normal file
File diff suppressed because it is too large
Load diff
96
src/polynomial/upolynomial_factorization.h
Normal file
96
src/polynomial/upolynomial_factorization.h
Normal 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):1853–1859, 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
|
420
src/polynomial/upolynomial_factorization_int.h
Normal file
420
src/polynomial/upolynomial_factorization_int.h
Normal 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):1853–1859, 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
|
44
src/util/cmd_context_types.cpp
Normal file
44
src/util/cmd_context_types.cpp
Normal 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;
|
||||
}
|
119
src/util/cmd_context_types.h
Normal file
119
src/util/cmd_context_types.h
Normal 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
87
src/util/cooperate.cpp
Normal 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
50
src/util/cooperate.h
Normal 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
37
src/util/error_codes.h
Normal 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_ */
|
||||
|
|
@ -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
716
src/util/params.cpp
Normal 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
112
src/util/params.h
Normal 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
871
src/util/skip_list_base.h
Normal 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
|
|
@ -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
74
src/util/z3_exception.cpp
Normal 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
49
src/util/z3_exception.h
Normal 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
38
src/util/z3_omp.h
Normal 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
|
Loading…
Add table
Add a link
Reference in a new issue