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

Merge branch 'upstream-master' into release-1.0

Conflicts:
	src/cmd_context/check_logic.cpp
	src/cmd_context/cmd_context.cpp
	src/cmd_context/cmd_context.h
	src/smt/params/smt_params_helper.pyg
	src/smt/smt_context.cpp
This commit is contained in:
Murphy Berzish 2017-02-18 15:04:44 -05:00
commit 235ea79043
588 changed files with 21784 additions and 15202 deletions

View file

@ -264,6 +264,10 @@ public:
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_le(func_decl const * n) const { return is_decl_of(n, m_afid, OP_LE); }
bool is_ge(func_decl const * n) const { return is_decl_of(n, m_afid, OP_GE); }
bool is_lt(func_decl const * n) const { return is_decl_of(n, m_afid, OP_LT); }
bool is_gt(func_decl const * n) const { return is_decl_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); }
@ -284,6 +288,18 @@ public:
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(get_sort(n)); }
bool is_sin(expr const* n) const { return is_app_of(n, m_afid, OP_SIN); }
bool is_cos(expr const* n) const { return is_app_of(n, m_afid, OP_COS); }
bool is_tan(expr const* n) const { return is_app_of(n, m_afid, OP_TAN); }
bool is_asin(expr const* n) const { return is_app_of(n, m_afid, OP_ASIN); }
bool is_acos(expr const* n) const { return is_app_of(n, m_afid, OP_ACOS); }
bool is_atan(expr const* n) const { return is_app_of(n, m_afid, OP_ATAN); }
bool is_asinh(expr const* n) const { return is_app_of(n, m_afid, OP_ASINH); }
bool is_acosh(expr const* n) const { return is_app_of(n, m_afid, OP_ACOSH); }
bool is_atanh(expr const* n) const { return is_app_of(n, m_afid, OP_ATANH); }
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); }
MATCH_UNARY(is_uminus);
MATCH_UNARY(is_to_real);
MATCH_UNARY(is_to_int);
@ -300,8 +316,16 @@ public:
MATCH_BINARY(is_idiv);
MATCH_BINARY(is_power);
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); }
MATCH_UNARY(is_sin);
MATCH_UNARY(is_asin);
MATCH_UNARY(is_asinh);
MATCH_UNARY(is_cos);
MATCH_UNARY(is_acos);
MATCH_UNARY(is_acosh);
MATCH_UNARY(is_tan);
MATCH_UNARY(is_atan);
MATCH_UNARY(is_atanh);
};
class arith_util : public arith_recognizers {
@ -348,6 +372,9 @@ public:
app * mk_int(int i) {
return mk_numeral(rational(i), true);
}
app * mk_real(int i) {
return mk_numeral(rational(i), false);
}
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); }
@ -422,5 +449,103 @@ public:
expr_ref mk_add_simplify(unsigned sz, expr* const* args);
};
inline app_ref mk_numeral(rational const& r, app_ref const& x) {
arith_util a(x.get_manager());
return app_ref(a.mk_numeral(r, r.is_int() && a.is_int(x)), x.get_manager());
}
inline app_ref operator+(app_ref const& x, app_ref const& y) {
arith_util a(x.get_manager());
return app_ref(a.mk_add(x, y), x.get_manager());
}
inline app_ref operator+(app_ref const& x, rational const& y) {
return x + mk_numeral(y, x);
}
inline app_ref operator+(app_ref const& x, int y) {
return x + rational(y);
}
inline app_ref operator+(rational const& x, app_ref const& y) {
return mk_numeral(x, y) + y;
}
inline app_ref operator+(int x, app_ref const& y) {
return rational(x) + y;
}
inline app_ref operator-(app_ref const& x, app_ref const& y) {
arith_util a(x.get_manager());
return app_ref(a.mk_sub(x, y), x.get_manager());
}
inline app_ref operator-(app_ref const& x, rational const& y) {
return x - mk_numeral(y, x);
}
inline app_ref operator-(app_ref const& x, int y) {
return x - rational(y);
}
inline app_ref operator-(rational const& x, app_ref const& y) {
return mk_numeral(x, y) - y;
}
inline app_ref operator-(int x, app_ref const& y) {
return rational(x) - y;
}
inline app_ref operator*(app_ref const& x, app_ref const& y) {
arith_util a(x.get_manager());
return app_ref(a.mk_mul(x, y), x.get_manager());
}
inline app_ref operator*(app_ref const& x, rational const& y) {
return x * mk_numeral(y, x);
}
inline app_ref operator*(rational const& x, app_ref const& y) {
return mk_numeral(x, y) * y;
}
inline app_ref operator*(app_ref const& x, int y) {
return x * rational(y);
}
inline app_ref operator*(int x, app_ref const& y) {
return rational(x) * y;
}
inline app_ref operator<=(app_ref const& x, app_ref const& y) {
arith_util a(x.get_manager());
return app_ref(a.mk_le(x, y), x.get_manager());
}
inline app_ref operator<=(app_ref const& x, rational const& y) {
return x <= mk_numeral(y, x);
}
inline app_ref operator<=(app_ref const& x, int y) {
return x <= rational(y);
}
inline app_ref operator>=(app_ref const& x, app_ref const& y) {
arith_util a(x.get_manager());
return app_ref(a.mk_ge(x, y), x.get_manager());
}
inline app_ref operator<(app_ref const& x, app_ref const& y) {
arith_util a(x.get_manager());
return app_ref(a.mk_lt(x, y), x.get_manager());
}
inline app_ref operator>(app_ref const& x, app_ref const& y) {
arith_util a(x.get_manager());
return app_ref(a.mk_gt(x, y), x.get_manager());
}
#endif /* ARITH_DECL_PLUGIN_H_ */

View file

@ -522,7 +522,7 @@ void array_decl_plugin::get_sort_names(svector<builtin_name>& sort_names, symbol
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) {
if (logic == symbol::null || logic == symbol("HORN")) {
// 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));

View file

@ -80,7 +80,10 @@ void parameter::del_eh(ast_manager & m, family_id fid) {
}
else if (is_external()) {
SASSERT(fid != null_family_id);
m.get_plugin(fid)->del(*this);
decl_plugin * plugin = m.get_plugin(fid);
if (plugin) {
plugin->del(*this);
}
}
}
@ -1391,6 +1394,22 @@ void ast_manager::init() {
inc_ref(m_false);
}
template<typename T>
static void mark_array_ref(ast_mark& mark, unsigned sz, T * const * a) {
for(unsigned i = 0; i < sz; i++) {
mark.mark(a[i], true);
}
}
static void mark_array_ref(ast_mark& mark, unsigned sz, parameter const * a) {
for(unsigned i = 0; i < sz; i++) {
if (a[i].is_ast()) {
mark.mark(a[i].get_ast(), true);
}
}
}
ast_manager::~ast_manager() {
SASSERT(is_format_manager() || !m_family_manager.has_family(symbol("format")));
@ -1407,29 +1426,72 @@ ast_manager::~ast_manager() {
}
it = m_plugins.begin();
for (; it != end; ++it) {
if (*it)
if (*it)
dealloc(*it);
}
DEBUG_CODE({
if (!m_ast_table.empty())
std::cout << "ast_manager LEAKED: " << m_ast_table.size() << std::endl;
});
#if 1
DEBUG_CODE({
m_plugins.reset();
while (!m_ast_table.empty()) {
DEBUG_CODE(std::cout << "ast_manager LEAKED: " << m_ast_table.size() << std::endl;);
ptr_vector<ast> roots;
ast_mark mark;
ast_table::iterator it_a = m_ast_table.begin();
ast_table::iterator end_a = m_ast_table.end();
for (; it_a != end_a; ++it_a) {
ast* a = (*it_a);
std::cout << "Leaked: ";
if (is_sort(a)) {
std::cout << to_sort(a)->get_name() << "\n";
ast* n = (*it_a);
switch (n->get_kind()) {
case AST_SORT: {
sort_info* info = to_sort(n)->get_info();
if (info != 0) {
mark_array_ref(mark, info->get_num_parameters(), info->get_parameters());
}
break;
}
else {
std::cout << mk_ll_pp(a, *this, false) << "id: " << a->get_id() << "\n";
case AST_FUNC_DECL: {
func_decl_info* info = to_func_decl(n)->get_info();
if (info != 0) {
mark_array_ref(mark, info->get_num_parameters(), info->get_parameters());
}
mark_array_ref(mark, to_func_decl(n)->get_arity(), to_func_decl(n)->get_domain());
mark.mark(to_func_decl(n)->get_range(), true);
break;
}
case AST_APP:
mark.mark(to_app(n)->get_decl(), true);
mark_array_ref(mark, to_app(n)->get_num_args(), to_app(n)->get_args());
break;
case AST_VAR:
mark.mark(to_var(n)->get_sort(), true);
break;
case AST_QUANTIFIER:
mark_array_ref(mark, to_quantifier(n)->get_num_decls(), to_quantifier(n)->get_decl_sorts());
mark.mark(to_quantifier(n)->get_expr(), true);
mark_array_ref(mark, to_quantifier(n)->get_num_patterns(), to_quantifier(n)->get_patterns());
mark_array_ref(mark, to_quantifier(n)->get_num_no_patterns(), to_quantifier(n)->get_no_patterns());
break;
}
}
it_a = m_ast_table.begin();
for (; it_a != end_a; ++it_a) {
ast* n = *it_a;
if (!mark.is_marked(n)) {
roots.push_back(n);
}
}
SASSERT(!roots.empty());
for (unsigned i = 0; i < roots.size(); ++i) {
ast* a = roots[i];
DEBUG_CODE(
std::cout << "Leaked: ";
if (is_sort(a)) {
std::cout << to_sort(a)->get_name() << "\n";
}
else {
std::cout << mk_ll_pp(a, *this, false) << "id: " << a->get_id() << "\n";
});
a->m_ref_count = 0;
delete_node(a);
}
});
#endif
}
if (m_format_manager != 0)
dealloc(m_format_manager);
if (m_trace_stream_owner) {
@ -1813,8 +1875,8 @@ void ast_manager::delete_node(ast * n) {
dec_array_ref(worklist, to_quantifier(n)->get_num_patterns(), to_quantifier(n)->get_patterns());
dec_array_ref(worklist, to_quantifier(n)->get_num_no_patterns(), to_quantifier(n)->get_no_patterns());
break;
default:
break;
default:
break;
}
if (m_debug_ref_count) {
m_debug_free_indices.insert(n->m_id,0);
@ -1971,7 +2033,7 @@ bool ast_manager::check_sorts(ast const * n) const {
return true;
}
catch (ast_exception & ex) {
warning_msg(ex.msg());
warning_msg("%s", ex.msg());
return false;
}
}
@ -2270,6 +2332,22 @@ bool ast_manager::is_pattern(expr const * n) const {
return true;
}
bool ast_manager::is_pattern(expr const * n, ptr_vector<expr> &args) {
if (!is_app_of(n, m_pattern_family_id, OP_PATTERN)) {
return false;
}
for (unsigned i = 0; i < to_app(n)->get_num_args(); ++i) {
expr *arg = to_app(n)->get_arg(i);
if (!is_app(arg)) {
return false;
}
args.push_back(arg);
}
return true;
}
quantifier * ast_manager::mk_quantifier(bool forall, unsigned num_decls, sort * const * decl_sorts, symbol const * decl_names,
expr * body, int weight , symbol const & qid, symbol const & skid,
unsigned num_patterns, expr * const * patterns,
@ -2569,6 +2647,8 @@ proof * ast_manager::mk_modus_ponens(proof * p1, proof * p2) {
CTRACE("mk_modus_ponens", to_app(get_fact(p2))->get_arg(0) != get_fact(p1),
tout << mk_pp(get_fact(p1), *this) << "\n" << mk_pp(get_fact(p2), *this) << "\n";);
SASSERT(to_app(get_fact(p2))->get_arg(0) == get_fact(p1));
CTRACE("mk_modus_ponens", !is_ground(p2) && !has_quantifiers(p2), tout << "Non-ground: " << mk_pp(p2, *this) << "\n";);
CTRACE("mk_modus_ponens", !is_ground(p1) && !has_quantifiers(p1), tout << "Non-ground: " << mk_pp(p1, *this) << "\n";);
if (is_reflexivity(p2))
return p1;
expr * f = to_app(get_fact(p2))->get_arg(1);
@ -2945,7 +3025,10 @@ proof * ast_manager::mk_unit_resolution(unsigned num_proofs, proof * const * pro
for (unsigned i = 0; i < num_proofs; i++) tout << mk_pp(get_fact(proofs[i]), *this) << "\n";
tout << "===>\n";
tout << mk_pp(new_fact, *this) << "\n";);
SASSERT(num_proofs == cls_sz || (num_proofs == cls_sz + 1 && is_false(new_fact)));
//
// typically: num_proofs == cls_sz || (num_proofs == cls_sz + 1 && is_false(new_fact))
// but formula could have repeated literals that are merged in the clausal representation.
//
unsigned num_matches = 0;
for (unsigned i = 0; i < cls_sz; i++) {
expr * lit = cls->get_arg(i);

View file

@ -1848,6 +1848,8 @@ public:
bool is_pattern(expr const * n) const;
bool is_pattern(expr const *n, ptr_vector<expr> &args);
public:
quantifier * mk_quantifier(bool forall, unsigned num_decls, sort * const * decl_sorts, symbol const * decl_names, expr * body,

View file

@ -1180,6 +1180,21 @@ void mk_smt2_format(func_decl * f, smt2_pp_environment & env, params_ref const &
pr(f, r);
}
void mk_smt2_format(unsigned sz, expr * const* es, smt2_pp_environment & env, params_ref const & p,
unsigned num_vars, char const * var_prefix,
format_ref & r, sbuffer<symbol> & var_names) {
smt2_printer pr(env, p);
ast_manager & m = env.get_manager();
format_ref_vector fmts(fm(m));
for (unsigned i = 0; i < sz; ++i) {
format_ref fr(fm(m));
pr(es[i], num_vars, var_prefix, fr, var_names);
fmts.push_back(fr);
}
r = mk_seq<format**, f2f>(m, fmts.c_ptr(), fmts.c_ptr() + fmts.size(), f2f());
}
std::ostream & ast_smt2_pp(std::ostream & out, expr * n, smt2_pp_environment & env, params_ref const & p, unsigned indent,
unsigned num_vars, char const * var_prefix) {
ast_manager & m = env.get_manager();
@ -1214,6 +1229,18 @@ std::ostream & ast_smt2_pp(std::ostream & out, func_decl * f, smt2_pp_environmen
return out;
}
std::ostream & ast_smt2_pp(std::ostream & out, unsigned sz, expr * const* es, smt2_pp_environment & env, params_ref const & p, unsigned indent,
unsigned num_vars, char const * var_prefix) {
ast_manager & m = env.get_manager();
format_ref r(fm(m));
sbuffer<symbol> var_names;
mk_smt2_format(sz, es, env, p, num_vars, var_prefix, r, var_names);
if (indent > 0)
r = mk_indent(m, indent, r.get());
pp(out, r.get(), m, p);
return out;
}
mk_ismt2_pp::mk_ismt2_pp(ast * t, ast_manager & m, params_ref const & p, unsigned indent, unsigned num_vars, char const * var_prefix):
m_ast(t),
m_manager(m),
@ -1233,13 +1260,16 @@ mk_ismt2_pp::mk_ismt2_pp(ast * t, ast_manager & m, unsigned indent, unsigned num
}
std::ostream& operator<<(std::ostream& out, mk_ismt2_pp const & p) {
smt2_pp_environment_dbg env(p.m_manager);
smt2_pp_environment_dbg env(p.m_manager);
if (is_expr(p.m_ast)) {
ast_smt2_pp(out, to_expr(p.m_ast), env, p.m_params, p.m_indent, p.m_num_vars, p.m_var_prefix);
}
else if (is_sort(p.m_ast)) {
ast_smt2_pp(out, to_sort(p.m_ast), env, p.m_params, p.m_indent);
}
else if (p.m_ast == 0) {
out << "null";
}
else {
SASSERT(is_func_decl(p.m_ast));
ast_smt2_pp(out, to_func_decl(p.m_ast), env, p.m_params, p.m_indent);
@ -1264,19 +1294,15 @@ std::ostream& operator<<(std::ostream& out, sort_ref const& e) {
}
std::ostream& operator<<(std::ostream& out, expr_ref_vector const& e) {
for (unsigned i = 0; i < e.size(); ++i) {
out << mk_ismt2_pp(e[i], e.get_manager());
if (i + 1 < e.size()) out << "; ";
}
return out;
smt2_pp_environment_dbg env(e.get_manager());
params_ref p;
return ast_smt2_pp(out, e.size(), e.c_ptr(), env, p, 0, 0, 0);
}
std::ostream& operator<<(std::ostream& out, app_ref_vector const& e) {
for (unsigned i = 0; i < e.size(); ++i) {
out << mk_ismt2_pp(e[i], e.get_manager());
if (i + 1 < e.size()) out << "; ";
}
return out;
smt2_pp_environment_dbg env(e.get_manager());
params_ref p;
return ast_smt2_pp(out, e.size(), (expr*const*)e.c_ptr(), env, p, 0, 0, 0);
}
std::ostream& operator<<(std::ostream& out, func_decl_ref_vector const& e) {

View file

@ -732,7 +732,8 @@ void datatype_decl_plugin::get_op_names(svector<builtin_name> & op_names, symbol
datatype_util::datatype_util(ast_manager & m):
m_manager(m),
m_family_id(m.mk_family_id("datatype")),
m_asts(m) {
m_asts(m),
m_start(0) {
}
datatype_util::~datatype_util() {
@ -807,11 +808,11 @@ func_decl * datatype_util::get_non_rec_constructor_core(sort * ty, ptr_vector<so
// 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 sz = constructors->size();
++m_start;
for (unsigned j = 0; j < sz; ++j) {
func_decl * c = (*constructors)[(j + m_start) % sz];
unsigned num_args = c->get_arity();
unsigned i = 0;
for (; i < num_args; i++) {
@ -823,9 +824,8 @@ func_decl * datatype_util::get_non_rec_constructor_core(sort * ty, ptr_vector<so
return c;
}
// step 2)
it = constructors->begin();
for (; it != end; ++it) {
func_decl * c = *it;
for (unsigned j = 0; j < sz; ++j) {
func_decl * c = (*constructors)[(j + m_start) % sz];
TRACE("datatype_util_bug", tout << "non_rec_constructor c: " << c->get_name() << "\n";);
unsigned num_args = c->get_arity();
unsigned i = 0;
@ -933,6 +933,25 @@ bool datatype_util::is_recursive(sort * ty) {
return r;
}
bool datatype_util::is_enum_sort(sort* s) {
if (!is_datatype(s)) {
return false;
}
bool r = false;
if (m_is_enum.find(s, r))
return r;
ptr_vector<func_decl> const& cnstrs = *get_datatype_constructors(s);
r = true;
for (unsigned i = 0; r && i < cnstrs.size(); ++i) {
r = cnstrs[i]->get_arity() == 0;
}
m_is_enum.insert(s, r);
m_asts.push_back(s);
return r;
}
void datatype_util::reset() {
m_datatype2constructors.reset();
m_datatype2nonrec_constructor.reset();
@ -941,9 +960,11 @@ void datatype_util::reset() {
m_recognizer2constructor.reset();
m_accessor2constructor.reset();
m_is_recursive.reset();
m_is_enum.reset();
std::for_each(m_vectors.begin(), m_vectors.end(), delete_proc<ptr_vector<func_decl> >());
m_vectors.reset();
m_asts.reset();
++m_start;
}
/**

View file

@ -173,9 +173,11 @@ class datatype_util {
obj_map<func_decl, func_decl *> m_recognizer2constructor;
obj_map<func_decl, func_decl *> m_accessor2constructor;
obj_map<sort, bool> m_is_recursive;
obj_map<sort, bool> m_is_enum;
ast_ref_vector m_asts;
ptr_vector<ptr_vector<func_decl> > m_vectors;
unsigned m_start;
func_decl * get_non_rec_constructor_core(sort * ty, ptr_vector<sort> & forbidden_set);
func_decl * get_constructor(sort * ty, unsigned c_id);
@ -184,6 +186,8 @@ public:
~datatype_util();
ast_manager & get_manager() const { return m_manager; }
bool is_datatype(sort * s) const { return is_sort_of(s, m_family_id, DATATYPE_SORT); }
bool is_enum_sort(sort* s);
bool is_recursive(sort * ty);
bool is_constructor(func_decl * f) const { return is_decl_of(f, m_family_id, OP_DT_CONSTRUCTOR); }
bool is_recognizer(func_decl * f) const { return is_decl_of(f, m_family_id, OP_DT_RECOGNISER); }

View file

@ -324,7 +324,7 @@ namespace datalog {
if (!is_rel_sort(r, sorts)) {
return 0;
}
unsigned index0;
unsigned index0 = 0;
sort* last_sort = 0;
SASSERT(num_params > 0);
for (unsigned i = 0; i < num_params; ++i) {
@ -461,7 +461,7 @@ namespace datalog {
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");
m_manager->raise_exception("second parameter should be a finite domain sort");
return 0;
}
sort* s = to_sort(ps.get_ast());

View file

@ -31,6 +31,14 @@ public:
virtual ~i_expr_pred() {}
};
class i_sort_pred {
public:
virtual bool operator()(sort* s) = 0;
virtual ~i_sort_pred() {}
};
/**
\brief Memoizing predicate functor on sub-expressions.

View file

@ -0,0 +1,558 @@
/*++
Copyright (c) 2012 Microsoft Corporation
Module Name:
bv2fpa_converter.cpp
Abstract:
Model conversion for fpa2bv_converter
Author:
Christoph (cwinter) 2016-10-15
Notes:
--*/
#include<math.h>
#include"ast_smt2_pp.h"
#include"well_sorted.h"
#include"th_rewriter.h"
#include"fpa_rewriter.h"
#include"bv2fpa_converter.h"
bv2fpa_converter::bv2fpa_converter(ast_manager & m) :
m(m),
m_fpa_util(m),
m_bv_util(m),
m_th_rw(m) {
}
bv2fpa_converter::bv2fpa_converter(ast_manager & m, fpa2bv_converter & conv) :
m(m),
m_fpa_util(m),
m_bv_util(m),
m_th_rw(m) {
for (obj_map<func_decl, expr*>::iterator it = conv.m_const2bv.begin();
it != conv.m_const2bv.end();
it++)
{
m_const2bv.insert(it->m_key, it->m_value);
m.inc_ref(it->m_key);
m.inc_ref(it->m_value);
}
for (obj_map<func_decl, expr*>::iterator it = conv.m_rm_const2bv.begin();
it != conv.m_rm_const2bv.end();
it++)
{
m_rm_const2bv.insert(it->m_key, it->m_value);
m.inc_ref(it->m_key);
m.inc_ref(it->m_value);
}
for (obj_map<func_decl, func_decl*>::iterator it = conv.m_uf2bvuf.begin();
it != conv.m_uf2bvuf.end();
it++)
{
m_uf2bvuf.insert(it->m_key, it->m_value);
m.inc_ref(it->m_key);
m.inc_ref(it->m_value);
}
for (obj_map<func_decl, std::pair<app*, app*> >::iterator it = conv.m_min_max_specials.begin();
it != conv.m_min_max_specials.end();
it++) {
m_specials.insert(it->m_key, it->m_value);
m.inc_ref(it->m_key);
m.inc_ref(it->m_value.first);
m.inc_ref(it->m_value.second);
}
}
bv2fpa_converter::~bv2fpa_converter() {
dec_ref_map_key_values(m, m_const2bv);
dec_ref_map_key_values(m, m_rm_const2bv);
dec_ref_map_key_values(m, m_uf2bvuf);
for (obj_map<func_decl, std::pair<app*, app*> >::iterator it = m_specials.begin();
it != m_specials.end();
it++) {
m.dec_ref(it->m_key);
m.dec_ref(it->m_value.first);
m.dec_ref(it->m_value.second);
}
}
expr_ref bv2fpa_converter::convert_bv2fp(sort * s, expr * sgn, expr * exp, expr * sig) {
unsynch_mpz_manager & mpzm = m_fpa_util.fm().mpz_manager();
unsynch_mpq_manager & mpqm = m_fpa_util.fm().mpq_manager();
expr_ref res(m);
mpf fp_val;
unsigned ebits = m_fpa_util.get_ebits(s);
unsigned sbits = m_fpa_util.get_sbits(s);
unsigned sgn_sz = 1;
unsigned exp_sz = ebits;
unsigned sig_sz = sbits - 1;
rational sgn_q(0), sig_q(0), exp_q(0);
if (sgn) m_bv_util.is_numeral(sgn, sgn_q, sgn_sz);
if (exp) m_bv_util.is_numeral(exp, exp_q, exp_sz);
if (sig) m_bv_util.is_numeral(sig, sig_q, sig_sz);
// un-bias exponent
rational exp_unbiased_q;
exp_unbiased_q = exp_q - m_fpa_util.fm().m_powers2.m1(ebits - 1);
mpz sig_z; mpf_exp_t exp_z;
mpzm.set(sig_z, sig_q.to_mpq().numerator());
exp_z = mpzm.get_int64(exp_unbiased_q.to_mpq().numerator());
m_fpa_util.fm().set(fp_val, ebits, sbits, !mpqm.is_zero(sgn_q.to_mpq()), exp_z, sig_z);
mpzm.del(sig_z);
res = m_fpa_util.mk_value(fp_val);
TRACE("bv2fpa", tout << "[" << mk_ismt2_pp(sgn, m) <<
" " << mk_ismt2_pp(exp, m) <<
" " << mk_ismt2_pp(sig, m) << "] == " <<
mk_ismt2_pp(res, m) << std::endl;);
m_fpa_util.fm().del(fp_val);
return res;
}
expr_ref bv2fpa_converter::convert_bv2fp(model_core * mc, sort * s, app * bv) {
SASSERT(m_bv_util.is_bv(bv));
unsigned ebits = m_fpa_util.get_ebits(s);
unsigned sbits = m_fpa_util.get_sbits(s);
unsigned bv_sz = sbits + ebits;
expr_ref bv_num(m);
if (m_bv_util.is_numeral(bv))
bv_num = bv;
else if (!mc->eval(bv->get_decl(), bv_num))
bv_num = m_bv_util.mk_numeral(0, m_bv_util.get_bv_size(bv));
expr_ref sgn(m), exp(m), sig(m);
sgn = m_bv_util.mk_extract(bv_sz - 1, bv_sz - 1, bv_num);
exp = m_bv_util.mk_extract(bv_sz - 2, sbits - 1, bv_num);
sig = m_bv_util.mk_extract(sbits - 2, 0, bv_num);
expr_ref v_sgn(m), v_exp(m), v_sig(m);
m_th_rw(sgn, v_sgn);
m_th_rw(exp, v_exp);
m_th_rw(sig, v_sig);
return convert_bv2fp(s, v_sgn, v_exp, v_sig);
}
expr_ref bv2fpa_converter::convert_bv2rm(expr * bv_rm) {
expr_ref res(m);
rational bv_val(0);
unsigned sz = 0;
if (m_bv_util.is_numeral(bv_rm, bv_val, sz)) {
SASSERT(bv_val.is_uint64());
switch (bv_val.get_uint64()) {
case BV_RM_TIES_TO_AWAY: res = m_fpa_util.mk_round_nearest_ties_to_away(); break;
case BV_RM_TIES_TO_EVEN: res = m_fpa_util.mk_round_nearest_ties_to_even(); break;
case BV_RM_TO_NEGATIVE: res = m_fpa_util.mk_round_toward_negative(); break;
case BV_RM_TO_POSITIVE: res = m_fpa_util.mk_round_toward_positive(); break;
case BV_RM_TO_ZERO:
default: res = m_fpa_util.mk_round_toward_zero();
}
}
return res;
}
expr_ref bv2fpa_converter::convert_bv2rm(model_core * mc, app * val) {
expr_ref res(m);
if (val) {
expr_ref eval_v(m);
if (m_bv_util.is_numeral(val))
res = convert_bv2rm(val);
else if (mc->eval(val->get_decl(), eval_v))
res = convert_bv2rm(eval_v);
else
res = m_fpa_util.mk_round_toward_zero();
}
return res;
}
expr_ref bv2fpa_converter::rebuild_floats(model_core * mc, sort * s, app * e) {
expr_ref result(m);
TRACE("bv2fpa", tout << "rebuild floats in " << mk_ismt2_pp(s, m) << " for ";
if (e) tout << mk_ismt2_pp(e, m);
else tout << "nil";
tout << std::endl; );
if (m_fpa_util.is_float(s)) {
if (e == 0)
result = m_fpa_util.mk_pzero(s);
else if (m_fpa_util.is_numeral(e))
result = e;
else {
SASSERT(m_bv_util.is_bv(e) && m_bv_util.get_bv_size(e) == (m_fpa_util.get_ebits(s) + m_fpa_util.get_sbits(s)));
result = convert_bv2fp(mc, s, e);
}
}
else if (m_fpa_util.is_rm(s)) {
if (e == 0)
result = m_fpa_util.mk_round_toward_zero();
else if (m_fpa_util.is_rm_numeral(e))
result = e;
else {
SASSERT(m_bv_util.is_bv(e) && m_bv_util.get_bv_size(e) == 3);
result = convert_bv2rm(mc, e);
}
}
else if (is_app(e)) {
app * a = to_app(e);
expr_ref_vector new_args(m);
for (unsigned i = 0; i < a->get_num_args(); i++)
new_args.push_back(rebuild_floats(mc, a->get_decl()->get_domain()[i], to_app(a->get_arg(i))));
result = m.mk_app(a->get_decl(), new_args.size(), new_args.c_ptr());
}
return result;
}
bv2fpa_converter::array_model bv2fpa_converter::convert_array_func_interp(model_core * mc, func_decl * f, func_decl * bv_f) {
SASSERT(f->get_arity() == 0);
array_util arr_util(m);
array_model am(m);
sort_ref_vector array_domain(m);
unsigned arity = f->get_range()->get_num_parameters()-1;
expr_ref as_arr_mdl(m);
as_arr_mdl = mc->get_const_interp(bv_f);
if (as_arr_mdl == 0) return am;
TRACE("bv2fpa", tout << "arity=0 func_interp for " << mk_ismt2_pp(f, m) << " := " << mk_ismt2_pp(as_arr_mdl, m) << std::endl;);
SASSERT(arr_util.is_as_array(as_arr_mdl));
for (unsigned i = 0; i < arity; i++)
array_domain.push_back(to_sort(f->get_range()->get_parameter(i).get_ast()));
sort * rng = to_sort(f->get_range()->get_parameter(arity).get_ast());
bv_f = arr_util.get_as_array_func_decl(to_app(as_arr_mdl));
am.new_float_fd = m.mk_fresh_func_decl(arity, array_domain.c_ptr(), rng);
am.new_float_fi = convert_func_interp(mc, am.new_float_fd, bv_f);
am.bv_fd = bv_f;
am.result = arr_util.mk_as_array(f->get_range(), am.new_float_fd);
return am;
}
func_interp * bv2fpa_converter::convert_func_interp(model_core * mc, func_decl * f, func_decl * bv_f) {
SASSERT(f->get_arity() > 0);
func_interp * result = 0;
sort * rng = f->get_range();
sort * const * dmn = f->get_domain();
unsigned arity = bv_f->get_arity();
func_interp * bv_fi = mc->get_func_interp(bv_f);
if (bv_fi != 0) {
fpa_rewriter rw(m);
expr_ref ai(m);
result = alloc(func_interp, m, arity);
for (unsigned i = 0; i < bv_fi->num_entries(); i++) {
func_entry const * bv_fe = bv_fi->get_entry(i);
expr * const * bv_args = bv_fe->get_args();
expr_ref_buffer new_args(m);
for (unsigned j = 0; j < arity; j++) {
sort * ft_dj = dmn[j];
expr * bv_aj = bv_args[j];
ai = rebuild_floats(mc, ft_dj, to_app(bv_aj));
m_th_rw(ai);
new_args.push_back(ai);
}
expr_ref bv_fres(m), ft_fres(m);
bv_fres = bv_fe->get_result();
ft_fres = rebuild_floats(mc, rng, to_app(bv_fres));
m_th_rw(ft_fres);
result->insert_new_entry(new_args.c_ptr(), ft_fres);
}
app_ref bv_els(m);
expr_ref ft_els(m);
bv_els = (app*)bv_fi->get_else();
ft_els = rebuild_floats(mc, rng, bv_els);
m_th_rw(ft_els);
result->set_else(ft_els);
}
return result;
}
void bv2fpa_converter::convert_consts(model_core * mc, model_core * target_model, obj_hashtable<func_decl> & seen) {
for (obj_map<func_decl, expr*>::iterator it = m_const2bv.begin();
it != m_const2bv.end();
it++)
{
func_decl * var = it->m_key;
app * val = to_app(it->m_value);
SASSERT(m_fpa_util.is_float(var->get_range()));
SASSERT(var->get_range()->get_num_parameters() == 2);
unsigned ebits = m_fpa_util.get_ebits(var->get_range());
unsigned sbits = m_fpa_util.get_sbits(var->get_range());
app * a0 = to_app(val->get_arg(0));
expr_ref v0(m), v1(m), v2(m);
#ifdef Z3DEBUG
app * a1 = to_app(val->get_arg(1));
app * a2 = to_app(val->get_arg(2));
v0 = mc->get_const_interp(a0->get_decl());
v1 = mc->get_const_interp(a1->get_decl());
v2 = mc->get_const_interp(a2->get_decl());
#else
expr * bv = mc->get_const_interp(to_app(to_app(a0)->get_arg(0))->get_decl());
if (bv == 0) {
v0 = m_bv_util.mk_numeral(0, 1);
v1 = m_bv_util.mk_numeral(0, ebits);
v2 = m_bv_util.mk_numeral(0, sbits-1);
}
else {
unsigned bv_sz = m_bv_util.get_bv_size(bv);
v0 = m_bv_util.mk_extract(bv_sz-1, bv_sz-1, bv);
v1 = m_bv_util.mk_extract(bv_sz-2, sbits-1, bv);
v2 = m_bv_util.mk_extract(sbits-2, 0, bv);
}
#endif
if (!v0) v0 = m_bv_util.mk_numeral(0, 1);
if (!v1) v1 = m_bv_util.mk_numeral(0, ebits);
if (!v2) v2 = m_bv_util.mk_numeral(0, sbits-1);
expr_ref sgn(m), exp(m), sig(m);
m_th_rw(v0, sgn);
m_th_rw(v1, exp);
m_th_rw(v2, sig);
SASSERT(val->is_app_of(m_fpa_util.get_family_id(), OP_FPA_FP));
#ifdef Z3DEBUG
SASSERT(to_app(val->get_arg(0))->get_decl()->get_arity() == 0);
SASSERT(to_app(val->get_arg(1))->get_decl()->get_arity() == 0);
SASSERT(to_app(val->get_arg(2))->get_decl()->get_arity() == 0);
seen.insert(to_app(val->get_arg(0))->get_decl());
seen.insert(to_app(val->get_arg(1))->get_decl());
seen.insert(to_app(val->get_arg(2))->get_decl());
#else
SASSERT(a->get_arg(0)->get_kind() == OP_EXTRACT);
SASSERT(to_app(a->get_arg(0))->get_arg(0)->get_kind() == OP_EXTRACT);
seen.insert(to_app(to_app(val->get_arg(0))->get_arg(0))->get_decl());
#endif
if (!sgn && !sig && !exp)
continue;
expr_ref cv(m);
cv = convert_bv2fp(var->get_range(), sgn, exp, sig);
target_model->register_decl(var, cv);
TRACE("bv2fpa", tout << var->get_name() << " == " << mk_ismt2_pp(cv, m) << std::endl;);
}
}
void bv2fpa_converter::convert_rm_consts(model_core * mc, model_core * target_model, obj_hashtable<func_decl> & seen) {
for (obj_map<func_decl, expr*>::iterator it = m_rm_const2bv.begin();
it != m_rm_const2bv.end();
it++)
{
func_decl * var = it->m_key;
SASSERT(m_fpa_util.is_rm(var->get_range()));
expr * val = it->m_value;
SASSERT(m_fpa_util.is_bv2rm(val));
expr * bvval = to_app(val)->get_arg(0);
expr_ref fv(m);
fv = convert_bv2rm(mc, to_app(bvval));
TRACE("bv2fpa", tout << var->get_name() << " == " << mk_ismt2_pp(fv, m) << ")" << std::endl;);
target_model->register_decl(var, fv);
seen.insert(to_app(bvval)->get_decl());
}
}
void bv2fpa_converter::convert_min_max_specials(model_core * mc, model_core * target_model, obj_hashtable<func_decl> & seen) {
for (obj_map<func_decl, std::pair<app*, app*> >::iterator it = m_specials.begin();
it != m_specials.end();
it++) {
func_decl * f = it->m_key;
app * pn_cnst = it->m_value.first;
app * np_cnst = it->m_value.second;
expr_ref pzero(m), nzero(m);
pzero = m_fpa_util.mk_pzero(f->get_range());
nzero = m_fpa_util.mk_nzero(f->get_range());
expr_ref pn(m), np(m);
if (!mc->eval(pn_cnst->get_decl(), pn)) pn = pzero;
if (!mc->eval(np_cnst->get_decl(), np)) np = pzero;
seen.insert(pn_cnst->get_decl());
seen.insert(np_cnst->get_decl());
rational pn_num, np_num;
unsigned bv_sz;
m_bv_util.is_numeral(pn, pn_num, bv_sz);
m_bv_util.is_numeral(np, np_num, bv_sz);
func_interp * flt_fi = alloc(func_interp, m, f->get_arity());
expr * pn_args[2] = { pzero, nzero };
if (pn != np) flt_fi->insert_new_entry(pn_args, (pn_num.is_one() ? nzero : pzero));
flt_fi->set_else(np_num.is_one() ? nzero : pzero);
target_model->register_decl(f, flt_fi);
TRACE("bv2fpa", tout << "fp.min/fp.max special: " << std::endl <<
mk_ismt2_pp(f, m) << " == " << mk_ismt2_pp(flt_fi->get_interp(), m) << std::endl;);
}
}
void bv2fpa_converter::convert_uf2bvuf(model_core * mc, model_core * target_model, obj_hashtable<func_decl> & seen) {
for (obj_map<func_decl, func_decl*>::iterator it = m_uf2bvuf.begin();
it != m_uf2bvuf.end();
it++) {
seen.insert(it->m_value);
func_decl * f = it->m_key;
if (f->get_arity() == 0)
{
array_util au(m);
if (au.is_array(f->get_range())) {
array_model am = convert_array_func_interp(mc, f, it->m_value);
if (am.new_float_fd) target_model->register_decl(am.new_float_fd, am.new_float_fi);
if (am.result) target_model->register_decl(f, am.result);
if (am.bv_fd) seen.insert(am.bv_fd);
}
else {
// Just keep.
SASSERT(!m_fpa_util.is_float(f->get_range()) && !m_fpa_util.is_rm(f->get_range()));
expr_ref var(m), val(m);
if (mc->eval(it->m_value, val))
target_model->register_decl(f, val);
}
}
else {
func_interp * fmv = convert_func_interp(mc, f, it->m_value);
if (fmv) target_model->register_decl(f, fmv);
}
}
}
void bv2fpa_converter::display(std::ostream & out) {
out << "(fpa2bv-model-converter";
for (obj_map<func_decl, expr*>::iterator it = m_const2bv.begin();
it != m_const2bv.end();
it++) {
const symbol & n = it->m_key->get_name();
out << "\n (" << n << " ";
unsigned indent = n.size() + 4;
out << mk_ismt2_pp(it->m_value, m, indent) << ")";
}
for (obj_map<func_decl, expr*>::iterator it = m_rm_const2bv.begin();
it != m_rm_const2bv.end();
it++) {
const symbol & n = it->m_key->get_name();
out << "\n (" << n << " ";
unsigned indent = n.size() + 4;
out << mk_ismt2_pp(it->m_value, m, indent) << ")";
}
for (obj_map<func_decl, func_decl*>::iterator it = m_uf2bvuf.begin();
it != m_uf2bvuf.end();
it++) {
const symbol & n = it->m_key->get_name();
out << "\n (" << n << " ";
unsigned indent = n.size() + 4;
out << mk_ismt2_pp(it->m_value, m, indent) << ")";
}
for (obj_map<func_decl, std::pair<app*, app*> >::iterator it = m_specials.begin();
it != m_specials.end();
it++) {
const symbol & n = it->m_key->get_name();
out << "\n (" << n << " ";
unsigned indent = n.size() + 4;
out << mk_ismt2_pp(it->m_value.first, m, indent) << "; " <<
mk_ismt2_pp(it->m_value.second, m, indent) << ")";
}
out << ")";
}
bv2fpa_converter * bv2fpa_converter::translate(ast_translation & translator) {
bv2fpa_converter * res = alloc(bv2fpa_converter, translator.to());
for (obj_map<func_decl, expr*>::iterator it = m_const2bv.begin();
it != m_const2bv.end();
it++)
{
func_decl * k = translator(it->m_key);
expr * v = translator(it->m_value);
res->m_const2bv.insert(k, v);
translator.to().inc_ref(k);
translator.to().inc_ref(v);
}
for (obj_map<func_decl, expr*>::iterator it = m_rm_const2bv.begin();
it != m_rm_const2bv.end();
it++)
{
func_decl * k = translator(it->m_key);
expr * v = translator(it->m_value);
res->m_rm_const2bv.insert(k, v);
translator.to().inc_ref(k);
translator.to().inc_ref(v);
}
for (obj_map<func_decl, func_decl*>::iterator it = m_uf2bvuf.begin();
it != m_uf2bvuf.end();
it++) {
func_decl * k = translator(it->m_key);
func_decl * v = translator(it->m_value);
res->m_uf2bvuf.insert(k, v);
translator.to().inc_ref(k);
translator.to().inc_ref(v);
}
for (obj_map<func_decl, std::pair<app*, app*> >::iterator it = m_specials.begin();
it != m_specials.end();
it++) {
func_decl * k = translator(it->m_key);
app * v1 = translator(it->m_value.first);
app * v2 = translator(it->m_value.second);
res->m_specials.insert(k, std::pair<app*, app*>(v1, v2));
translator.to().inc_ref(k);
translator.to().inc_ref(v1);
translator.to().inc_ref(v2);
}
return res;
}
void bv2fpa_converter::convert(model_core * mc, model_core * float_mdl) {
TRACE("bv2fpa", tout << "BV Model: " << std::endl;
for (unsigned i = 0; i < mc->get_num_constants(); i++)
tout << mc->get_constant(i)->get_name() << " --> " <<
mk_ismt2_pp(mc->get_const_interp(mc->get_constant(i)), m) << std::endl;
for (unsigned i = 0; i < mc->get_num_functions(); i++) {
func_decl * f = mc->get_function(i);
tout << f->get_name() << "(...) := " << std::endl;
func_interp * fi = mc->get_func_interp(f);
for (unsigned j = 0; j < fi->num_entries(); j++) {
func_entry const * fe = fi->get_entry(j);
for (unsigned k = 0; k < f->get_arity(); k++) {
tout << mk_ismt2_pp(fe->get_arg(k), m) << " ";
}
tout << "--> " << mk_ismt2_pp(fe->get_result(), m) << std::endl;
}
tout << "else " << mk_ismt2_pp(fi->get_else(), m) << std::endl;
});
}

View file

@ -0,0 +1,74 @@
/*++
Copyright (c) 2016 Microsoft Corporation
Module Name:
bv2fpa_converter.h
Abstract:
Model conversion for fpa2bv_converter
Author:
Christoph (cwinter) 2016-10-15
Notes:
--*/
#ifndef BV2FPA_CONVERTER_H_
#define BV2FPA_CONVERTER_H_
#include"fpa_decl_plugin.h"
#include"bv_decl_plugin.h"
#include"th_rewriter.h"
#include"model_core.h"
#include"fpa2bv_converter.h"
class bv2fpa_converter {
ast_manager & m;
fpa_util m_fpa_util;
bv_util m_bv_util;
th_rewriter m_th_rw;
obj_map<func_decl, expr*> m_const2bv;
obj_map<func_decl, expr*> m_rm_const2bv;
obj_map<func_decl, func_decl*> m_uf2bvuf;
obj_map<func_decl, std::pair<app*, app*> > m_specials;
public:
bv2fpa_converter(ast_manager & m);
bv2fpa_converter(ast_manager & m, fpa2bv_converter & conv);
virtual ~bv2fpa_converter();
void display(std::ostream & out);
bv2fpa_converter * translate(ast_translation & translator);
expr_ref convert_bv2fp(sort * s, expr * sgn, expr * exp, expr * sig);
expr_ref convert_bv2fp(model_core * mc, sort * s, app * bv);
expr_ref convert_bv2rm(expr * eval_v);
expr_ref convert_bv2rm(model_core * mc, app * val);
void convert(model_core * mc, model_core * float_mdl);
void convert_consts(model_core * mc, model_core * target_model, obj_hashtable<func_decl> & seen);
void convert_rm_consts(model_core * mc, model_core * target_model, obj_hashtable<func_decl> & seen);
void convert_min_max_specials(model_core * mc, model_core * target_model, obj_hashtable<func_decl> & seen);
void convert_uf2bvuf(model_core * mc, model_core * target_model, obj_hashtable<func_decl> & seen);
func_interp * convert_func_interp(model_core * mc, func_decl * f, func_decl * bv_f);
expr_ref rebuild_floats(model_core * mc, sort * s, app * e);
class array_model {
public:
func_decl * new_float_fd;
func_interp * new_float_fi;
func_decl * bv_fd;
expr_ref result;
array_model(ast_manager & m) : new_float_fd(0), new_float_fi(0), bv_fd(0), result(m) {}
};
array_model convert_array_func_interp(model_core * mc, func_decl * f, func_decl * bv_f);
};
#endif

View file

@ -23,9 +23,9 @@ Notes:
#include"th_rewriter.h"
#include"fpa2bv_converter.h"
#include"fpa_rewriter.h"
#define BVULT(X,Y,R) { expr_ref bvult_eq(m), bvult_not(m); m_simp.mk_eq(X, Y, bvult_eq); m_simp.mk_not(bvult_eq, bvult_not); expr_ref t(m); t = m_bv_util.mk_ule(X,Y); m_simp.mk_and(t, bvult_not, R); }
#define BVSLT(X,Y,R) { expr_ref bvslt_eq(m), bvslt_not(m); m_simp.mk_eq(X, Y, bvslt_eq); m_simp.mk_not(bvslt_eq, bvslt_not); expr_ref t(m); t = m_bv_util.mk_sle(X,Y); m_simp.mk_and(t, bvslt_not, R); }
fpa2bv_converter::fpa2bv_converter(ast_manager & m) :
m(m),
@ -33,7 +33,6 @@ fpa2bv_converter::fpa2bv_converter(ast_manager & m) :
m_util(m),
m_bv_util(m),
m_arith_util(m),
m_array_util(m),
m_dt_util(m),
m_seq_util(m),
m_mpf_manager(m_util.fm()),
@ -91,19 +90,28 @@ void fpa2bv_converter::mk_eq(expr * a, expr * b, expr_ref & result) {
}
void fpa2bv_converter::mk_ite(expr * c, expr * t, expr * f, expr_ref & result) {
SASSERT(m_util.is_fp(t) && m_util.is_fp(f));
if (m_util.is_fp(t) && m_util.is_fp(f)) {
expr *t_sgn, *t_sig, *t_exp;
expr *f_sgn, *f_sig, *f_exp;
split_fp(t, t_sgn, t_exp, t_sig);
split_fp(f, f_sgn, f_exp, f_sig);
expr *t_sgn, *t_sig, *t_exp;
expr *f_sgn, *f_sig, *f_exp;
split_fp(t, t_sgn, t_exp, t_sig);
split_fp(f, f_sgn, f_exp, f_sig);
expr_ref sgn(m), s(m), e(m);
m_simp.mk_ite(c, t_sgn, f_sgn, sgn);
m_simp.mk_ite(c, t_sig, f_sig, s);
m_simp.mk_ite(c, t_exp, f_exp, e);
expr_ref sgn(m), s(m), e(m);
m_simp.mk_ite(c, t_sgn, f_sgn, sgn);
m_simp.mk_ite(c, t_sig, f_sig, s);
m_simp.mk_ite(c, t_exp, f_exp, e);
result = m_util.mk_fp(sgn, e, s);
result = m_util.mk_fp(sgn, e, s);
}
else if (m_util.is_rm(t) && m_util.is_rm(f))
{
SASSERT(m_util.is_bv2rm(t) && m_util.is_bv2rm(f));
TRACE("fpa2bv", tout << "ite rm: t=" << mk_ismt2_pp(t, m) << " f=" << mk_ismt2_pp(f, m) << std::endl; );
m_simp.mk_ite(c, to_app(t)->get_arg(0), to_app(f)->get_arg(0), result);
result = m_util.mk_bv2rm(result);
}
else
UNREACHABLE();
}
void fpa2bv_converter::mk_distinct(func_decl * f, unsigned num, expr * const * args, expr_ref & result) {
@ -125,10 +133,12 @@ void fpa2bv_converter::mk_numeral(func_decl * f, unsigned num, expr * const * ar
SASSERT(num == 0);
SASSERT(f->get_num_parameters() == 1);
SASSERT(f->get_parameter(0).is_external());
unsigned p_id = f->get_parameter(0).get_ext_id();
mpf const & v = m_plugin->get_value(p_id);
mk_numeral(f->get_range(), v, result);
}
void fpa2bv_converter::mk_numeral(sort * s, mpf const & v, expr_ref & result) {
unsigned sbits = v.get_sbits();
unsigned ebits = v.get_ebits();
@ -137,12 +147,12 @@ void fpa2bv_converter::mk_numeral(func_decl * f, unsigned num, expr * const * ar
mpf_exp_t const & exp = m_util.fm().exp(v);
if (m_util.fm().is_nan(v))
mk_nan(f, result);
mk_nan(s, result);
else if (m_util.fm().is_inf(v)) {
if (m_util.fm().sgn(v))
mk_ninf(f, result);
mk_ninf(s, result);
else
mk_pinf(f, result);
mk_pinf(s, result);
}
else {
expr_ref bv_sgn(m), bv_sig(m), e(m), biased_exp(m);
@ -155,7 +165,6 @@ void fpa2bv_converter::mk_numeral(func_decl * f, unsigned num, expr * const * ar
result = m_util.mk_fp(bv_sgn, biased_exp, bv_sig);
TRACE("fpa2bv_dbg", tout << "value of [" << sign << " " << m_mpz_manager.to_string(sig) << " " << exp << "] is "
<< mk_ismt2_pp(result, m) << std::endl;);
}
}
@ -263,7 +272,7 @@ void fpa2bv_converter::mk_function(func_decl * f, unsigned num, expr * const * a
rng = f->get_range();
fapp = m.mk_app(f, num, args);
if (m_util.is_float(rng)) {
sort_ref bv_rng(m);
sort_ref bv_rng(m);
expr_ref new_eq(m);
unsigned ebits = m_util.get_ebits(rng);
unsigned sbits = m_util.get_sbits(rng);
@ -289,7 +298,7 @@ void fpa2bv_converter::mk_function(func_decl * f, unsigned num, expr * const * a
m_extra_assertions.push_back(new_eq);
result = flt_app;
}
else
else
result = fapp;
TRACE("fpa2bv", tout << "UF result: " << mk_ismt2_pp(result, m) << std::endl; );
@ -1012,15 +1021,17 @@ void fpa2bv_converter::mk_rem(sort * s, expr_ref & x, expr_ref & y, expr_ref & r
mk_ninf(s, ninf);
mk_pinf(s, pinf);
expr_ref x_is_nan(m), x_is_zero(m), x_is_pos(m), x_is_inf(m);
expr_ref y_is_nan(m), y_is_zero(m), y_is_pos(m), y_is_inf(m);
expr_ref x_is_nan(m), x_is_zero(m), x_is_pos(m), x_is_neg(m), x_is_inf(m);
expr_ref y_is_nan(m), y_is_zero(m), y_is_pos(m), y_is_neg(m), y_is_inf(m);
mk_is_nan(x, x_is_nan);
mk_is_zero(x, x_is_zero);
mk_is_pos(x, x_is_pos);
mk_is_neg(x, x_is_neg);
mk_is_inf(x, x_is_inf);
mk_is_nan(y, y_is_nan);
mk_is_zero(y, y_is_zero);
mk_is_pos(y, y_is_pos);
mk_is_neg(y, y_is_neg);
mk_is_inf(y, y_is_inf);
dbg_decouple("fpa2bv_rem_x_is_nan", x_is_nan);
@ -1056,31 +1067,117 @@ void fpa2bv_converter::mk_rem(sort * s, expr_ref & x, expr_ref & y, expr_ref & r
v5 = pzero;
// exp(x) < exp(y) -> x
unsigned ebits = m_util.get_ebits(s);
unsigned sbits = m_util.get_sbits(s);
expr * x_sgn, *x_sig, *x_exp;
expr * y_sgn, *y_sig, *y_exp;
split_fp(x, x_sgn, x_exp, x_sig);
split_fp(y, y_sgn, y_exp, y_sig);
BVSLT(x_exp, y_exp, c6);
expr_ref one_ebits(m), y_exp_m1(m), xe_lt_yem1(m), ye_neq_zero(m);
one_ebits = m_bv_util.mk_numeral(1, ebits);
y_exp_m1 = m_bv_util.mk_bv_sub(y_exp, one_ebits);
BVULT(x_exp, y_exp_m1, xe_lt_yem1);
ye_neq_zero = m.mk_not(m.mk_eq(y_exp, m_bv_util.mk_numeral(0, ebits)));
c6 = m.mk_and(ye_neq_zero, xe_lt_yem1);
v6 = x;
// else the actual remainder, r = x - y * n
expr_ref rne(m), nr(m), n(m), yn(m), r(m);
rne = m_bv_util.mk_numeral(BV_RM_TIES_TO_EVEN, 3);
mk_div(s, rne, x, y, nr);
mk_round_to_integral(s, rne, nr, n);
mk_mul(s, rne, y, n, yn);
mk_sub(s, rne, x, yn, r);
expr_ref a_sgn(m), a_sig(m), a_exp(m), a_lz(m);
expr_ref b_sgn(m), b_sig(m), b_exp(m), b_lz(m);
unpack(x, a_sgn, a_sig, a_exp, a_lz, true);
unpack(y, b_sgn, b_sig, b_exp, b_lz, true);
expr_ref r_is_zero(m), x_sgn_ref(x_sgn, m), x_sgn_zero(m);
mk_is_zero(r, r_is_zero);
mk_zero(s, x_sgn_ref, x_sgn_zero);
mk_ite(r_is_zero, x_sgn_zero, r, v7);
dbg_decouple("fpa2bv_rem_a_sgn", a_sgn);
dbg_decouple("fpa2bv_rem_a_sig", a_sig);
dbg_decouple("fpa2bv_rem_a_exp", a_exp);
dbg_decouple("fpa2bv_rem_a_lz", a_lz);
dbg_decouple("fpa2bv_rem_b_sgn", b_sgn);
dbg_decouple("fpa2bv_rem_b_sig", b_sig);
dbg_decouple("fpa2bv_rem_b_exp", b_exp);
dbg_decouple("fpa2bv_rem_b_lz", b_lz);
dbg_decouple("fpa2bv_rem_nr", nr);
dbg_decouple("fpa2bv_rem_n", n);
dbg_decouple("fpa2bv_rem_yn", yn);
dbg_decouple("fpa2bv_rem_r", r);
dbg_decouple("fpa2bv_rem_v7", v7);
// else the actual remainder.
// max. exponent difference is (2^ebits) - 3
const mpz & two_to_ebits = fu().fm().m_powers2(ebits);
mpz max_exp_diff;
m_mpz_manager.sub(two_to_ebits, 3, max_exp_diff);
SASSERT(m_mpz_manager.is_int64(max_exp_diff));
SASSERT(m_mpz_manager.get_uint64(max_exp_diff) <= UINT_MAX);
uint64 max_exp_diff_ui64 = m_mpz_manager.get_uint64(max_exp_diff);
SASSERT(max_exp_diff_ui64 <= UINT_MAX);
unsigned max_exp_diff_ui = (unsigned)max_exp_diff_ui64;
m_mpz_manager.del(max_exp_diff);
expr_ref a_exp_ext(m), b_exp_ext(m);
a_exp_ext = m_bv_util.mk_sign_extend(2, a_exp);
b_exp_ext = m_bv_util.mk_sign_extend(2, b_exp);
expr_ref a_lz_ext(m), b_lz_ext(m);
a_lz_ext = m_bv_util.mk_zero_extend(2, a_lz);
b_lz_ext = m_bv_util.mk_zero_extend(2, b_lz);
expr_ref exp_diff(m), neg_exp_diff(m), exp_diff_is_neg(m);
exp_diff = m_bv_util.mk_bv_sub(
m_bv_util.mk_bv_sub(a_exp_ext, a_lz_ext),
m_bv_util.mk_bv_sub(b_exp_ext, b_lz_ext));
neg_exp_diff = m_bv_util.mk_bv_neg(exp_diff);
exp_diff_is_neg = m_bv_util.mk_sle(exp_diff, m_bv_util.mk_numeral(0, ebits+2));
dbg_decouple("fpa2bv_rem_exp_diff", exp_diff);
// CMW: This creates _huge_ bit-vectors, which is potentially sub-optimal,
// but calculating this via rem = x - y * nearest(x/y) creates huge
// circuits, too. Lazy instantiation seems the way to go in the long run
// (using the lazy bit-blaster helps on simple instances).
expr_ref a_sig_ext(m), b_sig_ext(m), lshift(m), rshift(m), shifted(m), huge_rem(m);
a_sig_ext = m_bv_util.mk_concat(m_bv_util.mk_zero_extend(max_exp_diff_ui, a_sig), m_bv_util.mk_numeral(0, 3));
b_sig_ext = m_bv_util.mk_concat(m_bv_util.mk_zero_extend(max_exp_diff_ui, b_sig), m_bv_util.mk_numeral(0, 3));
lshift = m_bv_util.mk_zero_extend(max_exp_diff_ui + sbits - (ebits+2) + 3, exp_diff);
rshift = m_bv_util.mk_zero_extend(max_exp_diff_ui + sbits - (ebits+2) + 3, neg_exp_diff);
shifted = m.mk_ite(exp_diff_is_neg, m_bv_util.mk_bv_ashr(a_sig_ext, rshift),
m_bv_util.mk_bv_shl(a_sig_ext, lshift));
huge_rem = m_bv_util.mk_bv_urem(shifted, b_sig_ext);
dbg_decouple("fpa2bv_rem_huge_rem", huge_rem);
expr_ref rndd_sgn(m), rndd_exp(m), rndd_sig(m), rne_bv(m), rndd(m);
rndd_sgn = a_sgn;
rndd_exp = m_bv_util.mk_bv_sub(b_exp_ext, b_lz_ext);
rndd_sig = m_bv_util.mk_extract(sbits+3, 0, huge_rem);
rne_bv = m_bv_util.mk_numeral(BV_RM_TIES_TO_EVEN, 3);
round(s, rne_bv, rndd_sgn, rndd_sig, rndd_exp, rndd);
expr_ref y_half(m), ny_half(m), zero_e(m), two_e(m);
expr_ref y_half_is_zero(m), y_half_is_nz(m);
expr_ref r_ge_y_half(m), r_gt_ny_half(m), r_le_y_half(m), r_lt_ny_half(m);
expr_ref r_ge_zero(m), r_le_zero(m);
expr_ref rounded_sub_y(m), rounded_add_y(m);
mpf zero, two;
m_mpf_manager.set(two, ebits, sbits, 2);
m_mpf_manager.set(zero, ebits, sbits, 0);
mk_numeral(s, two, two_e);
mk_numeral(s, zero, zero_e);
mk_div(s, rne_bv, y, two_e, y_half);
mk_neg(s, y_half, ny_half);
mk_is_zero(y_half, y_half_is_zero);
y_half_is_nz = m.mk_not(y_half_is_zero);
mk_float_ge(s, rndd, y_half, r_ge_y_half);
mk_float_gt(s, rndd, ny_half, r_gt_ny_half);
mk_float_le(s, rndd, y_half, r_le_y_half);
mk_float_lt(s, rndd, ny_half, r_lt_ny_half);
mk_sub(s, rne_bv, rndd, y, rounded_sub_y);
mk_add(s, rne_bv, rndd, y, rounded_add_y);
expr_ref sub_cnd(m), add_cnd(m);
sub_cnd = m.mk_and(y_half_is_nz,
m.mk_or(m.mk_and(y_is_pos, r_ge_y_half),
m.mk_and(y_is_neg, r_le_y_half)));
add_cnd = m.mk_and(y_half_is_nz,
m.mk_or(m.mk_and(y_is_pos, r_lt_ny_half),
m.mk_and(y_is_neg, r_gt_ny_half)));
mk_ite(add_cnd, rounded_add_y, rndd, v7);
mk_ite(sub_cnd, rounded_sub_y, v7, v7);
// And finally, we tie them together.
mk_ite(c6, v6, v7, result);
@ -1102,9 +1199,15 @@ void fpa2bv_converter::mk_rem(sort * s, expr_ref & x, expr_ref & y, expr_ref & r
void fpa2bv_converter::mk_abs(func_decl * f, unsigned num, expr * const * args, expr_ref & result) {
SASSERT(num == 1);
expr * sgn, * s, * e;
split_fp(args[0], sgn, e, s);
result = m_util.mk_fp(m_bv_util.mk_numeral(0, 1), e, s);
expr_ref x(m);
x = args[0];
mk_abs(f->get_range(), x, result);
}
void fpa2bv_converter::mk_abs(sort * s, expr_ref & x, expr_ref & result) {
expr * sgn, *sig, *exp;
split_fp(x, sgn, exp, sig);
result = m_util.mk_fp(m_bv_util.mk_numeral(0, 1), exp, sig);
}
void fpa2bv_converter::mk_min(func_decl * f, unsigned num, expr * const * args, expr_ref & result) {
@ -1178,10 +1281,10 @@ expr_ref fpa2bv_converter::mk_min_max_unspecified(func_decl * f, expr * x, expr
// There is no "hardware interpretation" for fp.min/fp.max.
std::pair<app*, app*> decls(0, 0);
if (!m_specials.find(f, decls)) {
if (!m_min_max_specials.find(f, decls)) {
decls.first = m.mk_fresh_const(0, m_bv_util.mk_sort(1));
decls.second = m.mk_fresh_const(0, m_bv_util.mk_sort(1));
m_specials.insert(f, decls);
m_min_max_specials.insert(f, decls);
m.inc_ref(f);
m.inc_ref(decls.first);
m.inc_ref(decls.second);
@ -1360,11 +1463,17 @@ void fpa2bv_converter::mk_fma(func_decl * f, unsigned num, expr * const * args,
v6 = z;
// (x is 0) || (y is 0) -> z
expr_ref c71(m), xy_sgn(m), xyz_sgn(m);
m_simp.mk_or(x_is_zero, y_is_zero, c7);
expr_ref ite_c(m), rm_is_not_to_neg(m);
m_simp.mk_xor(x_is_neg, y_is_neg, xy_sgn);
m_simp.mk_xor(xy_sgn, z_is_neg, xyz_sgn);
m_simp.mk_and(z_is_zero, xyz_sgn, c71);
expr_ref zero_cond(m), rm_is_not_to_neg(m);
rm_is_not_to_neg = m.mk_not(rm_is_to_neg);
m_simp.mk_and(z_is_zero, rm_is_not_to_neg, ite_c);
mk_ite(ite_c, pzero, z, v7);
m_simp.mk_ite(rm_is_to_neg, nzero, pzero, zero_cond);
mk_ite(c71, zero_cond, z, v7);
// else comes the fused multiplication.
unsigned ebits = m_util.get_ebits(f->get_range());
@ -1954,11 +2063,15 @@ void fpa2bv_converter::mk_round_to_integral(sort * s, expr_ref & rm, expr_ref &
void fpa2bv_converter::mk_float_eq(func_decl * f, unsigned num, expr * const * args, expr_ref & result) {
SASSERT(num == 2);
expr_ref x(m), y(m);
x = args[0];
y = args[1];
mk_float_eq(f->get_range(), x, y, result);
}
expr * x = args[0], * y = args[1];
void fpa2bv_converter::mk_float_eq(sort * s, expr_ref & x, expr_ref & y, expr_ref & result) {
TRACE("fpa2bv_float_eq", tout << "X = " << mk_ismt2_pp(x, m) << std::endl;
tout << "Y = " << mk_ismt2_pp(y, m) << std::endl;);
tout << "Y = " << mk_ismt2_pp(y, m) << std::endl;);
expr_ref c1(m), c2(m), x_is_nan(m), y_is_nan(m), x_is_zero(m), y_is_zero(m);
mk_is_nan(x, x_is_nan);
@ -1992,9 +2105,13 @@ void fpa2bv_converter::mk_float_eq(func_decl * f, unsigned num, expr * const * a
void fpa2bv_converter::mk_float_lt(func_decl * f, unsigned num, expr * const * args, expr_ref & result) {
SASSERT(num == 2);
expr_ref x(m), y(m);
x = args[0];
y = args[1];
mk_float_lt(f->get_range(), x, y, result);
}
expr * x = args[0], * y = args[1];
void fpa2bv_converter::mk_float_lt(sort * s, expr_ref & x, expr_ref & y, expr_ref & result) {
expr_ref c1(m), c2(m), x_is_nan(m), y_is_nan(m), x_is_zero(m), y_is_zero(m);
mk_is_nan(x, x_is_nan);
mk_is_nan(y, y_is_nan);
@ -2039,11 +2156,15 @@ void fpa2bv_converter::mk_float_lt(func_decl * f, unsigned num, expr * const * a
void fpa2bv_converter::mk_float_gt(func_decl * f, unsigned num, expr * const * args, expr_ref & result) {
SASSERT(num == 2);
expr_ref x(m), y(m);
x = args[0];
y = args[1];
mk_float_gt(f->get_range(), x, y, result);
}
expr * x = args[0], * y = args[1];
void fpa2bv_converter::mk_float_gt(sort * s, expr_ref & x, expr_ref & y, expr_ref & result) {
expr_ref t3(m);
mk_float_le(f, num, args, t3);
mk_float_le(s, x, y, t3);
expr_ref nan_or(m), xy_zero(m), not_t3(m), r_else(m);
expr_ref x_is_nan(m), y_is_nan(m), x_is_zero(m), y_is_zero(m);
@ -2060,17 +2181,31 @@ void fpa2bv_converter::mk_float_gt(func_decl * f, unsigned num, expr * const * a
void fpa2bv_converter::mk_float_le(func_decl * f, unsigned num, expr * const * args, expr_ref & result) {
SASSERT(num == 2);
expr_ref x(m), y(m);
x = args[0];
y = args[1];
mk_float_le(f->get_range(), x, y, result);
}
void fpa2bv_converter::mk_float_le(sort * s, expr_ref & x, expr_ref & y, expr_ref & result) {
expr_ref a(m), b(m);
mk_float_lt(f, num, args, a);
mk_float_eq(f, num, args, b);
mk_float_lt(s, x, y, a);
mk_float_eq(s, x, y, b);
m_simp.mk_or(a, b, result);
}
void fpa2bv_converter::mk_float_ge(func_decl * f, unsigned num, expr * const * args, expr_ref & result) {
SASSERT(num == 2);
expr_ref x(m), y(m);
x = args[0];
y = args[1];
mk_float_ge(f->get_range(), x, y, result);
}
void fpa2bv_converter::mk_float_ge(sort * s, expr_ref & x, expr_ref & y, expr_ref & result) {
expr_ref a(m), b(m);
mk_float_gt(f, num, args, a);
mk_float_eq(f, num, args, b);
mk_float_gt(s, x, y, a);
mk_float_eq(s, x, y, b);
m_simp.mk_or(a, b, result);
}
@ -2146,6 +2281,7 @@ void fpa2bv_converter::mk_to_fp(func_decl * f, unsigned num, expr * const * args
expr * bv = args[0];
int sz = m_bv_util.get_bv_size(bv);
(void)to_sbits;
SASSERT((unsigned)sz == to_sbits + to_ebits);
result = m_util.mk_fp(m_bv_util.mk_extract(sz - 1, sz - 1, bv),
@ -2278,6 +2414,7 @@ void fpa2bv_converter::mk_to_fp_float(sort * to_srt, expr * rm, expr * x, expr_r
res_sig = m_bv_util.mk_zero_extend(1, res_sig); // extra zero in the front for the rounder.
unsigned sig_sz = m_bv_util.get_bv_size(res_sig);
(void) sig_sz;
SASSERT(sig_sz == to_sbits + 4);
expr_ref exponent_overflow(m), exponent_underflow(m);
@ -2640,6 +2777,7 @@ void fpa2bv_converter::mk_to_real(func_decl * f, unsigned num, expr * const * ar
expr_ref unspec(m);
unspec = mk_to_real_unspecified(ebits, sbits);
result = m.mk_ite(x_is_zero, zero, res);
result = m.mk_ite(x_is_inf, unspec, result);
result = m.mk_ite(x_is_nan, unspec, result);
@ -2941,13 +3079,55 @@ void fpa2bv_converter::mk_to_ieee_bv(func_decl * f, unsigned num, expr * const *
m_bv_util.mk_concat(m_bv_util.mk_numeral(-1, ebits),
m_bv_util.mk_concat(m_bv_util.mk_numeral(0, sbits - 2),
m_bv_util.mk_numeral(1, 1))));
else
nanv = mk_to_ieee_bv_unspecified(ebits, sbits);
else {
app_ref unspec(m);
unspec = m_util.mk_internal_to_ieee_bv_unspecified(ebits, sbits);
mk_to_ieee_bv_unspecified(unspec->get_decl(), 0, 0, nanv);
}
expr_ref sgn_e_s(m);
sgn_e_s = m_bv_util.mk_concat(m_bv_util.mk_concat(sgn, e), s);
m_simp.mk_ite(x_is_nan, nanv, sgn_e_s, result);
TRACE("fpa2bv_to_ieee_bv", tout << "result=" << mk_ismt2_pp(result, m) << std::endl;);
SASSERT(is_well_sorted(m, result));
}
void fpa2bv_converter::mk_to_ieee_bv_unspecified(func_decl * f, unsigned num, expr * const * args, expr_ref & result) {
SASSERT(num == 0);
unsigned ebits = f->get_parameter(0).get_int();
unsigned sbits = f->get_parameter(1).get_int();
if (m_hi_fp_unspecified) {
result = m_bv_util.mk_concat(m_bv_util.mk_concat(
m_bv_util.mk_numeral(0, 1),
m_bv_util.mk_numeral(-1, ebits)),
m_bv_util.mk_numeral(1, sbits-1));
}
else {
func_decl * fd;
if (m_uf2bvuf.find(f, fd))
result = m.mk_const(fd);
else {
fd = m.mk_fresh_func_decl(0, 0, 0, f->get_range());
m_uf2bvuf.insert(f, fd);
m.inc_ref(f);
m.inc_ref(fd);
result = m.mk_const(fd);
expr_ref exp_bv(m), exp_all_ones(m);
exp_bv = m_bv_util.mk_extract(ebits+sbits-2, sbits-1, result);
exp_all_ones = m.mk_eq(exp_bv, m_bv_util.mk_numeral(-1, ebits));
m_extra_assertions.push_back(exp_all_ones);
expr_ref sig_bv(m), sig_is_non_zero(m);
sig_bv = m_bv_util.mk_extract(sbits-2, 0, result);
sig_is_non_zero = m.mk_not(m.mk_eq(sig_bv, m_bv_util.mk_numeral(0, sbits-1)));
m_extra_assertions.push_back(sig_is_non_zero);
}
}
TRACE("fpa2bv_to_ieee_bv_unspecified", tout << "result=" << mk_ismt2_pp(result, m) << std::endl;);
SASSERT(is_well_sorted(m, result));
}
@ -2980,11 +3160,14 @@ void fpa2bv_converter::mk_to_bv(func_decl * f, unsigned num, expr * const * args
// NaN, Inf, or negative (except -0) -> unspecified
expr_ref c1(m), v1(m);
if (!is_signed)
if (!is_signed) {
c1 = m.mk_or(x_is_nan, x_is_inf, m.mk_and(x_is_neg, m.mk_not(x_is_nzero)));
else
v1 = mk_to_ubv_unspecified(ebits, sbits, bv_sz);
}
else {
c1 = m.mk_or(x_is_nan, x_is_inf);
v1 = mk_to_ubv_unspecified(ebits, sbits, bv_sz);
v1 = mk_to_sbv_unspecified(ebits, sbits, bv_sz);
}
dbg_decouple("fpa2bv_to_bv_c1", c1);
// +-Zero -> 0
@ -3094,7 +3277,8 @@ void fpa2bv_converter::mk_to_bv(func_decl * f, unsigned num, expr * const * args
dbg_decouple("fpa2bv_to_bv_rnd", rnd);
expr_ref unspec(m);
unspec = mk_to_ubv_unspecified(ebits, sbits, bv_sz);
unspec = is_signed ? mk_to_sbv_unspecified(ebits, sbits, bv_sz) :
mk_to_ubv_unspecified(ebits, sbits, bv_sz);
result = m.mk_ite(rnd_has_overflown, unspec, rnd);
result = m.mk_ite(c_in_limits, result, unspec);
result = m.mk_ite(c2, v2, result);
@ -3115,101 +3299,85 @@ void fpa2bv_converter::mk_to_sbv(func_decl * f, unsigned num, expr * const * arg
mk_to_bv(f, num, args, true, result);
}
expr_ref fpa2bv_converter::mk_to_ubv_unspecified(unsigned ebits, unsigned sbits, unsigned width) {
expr_ref result(m);
void fpa2bv_converter::mk_to_ubv_unspecified(func_decl * f, unsigned num, expr * const * args, expr_ref & result) {
SASSERT(num == 0);
unsigned width = m_bv_util.get_bv_size(f->get_range());
if (m_hi_fp_unspecified)
result = m_bv_util.mk_numeral(0, width);
else {
app_ref unspec(m);
unspec = m_util.mk_internal_to_ubv_unspecified(ebits, sbits, width);
func_decl * unspec_fd = unspec->get_decl();
func_decl * fd;
if (!m_uf2bvuf.find(unspec_fd, fd)) {
app_ref bvc(m);
bvc = m.mk_fresh_const(0, unspec_fd->get_range());
fd = bvc->get_decl();
m_uf2bvuf.insert(unspec_fd, fd);
m.inc_ref(unspec_fd);
if (!m_uf2bvuf.find(f, fd)) {
fd = m.mk_fresh_func_decl(0, 0, 0, f->get_range());
m_uf2bvuf.insert(f, fd);
m.inc_ref(f);
m.inc_ref(fd);
}
result = m.mk_const(fd);
}
return result;
TRACE("fpa2bv_to_ubv_unspecified", tout << "result=" << mk_ismt2_pp(result, m) << std::endl;);
SASSERT(is_well_sorted(m, result));
}
expr_ref fpa2bv_converter::mk_to_ubv_unspecified(unsigned ebits, unsigned sbits, unsigned width) {
expr_ref res(m);
app_ref u(m);
u = m_util.mk_internal_to_ubv_unspecified(ebits, sbits, width);
mk_to_sbv_unspecified(u->get_decl(), 0, 0, res);
return res;
}
void fpa2bv_converter::mk_to_sbv_unspecified(func_decl * f, unsigned num, expr * const * args, expr_ref & result) {
SASSERT(num == 0);
unsigned width = m_bv_util.get_bv_size(f->get_range());
if (m_hi_fp_unspecified)
result = m_bv_util.mk_numeral(0, width);
else {
func_decl * fd;
if (!m_uf2bvuf.find(f, fd)) {
fd = m.mk_fresh_func_decl(0, 0, 0, f->get_range());
m_uf2bvuf.insert(f, fd);
m.inc_ref(f);
m.inc_ref(fd);
}
result = m.mk_const(fd);
}
TRACE("fpa2bv_to_sbv_unspecified", tout << "result=" << mk_ismt2_pp(result, m) << std::endl;);
SASSERT(is_well_sorted(m, result));
}
expr_ref fpa2bv_converter::mk_to_sbv_unspecified(unsigned ebits, unsigned sbits, unsigned width) {
expr_ref result(m);
if (m_hi_fp_unspecified)
result = m_bv_util.mk_numeral(0, width);
else {
app_ref unspec(m);
unspec = m_util.mk_internal_to_sbv_unspecified(ebits, sbits, width);
func_decl * unspec_fd = unspec->get_decl();
func_decl * fd;
if (!m_uf2bvuf.find(unspec_fd, fd)) {
app_ref bvc(m);
bvc = m.mk_fresh_const(0, unspec_fd->get_range());
fd = bvc->get_decl();
m_uf2bvuf.insert(unspec_fd, fd);
m.inc_ref(unspec_fd);
m.inc_ref(fd);
}
result = m.mk_const(fd);
}
return result;
expr_ref res(m);
app_ref u(m);
u = m_util.mk_internal_to_sbv_unspecified(ebits, sbits, width);
mk_to_sbv_unspecified(u->get_decl(), 0, 0, res);
return res;
}
expr_ref fpa2bv_converter::mk_to_real_unspecified(unsigned ebits, unsigned sbits) {
expr_ref result(m);
void fpa2bv_converter::mk_to_real_unspecified(func_decl * f, unsigned num, expr * const * args, expr_ref & result) {
if (m_hi_fp_unspecified)
result = m_arith_util.mk_numeral(rational(0), false);
else {
app_ref unspec(m);
unspec = m_util.mk_internal_to_real_unspecified(ebits, sbits);
func_decl * unspec_fd = unspec->get_decl();
func_decl * fd;
if (!m_uf2bvuf.find(unspec_fd, fd)) {
app_ref bvc(m);
bvc = m.mk_fresh_const(0, unspec_fd->get_range());
fd = bvc->get_decl();
m_uf2bvuf.insert(unspec_fd, fd);
m.inc_ref(unspec_fd);
if (!m_uf2bvuf.find(f, fd)) {
fd = m.mk_fresh_func_decl(0, 0, 0, f->get_range());
m_uf2bvuf.insert(f, fd);
m.inc_ref(f);
m.inc_ref(fd);
}
result = m.mk_const(fd);
result = unspec;
}
return result;
}
expr_ref fpa2bv_converter::mk_to_ieee_bv_unspecified(unsigned ebits, unsigned sbits) {
expr_ref result(m);
app_ref unspec(m);
unspec = m_util.mk_internal_to_ieee_bv_unspecified(ebits, sbits);
func_decl * unspec_fd = unspec->get_decl();
func_decl * fd;
if (!m_uf2bvuf.find(unspec_fd, fd)) {
app_ref bvc(m);
bvc = m.mk_fresh_const(0, unspec_fd->get_range());
fd = bvc->get_decl();
m_uf2bvuf.insert(unspec_fd, fd);
m.inc_ref(unspec_fd);
m.inc_ref(fd);
}
result = m.mk_const(fd);
app_ref mask(m), extra(m), result_and_mask(m);
mask = m_bv_util.mk_concat(m_bv_util.mk_numeral(0, 1),
m_bv_util.mk_concat(m_bv_util.mk_numeral(-1, ebits),
m_bv_util.mk_concat(m_bv_util.mk_numeral(0, sbits - 2),
m_bv_util.mk_numeral(1, 1))));
expr * args[2] = { result, mask };
result_and_mask = m.mk_app(m_bv_util.get_fid(), OP_BAND, 2, args);
extra = m.mk_eq(result_and_mask, mask);
m_extra_assertions.push_back(extra);
return result;
expr_ref fpa2bv_converter::mk_to_real_unspecified(unsigned ebits, unsigned sbits) {
expr_ref res(m);
app_ref u(m);
u = m_util.mk_internal_to_real_unspecified(ebits, sbits);
mk_to_real_unspecified(u->get_decl(), 0, 0, res);
return res;
}
void fpa2bv_converter::mk_fp(func_decl * f, unsigned num, expr * const * args, expr_ref & result) {
@ -3518,11 +3686,11 @@ void fpa2bv_converter::unpack(expr * e, expr_ref & sgn, expr_ref & sig, expr_ref
// the maximum shift is `sbits', because after that the mantissa
// would be zero anyways. So we can safely cut the shift variable down,
// as long as we check the higher bits.
expr_ref sh(m), is_sh_zero(m), sl(m), sbits_s(m), short_shift(m);
zero_s = m_bv_util.mk_numeral(0, sbits-1);
expr_ref zero_ems(m), sh(m), is_sh_zero(m), sl(m), sbits_s(m), short_shift(m);
zero_ems = m_bv_util.mk_numeral(0, ebits - sbits);
sbits_s = m_bv_util.mk_numeral(sbits, sbits);
sh = m_bv_util.mk_extract(ebits-1, sbits, shift);
m_simp.mk_eq(zero_s, sh, is_sh_zero);
m_simp.mk_eq(zero_ems, sh, is_sh_zero);
short_shift = m_bv_util.mk_extract(sbits-1, 0, shift);
m_simp.mk_ite(is_sh_zero, short_shift, sbits_s, sl);
denormal_sig = m_bv_util.mk_bv_shl(denormal_sig, sl);
@ -3575,7 +3743,7 @@ void fpa2bv_converter::dbg_decouple(const char * prefix, expr_ref & e) {
// CMW: This works only for quantifier-free formulas.
if (m_util.is_fp(e)) {
expr_ref new_bv(m);
expr *e_sgn, *e_sig, *e_exp;
expr *e_sgn, *e_sig, *e_exp;
split_fp(e, e_sgn, e_exp, e_sig);
unsigned ebits = m_bv_util.get_bv_size(e_exp);
unsigned sbits = m_bv_util.get_bv_size(e_sig) + 1;
@ -3979,12 +4147,13 @@ void fpa2bv_converter::reset(void) {
dec_ref_map_key_values(m, m_const2bv);
dec_ref_map_key_values(m, m_rm_const2bv);
dec_ref_map_key_values(m, m_uf2bvuf);
for (obj_map<func_decl, std::pair<app*, app*> >::iterator it = m_specials.begin();
it != m_specials.end();
for (obj_map<func_decl, std::pair<app*, app*> >::iterator it = m_min_max_specials.begin();
it != m_min_max_specials.end();
it++) {
m.dec_ref(it->m_key);
m.dec_ref(it->m_value.first);
m.dec_ref(it->m_value.second);
}
m_min_max_specials.reset();
m_extra_assertions.reset();
}

View file

@ -32,13 +32,17 @@ Notes:
#include"basic_simplifier_plugin.h"
class fpa2bv_converter {
public:
typedef obj_map<func_decl, std::pair<app *, app *> > special_t;
typedef obj_map<func_decl, expr*> const2bv_t;
typedef obj_map<func_decl, func_decl*> uf2bvuf_t;
protected:
ast_manager & m;
basic_simplifier_plugin m_simp;
fpa_util m_util;
bv_util m_bv_util;
arith_util m_arith_util;
array_util m_array_util;
datatype_util m_dt_util;
seq_util m_seq_util;
mpf_manager & m_mpf_manager;
@ -46,13 +50,13 @@ protected:
fpa_decl_plugin * m_plugin;
bool m_hi_fp_unspecified;
obj_map<func_decl, expr*> m_const2bv;
obj_map<func_decl, expr*> m_rm_const2bv;
obj_map<func_decl, func_decl*> m_uf2bvuf;
obj_map<func_decl, std::pair<app *, app *> > m_specials;
const2bv_t m_const2bv;
const2bv_t m_rm_const2bv;
uf2bvuf_t m_uf2bvuf;
special_t m_min_max_specials;
friend class fpa2bv_model_converter;
friend class bv2fpa_converter;
public:
fpa2bv_converter(ast_manager & m);
@ -67,9 +71,9 @@ public:
bool is_rm(expr * e) { return is_app(e) && m_util.is_rm(e); }
bool is_rm(sort * s) { return m_util.is_rm(s); }
bool is_float_family(func_decl * f) { return f->get_family_id() == m_util.get_family_id(); }
void mk_fp(func_decl * f, unsigned num, expr * const * args, expr_ref & result);
void split_fp(expr * e, expr * & sgn, expr * & exp, expr * & sig) const;
void split_fp(expr * e, expr_ref & sgn, expr_ref & exp, expr_ref & sig) const;
@ -79,6 +83,7 @@ public:
void mk_rounding_mode(decl_kind k, expr_ref & result);
void mk_numeral(func_decl * f, unsigned num, expr * const * args, expr_ref & result);
void mk_numeral(sort * s, mpf const & v, expr_ref & result);
virtual void mk_const(func_decl * f, expr_ref & result);
virtual void mk_rm_const(func_decl * f, expr_ref & result);
virtual void mk_function(func_decl * f, unsigned num, expr * const * args, expr_ref & result);
@ -100,12 +105,18 @@ public:
void mk_fma(func_decl * f, unsigned num, expr * const * args, expr_ref & result);
void mk_sqrt(func_decl * f, unsigned num, expr * const * args, expr_ref & result);
void mk_round_to_integral(func_decl * f, unsigned num, expr * const * args, expr_ref & result);
void mk_abs(sort * s, expr_ref & x, expr_ref & result);
void mk_float_eq(func_decl * f, unsigned num, expr * const * args, expr_ref & result);
void mk_float_lt(func_decl * f, unsigned num, expr * const * args, expr_ref & result);
void mk_float_gt(func_decl * f, unsigned num, expr * const * args, expr_ref & result);
void mk_float_le(func_decl * f, unsigned num, expr * const * args, expr_ref & result);
void mk_float_ge(func_decl * f, unsigned num, expr * const * args, expr_ref & result);
void mk_float_eq(sort * s, expr_ref & x, expr_ref & y, expr_ref & result);
void mk_float_lt(sort * s, expr_ref & x, expr_ref & y, expr_ref & result);
void mk_float_gt(sort *, expr_ref & x, expr_ref & y, expr_ref & result);
void mk_float_le(sort * s, expr_ref & x, expr_ref & y, expr_ref & result);
void mk_float_ge(sort * s, expr_ref & x, expr_ref & y, expr_ref & result);
void mk_is_zero(func_decl * f, unsigned num, expr * const * args, expr_ref & result);
void mk_is_nzero(func_decl * f, unsigned num, expr * const * args, expr_ref & result);
@ -122,12 +133,16 @@ public:
void mk_to_fp_signed(func_decl * f, unsigned num, expr * const * args, expr_ref & result);
void mk_to_fp_unsigned(func_decl * f, unsigned num, expr * const * args, expr_ref & result);
void mk_to_ieee_bv(func_decl * f, unsigned num, expr * const * args, expr_ref & result);
void mk_to_ieee_bv_unspecified(func_decl * f, unsigned num, expr * const * args, expr_ref & result);
void mk_to_fp_real(func_decl * f, sort * s, expr * rm, expr * x, expr_ref & result);
void mk_to_fp_real_int(func_decl * f, unsigned num, expr * const * args, expr_ref & result);
void mk_to_ubv(func_decl * f, unsigned num, expr * const * args, expr_ref & result);
void mk_to_ubv_unspecified(func_decl * f, unsigned num, expr * const * args, expr_ref & result);
void mk_to_sbv(func_decl * f, unsigned num, expr * const * args, expr_ref & result);
void mk_to_sbv_unspecified(func_decl * f, unsigned num, expr * const * args, expr_ref & result);
void mk_to_real(func_decl * f, unsigned num, expr * const * args, expr_ref & result);
void mk_to_real_unspecified(func_decl * f, unsigned num, expr * const * args, expr_ref & result);
void set_unspecified_fp_hi(bool v) { m_hi_fp_unspecified = v; }
@ -138,18 +153,15 @@ public:
void mk_max(func_decl * f, unsigned num, expr * const * args, expr_ref & result);
void mk_max_i(func_decl * f, unsigned num, expr * const * args, expr_ref & result);
expr_ref mk_to_ubv_unspecified(unsigned ebits, unsigned sbits, unsigned width);
expr_ref mk_to_sbv_unspecified(unsigned ebits, unsigned sbits, unsigned width);
expr_ref mk_to_real_unspecified(unsigned ebits, unsigned sbits);
expr_ref mk_to_ieee_bv_unspecified(unsigned ebits, unsigned sbits);
void reset(void);
void dbg_decouple(const char * prefix, expr_ref & e);
expr_ref_vector m_extra_assertions;
bool is_special(func_decl * f) { return m_specials.contains(f); }
bool is_uf2bvuf(func_decl * f) { return m_uf2bvuf.contains(f); }
special_t const & get_min_max_specials() const { return m_min_max_specials; };
const2bv_t const & get_const2bv() const { return m_const2bv; };
const2bv_t const & get_rm_const2bv() const { return m_rm_const2bv; };
uf2bvuf_t const & get_uf2bvuf() const { return m_uf2bvuf; };
protected:
void mk_one(func_decl *f, expr_ref & sign, expr_ref & result);
@ -214,6 +226,10 @@ private:
void mk_round_to_integral(sort * s, expr_ref & rm, expr_ref & x, expr_ref & result);
void mk_to_fp_float(sort * s, expr * rm, expr * x, expr_ref & result);
expr_ref mk_to_ubv_unspecified(unsigned ebits, unsigned sbits, unsigned width);
expr_ref mk_to_sbv_unspecified(unsigned ebits, unsigned sbits, unsigned width);
expr_ref mk_to_real_unspecified(unsigned ebits, unsigned sbits);
};
#endif

View file

@ -86,10 +86,10 @@ br_status fpa2bv_rewriter_cfg::reduce_app(func_decl * f, unsigned num, expr * co
return BR_DONE;
}
return BR_FAILED;
}
}
else if (m().is_ite(f)) {
SASSERT(num == 3);
if (m_conv.is_float(args[1])) {
if (m_conv.is_float(args[1]) || m_conv.is_rm(args[1])) {
m_conv.mk_ite(args[0], args[1], args[2], result);
return BR_DONE;
}
@ -103,7 +103,7 @@ br_status fpa2bv_rewriter_cfg::reduce_app(func_decl * f, unsigned num, expr * co
}
return BR_FAILED;
}
if (m_conv.is_float_family(f)) {
switch (f->get_decl_kind()) {
case OP_FPA_RM_NEAREST_TIES_TO_AWAY:
@ -143,9 +143,13 @@ br_status fpa2bv_rewriter_cfg::reduce_app(func_decl * f, unsigned num, expr * co
case OP_FPA_TO_FP_UNSIGNED: m_conv.mk_to_fp_unsigned(f, num, args, result); return BR_DONE;
case OP_FPA_FP: m_conv.mk_fp(f, num, args, result); return BR_DONE;
case OP_FPA_TO_UBV: m_conv.mk_to_ubv(f, num, args, result); return BR_DONE;
case OP_FPA_INTERNAL_TO_UBV_UNSPECIFIED: m_conv.mk_to_ubv_unspecified(f, num, args, result); return BR_DONE;
case OP_FPA_TO_SBV: m_conv.mk_to_sbv(f, num, args, result); return BR_DONE;
case OP_FPA_INTERNAL_TO_SBV_UNSPECIFIED: m_conv.mk_to_sbv_unspecified(f, num, args, result); return BR_DONE;
case OP_FPA_TO_REAL: m_conv.mk_to_real(f, num, args, result); return BR_DONE;
case OP_FPA_INTERNAL_TO_REAL_UNSPECIFIED: m_conv.mk_to_real_unspecified(f, num, args, result); return BR_DONE;
case OP_FPA_TO_IEEE_BV: m_conv.mk_to_ieee_bv(f, num, args, result); return BR_DONE;
case OP_FPA_INTERNAL_TO_IEEE_BV_UNSPECIFIED: m_conv.mk_to_ieee_bv_unspecified(f, num, args, result); return BR_DONE;
case OP_FPA_MIN: m_conv.mk_min(f, num, args, result); return BR_REWRITE_FULL;
case OP_FPA_MAX: m_conv.mk_max(f, num, args, result); return BR_REWRITE_FULL;
@ -157,19 +161,15 @@ br_status fpa2bv_rewriter_cfg::reduce_app(func_decl * f, unsigned num, expr * co
case OP_FPA_INTERNAL_BVWRAP:
case OP_FPA_INTERNAL_BV2RM:
case OP_FPA_INTERNAL_TO_REAL_UNSPECIFIED:
case OP_FPA_INTERNAL_TO_UBV_UNSPECIFIED:
case OP_FPA_INTERNAL_TO_SBV_UNSPECIFIED:
case OP_FPA_INTERNAL_TO_IEEE_BV_UNSPECIFIED:
return BR_FAILED;
default:
TRACE("fpa2bv", tout << "unsupported operator: " << f->get_name() << "\n";
for (unsigned i = 0; i < num; i++) tout << mk_ismt2_pp(args[i], m()) << std::endl;);
NOT_IMPLEMENTED_YET();
}
}
else
else
{
SASSERT(!m_conv.is_float_family(f));
if (m_conv.fu().contains_floats(f)) {

View file

@ -665,14 +665,14 @@ func_decl * fpa_decl_plugin::mk_to_real(decl_kind k, unsigned num_parameters, pa
func_decl * fpa_decl_plugin::mk_to_ieee_bv(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 to_ieee_bv");
m_manager->raise_exception("invalid number of arguments to fp.to_ieee_bv");
if (!is_float_sort(domain[0]))
m_manager->raise_exception("sort mismatch, expected argument of FloatingPoint sort");
unsigned float_sz = domain[0]->get_parameter(0).get_int() + domain[0]->get_parameter(1).get_int();
parameter ps[] = { parameter(float_sz) };
sort * bv_srt = m_bv_plugin->mk_sort(BV_SORT, 1, ps);
symbol name("to_ieee_bv");
symbol name("fp.to_ieee_bv");
return m_manager->mk_func_decl(name, 1, domain, bv_srt, func_decl_info(m_family_id, k));
}
@ -758,15 +758,15 @@ func_decl * fpa_decl_plugin::mk_internal_to_ieee_bv_unspecified(
decl_kind k, unsigned num_parameters, parameter const * parameters,
unsigned arity, sort * const * domain, sort * range) {
if (arity != 0)
m_manager->raise_exception("invalid number of arguments to to_ieee_bv_unspecified; expecting none");
m_manager->raise_exception("invalid number of arguments to fp.to_ieee_bv_unspecified; expecting none");
if (num_parameters != 2)
m_manager->raise_exception("invalid number of parameters to to_ieee_bv_unspecified; expecting 2");
m_manager->raise_exception("invalid number of parameters to fp.to_ieee_bv_unspecified; expecting 2");
if (!parameters[0].is_int() || !parameters[1].is_int())
m_manager->raise_exception("invalid parameters type provided to to_ieee_bv_unspecified; expecting 2 integers");
m_manager->raise_exception("invalid parameters type provided to fp.to_ieee_bv_unspecified; expecting 2 integers");
parameter width_p[1] = { parameter(parameters[0].get_int() + parameters[1].get_int()) };
sort * bv_srt = m_bv_plugin->mk_sort(m_bv_fid, 1, width_p);
return m_manager->mk_func_decl(symbol("to_ieee_bv_unspecified"), 0, domain, bv_srt, func_decl_info(m_family_id, k, num_parameters, parameters));
return m_manager->mk_func_decl(symbol("fp.to_ieee_bv_unspecified"), 0, domain, bv_srt, func_decl_info(m_family_id, k, num_parameters, parameters));
}
@ -915,7 +915,8 @@ void fpa_decl_plugin::get_op_names(svector<builtin_name> & op_names, symbol cons
op_names.push_back(builtin_name("to_fp_unsigned", OP_FPA_TO_FP_UNSIGNED));
/* Extensions */
op_names.push_back(builtin_name("to_ieee_bv", OP_FPA_TO_IEEE_BV));
op_names.push_back(builtin_name("to_ieee_bv", OP_FPA_TO_IEEE_BV));
op_names.push_back(builtin_name("fp.to_ieee_bv", OP_FPA_TO_IEEE_BV));
}
void fpa_decl_plugin::get_sort_names(svector<builtin_name> & sort_names, symbol const & logic) {

View file

@ -259,7 +259,7 @@ public:
bool is_rm(sort * s) const { return is_sort_of(s, m_fid, ROUNDING_MODE_SORT); }
bool is_float(expr * e) const { return is_float(m_manager.get_sort(e)); }
bool is_rm(expr * e) const { return is_rm(m_manager.get_sort(e)); }
bool is_fp(expr * e) const { return is_app_of(e, m_fid, OP_FPA_FP); }
bool is_fp(expr * e) const { return is_app_of(e, m_fid, OP_FPA_FP); }
unsigned get_ebits(sort * s) const;
unsigned get_sbits(sort * s) const;
@ -288,19 +288,24 @@ public:
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_numeral(n, v) && fm().is_nan(v); }
bool is_inf(expr * n) { scoped_mpf v(fm()); return is_numeral(n, v) && fm().is_inf(v); }
bool is_pinf(expr * n) { scoped_mpf v(fm()); return is_numeral(n, v) && fm().is_pinf(v); }
bool is_ninf(expr * n) { scoped_mpf v(fm()); return is_numeral(n, v) && fm().is_ninf(v); }
bool is_zero(expr * n) { scoped_mpf v(fm()); return is_numeral(n, v) && fm().is_zero(v); }
bool is_pzero(expr * n) { scoped_mpf v(fm()); return is_numeral(n, v) && fm().is_pzero(v); }
bool is_nzero(expr * n) { scoped_mpf v(fm()); return is_numeral(n, v) && fm().is_nzero(v); }
bool is_normal(expr * n) { scoped_mpf v(fm()); return is_numeral(n, v) && fm().is_normal(v); }
bool is_subnormal(expr * n) { scoped_mpf v(fm()); return is_numeral(n, v) && fm().is_denormal(v); }
bool is_positive(expr * n) { scoped_mpf v(fm()); return is_numeral(n, v) && fm().is_pos(v); }
bool is_negative(expr * n) { scoped_mpf v(fm()); return is_numeral(n, v) && fm().is_neg(v); }
app * mk_fp(expr * sgn, expr * exp, expr * sig) {
app * mk_fp(expr * sgn, expr * exp, expr * sig) {
SASSERT(m_bv_util.is_bv(sgn) && m_bv_util.get_bv_size(sgn) == 1);
SASSERT(m_bv_util.is_bv(exp));
SASSERT(m_bv_util.is_bv(sig));
return m().mk_app(m_fid, OP_FPA_FP, sgn, exp, sig);
SASSERT(m_bv_util.is_bv(sig));
return m().mk_app(m_fid, OP_FPA_FP, sgn, exp, sig);
}
app * mk_to_fp(sort * s, expr * bv_t) {
SASSERT(is_float(s) && s->get_num_parameters() == 2);
return m().mk_app(m_fid, OP_FPA_TO_FP, 2, s->get_parameters(), 1, &bv_t);
@ -377,28 +382,28 @@ public:
app * mk_internal_to_ieee_bv_unspecified(unsigned ebits, unsigned sbits);
app * mk_internal_to_real_unspecified(unsigned ebits, unsigned sbits);
bool is_bvwrap(expr * e) const { return is_app_of(e, get_family_id(), OP_FPA_INTERNAL_BVWRAP); }
bool is_bvwrap(func_decl * f) const { return f->get_family_id() == get_family_id() && f->get_decl_kind() == OP_FPA_INTERNAL_BVWRAP; }
bool is_bv2rm(expr * e) const { return is_app_of(e, get_family_id(), OP_FPA_INTERNAL_BV2RM); }
bool is_bv2rm(func_decl * f) const { return f->get_family_id() == get_family_id() && f->get_decl_kind() == OP_FPA_INTERNAL_BV2RM; }
bool is_bvwrap(expr const * e) const { return is_app_of(e, get_family_id(), OP_FPA_INTERNAL_BVWRAP); }
bool is_bvwrap(func_decl const * f) const { return f->get_family_id() == get_family_id() && f->get_decl_kind() == OP_FPA_INTERNAL_BVWRAP; }
bool is_bv2rm(expr const * e) const { return is_app_of(e, get_family_id(), OP_FPA_INTERNAL_BV2RM); }
bool is_bv2rm(func_decl const * f) const { return f->get_family_id() == get_family_id() && f->get_decl_kind() == OP_FPA_INTERNAL_BV2RM; }
bool is_min_interpreted(expr * e) { return is_app_of(e, get_family_id(), OP_FPA_INTERNAL_MIN_I); }
bool is_min_unspecified(expr * e) { return is_app_of(e, get_family_id(), OP_FPA_INTERNAL_MIN_UNSPECIFIED); }
bool is_max_interpreted(expr * e) { return is_app_of(e, get_family_id(), OP_FPA_INTERNAL_MAX_I); }
bool is_max_unspecified(expr * e) { return is_app_of(e, get_family_id(), OP_FPA_INTERNAL_MAX_UNSPECIFIED); }
bool is_to_ubv_unspecified(expr * e) { return is_app_of(e, get_family_id(), OP_FPA_INTERNAL_TO_UBV_UNSPECIFIED); }
bool is_to_sbv_unspecified(expr * e) { return is_app_of(e, get_family_id(), OP_FPA_INTERNAL_TO_SBV_UNSPECIFIED); }
bool is_to_ieee_bv_unspecified(expr * e) { return is_app_of(e, get_family_id(), OP_FPA_INTERNAL_TO_IEEE_BV_UNSPECIFIED); }
bool is_to_real_unspecified(expr * e) { return is_app_of(e, get_family_id(), OP_FPA_INTERNAL_TO_REAL_UNSPECIFIED); }
bool is_min_interpreted(expr const * e) const { return is_app_of(e, get_family_id(), OP_FPA_INTERNAL_MIN_I); }
bool is_min_unspecified(expr const * e) const { return is_app_of(e, get_family_id(), OP_FPA_INTERNAL_MIN_UNSPECIFIED); }
bool is_max_interpreted(expr const * e) const { return is_app_of(e, get_family_id(), OP_FPA_INTERNAL_MAX_I); }
bool is_max_unspecified(expr const * e) const { return is_app_of(e, get_family_id(), OP_FPA_INTERNAL_MAX_UNSPECIFIED); }
bool is_to_ubv_unspecified(expr const * e) const { return is_app_of(e, get_family_id(), OP_FPA_INTERNAL_TO_UBV_UNSPECIFIED); }
bool is_to_sbv_unspecified(expr const * e) const { return is_app_of(e, get_family_id(), OP_FPA_INTERNAL_TO_SBV_UNSPECIFIED); }
bool is_to_ieee_bv_unspecified(expr const * e) const { return is_app_of(e, get_family_id(), OP_FPA_INTERNAL_TO_IEEE_BV_UNSPECIFIED); }
bool is_to_real_unspecified(expr const * e) const { return is_app_of(e, get_family_id(), OP_FPA_INTERNAL_TO_REAL_UNSPECIFIED); }
bool is_min_interpreted(func_decl * f) { return f->get_family_id() == get_family_id() && f->get_decl_kind() == OP_FPA_INTERNAL_MIN_I; }
bool is_min_unspecified(func_decl * f) { return f->get_family_id() == get_family_id() && f->get_decl_kind() == OP_FPA_INTERNAL_MIN_UNSPECIFIED; }
bool is_max_interpreted(func_decl * f) { return f->get_family_id() == get_family_id() && f->get_decl_kind() == OP_FPA_INTERNAL_MAX_I; }
bool is_max_unspecified(func_decl * f) { return f->get_family_id() == get_family_id() && f->get_decl_kind() == OP_FPA_INTERNAL_MAX_UNSPECIFIED; }
bool is_to_ubv_unspecified(func_decl * f) { return f->get_family_id() == get_family_id() && f->get_decl_kind() == OP_FPA_INTERNAL_TO_UBV_UNSPECIFIED; }
bool is_to_sbv_unspecified(func_decl * f) { return f->get_family_id() == get_family_id() && f->get_decl_kind() == OP_FPA_INTERNAL_TO_SBV_UNSPECIFIED; }
bool is_to_ieee_bv_unspecified(func_decl * f) { return f->get_family_id() == get_family_id() && f->get_decl_kind() == OP_FPA_INTERNAL_TO_IEEE_BV_UNSPECIFIED; }
bool is_to_real_unspecified(func_decl * f) { return f->get_family_id() == get_family_id() && f->get_decl_kind() == OP_FPA_INTERNAL_TO_REAL_UNSPECIFIED; }
bool is_min_interpreted(func_decl const * f) const { return f->get_family_id() == get_family_id() && f->get_decl_kind() == OP_FPA_INTERNAL_MIN_I; }
bool is_min_unspecified(func_decl const * f) const { return f->get_family_id() == get_family_id() && f->get_decl_kind() == OP_FPA_INTERNAL_MIN_UNSPECIFIED; }
bool is_max_interpreted(func_decl const * f) const { return f->get_family_id() == get_family_id() && f->get_decl_kind() == OP_FPA_INTERNAL_MAX_I; }
bool is_max_unspecified(func_decl const * f) const { return f->get_family_id() == get_family_id() && f->get_decl_kind() == OP_FPA_INTERNAL_MAX_UNSPECIFIED; }
bool is_to_ubv_unspecified(func_decl const * f) const { return f->get_family_id() == get_family_id() && f->get_decl_kind() == OP_FPA_INTERNAL_TO_UBV_UNSPECIFIED; }
bool is_to_sbv_unspecified(func_decl const * f) const { return f->get_family_id() == get_family_id() && f->get_decl_kind() == OP_FPA_INTERNAL_TO_SBV_UNSPECIFIED; }
bool is_to_ieee_bv_unspecified(func_decl const * f) const { return f->get_family_id() == get_family_id() && f->get_decl_kind() == OP_FPA_INTERNAL_TO_IEEE_BV_UNSPECIFIED; }
bool is_to_real_unspecified(func_decl const * f) const { return f->get_family_id() == get_family_id() && f->get_decl_kind() == OP_FPA_INTERNAL_TO_REAL_UNSPECIFIED; }
bool contains_floats(ast * a);
};

View file

@ -22,7 +22,7 @@ Revision History:
#include"ast_pp.h"
#include"ast_ll_pp.h"
bool macro_finder::is_macro(expr * n, app * & head, expr * & def) {
bool macro_finder::is_macro(expr * n, app_ref & head, expr_ref & def) {
if (!is_quantifier(n) || !to_quantifier(n)->is_forall())
return false;
TRACE("macro_finder", tout << "processing: " << mk_pp(n, m_manager) << "\n";);
@ -171,23 +171,20 @@ bool macro_finder::expand_macros(unsigned num, expr * const * exprs, proof * con
for (unsigned i = 0; i < num; i++) {
expr * n = exprs[i];
proof * pr = m_manager.proofs_enabled() ? prs[i] : 0;
expr_ref new_n(m_manager);
expr_ref new_n(m_manager), def(m_manager);
proof_ref new_pr(m_manager);
m_macro_manager.expand_macros(n, pr, new_n, new_pr);
app * head = 0;
expr * def = 0;
app * t = 0;
app_ref head(m_manager), t(m_manager);
if (is_macro(new_n, head, def) && m_macro_manager.insert(head->get_decl(), to_quantifier(new_n.get()), new_pr)) {
TRACE("macro_finder_found", tout << "found new macro: " << head->get_decl()->get_name() << "\n" << mk_pp(new_n, m_manager) << "\n";);
TRACE("macro_finder_found", tout << "found new macro: " << head->get_decl()->get_name() << "\n" << new_n << "\n";);
found_new_macro = true;
}
else if (is_arith_macro(new_n, new_pr, new_exprs, new_prs)) {
TRACE("macro_finder_found", tout << "found new arith macro:\n" << mk_pp(new_n, m_manager) << "\n";);
TRACE("macro_finder_found", tout << "found new arith macro:\n" << new_n << "\n";);
found_new_macro = true;
}
else if (m_util.is_pseudo_predicate_macro(new_n, head, t, def)) {
TRACE("macro_finder_found", tout << "found new pseudo macro:\n" << mk_pp(head, m_manager) << "\n" << mk_pp(t, m_manager) << "\n" <<
mk_pp(def, m_manager) << "\n";);
TRACE("macro_finder_found", tout << "found new pseudo macro:\n" << head << "\n" << t << "\n" << def << "\n";);
pseudo_predicate_macro2macro(m_manager, head, t, def, to_quantifier(new_n), new_pr, new_exprs, new_prs);
found_new_macro = true;
}

View file

@ -41,7 +41,7 @@ class macro_finder {
bool expand_macros(unsigned num, expr * const * exprs, proof * const * prs, expr_ref_vector & new_exprs, proof_ref_vector & new_prs);
bool is_arith_macro(expr * n, proof * pr, expr_ref_vector & new_exprs, proof_ref_vector & new_prs);
bool is_macro(expr * n, app * & head, expr * & def);
bool is_macro(expr * n, app_ref & head, expr_ref & def);
bool is_pseudo_head(expr * n, unsigned num_decls, app * & head, app * & t);
bool is_pseudo_predicate_macro(expr * n, app * & head, app * & t, expr * & def);

View file

@ -106,7 +106,7 @@ bool macro_manager::insert(func_decl * f, quantifier * m, proof * pr) {
if (!m_deps.insert(f, s)) {
return false;
}
// add macro
m_decl2macro.insert(f, m);
m_decls.push_back(f);
@ -117,8 +117,8 @@ bool macro_manager::insert(func_decl * f, quantifier * m, proof * pr) {
}
TRACE("macro_insert", tout << "A macro was successfully created for: " << f->get_name() << "\n";);
// Nothing's forbidden anymore; if something's bad, we detected it earlier.
// Nothing's forbidden anymore; if something's bad, we detected it earlier.
// mark_forbidden(m->get_expr());
return true;
}
@ -144,7 +144,7 @@ namespace macro_manager_ns {
\brief Mark all func_decls used in exprs as forbidden.
*/
void macro_manager::mark_forbidden(unsigned n, expr * const * exprs) {
expr_mark visited;
expr_mark visited;
macro_manager_ns::proc p(m_forbidden_set, m_forbidden);
for (unsigned i = 0; i < n; i++)
for_each_expr(p, visited, exprs[i]);
@ -187,9 +187,9 @@ func_decl * macro_manager::get_macro_interpretation(unsigned i, expr_ref & inter
app * head;
expr * def;
get_head_def(q, f, head, def);
TRACE("macro_bug",
TRACE("macro_bug",
tout << f->get_name() << "\n" << mk_pp(head, m_manager) << "\n" << mk_pp(q, m_manager) << "\n";);
m_util.mk_macro_interpretation(head, def, interp);
m_util.mk_macro_interpretation(head, q->get_num_decls(), def, interp);
return f;
}
@ -237,7 +237,7 @@ void macro_manager::macro_expander::reduce1_quantifier(quantifier * q) {
erase_patterns = true;
}
for (unsigned i = 0; !erase_patterns && i < q->get_num_no_patterns(); i++) {
if (q->get_no_pattern(i) != new_q->get_no_pattern(i))
if (q->get_no_pattern(i) != new_q->get_no_pattern(i))
erase_patterns = true;
}
}
@ -254,7 +254,7 @@ bool macro_manager::macro_expander::get_subst(expr * _n, expr_ref & r, proof_ref
return false;
app * n = to_app(_n);
quantifier * q = 0;
func_decl * d = n->get_decl();
func_decl * d = n->get_decl();
TRACE("macro_manager_bug", tout << "trying to expand:\n" << mk_pp(n, m) << "\nd:\n" << d->get_name() << "\n";);
if (m_macro_manager.m_decl2macro.find(d, q)) {
TRACE("macro_manager", tout << "expanding: " << mk_pp(n, m) << "\n";);
@ -308,7 +308,7 @@ void macro_manager::expand_macros(expr * n, proof * pr, expr_ref & r, proof_ref
if (r.get() == old_n.get())
return;
old_n = r;
old_pr = new_pr;
old_pr = new_pr;
}
}
else {

View file

@ -34,7 +34,7 @@ macro_util::macro_util(ast_manager & m, simplifier & s):
m_simplifier(s),
m_arith_simp(0),
m_bv_simp(0),
m_basic_simp(0),
m_basic_simp(0),
m_forbidden_set(0),
m_curr_clause(0) {
}
@ -64,23 +64,23 @@ basic_simplifier_plugin * macro_util::get_basic_simp() const {
}
bool macro_util::is_bv(expr * n) const {
return get_bv_simp()->is_bv(n);
return get_bv_simp()->is_bv(n);
}
bool macro_util::is_bv_sort(sort * s) const {
return get_bv_simp()->is_bv_sort(s);
return get_bv_simp()->is_bv_sort(s);
}
bool macro_util::is_add(expr * n) const {
return get_arith_simp()->is_add(n) || get_bv_simp()->is_add(n);
return get_arith_simp()->is_add(n) || get_bv_simp()->is_add(n);
}
bool macro_util::is_times_minus_one(expr * n, expr * & arg) const {
return get_arith_simp()->is_times_minus_one(n, arg) || get_bv_simp()->is_times_minus_one(n, arg);
}
bool macro_util::is_le(expr * n) const {
return get_arith_simp()->is_le(n) || get_bv_simp()->is_le(n);
bool macro_util::is_le(expr * n) const {
return get_arith_simp()->is_le(n) || get_bv_simp()->is_le(n);
}
bool macro_util::is_le_ge(expr * n) const {
@ -130,7 +130,7 @@ void macro_util::mk_add(unsigned num_args, expr * const * args, sort * s, expr_r
/**
\brief Return true if \c n is an application of the form
(f x_{k_1}, ..., x_{k_n})
where f is uninterpreted
@ -147,7 +147,7 @@ bool macro_util::is_macro_head(expr * n, unsigned num_decls) const {
var2pos.resize(num_decls, -1);
for (unsigned i = 0; i < num_decls; i++) {
expr * c = to_app(n)->get_arg(i);
if (!is_var(c))
if (!is_var(c))
return false;
unsigned idx = to_var(c)->get_idx();
if (idx >= num_decls || var2pos[idx] != -1)
@ -161,12 +161,12 @@ bool macro_util::is_macro_head(expr * n, unsigned num_decls) const {
/**
\brief Return true if n is of the form
(= (f x_{k_1}, ..., x_{k_n}) t) OR
(iff (f x_{k_1}, ..., x_{k_n}) t)
(iff (f x_{k_1}, ..., x_{k_n}) t)
where
is_macro_head((f x_{k_1}, ..., x_{k_n})) returns true AND
t does not contain f AND
f is not in forbidden_set
@ -176,11 +176,12 @@ bool macro_util::is_macro_head(expr * n, unsigned num_decls) const {
def will contain t
*/
bool macro_util::is_left_simple_macro(expr * n, unsigned num_decls, app * & head, expr * & def) const {
bool macro_util::is_left_simple_macro(expr * n, unsigned num_decls, app_ref & head, expr_ref & def) const {
if (m_manager.is_eq(n) || m_manager.is_iff(n)) {
expr * lhs = to_app(n)->get_arg(0);
expr * rhs = to_app(n)->get_arg(1);
if (is_macro_head(lhs, num_decls) && !is_forbidden(to_app(lhs)->get_decl()) && !occurs(to_app(lhs)->get_decl(), rhs)) {
if (is_macro_head(lhs, num_decls) && !is_forbidden(to_app(lhs)->get_decl()) &&
!occurs(to_app(lhs)->get_decl(), rhs)) {
head = to_app(lhs);
def = rhs;
return true;
@ -189,14 +190,15 @@ bool macro_util::is_left_simple_macro(expr * n, unsigned num_decls, app * & head
return false;
}
/**
\brief Return true if n is of the form
(= t (f x_{k_1}, ..., x_{k_n})) OR
(iff t (f x_{k_1}, ..., x_{k_n}))
where
is_macro_head((f x_{k_1}, ..., x_{k_n})) returns true AND
t does not contain f AND
f is not in forbidden_set
@ -206,11 +208,12 @@ bool macro_util::is_left_simple_macro(expr * n, unsigned num_decls, app * & head
def will contain t
*/
bool macro_util::is_right_simple_macro(expr * n, unsigned num_decls, app * & head, expr * & def) const {
bool macro_util::is_right_simple_macro(expr * n, unsigned num_decls, app_ref & head, expr_ref & def) const {
if (m_manager.is_eq(n) || m_manager.is_iff(n)) {
expr * lhs = to_app(n)->get_arg(0);
expr * rhs = to_app(n)->get_arg(1);
if (is_macro_head(rhs, num_decls) && !is_forbidden(to_app(rhs)->get_decl()) && !occurs(to_app(rhs)->get_decl(), lhs)) {
if (is_macro_head(rhs, num_decls) && !is_forbidden(to_app(rhs)->get_decl()) &&
!occurs(to_app(rhs)->get_decl(), lhs)) {
head = to_app(rhs);
def = lhs;
return true;
@ -253,7 +256,7 @@ bool macro_util::is_arith_macro(expr * n, unsigned num_decls, app_ref & head, ex
if (!as->is_numeral(rhs))
return false;
inv = false;
ptr_buffer<expr> args;
expr * h = 0;
@ -270,15 +273,15 @@ bool macro_util::is_arith_macro(expr * n, unsigned num_decls, app_ref & head, ex
for (unsigned i = 0; i < lhs_num_args; i++) {
expr * arg = lhs_args[i];
expr * neg_arg;
if (h == 0 &&
is_macro_head(arg, num_decls) &&
!is_forbidden(to_app(arg)->get_decl()) &&
if (h == 0 &&
is_macro_head(arg, num_decls) &&
!is_forbidden(to_app(arg)->get_decl()) &&
!poly_contains_head(lhs, to_app(arg)->get_decl(), arg)) {
h = arg;
}
else if (h == 0 && as->is_times_minus_one(arg, neg_arg) &&
is_macro_head(neg_arg, num_decls) &&
!is_forbidden(to_app(neg_arg)->get_decl()) &&
is_macro_head(neg_arg, num_decls) &&
!is_forbidden(to_app(neg_arg)->get_decl()) &&
!poly_contains_head(lhs, to_app(neg_arg)->get_decl(), arg)) {
h = neg_arg;
inv = true;
@ -302,8 +305,8 @@ bool macro_util::is_arith_macro(expr * n, unsigned num_decls, app_ref & head, ex
/**
\brief Auxiliary function for is_pseudo_predicate_macro. It detects the pattern (= (f X) t)
*/
bool macro_util::is_pseudo_head(expr * n, unsigned num_decls, app * & head, app * & t) {
if (!m_manager.is_eq(n))
bool macro_util::is_pseudo_head(expr * n, unsigned num_decls, app_ref & head, app_ref & t) {
if (!m_manager.is_eq(n))
return false;
expr * lhs = to_app(n)->get_arg(0);
expr * rhs = to_app(n)->get_arg(1);
@ -330,9 +333,9 @@ bool macro_util::is_pseudo_head(expr * n, unsigned num_decls, app * & head, app
/**
\brief Returns true if n if of the form (forall (X) (iff (= (f X) t) def[X]))
where t is a ground term, (f X) is the head.
where t is a ground term, (f X) is the head.
*/
bool macro_util::is_pseudo_predicate_macro(expr * n, app * & head, app * & t, expr * & def) {
bool macro_util::is_pseudo_predicate_macro(expr * n, app_ref & head, app_ref & t, expr_ref & def) {
if (!is_quantifier(n) || !to_quantifier(n)->is_forall())
return false;
TRACE("macro_util", tout << "processing: " << mk_pp(n, m_manager) << "\n";);
@ -342,14 +345,14 @@ bool macro_util::is_pseudo_predicate_macro(expr * n, app * & head, app * & t, ex
return false;
expr * lhs = to_app(body)->get_arg(0);
expr * rhs = to_app(body)->get_arg(1);
if (is_pseudo_head(lhs, num_decls, head, t) &&
!is_forbidden(head->get_decl()) &&
if (is_pseudo_head(lhs, num_decls, head, t) &&
!is_forbidden(head->get_decl()) &&
!occurs(head->get_decl(), rhs)) {
def = rhs;
return true;
}
if (is_pseudo_head(rhs, num_decls, head, t) &&
!is_forbidden(head->get_decl()) &&
if (is_pseudo_head(rhs, num_decls, head, t) &&
!is_forbidden(head->get_decl()) &&
!occurs(head->get_decl(), lhs)) {
def = lhs;
return true;
@ -360,7 +363,7 @@ bool macro_util::is_pseudo_predicate_macro(expr * n, app * & head, app * & t, ex
/**
\brief A quasi-macro head is of the form f[X_1, ..., X_n],
where n == num_decls, f[X_1, ..., X_n] is a term starting with symbol f, f is uninterpreted,
contains all universally quantified variables as arguments.
contains all universally quantified variables as arguments.
Note that, some arguments of f[X_1, ..., X_n] may not be variables.
Examples of quasi-macros:
@ -402,7 +405,7 @@ bool macro_util::is_quasi_macro_head(expr * n, unsigned num_decls) const {
\brief Convert a quasi-macro head into a macro head, and store the conditions under
which it is valid in cond.
*/
void macro_util::quasi_macro_head_to_macro_head(app * qhead, unsigned num_decls, app_ref & head, expr_ref & cond) const {
void macro_util::quasi_macro_head_to_macro_head(app * qhead, unsigned & num_decls, app_ref & head, expr_ref & cond) const {
unsigned num_args = qhead->get_num_args();
sbuffer<bool> found_vars;
found_vars.resize(num_decls, false);
@ -428,6 +431,7 @@ void macro_util::quasi_macro_head_to_macro_head(app * qhead, unsigned num_decls,
}
get_basic_simp()->mk_and(new_conds.size(), new_conds.c_ptr(), cond);
head = m_manager.mk_app(qhead->get_decl(), new_args.size(), new_args.c_ptr());
num_decls = next_var_idx;
}
/**
@ -437,10 +441,10 @@ void macro_util::quasi_macro_head_to_macro_head(app * qhead, unsigned num_decls,
See normalize_expr
*/
void macro_util::mk_macro_interpretation(app * head, expr * def, expr_ref & interp) const {
void macro_util::mk_macro_interpretation(app * head, unsigned num_decls, expr * def, expr_ref & interp) const {
SASSERT(is_macro_head(head, head->get_num_args()));
SASSERT(!occurs(head->get_decl(), def));
normalize_expr(head, def, interp);
normalize_expr(head, num_decls, def, interp);
}
/**
@ -453,40 +457,36 @@ void macro_util::mk_macro_interpretation(app * head, expr * def, expr_ref & inte
f(x_1, x_2) --> f(x_0, x_1)
f(x_3, x_2) --> f(x_0, x_1)
*/
void macro_util::normalize_expr(app * head, expr * t, expr_ref & norm_t) const {
expr_ref_buffer var_mapping(m_manager);
void macro_util::normalize_expr(app * head, unsigned num_decls, expr * t, expr_ref & norm_t) const {
expr_ref_buffer var_mapping(m_manager);
var_mapping.resize(num_decls);
bool changed = false;
unsigned num_args = head->get_num_args();
unsigned max = num_args;
for (unsigned i = 0; i < num_args; i++) {
var * v = to_var(head->get_arg(i));
if (v->get_idx() >= max)
max = v->get_idx() + 1;
}
TRACE("normalize_expr_bug",
TRACE("macro_util",
tout << "head: " << mk_pp(head, m_manager) << "\n";
tout << "applying substitution to:\n" << mk_bounded_pp(t, m_manager) << "\n";);
for (unsigned i = 0; i < num_args; i++) {
var * v = to_var(head->get_arg(i));
if (v->get_idx() != i) {
var * v = to_var(head->get_arg(i));
unsigned vi = v->get_idx();
SASSERT(vi < num_decls);
if (vi != i) {
changed = true;
var * new_var = m_manager.mk_var(i, v->get_sort());
CTRACE("normalize_expr_bug", v->get_idx() >= num_args, tout << mk_pp(v, m_manager) << ", num_args: " << num_args << "\n";);
SASSERT(v->get_idx() < max);
var_mapping.setx(max - v->get_idx() - 1, new_var);
}
else {
var_mapping.setx(max - i - 1, v);
var_ref new_var(m_manager.mk_var(i, v->get_sort()), m_manager);
var_mapping.setx(num_decls - vi - 1, new_var);
}
else
var_mapping.setx(num_decls - i - 1, v);
}
if (changed) {
// REMARK: t may have nested quantifiers... So, I must use the std order for variable substitution.
var_subst subst(m_manager);
TRACE("macro_util_bug",
var_subst subst(m_manager, true);
TRACE("macro_util",
tout << "head: " << mk_pp(head, m_manager) << "\n";
tout << "applying substitution to:\n" << mk_ll_pp(t, m_manager) << "\nsubstitituion:\n";
tout << "applying substitution to:\n" << mk_ll_pp(t, m_manager) << "\nsubstitution:\n";
for (unsigned i = 0; i < var_mapping.size(); i++) {
tout << "#" << i << " -> " << mk_pp(var_mapping[i], m_manager) << "\n";
if (var_mapping[i] != 0)
tout << "#" << i << " -> " << mk_ll_pp(var_mapping[i], m_manager);
});
subst(t, var_mapping.size(), var_mapping.c_ptr(), norm_t);
}
@ -497,8 +497,8 @@ void macro_util::normalize_expr(app * head, expr * t, expr_ref & norm_t) const {
// -----------------------------
//
// "Hint" support
// See comment at is_hint_atom
// "Hint" support
// See comment at is_hint_atom
// for a definition of what a hint is.
//
// -----------------------------
@ -510,7 +510,7 @@ bool is_hint_head(expr * n, ptr_buffer<var> & vars) {
return false;
unsigned num_args = to_app(n)->get_num_args();
for (unsigned i = 0; i < num_args; i++) {
expr * arg = to_app(n)->get_arg(i);
expr * arg = to_app(n)->get_arg(i);
if (is_var(arg))
vars.push_back(to_var(arg));
}
@ -546,7 +546,7 @@ bool vars_of_is_subset(expr * n, ptr_buffer<var> const & vars) {
}
}
else {
SASSERT(is_quantifier(curr));
SASSERT(is_quantifier(curr));
return false; // do no support nested quantifier... being conservative.
}
}
@ -554,7 +554,7 @@ bool vars_of_is_subset(expr * n, ptr_buffer<var> const & vars) {
}
/**
\brief (= lhs rhs) is a hint atom if
\brief (= lhs rhs) is a hint atom if
lhs is of the form (f t_1 ... t_n)
and all variables occurring in rhs are direct arguments of lhs.
*/
@ -565,7 +565,7 @@ bool is_hint_atom(expr * lhs, expr * rhs) {
return !occurs(to_app(lhs)->get_decl(), rhs) && vars_of_is_subset(rhs, vars);
}
void hint_to_macro_head(ast_manager & m, app * head, unsigned num_decls, app_ref & new_head) {
void hint_to_macro_head(ast_manager & m, app * head, unsigned & num_decls, app_ref & new_head) {
unsigned num_args = head->get_num_args();
ptr_buffer<expr> new_args;
sbuffer<bool> found_vars;
@ -587,21 +587,22 @@ void hint_to_macro_head(ast_manager & m, app * head, unsigned num_decls, app_ref
new_args.push_back(new_var);
}
new_head = m.mk_app(head->get_decl(), new_args.size(), new_args.c_ptr());
num_decls = next_var_idx;
}
/**
\brief Return true if n can be viewed as a polynomial "hint" based on head.
That is, n (but the monomial exception) only uses the variables in head, and does not use
head->get_decl().
head->get_decl().
is_hint_head(head, vars) must also return true
*/
bool macro_util::is_poly_hint(expr * n, app * head, expr * exception) {
TRACE("macro_util_hint", tout << "is_poly_hint n:\n" << mk_pp(n, m_manager) << "\nhead:\n" << mk_pp(head, m_manager) << "\nexception:\n";
TRACE("macro_util", tout << "is_poly_hint n:\n" << mk_pp(n, m_manager) << "\nhead:\n" << mk_pp(head, m_manager) << "\nexception:\n";
if (exception) tout << mk_pp(exception, m_manager); else tout << "<null>";
tout << "\n";);
ptr_buffer<var> vars;
if (!is_hint_head(head, vars)) {
TRACE("macro_util_hint", tout << "failed because head is not hint head\n";);
TRACE("macro_util", tout << "failed because head is not hint head\n";);
return false;
}
func_decl * f = head->get_decl();
@ -618,13 +619,13 @@ bool macro_util::is_poly_hint(expr * n, app * head, expr * exception) {
for (unsigned i = 0; i < num_args; i++) {
expr * arg = args[i];
if (arg != exception && (occurs(f, arg) || !vars_of_is_subset(arg, vars))) {
TRACE("macro_util_hint", tout << "failed because of:\n" << mk_pp(arg, m_manager) << "\n";);
TRACE("macro_util", tout << "failed because of:\n" << mk_pp(arg, m_manager) << "\n";);
return false;
}
}
TRACE("macro_util_hint", tout << "succeeded\n";);
TRACE("macro_util", tout << "succeeded\n";);
return true;
}
// -----------------------------
@ -663,19 +664,19 @@ void macro_util::macro_candidates::insert(func_decl * f, expr * def, expr * cond
//
// -----------------------------
void macro_util::insert_macro(app * head, expr * def, expr * cond, bool ineq, bool satisfy_atom, bool hint, macro_candidates & r) {
void macro_util::insert_macro(app * head, unsigned num_decls, expr * def, expr * cond, bool ineq, bool satisfy_atom, bool hint, macro_candidates & r) {
expr_ref norm_def(m_manager);
expr_ref norm_cond(m_manager);
normalize_expr(head, def, norm_def);
normalize_expr(head, num_decls, def, norm_def);
if (cond != 0)
normalize_expr(head, cond, norm_cond);
normalize_expr(head, num_decls, cond, norm_cond);
else if (!hint)
norm_cond = m_manager.mk_true();
SASSERT(!hint || norm_cond.get() == 0);
r.insert(head->get_decl(), norm_def.get(), norm_cond.get(), ineq, satisfy_atom, hint);
}
void macro_util::insert_quasi_macro(app * head, unsigned num_decls, expr * def, expr * cond, bool ineq, bool satisfy_atom,
void macro_util::insert_quasi_macro(app * head, unsigned num_decls, expr * def, expr * cond, bool ineq, bool satisfy_atom,
bool hint, macro_candidates & r) {
if (!is_macro_head(head, head->get_num_args())) {
app_ref new_head(m_manager);
@ -690,11 +691,14 @@ void macro_util::insert_quasi_macro(app * head, unsigned num_decls, expr * def,
}
else {
hint_to_macro_head(m_manager, head, num_decls, new_head);
TRACE("macro_util",
tout << "hint macro head: " << mk_ismt2_pp(new_head, m_manager) << std::endl;
tout << "hint macro def: " << mk_ismt2_pp(def, m_manager) << std::endl; );
}
insert_macro(new_head, def, new_cond, ineq, satisfy_atom, hint, r);
insert_macro(new_head, num_decls, def, new_cond, ineq, satisfy_atom, hint, r);
}
else {
insert_macro(head, def, cond, ineq, satisfy_atom, hint, r);
insert_macro(head, num_decls, def, cond, ineq, satisfy_atom, hint, r);
}
}
@ -777,8 +781,8 @@ void macro_util::collect_arith_macro_candidates(expr * lhs, expr * rhs, expr * a
if (!is_app(arg))
continue;
func_decl * f = to_app(arg)->get_decl();
bool _is_arith_macro =
bool _is_arith_macro =
is_quasi_macro_head(arg, num_decls) &&
!is_forbidden(f) &&
!poly_contains_head(lhs, f, arg) &&
@ -799,14 +803,14 @@ void macro_util::collect_arith_macro_candidates(expr * lhs, expr * rhs, expr * a
}
else if (is_times_minus_one(arg, neg_arg) && is_app(neg_arg)) {
f = to_app(neg_arg)->get_decl();
bool _is_arith_macro =
bool _is_arith_macro =
is_quasi_macro_head(neg_arg, num_decls) &&
!is_forbidden(f) &&
!poly_contains_head(lhs, f, arg) &&
!occurs(f, rhs) &&
!rest_contains_decl(f, atom);
bool _is_poly_hint = !_is_arith_macro && is_poly_hint(lhs, to_app(neg_arg), arg);
if (_is_arith_macro || _is_poly_hint) {
collect_poly_args(lhs, arg, args);
expr_ref rest(m_manager);
@ -823,7 +827,7 @@ void macro_util::collect_arith_macro_candidates(expr * lhs, expr * rhs, expr * a
}
void macro_util::collect_arith_macro_candidates(expr * atom, unsigned num_decls, macro_candidates & r) {
TRACE("macro_util_hint", tout << "collect_arith_macro_candidates:\n" << mk_pp(atom, m_manager) << "\n";);
TRACE("macro_util", tout << "collect_arith_macro_candidates:\n" << mk_pp(atom, m_manager) << "\n";);
if (!m_manager.is_eq(atom) && !is_le_ge(atom))
return;
expr * lhs = to_app(atom)->get_arg(0);
@ -836,45 +840,47 @@ void macro_util::collect_arith_macro_candidates(expr * atom, unsigned num_decls,
/**
\brief Collect macro candidates for atom \c atom.
The candidates are stored in \c r.
The following post-condition holds:
for each i in [0, r.size() - 1]
we have a conditional macro of the form
r.get_cond(i) IMPLIES f(x_1, ..., x_n) = r.get_def(i)
where
f == r.get_fs(i) .., x_n), f is uninterpreted and x_1, ..., x_n are variables.
r.get_cond(i) and r.get_defs(i) do not contain f or variables not in {x_1, ..., x_n}
The idea is to use r.get_defs(i) as the interpretation for f in a model M whenever r.get_cond(i)
Given a model M and values { v_1, ..., v_n }
Given a model M and values { v_1, ..., v_n }
Let M' be M{x_1 -> v_1, ..., v_n -> v_n}
Note that M'(f(x_1, ..., x_n)) = M(f)(v_1, ..., v_n)
Then, IF we have that M(f)(v_1, ..., v_n) = M'(r.get_def(i)) AND
M'(r.get_cond(i)) = true
THEN M'(atom) = true
That is, if the conditional macro is used then the atom is satisfied when M'(r.get_cond(i)) = true
IF r.is_ineq(i) = false, then
M(f)(v_1, ..., v_n) ***MUST BE*** M'(r.get_def(i)) whenever M'(r.get_cond(i)) = true
IF r.satisfy_atom(i) = true, then we have the stronger property:
Then, IF we have that (M'(r.get_cond(i)) = true IMPLIES M(f)(v_1, ..., v_n) = M'(r.get_def(i)))
THEN M'(atom) = true
*/
void macro_util::collect_macro_candidates_core(expr * atom, unsigned num_decls, macro_candidates & r) {
if (m_manager.is_eq(atom) || m_manager.is_iff(atom)) {
expr * lhs = to_app(atom)->get_arg(0);
expr * rhs = to_app(atom)->get_arg(1);
if (is_quasi_macro_head(lhs, num_decls) &&
!is_forbidden(to_app(lhs)->get_decl()) &&
expr* lhs, *rhs;
TRACE("macro_util", tout << "Candidate check for: " << mk_ismt2_pp(atom, m_manager) << std::endl;);
if (m_manager.is_eq(atom, lhs, rhs) || m_manager.is_iff(atom, lhs, rhs)) {
if (is_quasi_macro_head(lhs, num_decls) &&
!is_forbidden(to_app(lhs)->get_decl()) &&
!occurs(to_app(lhs)->get_decl(), rhs) &&
!rest_contains_decl(to_app(lhs)->get_decl(), atom)) {
expr_ref cond(m_manager);
@ -885,9 +891,8 @@ void macro_util::collect_macro_candidates_core(expr * atom, unsigned num_decls,
insert_quasi_macro(to_app(lhs), num_decls, rhs, 0, false, true, true, r);
}
if (is_quasi_macro_head(rhs, num_decls) &&
!is_forbidden(to_app(rhs)->get_decl()) &&
if (is_quasi_macro_head(rhs, num_decls) &&
!is_forbidden(to_app(rhs)->get_decl()) &&
!occurs(to_app(rhs)->get_decl(), lhs) &&
!rest_contains_decl(to_app(rhs)->get_decl(), atom)) {
expr_ref cond(m_manager);

View file

@ -74,9 +74,9 @@ private:
void collect_arith_macros(expr * n, unsigned num_decls, unsigned max_macros, bool allow_cond_macros,
macro_candidates & r);
void normalize_expr(app * head, expr * t, expr_ref & norm_t) const;
void insert_macro(app * head, expr * def, expr * cond, bool ineq, bool satisfy_atom, bool hint, macro_candidates & r);
void insert_quasi_macro(app * head, unsigned num_decls, expr * def, expr * cond, bool ineq, bool satisfy_atom, bool hint,
void normalize_expr(app * head, unsigned num_decls, expr * t, expr_ref & norm_t) const;
void insert_macro(app * head, unsigned num_decls, expr * def, expr * cond, bool ineq, bool satisfy_atom, bool hint, macro_candidates & r);
void insert_quasi_macro(app * head, unsigned num_decls, expr * def, expr * cond, bool ineq, bool satisfy_atom, bool hint,
macro_candidates & r);
expr * m_curr_clause; // auxiliary var used in collect_macro_candidates.
@ -102,10 +102,10 @@ public:
basic_simplifier_plugin * get_basic_simp() const;
bool is_macro_head(expr * n, unsigned num_decls) const;
bool is_left_simple_macro(expr * n, unsigned num_decls, app * & head, expr * & def) const;
bool is_right_simple_macro(expr * n, unsigned num_decls, app * & head, expr * & def) const;
bool is_simple_macro(expr * n, unsigned num_decls, app * & head, expr * & def) const {
return is_left_simple_macro(n, num_decls, head, def) || is_right_simple_macro(n, num_decls, head, def);
bool is_left_simple_macro(expr * n, unsigned num_decls, app_ref & head, expr_ref & def) const;
bool is_right_simple_macro(expr * n, unsigned num_decls, app_ref & head, expr_ref & def) const;
bool is_simple_macro(expr * n, unsigned num_decls, app_ref& head, expr_ref & def) const {
return is_left_simple_macro(n, num_decls, head, def) || is_right_simple_macro(n, num_decls, head, def);
}
bool is_arith_macro(expr * n, unsigned num_decls, app_ref & head, expr_ref & def, bool & inv) const;
@ -113,20 +113,20 @@ public:
bool inv;
return is_arith_macro(n, num_decls, head, def, inv);
}
bool is_pseudo_head(expr * n, unsigned num_decls, app * & head, app * & t);
bool is_pseudo_predicate_macro(expr * n, app * & head, app * & t, expr * & def);
bool is_pseudo_head(expr * n, unsigned num_decls, app_ref & head, app_ref & t);
bool is_pseudo_predicate_macro(expr * n, app_ref & head, app_ref & t, expr_ref & def);
bool is_quasi_macro_head(expr * n, unsigned num_decls) const;
void quasi_macro_head_to_macro_head(app * qhead, unsigned num_decls, app_ref & head, expr_ref & cond) const;
void quasi_macro_head_to_macro_head(app * qhead, unsigned & num_decls, app_ref & head, expr_ref & cond) const;
void mk_macro_interpretation(app * head, expr * def, expr_ref & interp) const;
void mk_macro_interpretation(app * head, unsigned num_decls, expr * def, expr_ref & interp) const;
void collect_macro_candidates(expr * atom, unsigned num_decls, macro_candidates & r);
void collect_macro_candidates(quantifier * q, macro_candidates & r);
//
// Auxiliary goodness that allows us to manipulate BV and Arith polynomials.
// Auxiliary goodness that allows us to manipulate BV and Arith polynomials.
//
bool is_bv(expr * n) const;
bool is_bv_sort(sort * s) const;

View file

@ -210,7 +210,7 @@ bool defined_names::impl::mk_name(expr * e, expr_ref & new_def, proof_ref & new_
TRACE("mk_definition_bug", tout << "name for expression is already cached..., returning false...\n";);
n = n_ptr;
if (m_manager.proofs_enabled()) {
proof * pr_ptr;
proof * pr_ptr = 0;
m_expr2proof.find(e, pr_ptr);
SASSERT(pr_ptr);
pr = pr_ptr;

View file

@ -58,7 +58,7 @@ struct pull_quant::imp {
}
bool found_quantifier = false;
bool forall_children;
bool forall_children = false;
for (unsigned i = 0; i < num_children; i++) {
expr * child = children[i];
@ -125,8 +125,8 @@ struct pull_quant::imp {
// of nested_q->get_expr().
m_shift(nested_q->get_expr(),
nested_q->get_num_decls(), // bound for shift1/shift2
num_decls - nested_q->get_num_decls(), // shift1 (shift by this ammount if var idx >= bound)
shift_amount, // shift2 (shift by this ammount if var idx < bound)
num_decls - nested_q->get_num_decls(), // shift1 (shift by this amount if var idx >= bound)
shift_amount, // shift2 (shift by this amount if var idx < bound)
adjusted_child);
TRACE("pull_quant", tout << "shifted bound: " << nested_q->get_num_decls() << " shift1: " << shift_amount <<
" shift2: " << (num_decls - nested_q->get_num_decls()) << "\n" << mk_pp(nested_q->get_expr(), m_manager) <<

View file

@ -388,7 +388,10 @@ expr_pattern_match::initialize(char const * spec_string) {
std::istringstream is(spec_string);
cmd_context ctx(true, &m_manager);
bool ps = ctx.print_success_enabled();
ctx.set_print_success(false);
VERIFY(parse_smt2_commands(ctx, is));
ctx.set_print_success(ps);
ptr_vector<expr>::const_iterator it = ctx.begin_assertions();
ptr_vector<expr>::const_iterator end = ctx.end_assertions();

View file

@ -474,13 +474,15 @@ void pattern_inference::reset_pre_patterns() {
m_pre_patterns.reset();
}
#ifdef _TRACE
static void dump_app_vector(std::ostream & out, ptr_vector<app> const & v, ast_manager & m) {
ptr_vector<app>::const_iterator it = v.begin();
ptr_vector<app>::const_iterator end = v.end();
for (; it != end; ++it)
out << mk_pp(*it, m) << "\n";
}
#endif
bool pattern_inference::is_forbidden(app * n) const {
func_decl const * decl = n->get_decl();
if (is_ground(n))

View file

@ -30,3 +30,18 @@ void pattern_inference_params::updt_params(params_ref const & _p) {
m_pi_pull_quantifiers = p.pull_quantifiers();
m_pi_warnings = p.warnings();
}
#define DISPLAY_PARAM(X) out << #X"=" << X << std::endl;
void pattern_inference_params::display(std::ostream & out) const {
DISPLAY_PARAM(m_pi_max_multi_patterns);
DISPLAY_PARAM(m_pi_block_loop_patterns);
DISPLAY_PARAM(m_pi_arith);
DISPLAY_PARAM(m_pi_use_database);
DISPLAY_PARAM(m_pi_arith_weight);
DISPLAY_PARAM(m_pi_non_nested_arith_weight);
DISPLAY_PARAM(m_pi_pull_quantifiers);
DISPLAY_PARAM(m_pi_nopat_weight);
DISPLAY_PARAM(m_pi_avoid_skolems);
DISPLAY_PARAM(m_pi_warnings);
}

View file

@ -46,6 +46,8 @@ struct pattern_inference_params {
}
void updt_params(params_ref const & _p);
void display(std::ostream & out) const;
};
#endif /* PATTERN_INFERENCE_PARAMS_H_ */

View file

@ -18,6 +18,7 @@ Revision History:
--*/
#include "pb_decl_plugin.h"
#include "ast_util.h"
pb_decl_plugin::pb_decl_plugin():
m_at_most_sym("at-most"),
@ -90,7 +91,7 @@ func_decl * pb_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, p
}
void pb_decl_plugin::get_op_names(svector<builtin_name> & op_names, symbol const & logic) {
if (logic == symbol::null) {
if (logic == symbol::null || logic == "QF_FD") {
op_names.push_back(builtin_name(m_at_most_sym.bare_str(), OP_AT_MOST_K));
op_names.push_back(builtin_name(m_at_least_sym.bare_str(), OP_AT_LEAST_K));
op_names.push_back(builtin_name(m_pble_sym.bare_str(), OP_PB_LE));
@ -99,31 +100,61 @@ void pb_decl_plugin::get_op_names(svector<builtin_name> & op_names, symbol const
}
}
app * pb_util::mk_le(unsigned num_args, rational const * coeffs, expr * const * args, rational const& k) {
vector<parameter> params;
params.push_back(parameter(k));
for (unsigned i = 0; i < num_args; ++i) {
params.push_back(parameter(coeffs[i]));
void pb_util::normalize(unsigned num_args, rational const* coeffs, rational const& k) {
m_coeffs.reset();
bool all_ones = true;
for (unsigned i = 0; i < num_args && all_ones; ++i) {
all_ones = denominator(coeffs[i]).is_one();
}
return m.mk_app(m_fid, OP_PB_LE, params.size(), params.c_ptr(), num_args, args, m.mk_bool_sort());
if (all_ones) {
for (unsigned i = 0; i < num_args; ++i) {
m_coeffs.push_back(coeffs[i]);
}
m_k = k;
}
else {
rational d(1);
for (unsigned i = 0; i < num_args; ++i) {
d = lcm(d, denominator(coeffs[i]));
}
for (unsigned i = 0; i < num_args; ++i) {
m_coeffs.push_back(d*coeffs[i]);
}
m_k = d*k;
}
}
app * pb_util::mk_le(unsigned num_args, rational const * coeffs, expr * const * args, rational const& k) {
normalize(num_args, coeffs, k);
m_params.reset();
m_params.push_back(parameter(floor(m_k)));
for (unsigned i = 0; i < num_args; ++i) {
m_params.push_back(parameter(m_coeffs[i]));
}
return m.mk_app(m_fid, OP_PB_LE, m_params.size(), m_params.c_ptr(), num_args, args, m.mk_bool_sort());
}
app * pb_util::mk_ge(unsigned num_args, rational const * coeffs, expr * const * args, rational const& k) {
vector<parameter> params;
params.push_back(parameter(k));
normalize(num_args, coeffs, k);
m_params.reset();
m_params.push_back(parameter(ceil(m_k)));
for (unsigned i = 0; i < num_args; ++i) {
params.push_back(parameter(coeffs[i]));
m_params.push_back(parameter(m_coeffs[i]));
}
return m.mk_app(m_fid, OP_PB_GE, params.size(), params.c_ptr(), num_args, args, m.mk_bool_sort());
return m.mk_app(m_fid, OP_PB_GE, m_params.size(), m_params.c_ptr(), num_args, args, m.mk_bool_sort());
}
app * pb_util::mk_eq(unsigned num_args, rational const * coeffs, expr * const * args, rational const& k) {
vector<parameter> params;
params.push_back(parameter(k));
for (unsigned i = 0; i < num_args; ++i) {
params.push_back(parameter(coeffs[i]));
normalize(num_args, coeffs, k);
if (!m_k.is_int()) {
return m.mk_false();
}
return m.mk_app(m_fid, OP_PB_EQ, params.size(), params.c_ptr(), num_args, args, m.mk_bool_sort());
m_params.reset();
m_params.push_back(parameter(m_k));
for (unsigned i = 0; i < num_args; ++i) {
m_params.push_back(parameter(m_coeffs[i]));
}
return m.mk_app(m_fid, OP_PB_EQ, m_params.size(), m_params.c_ptr(), num_args, args, m.mk_bool_sort());
}
// ax + by < k
@ -132,33 +163,18 @@ app * pb_util::mk_eq(unsigned num_args, rational const * coeffs, expr * const *
// <=>
// a(1-x) + b(1-y) >= -k + a + b + 1
app * pb_util::mk_lt(unsigned num_args, rational const * _coeffs, expr * const * _args, rational const& _k) {
vector<rational> coeffs;
rational k(_k);
normalize(num_args, _coeffs, _k);
expr_ref_vector args(m);
expr* f;
rational d(denominator(k));
for (unsigned i = 0; i < num_args; ++i) {
coeffs.push_back(_coeffs[i]);
d = lcm(d, denominator(coeffs[i]));
if (m.is_not(_args[i], f)) {
args.push_back(f);
}
else {
args.push_back(m.mk_not(_args[i]));
}
args.push_back(mk_not(m, _args[i]));
}
if (!d.is_one()) {
k *= d;
for (unsigned i = 0; i < num_args; ++i) {
coeffs[i] *= d;
}
}
k.neg();
k += rational::one();
m_k = floor(m_k);
m_k.neg();
m_k += rational::one();
for (unsigned i = 0; i < num_args; ++i) {
k += coeffs[i];
m_k += m_coeffs[i];
}
return mk_ge(num_args, coeffs.c_ptr(), args.c_ptr(), k);
return mk_ge(num_args, m_coeffs.c_ptr(), args.c_ptr(), m_k);
}

View file

@ -73,12 +73,18 @@ public:
unsigned arity, sort * const * domain, sort * range);
virtual void get_op_names(svector<builtin_name> & op_names, symbol const & logic);
virtual bool is_considered_uninterpreted(func_decl * f) { return false; }
};
class pb_util {
ast_manager & m;
family_id m_fid;
vector<rational> m_coeffs;
vector<parameter> m_params;
rational m_k;
void normalize(unsigned num_args, rational const* coeffs, rational const& k);
public:
pb_util(ast_manager& m):m(m), m_fid(m.mk_family_id("pb")) {}
ast_manager & get_manager() const { return m; }

View file

@ -15,5 +15,6 @@ def_module_params('pp',
('flat_assoc', BOOL, True, 'flat associative operators (when pretty printing SMT2 terms/formulas)'),
('fixed_indent', BOOL, False, 'use a fixed indentation for applications'),
('single_line', BOOL, False, 'ignore line breaks when true'),
('bounded', BOOL, False, 'ignore characters exceeding max widht'),
('bounded', BOOL, False, 'ignore characters exceeding max width'),
('pretty_proof', BOOL, False, 'use slower, but prettier, printer for proofs'),
('simplify_implies', BOOL, True, 'simplify nested implications for pretty printing')))

View file

@ -162,8 +162,8 @@ bool arith_rewriter::div_polynomial(expr * t, numeral const & g, const_treatment
}
bool arith_rewriter::is_bound(expr * arg1, expr * arg2, op_kind kind, expr_ref & result) {
numeral c;
if (!is_add(arg1) && is_numeral(arg2, c)) {
numeral b, c;
if (!is_add(arg1) && !m_util.is_mod(arg1) && is_numeral(arg2, c)) {
numeral a;
bool r = false;
expr * pp = get_power_product(arg1, a);
@ -193,6 +193,45 @@ bool arith_rewriter::is_bound(expr * arg1, expr * arg2, op_kind kind, expr_ref &
case EQ: result = m_util.mk_eq(pp, k); return true;
}
}
expr* t1, *t2;
bool is_int;
if (m_util.is_mod(arg2)) {
std::swap(arg1, arg2);
switch (kind) {
case LE: kind = GE; break;
case GE: kind = LE; break;
case EQ: break;
}
}
if (m_util.is_numeral(arg2, c, is_int) && is_int &&
m_util.is_mod(arg1, t1, t2) && m_util.is_numeral(t2, b, is_int) && !b.is_zero()) {
// mod x b <= c = false if c < 0, b != 0, true if c >= b, b != 0
if (c.is_neg()) {
switch (kind) {
case EQ:
case LE: result = m().mk_false(); return true;
case GE: result = m().mk_true(); return true;
}
}
if (c.is_zero() && kind == GE) {
result = m().mk_true();
return true;
}
if (c.is_pos() && c >= abs(b)) {
switch (kind) {
case LE: result = m().mk_true(); return true;
case EQ:
case GE: result = m().mk_false(); return true;
}
}
// mod x b <= b - 1
if (c + rational::one() == abs(b) && kind == LE) {
result = m().mk_true();
return true;
}
}
return false;
}
@ -946,12 +985,13 @@ br_status arith_rewriter::mk_power_core(expr * arg1, expr * arg2, expr_ref & res
br_status arith_rewriter::mk_to_int_core(expr * arg, expr_ref & result) {
numeral a;
expr* x;
if (m_util.is_numeral(arg, a)) {
result = m_util.mk_numeral(floor(a), true);
return BR_DONE;
}
else if (m_util.is_to_real(arg)) {
result = to_app(arg)->get_arg(0);
else if (m_util.is_to_real(arg, x)) {
result = x;
return BR_DONE;
}
else {
@ -982,8 +1022,8 @@ br_status arith_rewriter::mk_to_int_core(expr * arg, expr_ref & result) {
new_args.push_back(m_util.mk_numeral(a, true));
}
else {
SASSERT(m_util.is_to_real(c));
new_args.push_back(to_app(c)->get_arg(0));
VERIFY (m_util.is_to_real(c, x));
new_args.push_back(x);
}
}
SASSERT(num_args == new_args.size());
@ -1196,11 +1236,17 @@ expr * arith_rewriter::mk_sin_value(rational const & k) {
}
br_status arith_rewriter::mk_sin_core(expr * arg, expr_ref & result) {
if (is_app_of(arg, get_fid(), OP_ASIN)) {
expr * m, *x;
if (m_util.is_asin(arg, x)) {
// sin(asin(x)) == x
result = to_app(arg)->get_arg(0);
result = x;
return BR_DONE;
}
if (m_util.is_acos(arg, x)) {
// sin(acos(x)) == sqrt(1 - x^2)
result = m_util.mk_power(m_util.mk_sub(m_util.mk_real(1), m_util.mk_mul(x,x)), m_util.mk_numeral(rational(1,2), false));
return BR_REWRITE_FULL;
}
rational k;
if (is_numeral(arg, k) && k.is_zero()) {
// sin(0) == 0
@ -1214,7 +1260,6 @@ br_status arith_rewriter::mk_sin_core(expr * arg, expr_ref & result) {
return BR_REWRITE_FULL;
}
expr * m;
if (is_pi_offset(arg, k, m)) {
rational k_prime = mod(floor(k), rational(2)) + k - floor(k);
SASSERT(k_prime >= rational(0) && k_prime < rational(2));
@ -1250,11 +1295,15 @@ br_status arith_rewriter::mk_sin_core(expr * arg, expr_ref & result) {
}
br_status arith_rewriter::mk_cos_core(expr * arg, expr_ref & result) {
if (is_app_of(arg, get_fid(), OP_ACOS)) {
expr* x;
if (m_util.is_acos(arg, x)) {
// cos(acos(x)) == x
result = to_app(arg)->get_arg(0);
result = x;
return BR_DONE;
}
if (m_util.is_asin(arg, x)) {
// cos(asin(x)) == ...
}
rational k;
if (is_numeral(arg, k) && k.is_zero()) {
@ -1306,9 +1355,10 @@ br_status arith_rewriter::mk_cos_core(expr * arg, expr_ref & result) {
}
br_status arith_rewriter::mk_tan_core(expr * arg, expr_ref & result) {
if (is_app_of(arg, get_fid(), OP_ATAN)) {
expr* x;
if (m_util.is_atan(arg, x)) {
// tan(atan(x)) == x
result = to_app(arg)->get_arg(0);
result = x;
return BR_DONE;
}
@ -1488,9 +1538,10 @@ br_status arith_rewriter::mk_atan_core(expr * arg, expr_ref & result) {
}
br_status arith_rewriter::mk_sinh_core(expr * arg, expr_ref & result) {
if (is_app_of(arg, get_fid(), OP_ASINH)) {
expr* x;
if (m_util.is_asinh(arg, x)) {
// sinh(asinh(x)) == x
result = to_app(arg)->get_arg(0);
result = x;
return BR_DONE;
}
expr * t;
@ -1503,12 +1554,12 @@ br_status arith_rewriter::mk_sinh_core(expr * arg, expr_ref & result) {
}
br_status arith_rewriter::mk_cosh_core(expr * arg, expr_ref & result) {
if (is_app_of(arg, get_fid(), OP_ACOSH)) {
// cosh(acosh(x)) == x
result = to_app(arg)->get_arg(0);
expr* t;
if (m_util.is_acosh(arg, t)) {
// cosh(acosh(t)) == t
result = t;
return BR_DONE;
}
expr * t;
if (m_util.is_times_minus_one(arg, t)) {
// cosh(-t) == cosh
result = m_util.mk_cosh(t);
@ -1518,12 +1569,12 @@ br_status arith_rewriter::mk_cosh_core(expr * arg, expr_ref & result) {
}
br_status arith_rewriter::mk_tanh_core(expr * arg, expr_ref & result) {
if (is_app_of(arg, get_fid(), OP_ATANH)) {
// tanh(atanh(x)) == x
result = to_app(arg)->get_arg(0);
expr * t;
if (m_util.is_atanh(arg, t)) {
// tanh(atanh(t)) == t
result = t;
return BR_DONE;
}
expr * t;
if (m_util.is_times_minus_one(arg, t)) {
// tanh(-t) == -tanh(t)
result = m_util.mk_uminus(m_util.mk_tanh(t));

View file

@ -26,6 +26,7 @@ void array_rewriter::updt_params(params_ref const & _p) {
m_sort_store = p.sort_store();
m_expand_select_store = p.expand_select_store();
m_expand_store_eq = p.expand_store_eq();
m_expand_select_ite = false;
}
void array_rewriter::get_param_descrs(param_descrs & r) {
@ -201,6 +202,17 @@ br_status array_rewriter::mk_select_core(unsigned num_args, expr * const * args,
result = m().mk_app(f, num_args - 1, args + 1);
return BR_REWRITE1;
}
expr* c, *th, *el;
if (m_expand_select_ite && m().is_ite(args[0], c, th, el)) {
ptr_vector<expr> args1, args2;
args1.push_back(th);
args1.append(num_args-1, args + 1);
args2.push_back(el);
args2.append(num_args-1, args + 1);
result = m().mk_ite(c, m_util.mk_select(num_args, args1.c_ptr()), m_util.mk_select(num_args, args2.c_ptr()));
return BR_REWRITE2;
}
return BR_FAILED;
}

View file

@ -32,6 +32,7 @@ class array_rewriter {
bool m_sort_store;
bool m_expand_select_store;
bool m_expand_store_eq;
bool m_expand_select_ite;
template<bool CHECK_DISEQ>
lbool compare_args(unsigned num_args, expr * const * args1, expr * const * args2);
public:
@ -43,6 +44,8 @@ public:
ast_manager & m() const { return m_util.get_manager(); }
family_id get_fid() const { return m_util.get_family_id(); }
void set_expand_select_store(bool f) { m_expand_select_store = f; }
void set_expand_select_ite(bool f) { m_expand_select_ite = f; }
void updt_params(params_ref const & p);
static void get_param_descrs(param_descrs & r);

View file

@ -22,7 +22,7 @@ Revision History:
struct bit_blaster_params {
bool m_bb_ext_gates;
bool m_bb_quantifiers;
bit_blaster_params():
bit_blaster_params() :
m_bb_ext_gates(false),
m_bb_quantifiers(false) {
}
@ -32,6 +32,11 @@ struct bit_blaster_params {
p.register_bool_param("bb_quantifiers", m_bb_quantifiers, "convert bit-vectors to Booleans in quantifiers");
}
#endif
void display(std::ostream & out) const {
out << "m_bb_ext_gates=" << m_bb_ext_gates << std::endl;
out << "m_bb_quantifiers=" << m_bb_quantifiers << std::endl;
}
};
#endif /* BIT_BLASTER_PARAMS_H_ */

View file

@ -66,9 +66,6 @@ struct blaster_cfg {
void mk_nor(expr * a, expr * b, expr_ref & r) { m_rewriter.mk_nor(a, b, r); }
};
// CMW: GCC/LLVM do not like this definition because a symbol of the same name exists in assert_set_bit_blaster.o
// template class bit_blaster_tpl<blaster_cfg>;
class blaster : public bit_blaster_tpl<blaster_cfg> {
bool_rewriter m_rewriter;
bv_util m_util;
@ -165,6 +162,10 @@ struct blaster_rewriter_cfg : public default_rewriter_cfg {
m_keyval_lim.push_back(m_keys.size());
}
unsigned get_num_scopes() const {
return m_keyval_lim.size();
}
void pop(unsigned num_scopes) {
if (num_scopes > 0) {
SASSERT(num_scopes <= m_keyval_lim.size());
@ -621,9 +622,6 @@ MK_PARAMETRIC_UNARY_REDUCE(reduce_sign_extend, mk_sign_extend);
}
};
// CMW: GCC/LLVM do not like this definition because a symbol of the same name exists in assert_set_bit_blaster.o
// template class rewriter_tpl<blaster_rewriter_cfg>;
struct bit_blaster_rewriter::imp : public rewriter_tpl<blaster_rewriter_cfg> {
blaster m_blaster;
blaster_rewriter_cfg m_cfg;
@ -637,6 +635,7 @@ struct bit_blaster_rewriter::imp : public rewriter_tpl<blaster_rewriter_cfg> {
}
void push() { m_cfg.push(); }
void pop(unsigned s) { m_cfg.pop(s); }
unsigned get_num_scopes() const { return m_cfg.get_num_scopes(); }
};
bit_blaster_rewriter::bit_blaster_rewriter(ast_manager & m, params_ref const & p):
@ -680,3 +679,7 @@ void bit_blaster_rewriter::operator()(expr * e, expr_ref & result, proof_ref & r
m_imp->operator()(e, result, result_proof);
}
unsigned bit_blaster_rewriter::get_num_scopes() const {
return m_imp->get_num_scopes();
}

View file

@ -37,6 +37,7 @@ public:
void operator()(expr * e, expr_ref & result, proof_ref & result_proof);
void push();
void pop(unsigned num_scopes);
unsigned get_num_scopes() const;
};
#endif

View file

@ -59,9 +59,12 @@ br_status bool_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * co
mk_implies(args[0], args[1], result);
return BR_DONE;
case OP_XOR:
SASSERT(num_args == 2);
mk_xor(args[0], args[1], result);
return BR_DONE;
switch (num_args) {
case 0: return BR_FAILED;
case 1: result = args[0]; return BR_DONE;
case 2: mk_xor(args[0], args[1], result); return BR_DONE;
default: UNREACHABLE(); return BR_FAILED;
}
default:
return BR_FAILED;
}
@ -456,6 +459,22 @@ bool bool_rewriter::simp_nested_eq_ite(expr * t, expr_fast_mark1 & neg_lits, exp
return false;
}
void bool_rewriter::push_new_arg(expr* arg, expr_ref_vector& new_args, expr_fast_mark1& neg_lits, expr_fast_mark2& pos_lits) {
expr* narg;
if (m().is_not(arg, narg)) {
if (!neg_lits.is_marked(narg)) {
neg_lits.mark(narg);
new_args.push_back(arg);
}
}
else {
if (!pos_lits.is_marked(arg)) {
pos_lits.mark(arg);
new_args.push_back(arg);
}
}
}
/**
\brief Apply local context simplification at (OR args[0] ... args[num_args-1])
Basic idea:
@ -473,6 +492,7 @@ bool bool_rewriter::local_ctx_simp(unsigned num_args, expr * const * args, expr_
bool modified = false;
bool forward = true;
unsigned rounds = 0;
expr* narg;
while (true) {
rounds++;
@ -481,20 +501,13 @@ bool bool_rewriter::local_ctx_simp(unsigned num_args, expr * const * args, expr_
verbose_stream() << "rounds: " << rounds << "\n";
#endif
#define PUSH_NEW_ARG(ARG) { \
new_args.push_back(ARG); \
if (m().is_not(ARG)) \
neg_lits.mark(to_app(ARG)->get_arg(0)); \
else \
pos_lits.mark(ARG); \
}
#define PROCESS_ARG() \
{ \
expr * arg = args[i]; \
if (m().is_not(arg) && m().is_or(to_app(arg)->get_arg(0)) && \
simp_nested_not_or(to_app(to_app(arg)->get_arg(0))->get_num_args(), \
to_app(to_app(arg)->get_arg(0))->get_args(), \
if (m().is_not(arg, narg) && m().is_or(narg) && \
simp_nested_not_or(to_app(narg)->get_num_args(), \
to_app(narg)->get_args(), \
neg_lits, \
pos_lits, \
new_arg)) { \
@ -515,11 +528,11 @@ bool bool_rewriter::local_ctx_simp(unsigned num_args, expr * const * args, expr_
unsigned sz = to_app(arg)->get_num_args(); \
for (unsigned j = 0; j < sz; j++) { \
expr * arg_arg = to_app(arg)->get_arg(j); \
PUSH_NEW_ARG(arg_arg); \
push_new_arg(arg_arg, new_args, neg_lits, pos_lits); \
} \
} \
else { \
PUSH_NEW_ARG(arg); \
push_new_arg(arg, new_args, neg_lits, pos_lits); \
} \
}
@ -528,7 +541,7 @@ bool bool_rewriter::local_ctx_simp(unsigned num_args, expr * const * args, expr_
static unsigned counter = 0;
counter++;
if (counter % 10000 == 0)
verbose_stream() << "local-ctx-cost: " << m_local_ctx_cost << "\n";
verbose_stream() << "local-ctx-cost: " << m_local_ctx_cost << " " << num_args << "\n";
#endif
if (forward) {
@ -572,7 +585,7 @@ bool bool_rewriter::local_ctx_simp(unsigned num_args, expr * const * args, expr_
*/
br_status bool_rewriter::try_ite_value(app * ite, app * val, expr_ref & result) {
expr* cond, *t, *e;
expr* cond = 0, *t = 0, *e = 0;
VERIFY(m().is_ite(ite, cond, t, e));
SASSERT(m().is_value(val));
@ -581,38 +594,40 @@ br_status bool_rewriter::try_ite_value(app * ite, app * val, expr_ref & result)
TRACE("try_ite_value", tout << mk_ismt2_pp(t, m()) << " " << mk_ismt2_pp(e, m()) << " " << mk_ismt2_pp(val, m()) << "\n";
tout << t << " " << e << " " << val << "\n";);
result = m().mk_false();
}
}
else if (t == val && e == val) {
result = m().mk_true();
}
}
else if (t == val) {
result = cond;
}
else {
SASSERT(e == val);
SASSERT(e == val);
mk_not(cond, result);
}
return BR_DONE;
}
if (m().is_value(t)) {
if (val == t) {
result = m().mk_or(cond, m().mk_eq(val, e));
if (m_ite_extra_rules) {
if (m().is_value(t)) {
if (val == t) {
result = m().mk_or(cond, m().mk_eq(val, e));
}
else {
mk_not(cond, result);
result = m().mk_and(result, m().mk_eq(val, e));
}
return BR_REWRITE2;
}
else {
mk_not(cond, result);
result = m().mk_and(result, m().mk_eq(val, e));
if (m().is_value(e)) {
if (val == e) {
mk_not(cond, result);
result = m().mk_or(result, m().mk_eq(val, t));
}
else {
result = m().mk_and(cond, m().mk_eq(val, t));
}
return BR_REWRITE2;
}
return BR_REWRITE2;
}
if (m().is_value(e)) {
if (val == e) {
mk_not(cond, result);
result = m().mk_or(result, m().mk_eq(val, t));
}
else {
result = m().mk_and(cond, m().mk_eq(val, t));
}
return BR_REWRITE2;
}
expr* cond2, *t2, *e2;
if (m().is_ite(t, cond2, t2, e2) && m().is_value(t2) && m().is_value(e2)) {

View file

@ -75,6 +75,8 @@ class bool_rewriter {
bool local_ctx_simp(unsigned num_args, expr * const * args, expr_ref & result);
br_status try_ite_value(app * ite, app * val, expr_ref & result);
void push_new_arg(expr* arg, expr_ref_vector& new_args, expr_fast_mark1& neg_lits, expr_fast_mark2& pos_lits);
public:
bool_rewriter(ast_manager & m, params_ref const & p = params_ref()):m_manager(m), m_local_ctx_cost(0) { updt_params(p); }
ast_manager & m() const { return m_manager; }

View file

@ -0,0 +1,664 @@
/*++
Copyright (c) 2016 Microsoft Corporation
Module Name:
bv_bounds.cpp
Abstract:
Author:
Mikolas Janota (MikolasJanota)
Revision History:
--*/
#include"bv_bounds.h"
#include"ast_smt2_pp.h"
bv_bounds::~bv_bounds() {
reset();
}
bv_bounds::conv_res bv_bounds::record(app * v, numeral lo, numeral hi, bool negated, vector<ninterval>& nis) {
TRACE("bv_bounds", tout << "record0 " << mk_ismt2_pp(v, m_m) << ":" << (negated ? "~[" : "[") << lo << ";" << hi << "]" << std::endl;);
const unsigned bv_sz = m_bv_util.get_bv_size(v);
const numeral& one = numeral::one();
SASSERT(numeral::zero() <= lo);
SASSERT(lo <= hi);
SASSERT(hi < numeral::power_of_two(bv_sz));
numeral vmax, vmin;
const bool has_upper = m_unsigned_uppers.find(v, vmax);
const bool has_lower = m_unsigned_lowers.find(v, vmin);
if (!has_lower) vmin = numeral::zero();
if (!has_upper) vmax = (numeral::power_of_two(bv_sz) - one);
bool lo_min = lo <= vmin;
bool hi_max = hi >= vmax;
if (negated) {
if (lo_min && hi_max) return UNSAT;
if (lo > vmax) return CONVERTED;
if (hi < vmin) return CONVERTED;
if (lo_min) {
negated = false; lo = hi + one; hi = vmax;
lo_min = lo <= vmin;
hi_max = true;
} else if (hi_max) {
negated = false; hi = lo - one; lo = vmin;
hi_max = hi >= vmax;
lo_min = true;
}
SASSERT(lo.is_nonneg());
SASSERT(lo <= hi);
SASSERT(hi < numeral::power_of_two(bv_sz));
}
if (lo_min) lo = vmin;
if (hi_max) hi = vmax;
TRACE("bv_bounds", tout << "record1 " << mk_ismt2_pp(v, m_m) << ":" << (negated ? "~[" : "[") << lo << ";" << hi << "]" << std::endl;);
if (lo > hi) return negated ? CONVERTED : UNSAT;
if (lo_min && hi_max) return negated ? UNSAT : CONVERTED;
nis.resize(nis.size() + 1);
nis.back().v = v;
nis.back().lo = lo;
nis.back().hi = hi;
nis.back().negated = negated;
return CONVERTED;
}
bool bv_bounds::is_uleq(expr * e, expr * & v, numeral & c) {
// To detect the following rewrite from bv_rewriter:
// m().mk_and(
// m().mk_eq(m_mk_extract(bv_sz - 1, first_non_zero + 1, a), m_util.mk_numeral(numeral(0), bv_sz - first_non_zero - 1)),
// m_util.mk_ule(m_mk_extract(first_non_zero, 0, a), m_mk_extract(first_non_zero, 0, b)));
expr * eq;
expr * eql;
expr * eqr;
expr * ule;
expr * ulel;
expr * uler;
numeral eqr_val, uleqr_val;
unsigned eqr_sz, uleqr_sz;
if (!m_m.is_and(e, eq, ule)) return false;
if (!m_m.is_eq(eq, eql, eqr)) return false;
if (!m_bv_util.is_bv_ule(ule, ulel, uler)) return false;
if (!m_bv_util.is_extract(eql)) return false;
expr * const eql0 = to_app(eql)->get_arg(0);
const unsigned eql0_sz = m_bv_util.get_bv_size(eql0);
if (m_bv_util.get_extract_high(eql) != (eql0_sz - 1)) return false;
if (!m_bv_util.is_numeral(eqr, eqr_val, eqr_sz)) return false;
if (!eqr_val.is_zero()) return false;
if (!m_bv_util.is_extract(ulel)) return false;
expr * const ulel0 = to_app(ulel)->get_arg(0);
if (ulel0 != eql0) return false;
if ((m_bv_util.get_extract_high(ulel) + 1) != m_bv_util.get_extract_low(eql)) return false;
if (m_bv_util.get_extract_low(ulel) != 0) return false;
if (!m_bv_util.is_numeral(uler, uleqr_val, uleqr_sz)) return false;
SASSERT(m_bv_util.get_bv_size(ulel0) == uleqr_sz + eqr_sz);
v = ulel0;
c = uleqr_val;
return true;
}
bv_bounds::conv_res bv_bounds::convert(expr * e, vector<ninterval>& nis, bool negated) {
TRACE("bv_bounds", tout << "new constraint: " << (negated ? "~" : "" ) << mk_ismt2_pp(e, m_m) << std::endl;);
if (m_m.is_not(e)) {
negated = !negated;
e = to_app(e)->get_arg(0);
}
expr *lhs, *rhs;
numeral val, val1;
unsigned bv_sz1;
if (0) {
if (m_m.is_eq(e, lhs, rhs) && to_bound(lhs) && m_bv_util.is_numeral(rhs, val, bv_sz1)) {
return record(to_app(lhs), val, val, negated, nis);
}
if (m_m.is_eq(e, lhs, rhs) && to_bound(rhs) && m_bv_util.is_numeral(lhs, val, bv_sz1)) {
return record(to_app(rhs), val, val, negated, nis);
}
}
if (is_uleq(e, lhs, val) && to_bound(lhs)) {
return record(to_app(lhs), numeral::zero(), val, negated, nis);
}
if (1) {
numeral rhs_val;
unsigned rhs_sz;
if (m_m.is_eq(e, lhs, rhs)
&& m_bv_util.is_numeral(rhs, rhs_val, rhs_sz)
&& rhs_val.is_zero()
&& m_bv_util.is_extract(lhs)) {
expr * const lhs0 = to_app(lhs)->get_arg(0);
const unsigned lhs0_sz = m_bv_util.get_bv_size(lhs0);
if (m_bv_util.get_extract_high(lhs)+1 == lhs0_sz) {
const numeral u = numeral::power_of_two(m_bv_util.get_extract_low(lhs)) - numeral::one();
return record(to_app(lhs0), numeral::zero(), u, negated, nis);
}
}
}
if (m_bv_util.is_bv_ule(e, lhs, rhs)) {
unsigned bv_sz = m_bv_util.get_bv_size(lhs);
// unsigned inequality with one variable and a constant
if (to_bound(lhs) && m_bv_util.is_numeral(rhs, val, bv_sz)) // v <= val
return record(to_app(lhs), numeral::zero(), val, negated, nis);
if (to_bound(rhs) && m_bv_util.is_numeral(lhs, val, bv_sz)) // val <= v
return record(to_app(rhs), val, numeral::power_of_two(bv_sz) - numeral::one(), negated, nis);
// unsigned inequality with one variable, constant, and addition
expr *t1, *t2;
if (m_bv_util.is_bv_add(lhs, t1, t2)
&& m_bv_util.is_numeral(t1, val, bv_sz)
&& to_bound(t2)
&& t2 == rhs) { // val + v <= v
if (val.is_zero()) return negated ? UNSAT : CONVERTED;
SASSERT(val.is_pos());
const numeral mod = numeral::power_of_two(bv_sz);
return record(to_app(rhs), mod - val, mod - numeral::one(), negated, nis);
}
if (m_bv_util.is_bv_add(rhs, t1, t2)
&& m_bv_util.is_numeral(t1, val, bv_sz)
&& to_bound(t2)
&& m_bv_util.is_numeral(lhs, val1, bv_sz1)) { // val1 <= val + v
SASSERT(bv_sz1 == bv_sz);
const numeral mod = numeral::power_of_two(bv_sz);
if (val1.is_zero()) return negated ? UNSAT : CONVERTED;
if (val1 < val) {
const numeral nl = mod - val;
const numeral nh = mod + val1 - val - numeral::one();
return nl <= nh ? record(to_app(t2), nl, nh, !negated, nis) : (negated ? UNSAT : CONVERTED);
}
else {
const numeral l = val1 - val;
const numeral h = mod - val - numeral::one();
return l <= h ? record(to_app(t2), l, h, negated, nis) : (negated ? CONVERTED : UNSAT);
}
}
if (m_bv_util.is_bv_add(lhs, t1, t2)
&& m_bv_util.is_numeral(t1, val, bv_sz)
&& to_bound(t2)
&& m_bv_util.is_numeral(rhs, val1, bv_sz1)) { // val + v <= val1
SASSERT(bv_sz1 == bv_sz);
if (!val.is_pos() || !val1.is_pos()) return UNDEF;
const numeral mod = numeral::power_of_two(bv_sz);
if (val <= val1) {
const numeral nl = val1 - val + numeral::one();
const numeral nh = mod - val - numeral::one();
return nl <= nh ? record(to_app(t2), nl, nh, !negated, nis) : (negated ? UNSAT : CONVERTED);
}
else {
const numeral l = mod - val;
const numeral h = l + val1;
return record(to_app(t2), l, h, negated, nis);
}
}
// v + c1 <= v + c2
app * v1(NULL), *v2(NULL);
numeral val1, val2;
if (is_constant_add(bv_sz, lhs, v1, val1)
&& is_constant_add(bv_sz, rhs, v2, val2)
&& v1 == v2) {
if (val1 == val2) return negated ? UNSAT : CONVERTED;
const numeral mod = numeral::power_of_two(bv_sz);
if (val1 < val2) {
SASSERT(val1 < (mod - numeral::one()));
SASSERT(val2 > numeral::zero());
return record(v1, mod - val2, mod - val1 - numeral::one(), !negated, nis);
}
else {
SASSERT(val1 > val2);
SASSERT(val2 < (mod - numeral::one()));
SASSERT(val1 > numeral::zero());
return record(v1, mod - val1, mod - val2 - numeral::one(), negated, nis);
}
}
}
if (m_bv_util.is_bv_sle(e, lhs, rhs)) {
unsigned bv_sz = m_bv_util.get_bv_size(lhs);
// signed inequality with one variable and a constant
if (to_bound(lhs) && m_bv_util.is_numeral(rhs, val, bv_sz)) { // v <= val
val = m_bv_util.norm(val, bv_sz, true);
return convert_signed(to_app(lhs), -numeral::power_of_two(bv_sz - 1), val, negated, nis);
}
if (to_bound(rhs) && m_bv_util.is_numeral(lhs, val, bv_sz)) { // val <= v
val = m_bv_util.norm(val, bv_sz, true);
return convert_signed(to_app(rhs), val, numeral::power_of_two(bv_sz - 1) - numeral::one(), negated, nis);
}
}
return UNDEF;
}
void bv_bounds::reset() {
intervals_map::iterator it = m_negative_intervals.begin();
const intervals_map::iterator end = m_negative_intervals.end();
for (; it != end; ++it) dealloc(it->m_value);
}
br_status bv_bounds::rewrite(unsigned limit, func_decl * f, unsigned num, expr * const * args, expr_ref& result) {
if (!m_m.is_bool(f->get_range())) return BR_FAILED;
const decl_kind k = f->get_decl_kind();
if ((k != OP_OR && k != OP_AND) || num > limit) return BR_FAILED;
const bool negated = k == OP_OR;
vector<ninterval> nis;
vector<unsigned> lengths;
vector<bool> ignore;
unsigned nis_head = 0;
for (unsigned i = 0; i < num && m_okay; ++i) {
expr * const curr = args[i];
const conv_res cr = convert(curr, nis, negated);
ignore.push_back(cr == UNDEF);
switch (cr) {
case UNDEF: continue;
case UNSAT: m_okay = false; break;
case CONVERTED:
{
for (unsigned i = nis_head; i < nis.size(); ++i) {
const ninterval& ni = nis[i];
m_okay = m_okay && add_bound_unsigned(ni.v, ni.lo, ni.hi, ni.negated);
}
lengths.push_back(nis.size());
nis_head = nis.size();
break;
}
default: UNREACHABLE();
}
}
if (!m_okay || !is_sat()) {
result = negated ? m_m.mk_true() : m_m.mk_false();
return BR_DONE;
}
nis_head = 0;
unsigned count = 0;
expr_ref_vector nargs(m_m);
bool has_singls = false;
for (unsigned i = 0; i < num && m_okay; ++i) {
TRACE("bv_bounds", tout << "check red: " << mk_ismt2_pp(args[i], m_m) << std::endl;);
if (ignore[i]) {
TRACE("bv_bounds", tout << "unprocessed" << std::endl;);
nargs.push_back(args[i]);
continue;
}
SASSERT(nis_head <= lengths[count]);
const bool redundant = nis_head == lengths[count];
bool is_singl = false;
if (nis_head < lengths[count]) {
app * const v = nis[nis_head].v;
numeral th, tl;
const unsigned bv_sz = m_bv_util.get_bv_size(v);
const bool has_upper = m_unsigned_uppers.find(v, th);
const bool has_lower = m_unsigned_lowers.find(v, tl);
const numeral& one = numeral::one();
if (!has_lower) tl = numeral::zero();
if (!has_upper) th = (numeral::power_of_two(bv_sz) - one);
TRACE("bv_bounds", tout << "bounds: " << mk_ismt2_pp(v, m_m) << "[" << tl << "-" << th << "]" << std::endl;);
is_singl = tl == th;
nis_head = lengths[count];
}
if (!redundant && !is_singl) nargs.push_back(args[i]);
has_singls |= is_singl;
CTRACE("bv_bounds", redundant, tout << "redundant: " << mk_ismt2_pp(args[i], m_m) << std::endl;);
++count;
}
if (nargs.size() == num && !has_singls) return BR_FAILED;
expr_ref eq(m_m);
for (bv_bounds::bound_map::iterator i = m_singletons.begin(); i != m_singletons.end(); ++i) {
app * const v = i->m_key;
const rational val = i->m_value;
eq = m_m.mk_eq(v, bvu().mk_numeral(val, v->get_decl()->get_range()));
if (negated) eq = m_m.mk_not(eq);
nargs.push_back(eq);
}
switch (nargs.size()) {
case 0: result = negated ? m_m.mk_false() : m_m.mk_true(); return BR_DONE;
case 1: result = nargs.get(0); return BR_DONE;
default: result = negated ? m_m.mk_or(nargs.size(), nargs.c_ptr())
: m_m.mk_and(nargs.size(), nargs.c_ptr());
return BR_DONE;
}
}
bool bv_bounds::add_constraint(expr* e) {
TRACE("bv_bounds", tout << "new constraint" << mk_ismt2_pp(e, m_m) << std::endl;);
if (!m_okay) return false;
bool negated = false;
if (m_m.is_not(e)) {
negated = true;
e = to_app(e)->get_arg(0);
}
expr *lhs, *rhs;
numeral val, val1;
unsigned bv_sz1;
if (0) {
if (m_m.is_eq(e, lhs, rhs) && to_bound(lhs) && m_bv_util.is_numeral(rhs, val, bv_sz1)) {
return add_bound_unsigned(to_app(lhs), val, val, negated);
}
if (m_m.is_eq(e, lhs, rhs) && to_bound(rhs) && m_bv_util.is_numeral(lhs, val, bv_sz1)) {
return add_bound_unsigned(to_app(rhs), val, val, negated);
}
}
if (m_bv_util.is_bv_ule(e, lhs, rhs)) {
unsigned bv_sz = m_bv_util.get_bv_size(lhs);
// unsigned inequality with one variable and a constant
if (to_bound(lhs) && m_bv_util.is_numeral(rhs, val, bv_sz)) // v <= val
return add_bound_unsigned(to_app(lhs), numeral::zero(), val, negated);
if (to_bound(rhs) && m_bv_util.is_numeral(lhs, val, bv_sz)) // val <= v
return add_bound_unsigned(to_app(rhs), val, numeral::power_of_two(bv_sz) - numeral::one(), negated);
// unsigned inequality with one variable, constant, and addition
expr *t1, *t2;
if (m_bv_util.is_bv_add(lhs, t1, t2)
&& m_bv_util.is_numeral(t1, val, bv_sz)
&& to_bound(t2)
&& t2 == rhs) { // val + v <= v
if (!val.is_pos()) return m_okay;
const numeral mod = numeral::power_of_two(bv_sz);
return add_bound_unsigned(to_app(rhs), mod - val, mod - numeral::one(), negated);
}
if (m_bv_util.is_bv_add(rhs, t1, t2)
&& m_bv_util.is_numeral(t1, val, bv_sz)
&& to_bound(t2)
&& m_bv_util.is_numeral(lhs, val1, bv_sz1)) { // val1 <= val + v
SASSERT(bv_sz1 == bv_sz);
if (!val.is_pos() || !val1.is_pos()) return m_okay;
const numeral mod = numeral::power_of_two(bv_sz);
if (val1 < val) {
const numeral nl = mod - val;
const numeral nh = mod + val1 - val - numeral::one();
return nl <= nh ? add_bound_unsigned(to_app(t2), nl, nh, !negated) : m_okay;
}
else {
const numeral l = val1 - val;
const numeral h = mod - val - numeral::one();
return l <= h ? add_bound_unsigned(to_app(t2), l, h, negated) : m_okay;
}
}
if (m_bv_util.is_bv_add(lhs, t1, t2)
&& m_bv_util.is_numeral(t1, val, bv_sz)
&& to_bound(t2)
&& m_bv_util.is_numeral(rhs, val1, bv_sz1)) { // val + v <= val1
SASSERT(bv_sz1 == bv_sz);
if (!val.is_pos() || !val1.is_pos()) return m_okay;
const numeral mod = numeral::power_of_two(bv_sz);
if (val <= val1) {
const numeral nl = val1 - val + numeral::one();
const numeral nh = mod - val - numeral::one();
return nl <= nh ? add_bound_unsigned(to_app(t2), nl, nh, !negated) : m_okay;
}
else {
const numeral l = mod - val;
const numeral h = l + val1;
return add_bound_unsigned(to_app(t2), l, h, negated);
}
}
// v + c1 <= v + c2
app * v1(NULL), *v2(NULL);
numeral val1, val2;
if (is_constant_add(bv_sz, lhs, v1, val1)
&& is_constant_add(bv_sz, rhs, v2, val2)
&& v1 == v2) {
if (val1 == val2) return m_okay;
const numeral mod = numeral::power_of_two(bv_sz);
if (val1 < val2) {
SASSERT(val1 < (mod - numeral::one()));
SASSERT(val2 > numeral::zero());
return add_bound_unsigned(v1, mod - val2, mod - val1 - numeral::one(), !negated);
}
else {
SASSERT(val1 > val2);
SASSERT(val2 < (mod - numeral::one()));
SASSERT(val1 > numeral::zero());
return add_bound_unsigned(v1, mod - val1, mod - val2 - numeral::one(), negated);
}
}
}
if (m_bv_util.is_bv_sle(e, lhs, rhs)) {
unsigned bv_sz = m_bv_util.get_bv_size(lhs);
// signed inequality with one variable and a constant
if (to_bound(lhs) && m_bv_util.is_numeral(rhs, val, bv_sz)) { // v <= val
val = m_bv_util.norm(val, bv_sz, true);
return add_bound_signed(to_app(lhs), -numeral::power_of_two(bv_sz - 1), val, negated);
}
if (to_bound(rhs) && m_bv_util.is_numeral(lhs, val, bv_sz)) { // val <= v
val = m_bv_util.norm(val, bv_sz, true);
return add_bound_signed(to_app(rhs), val, numeral::power_of_two(bv_sz - 1) - numeral::one(), negated);
}
}
return m_okay;
}
bool bv_bounds::add_bound_unsigned(app * v, numeral a, numeral b, bool negate) {
TRACE("bv_bounds", tout << "bound_unsigned " << mk_ismt2_pp(v, m_m) << ": " << (negate ? "~[" : "[") << a << ";" << b << "]" << std::endl;);
const unsigned bv_sz = m_bv_util.get_bv_size(v);
const numeral& zero = numeral::zero();
const numeral& one = numeral::one();
SASSERT(zero <= a);
SASSERT(a <= b);
SASSERT(b < numeral::power_of_two(bv_sz));
const bool a_min = a == zero;
const bool b_max = b == (numeral::power_of_two(bv_sz) - one);
if (negate) {
if (a_min && b_max) return m_okay = false;
if (a_min) return bound_lo(v, b + one);
if (b_max) return bound_up(v, a - one);
return add_neg_bound(v, a, b);
}
else {
if (!a_min) m_okay &= bound_lo(v, a);
if (!b_max) m_okay &= bound_up(v, b);
return m_okay;
}
}
bv_bounds::conv_res bv_bounds::convert_signed(app * v, numeral a, numeral b, bool negate, vector<ninterval>& nis) {
TRACE("bv_bounds", tout << "convert_signed " << mk_ismt2_pp(v, m_m) << ":" << (negate ? "~[" : "[") << a << ";" << b << "]" << std::endl;);
const unsigned bv_sz = m_bv_util.get_bv_size(v);
SASSERT(a <= b);
const numeral& zero = numeral::zero();
const numeral& one = numeral::one();
const bool a_neg = a < zero;
const bool b_neg = b < zero;
if (!a_neg && !b_neg) return record(v, a, b, negate, nis);
const numeral mod = numeral::power_of_two(bv_sz);
if (a_neg && b_neg) return record(v, mod + a, mod + b, negate, nis);
SASSERT(a_neg && !b_neg);
if (negate) {
const conv_res r1 = record(v, mod + a, mod - one, true, nis);
const conv_res r2 = record(v, zero, b, true, nis);
return r1 == UNSAT || r2 == UNSAT ? UNSAT : CONVERTED;
}
else {
const numeral l = b + one;
const numeral u = mod + a - one;
return l <= u ? record(v, l, u, true, nis) : CONVERTED;
}
}
bool bv_bounds::add_bound_signed(app * v, numeral a, numeral b, bool negate) {
TRACE("bv_bounds", tout << "bound_signed " << mk_ismt2_pp(v, m_m) << ":" << (negate ? "~" : " ") << a << ";" << b << std::endl;);
const unsigned bv_sz = m_bv_util.get_bv_size(v);
SASSERT(a <= b);
const numeral& zero = numeral::zero();
const numeral& one = numeral::one();
const bool a_neg = a < zero;
const bool b_neg = b < zero;
if (!a_neg && !b_neg) return add_bound_unsigned(v, a, b, negate);
const numeral mod = numeral::power_of_two(bv_sz);
if (a_neg && b_neg) return add_bound_unsigned(v, mod + a, mod + b, negate);
SASSERT(a_neg && !b_neg);
if (negate) {
return add_bound_unsigned(v, mod + a, mod - one, true)
&& add_bound_unsigned(v, zero, b, true);
}
else {
const numeral l = b + one;
const numeral u = mod + a - one;
return (l <= u) ? add_bound_unsigned(v, l, u, true) : m_okay;
}
}
bool bv_bounds::bound_lo(app * v, numeral l) {
SASSERT(in_range(v, l));
TRACE("bv_bounds", tout << "lower " << mk_ismt2_pp(v, m_m) << ":" << l << std::endl;);
// l <= v
bound_map::obj_map_entry * const entry = m_unsigned_lowers.insert_if_not_there2(v, l);
if (!(entry->get_data().m_value < l)) return m_okay;
// improve bound
entry->get_data().m_value = l;
return m_okay;
}
bool bv_bounds::bound_up(app * v, numeral u) {
SASSERT(in_range(v, u));
TRACE("bv_bounds", tout << "upper " << mk_ismt2_pp(v, m_m) << ":" << u << std::endl;);
// v <= u
bound_map::obj_map_entry * const entry = m_unsigned_uppers.insert_if_not_there2(v, u);
if (!(u < entry->get_data().m_value)) return m_okay;
// improve bound
entry->get_data().m_value = u;
return m_okay;
}
bool bv_bounds::add_neg_bound(app * v, numeral a, numeral b) {
TRACE("bv_bounds", tout << "negative bound " << mk_ismt2_pp(v, m_m) << ":" << a << ";" << b << std::endl;);
bv_bounds::interval negative_interval(a, b);
SASSERT(m_bv_util.is_bv(v));
SASSERT(a >= numeral::zero());
SASSERT(b < numeral::power_of_two(m_bv_util.get_bv_size(v)));
SASSERT(a <= b);
intervals_map::obj_map_entry * const e = m_negative_intervals.find_core(v);
intervals * ivs(NULL);
if (e == 0) {
ivs = alloc(intervals);
m_negative_intervals.insert(v, ivs);
}
else {
ivs = e->get_data().get_value();
}
ivs->push_back(negative_interval);
return m_okay;
}
bool bv_bounds::is_sat() {
if (!m_okay) return false;
obj_hashtable<app> seen;
obj_hashtable<app>::entry *dummy;
for (bound_map::iterator i = m_unsigned_lowers.begin(); i != m_unsigned_lowers.end(); ++i) {
app * const v = i->m_key;
if (!seen.insert_if_not_there_core(v, dummy)) continue;
if (!is_sat(v)) return false;
}
for (bound_map::iterator i = m_unsigned_uppers.begin(); i != m_unsigned_uppers.end(); ++i) {
app * const v = i->m_key;
if (!seen.insert_if_not_there_core(v, dummy)) continue;
if (!is_sat(v)) return false;
}
for (intervals_map::iterator i = m_negative_intervals.begin(); i != m_negative_intervals.end(); ++i) {
app * const v = i->m_key;
if (!seen.insert_if_not_there_core(v, dummy)) continue;
if (!is_sat(v)) return false;
}
return true;
}
struct interval_comp_t {
bool operator() (bv_bounds::interval i, bv_bounds::interval j) {
return (i.first < j.first);
}
} interval_comp;
void bv_bounds::record_singleton(app * v, numeral& singleton_value) {
TRACE("bv_bounds", tout << "singleton:" << mk_ismt2_pp(v, m_m) << ":" << singleton_value << std::endl;);
SASSERT(!m_singletons.find(v, singleton_value));
m_singletons.insert(v, singleton_value);
}
bool bv_bounds::is_sat(app * v) {
TRACE("bv_bounds", tout << "is_sat " << mk_ismt2_pp(v, m_m) << std::endl;);
const bool rv = is_sat_core(v);
TRACE("bv_bounds", tout << "is_sat " << mk_ismt2_pp(v, m_m) << "\nres: " << rv << std::endl;);
return rv;
}
bool bv_bounds::is_sat_core(app * v) {
SASSERT(m_bv_util.is_bv(v));
if (!m_okay) return false;
unsigned const bv_sz = m_bv_util.get_bv_size(v);
numeral lower, upper;
const bool has_upper = m_unsigned_uppers.find(v, upper);
const bool has_lower = m_unsigned_lowers.find(v, lower);
if (has_upper && has_lower && lower > upper) return false;
const numeral& one = numeral::one();
if (!has_lower) lower = numeral::zero();
if (!has_upper) upper = (numeral::power_of_two(bv_sz) - one);
TRACE("bv_bounds", tout << "is_sat bound:" << lower << "-" << upper << std::endl;);
intervals * negative_intervals(NULL);
const bool has_neg_intervals = m_negative_intervals.find(v, negative_intervals);
bool is_sat(false);
numeral new_lo = lower;
numeral new_hi = lower - one;
numeral ptr = lower;
if (has_neg_intervals) {
SASSERT(negative_intervals != NULL);
std::sort(negative_intervals->begin(), negative_intervals->end(), interval_comp);
intervals::const_iterator e = negative_intervals->end();
for (intervals::const_iterator i = negative_intervals->begin(); i != e; ++i) {
const numeral negative_lower = i->first;
const numeral negative_upper = i->second;
if (ptr > negative_upper) continue;
if (ptr < negative_lower) {
if (!is_sat) new_lo = ptr;
new_hi = negative_lower - one;
if (new_hi > upper) new_hi = upper;
is_sat = true;
}
TRACE("bv_bounds", tout << "is_sat new_lo, new_hi:" << new_lo << "-" << new_hi << std::endl;);
ptr = negative_upper + one;
TRACE("bv_bounds", tout << "is_sat ptr, new_hi:" << ptr << "-" << new_hi << std::endl;);
if (ptr > upper) break;
}
}
if (ptr <= upper) {
if (!is_sat) new_lo = ptr;
new_hi = upper;
is_sat = true;
}
if (new_hi < upper) bound_up(v, new_hi);
if (new_lo > lower) bound_lo(v, new_lo);
TRACE("bv_bounds", tout << "is_sat new_lo, new_hi:" << new_lo << "-" << new_hi << std::endl;);
const bool is_singleton = is_sat && new_hi == new_lo;
if (is_singleton) record_singleton(v, new_lo);
return is_sat;
}

View file

@ -0,0 +1,130 @@
/*++
Copyright (c) 2016 Microsoft Corporation
Module Name:
bv_bounds.h
Abstract:
A class used to determine bounds on bit-vector variables.
The satisfiability procedure is polynomial.
Author:
Mikolas Janota (MikolasJanota)
Revision History:
--*/
#ifndef BV_BOUNDS_H_23754
#define BV_BOUNDS_H_23754
#include"ast.h"
#include"bv_decl_plugin.h"
#include"rewriter_types.h"
/* \brief A class to analyze constraints on bit vectors.
The objective is to identify inconsistencies in polynomial time.
All bounds/intervals are closed. Methods that add new constraints
return false if inconsistency has already been reached.
Typical usage is to call repeatedly add_constraint(e) and call is_sat() in the end.
*/
class bv_bounds {
public:
typedef rational numeral;
typedef std::pair<numeral, numeral> interval;
typedef obj_map<app, numeral> bound_map;
bv_bounds(ast_manager& m) : m_m(m), m_bv_util(m), m_okay(true) {};
~bv_bounds();
public: // bounds addition methods
br_status rewrite(unsigned limit, func_decl * f, unsigned num, expr * const * args, expr_ref& result);
/** \brief Add a constraint to the system.
The added constraints are to be considered by is_sat.
Currently, only special types of inequalities are supported, e.g. v <= v+1.
Other constraints are ignored.
Returns false if the system became trivially unsatisfiable
**/
bool add_constraint(expr* e);
bool bound_up(app * v, numeral u); // v <= u
bool bound_lo(app * v, numeral l); // l <= v
inline bool add_neg_bound(app * v, numeral a, numeral b); // not (a<=v<=b)
bool add_bound_signed(app * v, numeral a, numeral b, bool negate);
bool add_bound_unsigned(app * v, numeral a, numeral b, bool negate);
public:
bool is_sat(); ///< Determine if the set of considered constraints is satisfiable.
bool is_okay();
const bound_map& singletons() { return m_singletons; }
bv_util& bvu() { return m_bv_util; }
void reset();
protected:
struct ninterval {
//ninterval(app * v, numeral lo, numeral hi, bool negated) : v(v), lo(lo), hi(hi), negated(negated) {}
app * v;
numeral lo, hi;
bool negated;
};
enum conv_res { CONVERTED, UNSAT, UNDEF };
conv_res convert(expr * e, vector<ninterval>& nis, bool negated);
conv_res record(app * v, numeral lo, numeral hi, bool negated, vector<ninterval>& nis);
conv_res convert_signed(app * v, numeral a, numeral b, bool negate, vector<ninterval>& nis);
typedef vector<interval> intervals;
typedef obj_map<app, intervals*> intervals_map;
ast_manager& m_m;
bound_map m_unsigned_lowers;
bound_map m_unsigned_uppers;
intervals_map m_negative_intervals;
bound_map m_singletons;
bv_util m_bv_util;
bool m_okay;
bool is_sat(app * v);
bool is_sat_core(app * v);
inline bool in_range(app *v, numeral l);
inline bool is_constant_add(unsigned bv_sz, expr * e, app*& v, numeral& val);
void record_singleton(app * v, numeral& singleton_value);
inline bool to_bound(const expr * e) const;
bool is_uleq(expr * e, expr * & v, numeral & c);
};
inline bool bv_bounds::is_okay() { return m_okay; }
inline bool bv_bounds::to_bound(const expr * e) const {
return is_app(e) && m_bv_util.is_bv(e)
&& !m_bv_util.is_bv_add(e)
&& !m_bv_util.is_numeral(e);
}
inline bool bv_bounds::in_range(app *v, bv_bounds::numeral n) {
const unsigned bv_sz = m_bv_util.get_bv_size(v);
const bv_bounds::numeral zero(0);
const bv_bounds::numeral mod(rational::power_of_two(bv_sz));
return (zero <= n) && (n < mod);
}
inline bool bv_bounds::is_constant_add(unsigned bv_sz, expr * e, app*& v, numeral& val) {
SASSERT(e && !v);
SASSERT(m_bv_util.get_bv_size(e) == bv_sz);
expr *lhs(NULL), *rhs(NULL);
if (!m_bv_util.is_bv_add(e, lhs, rhs)) {
v = to_app(e);
val = rational(0);
return true;
}
if (to_bound(lhs) && m_bv_util.is_numeral(rhs, val, bv_sz)) {
v = to_app(lhs);
return true;
}
if (to_bound(rhs) && m_bv_util.is_numeral(lhs, val, bv_sz)) {
v = to_app(rhs);
return true;
}
return false;
}
#endif /* BV_BOUNDS_H_23754 */

View file

@ -29,12 +29,18 @@ void bv_rewriter::updt_local_params(params_ref const & _p) {
m_mul2concat = p.mul2concat();
m_bit2bool = p.bit2bool();
m_trailing = p.bv_trailing();
m_urem_simpl = p.bv_urem_simpl();
m_blast_eq_value = p.blast_eq_value();
m_split_concat_eq = p.split_concat_eq();
m_udiv2mul = p.udiv2mul();
m_bvnot2arith = p.bvnot2arith();
m_bvnot_simpl = p.bv_not_simpl();
m_bv_sort_ac = p.bv_sort_ac();
m_mkbv2num = _p.get_bool("mkbv2num", false);
m_extract_prop = p.bv_extract_prop();
m_ite2id = p.bv_ite2id();
m_le_extra = p.bv_le_extra();
set_sort_sums(p.bv_sort_ac());
}
void bv_rewriter::updt_params(params_ref const & p) {
@ -189,6 +195,12 @@ br_status bv_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * cons
return mk_bv_comp(args[0], args[1], result);
case OP_MKBV:
return mk_mkbv(num_args, args, result);
case OP_BSMUL_NO_OVFL:
return mk_bvsmul_no_overflow(num_args, args, result);
case OP_BUMUL_NO_OVFL:
return mk_bvumul_no_overflow(num_args, args, result);
case OP_BSMUL_NO_UDFL:
return mk_bvsmul_no_underflow(num_args, args, result);
default:
return BR_FAILED;
}
@ -228,6 +240,198 @@ br_status bv_rewriter::mk_slt(expr * a, expr * b, expr_ref & result) {
return BR_REWRITE2;
}
// short-circuited concat
expr * bv_rewriter::concat(unsigned num_args, expr * const * args) {
SASSERT(num_args);
switch (num_args) {
case 0: return m_util.mk_concat(num_args, args);
case 1: return args[0];
default: return m_util.mk_concat(num_args, args);
}
}
// finds a commonality in sums, e.g. 2 + x + y and 5 + x + y
bool bv_rewriter::are_eq_upto_num(expr * _a, expr * _b,
expr_ref& common,
numeral& a0_val, numeral& b0_val) {
const bool aadd = m_util.is_bv_add(_a);
const bool badd = m_util.is_bv_add(_b);
const bool has_num_a = aadd && to_app(_a)->get_num_args() && is_numeral(to_app(_a)->get_arg(0));
const bool has_num_b = badd && to_app(_b)->get_num_args() && is_numeral(to_app(_b)->get_arg(0));
a0_val = numeral::zero();
b0_val = numeral::zero();
if (!aadd && !badd) {
if (_a == _b) {
common = _a;
return true;
} else {
return false;
}
}
if (!aadd && badd) {
if (to_app(_a)->get_num_args() != 2 || !has_num_a || to_app(_a)->get_arg(0) != _b)
return false;
common = _b;
return true;
}
if (aadd && !badd) {
if (to_app(_b)->get_num_args() != 2 || !has_num_b || to_app(_b)->get_arg(0) != _a)
return false;
common = _a;
return true;
}
SASSERT(aadd && badd);
app * const a = to_app(_a);
app * const b = to_app(_b);
const unsigned numa = a->get_num_args();
const unsigned numb = b->get_num_args();
if (!numa || !numb) return false;
if ((numa - (has_num_a ? 1 : 0)) != (numb - (has_num_b ? 1 : 0))) return false;
unsigned ai = has_num_a ? 1 : 0;
unsigned bi = has_num_b ? 1 : 0;
while (ai < numa) {
if (a->get_arg(ai) != b->get_arg(bi)) return false;
++ai;
++bi;
}
a0_val = numeral::zero();
b0_val = numeral::zero();
const unsigned sz = m_util.get_bv_size(a);
unsigned a0_sz(sz), b0_sz(sz);
if (has_num_a) is_numeral(a->get_arg(0), a0_val, a0_sz);
if (has_num_b) is_numeral(b->get_arg(0), b0_val, b0_sz);
SASSERT(a0_sz == m_util.get_bv_size(a) && b0_sz == m_util.get_bv_size(a));
if (has_num_a && numa > 2) {
common = m().mk_app(m_util.get_fid(), add_decl_kind(), numa - 1, a->get_args() + 1);
}
else {
common = has_num_a ? a->get_arg(1) : a;
}
return true;
}
// simplifies expressions as (bvuleq (X + c1) (X + c2)) for some common expression X and numerals c1, c2
br_status bv_rewriter::rw_leq_overflow(bool is_signed, expr * a, expr * b, expr_ref & result) {
if (is_signed) return BR_FAILED;
expr_ref common(m());
numeral a0_val, b0_val;
if (!are_eq_upto_num(a, b, common, a0_val, b0_val)) return BR_FAILED;
SASSERT(a0_val.is_nonneg() && b0_val.is_nonneg());
const unsigned sz = m_util.get_bv_size(a);
if (a0_val == b0_val) {
result = m().mk_true();
return BR_DONE;
}
if (a0_val < b0_val) {
result = m_util.mk_ule(m_util.mk_numeral(b0_val - a0_val, sz), b);
return BR_REWRITE2;
}
SASSERT(a0_val > b0_val);
SASSERT(!a0_val.is_zero());
const numeral lower = rational::power_of_two(sz) - a0_val;
const numeral upper = rational::power_of_two(sz) - b0_val - numeral::one();
if (lower == upper) {
result = m().mk_eq(common, mk_numeral(lower, sz));
}
else if (b0_val.is_zero()) {
result = m_util.mk_ule(mk_numeral(lower, sz), common);
}
else {
SASSERT(lower.is_pos());
result = m().mk_and(m_util.mk_ule(mk_numeral(lower, sz), common),
m_util.mk_ule(common, mk_numeral(upper, sz)));
}
return BR_REWRITE2;
}
// simplification for leq comparison between two concatenations
br_status bv_rewriter::rw_leq_concats(bool is_signed, expr * _a, expr * _b, expr_ref & result) {
if (!m_util.is_concat(_a) || !m_util.is_concat(_b))
return BR_FAILED;
const app * const a = to_app(_a);
const app * const b = to_app(_b);
const unsigned numa = a->get_num_args();
const unsigned numb = b->get_num_args();
const unsigned num_min = std::min(numa, numb);
if (numa && numb) { // first arg numeral
numeral af, bf;
unsigned af_sz, bf_sz;
if ( is_numeral(a->get_arg(0), af, af_sz)
&& is_numeral(b->get_arg(0), bf, bf_sz) ) {
const unsigned sz_min = std::min(af_sz, bf_sz);
const numeral hi_af = m_util.norm(af_sz > sz_min ? div(af, rational::power_of_two(af_sz - sz_min)) : af,
sz_min, is_signed);
const numeral hi_bf = m_util.norm(bf_sz > sz_min ? div(bf, rational::power_of_two(bf_sz - sz_min)) : bf,
sz_min, is_signed);
if (hi_af != hi_bf) {
result = hi_af < hi_bf ? m().mk_true() : m().mk_false();
return BR_DONE;
}
expr_ref new_a(m());
expr_ref new_b(m());
if (af_sz > sz_min) {
ptr_buffer<expr> new_args;
new_args.push_back(mk_numeral(af, af_sz - sz_min));
for (unsigned i = 1; i < numa; ++i) new_args.push_back(a->get_arg(i));
new_a = concat(new_args.size(), new_args.c_ptr());
} else {
new_a = concat(numa - 1, a->get_args() + 1);
}
if (bf_sz > sz_min) {
ptr_buffer<expr> new_args;
new_args.push_back(mk_numeral(bf, bf_sz - sz_min));
for (unsigned i = 1; i < numb; ++i) new_args.push_back(b->get_arg(i));
new_b = concat(new_args.size(), new_args.c_ptr());
} else {
new_b = concat(numb - 1, b->get_args() + 1);
}
result = m_util.mk_ule(new_a, new_b);
return BR_REWRITE2;
}
}
{ // common prefix
unsigned common = 0;
while (common < num_min && m().are_equal(a->get_arg(common), b->get_arg(common))) ++common;
SASSERT((common == numa) == (common == numb));
if (common == numa) {
SASSERT(0); // shouldn't get here as both sides are equal
result = m().mk_true();
return BR_DONE;
}
if (common > 0) {
result = m_util.mk_ule(concat(numa - common, a->get_args() + common),
concat(numb - common, b->get_args() + common));
return BR_REWRITE2;
}
}
{ // common postfix
unsigned new_numa = a->get_num_args();
unsigned new_numb = b->get_num_args();
while (new_numa && new_numb) {
expr * const last_a = a->get_arg(new_numa - 1);
expr * const last_b = b->get_arg(new_numb - 1);
if (!m().are_equal(last_a, last_b)) break;
new_numa--;
new_numb--;
}
if (new_numa == 0) {
SASSERT(0); // shouldn't get here as both sides are equal
result = m().mk_true();
return BR_DONE;
}
if (new_numa != numa) {
result = is_signed ? m_util.mk_sle(concat(new_numa, a->get_args()), concat(new_numb, b->get_args()))
: m_util.mk_ule(concat(new_numa, a->get_args()), concat(new_numb, b->get_args()));
return BR_REWRITE2;
}
}
return BR_FAILED;
}
br_status bv_rewriter::mk_leq_core(bool is_signed, expr * a, expr * b, expr_ref & result) {
numeral r1, r2, r3;
@ -246,7 +450,7 @@ br_status bv_rewriter::mk_leq_core(bool is_signed, expr * a, expr * b, expr_ref
r2 = m_util.norm(r2, sz, is_signed);
if (is_num1 && is_num2) {
result = r1 <= r2 ? m().mk_true() : m().mk_false();
result = m().mk_bool_val(r1 <= r2);
return BR_DONE;
}
@ -303,6 +507,24 @@ br_status bv_rewriter::mk_leq_core(bool is_signed, expr * a, expr * b, expr_ref
return BR_REWRITE2;
}
if (m_le_extra) {
const br_status cst = rw_leq_concats(is_signed, a, b, result);
if (cst != BR_FAILED) {
TRACE("le_extra", tout << (is_signed ? "bv_sle\n" : "bv_ule\n")
<< mk_ismt2_pp(a, m(), 2) << "\n" << mk_ismt2_pp(b, m(), 2) << "\n--->\n"<< mk_ismt2_pp(result, m(), 2) << "\n";);
return cst;
}
}
if (m_le_extra) {
const br_status cst = rw_leq_overflow(is_signed, a, b, result);
if (cst != BR_FAILED) {
TRACE("le_extra", tout << (is_signed ? "bv_sle\n" : "bv_ule\n")
<< mk_ismt2_pp(a, m(), 2) << "\n" << mk_ismt2_pp(b, m(), 2) << "\n--->\n"<< mk_ismt2_pp(result, m(), 2) << "\n";);
return cst;
}
}
#if 0
if (!is_signed && m_util.is_concat(b) && to_app(b)->get_num_args() == 2 && m_util.is_zero(to_app(b)->get_arg(0))) {
//
@ -360,6 +582,88 @@ br_status bv_rewriter::mk_leq_core(bool is_signed, expr * a, expr * b, expr_ref
return BR_FAILED;
}
// attempt to chop off bits that are above the position high for bv_mul and bv_add,
// returns how many bits were chopped off
// e.g. (bvadd(concat #b11 p) #x1)) with high=1, returns 2 and sets result = p + #b01
// the sz of results is the sz of arg minus the return value
unsigned bv_rewriter::propagate_extract(unsigned high, expr * arg, expr_ref & result) {
if (!m_util.is_bv_add(arg) && !m_util.is_bv_mul(arg))
return 0;
const unsigned sz = m_util.get_bv_size(arg);
const unsigned to_remove = high + 1 < sz ? sz - high - 1 : 0;
if (to_remove == 0)
return 0; // high goes to the top, nothing to do
const app * const a = to_app(arg);
const unsigned num = a->get_num_args();
bool all_numerals = true;
unsigned removable = to_remove;
numeral val;
unsigned curr_first_sz = -1;
// calculate how much can be removed
for (unsigned i = 0; i < num; i++) {
expr * const curr = a->get_arg(i);
const bool curr_is_conc = m_util.is_concat(curr);
if (curr_is_conc && to_app(curr)->get_num_args() == 0) continue;
expr * const curr_first = curr_is_conc ? to_app(curr)->get_arg(0) : curr;
if (!all_numerals) {
if (removable != m_util.get_bv_size(curr_first))
return 0;
continue;
}
if (is_numeral(curr_first, val, curr_first_sz)) {
removable = std::min(removable, curr_first_sz);
} else {
all_numerals = false;
curr_first_sz = m_util.get_bv_size(curr_first);
if (curr_first_sz > removable) return 0;
removable = curr_first_sz;
}
if (removable == 0) return 0;
}
// perform removal
SASSERT(removable <= to_remove);
ptr_buffer<expr> new_args;
ptr_buffer<expr> new_concat_args;
for (unsigned i = 0; i < num; i++) {
expr * const curr = a->get_arg(i);
const bool curr_is_conc = m_util.is_concat(curr);
if (curr_is_conc && to_app(curr)->get_num_args() == 0) continue;
expr * const curr_first = curr_is_conc ? to_app(curr)->get_arg(0) : curr;
expr * new_first = NULL;
if (is_numeral(curr_first, val, curr_first_sz)) {
SASSERT(curr_first_sz >= removable);
const unsigned new_num_sz = curr_first_sz - removable;
new_first = new_num_sz ? mk_numeral(val, new_num_sz) : NULL;
}
expr * new_arg = NULL;
if (curr_is_conc) {
const unsigned conc_num = to_app(curr)->get_num_args();
if (new_first) {
new_concat_args.reset();
new_concat_args.push_back(new_first);
for (unsigned j = 1; j < conc_num; ++j)
new_concat_args.push_back(to_app(curr)->get_arg(j));
new_arg = m_util.mk_concat(new_concat_args.size(), new_concat_args.c_ptr());
} else {
// remove first element of concat
expr * const * const old_conc_args = to_app(curr)->get_args();
switch (conc_num) {
case 0: UNREACHABLE(); break;
case 1: new_arg = NULL; break;
case 2: new_arg = to_app(curr)->get_arg(1); break;
default: new_arg = m_util.mk_concat(conc_num - 1, old_conc_args + 1);
}
}
} else {
new_arg = new_first;
}
if (new_arg) new_args.push_back(new_arg);
}
result = m().mk_app(get_fid(), a->get_decl()->get_decl_kind(), new_args.size(), new_args.c_ptr());
SASSERT(m_util.is_bv(result));
return removable;
}
br_status bv_rewriter::mk_extract(unsigned high, unsigned low, expr * arg, expr_ref & result) {
unsigned sz = get_bv_size(arg);
SASSERT(sz > 0);
@ -463,6 +767,17 @@ br_status bv_rewriter::mk_extract(unsigned high, unsigned low, expr * arg, expr_
return BR_REWRITE2;
}
if (m_extract_prop && (high >= low)) {
expr_ref ep_res(m());
const unsigned ep_rm = propagate_extract(high, arg, ep_res);
if (ep_rm != 0) {
result = m_mk_extract(high, low, ep_res);
TRACE("extract_prop", tout << mk_ismt2_pp(arg, m()) << "\n[" << high <<"," << low << "]\n" << ep_rm << "---->\n"
<< mk_ismt2_pp(result.get(), m()) << "\n";);
return BR_REWRITE2;
}
}
if (m().is_ite(arg)) {
result = m().mk_ite(to_app(arg)->get_arg(0),
m_mk_extract(high, low, to_app(arg)->get_arg(1)),
@ -836,6 +1151,22 @@ bool bv_rewriter::is_minus_one_core(expr * arg) const {
return false;
}
bool bv_rewriter::is_negatable(expr * arg, expr_ref& x) {
numeral r;
unsigned bv_size;
if (is_numeral(arg, r, bv_size)) {
r = bitwise_not(bv_size, r);
x = mk_numeral(r, bv_size);
return true;
}
if (m_util.is_bv_not(arg)) {
SASSERT(to_app(arg)->get_num_args() == 1);
x = to_app(arg)->get_arg(0);
return true;
}
return false;
}
bool bv_rewriter::is_x_minus_one(expr * arg, expr * & x) {
if (is_add(arg) && to_app(arg)->get_num_args() == 2) {
if (is_minus_one_core(to_app(arg)->get_arg(0))) {
@ -1040,6 +1371,7 @@ br_status bv_rewriter::mk_bv2int(expr * arg, expr_ref & result) {
return BR_FAILED;
}
br_status bv_rewriter::mk_concat(unsigned num_args, expr * const * args, expr_ref & result) {
expr_ref_buffer new_args(m());
numeral v1;
@ -1100,6 +1432,8 @@ br_status bv_rewriter::mk_concat(unsigned num_args, expr * const * args, expr_re
return BR_DONE;
}
br_status bv_rewriter::mk_zero_extend(unsigned n, expr * arg, expr_ref & result) {
if (n == 0) {
result = arg;
@ -1526,6 +1860,35 @@ br_status bv_rewriter::mk_bv_not(expr * arg, expr_ref & result) {
return BR_REWRITE1;
}
if (m_bvnot_simpl) {
expr *s(0), *t(0);
if (m_util.is_bv_mul(arg, s, t)) {
// ~(-1 * x) --> (x - 1)
bv_size = m_util.get_bv_size(s);
if (m_util.is_allone(s)) {
rational minus_one = (rational::power_of_two(bv_size) - rational::one());
result = m_util.mk_bv_add(m_util.mk_numeral(minus_one, bv_size), t);
return BR_REWRITE1;
}
if (m_util.is_allone(t)) {
rational minus_one = (rational::power_of_two(bv_size) - rational::one());
result = m_util.mk_bv_add(m_util.mk_numeral(minus_one, bv_size), s);
return BR_REWRITE1;
}
}
if (m_util.is_bv_add(arg, s, t)) {
expr_ref ns(m());
expr_ref nt(m());
// ~(x + y) --> (~x + ~y + 1) when x and y are easy to negate
if (is_negatable(t, nt) && is_negatable(s, ns)) {
bv_size = m_util.get_bv_size(s);
expr * nargs[3] = { m_util.mk_numeral(rational::one(), bv_size), ns.get(), nt.get() };
result = m().mk_app(m_util.get_fid(), OP_BADD, 3, nargs);
return BR_REWRITE1;
}
}
}
return BR_FAILED;
}
@ -1777,7 +2140,7 @@ br_status bv_rewriter::mk_bit2bool(expr * lhs, expr * rhs, expr_ref & result) {
if (is_numeral(lhs)) {
SASSERT(is_numeral(rhs));
result = lhs == rhs ? m().mk_true() : m().mk_false();
result = m().mk_bool_val(lhs == rhs);
return BR_DONE;
}
@ -2068,6 +2431,16 @@ br_status bv_rewriter::mk_mul_eq(expr * lhs, expr * rhs, expr_ref & result) {
return BR_FAILED;
}
bool bv_rewriter::is_urem_any(expr * e, expr * & dividend, expr * & divisor) {
if (!m_util.is_bv_urem(e) && !m_util.is_bv_uremi(e))
return false;
const app * const a = to_app(e);
SASSERT(a->get_num_args() == 2);
dividend = a->get_arg(0);
divisor = a->get_arg(1);
return true;
}
br_status bv_rewriter::mk_eq_core(expr * lhs, expr * rhs, expr_ref & result) {
if (lhs == rhs) {
result = m().mk_true();
@ -2119,6 +2492,25 @@ br_status bv_rewriter::mk_eq_core(expr * lhs, expr * rhs, expr_ref & result) {
return st;
}
if (m_urem_simpl) {
expr * dividend;
expr * divisor;
numeral divisor_val, rhs_val;
unsigned divisor_sz, rhs_sz;
if (is_urem_any(lhs, dividend, divisor)
&& is_numeral(rhs, rhs_val, rhs_sz)
&& is_numeral(divisor, divisor_val, divisor_sz)) {
if (rhs_val >= divisor_val) {//(= (bvurem x c1) c2) where c2 >= c1
result = m().mk_false();
return BR_DONE;
}
if ((divisor_val + rhs_val) >= rational::power_of_two(divisor_sz)) {//(= (bvurem x c1) c2) where c1+c2 >= 2^width
result = m().mk_eq(dividend, rhs);
return BR_REWRITE2;
}
}
}
expr_ref new_lhs(m());
expr_ref new_rhs(m());
@ -2126,7 +2518,7 @@ br_status bv_rewriter::mk_eq_core(expr * lhs, expr * rhs, expr_ref & result) {
st = cancel_monomials(lhs, rhs, false, new_lhs, new_rhs);
if (st != BR_FAILED) {
if (is_numeral(new_lhs) && is_numeral(new_rhs)) {
result = new_lhs == new_rhs ? m().mk_true() : m().mk_false();
result = m().mk_bool_val(new_lhs == new_rhs);
return BR_DONE;
}
}
@ -2186,6 +2578,137 @@ br_status bv_rewriter::mk_mkbv(unsigned num, expr * const * args, expr_ref & res
return BR_FAILED;
}
br_status bv_rewriter::mk_ite_core(expr * c, expr * t, expr * e, expr_ref & result) {
TRACE("bv_ite", tout << "mk_ite_core:\n" << mk_ismt2_pp(c, m()) << "?\n"
<< mk_ismt2_pp(t, m()) << "\n:" << mk_ismt2_pp(e, m()) << "\n";);
if (m().are_equal(t, e)) {
result = e;
return BR_REWRITE1;
}
if (m().is_not(c)) {
result = m().mk_ite(to_app(c)->get_arg(0), e, t);
return BR_REWRITE1;
}
if (m_ite2id && m().is_eq(c) && is_bv(t) && is_bv(e)) {
// detect when ite is actually some simple function based on the pattern (lhs=rhs) ? t : e
expr * lhs = to_app(c)->get_arg(0);
expr * rhs = to_app(c)->get_arg(1);
if (is_bv(rhs)) {
if (is_numeral(lhs))
std::swap(lhs, rhs);
if ( (m().are_equal(lhs, t) && m().are_equal(rhs, e))
|| (m().are_equal(lhs, e) && m().are_equal(rhs, t))) {
// (a = b ? a : b) is b. (a = b ? b : a) is a
result = e;
return BR_REWRITE1;
}
const unsigned sz = m_util.get_bv_size(rhs);
if (sz == 1) { // detect (lhs = N) ? C : D, where N, C, D are 1 bit numberals
numeral rhs_n, e_n, t_n;
unsigned rhs_sz, e_sz, t_sz;
if (is_numeral(rhs, rhs_n, rhs_sz)
&& is_numeral(t, t_n, t_sz) && is_numeral(e, e_n, e_sz)) {
if (t_sz == 1) {
SASSERT(rhs_sz == sz && e_sz == sz && t_sz == sz);
SASSERT(!m().are_equal(t, e));
result = m().are_equal(rhs, t) ? lhs : m_util.mk_bv_not(lhs);
return BR_REWRITE1;
}
}
}
}
}
return BR_FAILED;
}
br_status bv_rewriter::mk_bvsmul_no_overflow(unsigned num, expr * const * args, expr_ref & result) {
SASSERT(num == 2);
unsigned bv_sz;
rational a0_val, a1_val;
bool is_num1 = is_numeral(args[0], a0_val, bv_sz);
bool is_num2 = is_numeral(args[1], a1_val, bv_sz);
if (is_num1 && (a0_val.is_zero() || a0_val.is_one())) {
result = m().mk_true();
return BR_DONE;
}
if (is_num2 && (a1_val.is_zero() || a1_val.is_one())) {
result = m().mk_true();
return BR_DONE;
}
if (is_num1 && is_num2) {
rational mr = a0_val * a1_val;
rational lim = rational::power_of_two(bv_sz-1);
result = m().mk_bool_val(mr < lim);
return BR_DONE;
}
return BR_FAILED;
}
br_status bv_rewriter::mk_bvumul_no_overflow(unsigned num, expr * const * args, expr_ref & result) {
SASSERT(num == 2);
unsigned bv_sz;
rational a0_val, a1_val;
bool is_num1 = is_numeral(args[0], a0_val, bv_sz);
bool is_num2 = is_numeral(args[1], a1_val, bv_sz);
if (is_num1 && (a0_val.is_zero() || a0_val.is_one())) {
result = m().mk_true();
return BR_DONE;
}
if (is_num2 && (a1_val.is_zero() || a1_val.is_one())) {
result = m().mk_true();
return BR_DONE;
}
if (is_num1 && is_num2) {
rational mr = a0_val * a1_val;
rational lim = rational::power_of_two(bv_sz);
result = m().mk_bool_val(mr < lim);
return BR_DONE;
}
return BR_FAILED;
}
br_status bv_rewriter::mk_bvsmul_no_underflow(unsigned num, expr * const * args, expr_ref & result) {
SASSERT(num == 2);
unsigned bv_sz;
rational a0_val, a1_val;
bool is_num1 = is_numeral(args[0], a0_val, bv_sz);
bool is_num2 = is_numeral(args[1], a1_val, bv_sz);
if (is_num1 && (a0_val.is_zero() || a0_val.is_one())) {
result = m().mk_true();
return BR_DONE;
}
if (is_num2 && (a1_val.is_zero() || a1_val.is_one())) {
result = m().mk_true();
return BR_DONE;
}
if (is_num1 && is_num2) {
rational ul = rational::power_of_two(bv_sz);
rational lim = rational::power_of_two(bv_sz-1);
if (a0_val >= lim) a0_val -= ul;
if (a1_val >= lim) a1_val -= ul;
rational mr = a0_val * a1_val;
rational neg_lim = -lim;
TRACE("bv_rewriter_bvsmul_no_underflow", tout << "a0:" << a0_val << " a1:" << a1_val << " mr:" << mr << " neg_lim:" << neg_lim << std::endl;);
result = m().mk_bool_val(mr >= neg_lim);
return BR_DONE;
}
return BR_FAILED;
}
template class poly_rewriter<bv_rewriter_core>;

View file

@ -56,11 +56,16 @@ class bv_rewriter : public poly_rewriter<bv_rewriter_core> {
bool m_bit2bool;
bool m_blast_eq_value;
bool m_mkbv2num;
bool m_ite2id;
bool m_split_concat_eq;
bool m_udiv2mul;
bool m_bvnot2arith;
bool m_bv_sort_ac;
bool m_trailing;
bool m_extract_prop;
bool m_bvnot_simpl;
bool m_le_extra;
bool m_urem_simpl;
bool is_zero_bit(expr * x, unsigned idx);
@ -70,13 +75,18 @@ class bv_rewriter : public poly_rewriter<bv_rewriter_core> {
br_status mk_sle(expr * a, expr * b, expr_ref & result);
br_status mk_sge(expr * a, expr * b, expr_ref & result);
br_status mk_slt(expr * a, expr * b, expr_ref & result);
br_status rw_leq_concats(bool is_signed, expr * a, expr * b, expr_ref & result);
bool are_eq_upto_num(expr * a, expr * b, expr_ref& common, numeral& a0_val, numeral& b0_val);
br_status rw_leq_overflow(bool is_signed, expr * _a, expr * _b, expr_ref & result);
br_status mk_leq_core(bool is_signed, expr * a, expr * b, expr_ref & result);
br_status mk_concat(unsigned num_args, expr * const * args, expr_ref & result);
unsigned propagate_extract(unsigned high, expr * arg, expr_ref & result);
br_status mk_extract(unsigned high, unsigned low, expr * arg, expr_ref & result);
br_status mk_repeat(unsigned n, expr * arg, expr_ref & result);
br_status mk_zero_extend(unsigned n, expr * arg, expr_ref & result);
br_status mk_sign_extend(unsigned n, expr * arg, expr_ref & result);
bool is_negatable(expr * arg, expr_ref& x);
br_status mk_bv_not(expr * arg, expr_ref & result);
br_status mk_bv_or(unsigned num, expr * const * args, expr_ref & result);
br_status mk_bv_xor(unsigned num, expr * const * args, expr_ref & result);
@ -123,6 +133,9 @@ class bv_rewriter : public poly_rewriter<bv_rewriter_core> {
br_status mk_blast_eq_value(expr * lhs, expr * rhs, expr_ref & result);
br_status mk_eq_concat(expr * lhs, expr * rhs, expr_ref & result);
br_status mk_mkbv(unsigned num, expr * const * args, expr_ref & result);
br_status mk_bvsmul_no_overflow(unsigned num, expr * const * args, expr_ref & result);
br_status mk_bvumul_no_overflow(unsigned num, expr * const * args, expr_ref & result);
br_status mk_bvsmul_no_underflow(unsigned num, expr * const * args, expr_ref & result);
bool is_minus_one_times_t(expr * arg);
void mk_t1_add_t2_eq_c(expr * t1, expr * t2, expr * c, expr_ref & result);
@ -136,6 +149,7 @@ class bv_rewriter : public poly_rewriter<bv_rewriter_core> {
void updt_local_params(params_ref const & p);
expr * concat(unsigned num_args, expr * const * args);
public:
bv_rewriter(ast_manager & m, params_ref const & p = params_ref()):
poly_rewriter<bv_rewriter_core>(m, p),
@ -164,7 +178,9 @@ public:
result = m().mk_app(f, num_args, args);
}
bool is_urem_any(expr * e, expr * & dividend, expr * & divisor);
br_status mk_eq_core(expr * lhs, expr * rhs, expr_ref & result);
br_status mk_ite_core(expr * c, expr * t, expr * e, expr_ref & resul);
bool hi_div0() const { return m_hi_div0; }

View file

@ -10,5 +10,10 @@ def_module_params(module_name='rewriter',
("mul2concat", BOOL, False, "replace multiplication by a power of two into a concatenation"),
("bvnot2arith", BOOL, False, "replace (bvnot x) with (bvsub -1 x)"),
("bv_sort_ac", BOOL, False, "sort the arguments of all AC operators"),
("bv_trailing", BOOL, False, "lean removal of trailing zeros")
("bv_trailing", BOOL, False, "lean removal of trailing zeros"),
("bv_extract_prop", BOOL, False, "attempt to partially propagate extraction inwards"),
("bv_not_simpl", BOOL, False, "apply simplifications for bvnot"),
("bv_ite2id", BOOL, False, "rewrite ite that can be simplified to identity"),
("bv_le_extra", BOOL, False, "additional bu_(u/s)le simplifications"),
("bv_urem_simpl", BOOL, False, "additional simplification for bvurem")
))

View file

@ -36,11 +36,14 @@ struct bv_trailing::imp {
: m_mk_extract(mk_extract)
, m_util(mk_extract.bvutil())
, m(mk_extract.m()) {
TRACE("bv-trailing", tout << "ctor\n";);
for (unsigned i = 0; i <= TRAILING_DEPTH; ++i)
m_count_cache[i] = NULL;
}
virtual ~imp() {
TRACE("bv-trailing", tout << "dtor\n";);
reset_cache(0);
}
@ -67,10 +70,8 @@ struct bv_trailing::imp {
}
expr_ref out1(m);
expr_ref out2(m);
DEBUG_CODE(
const unsigned rm1 = remove_trailing(e1, min, out1, TRAILING_DEPTH);
const unsigned rm2 = remove_trailing(e2, min, out2, TRAILING_DEPTH);
SASSERT(rm1 == min && rm2 == min););
VERIFY(min == remove_trailing(e1, min, out1, TRAILING_DEPTH));
VERIFY(min == remove_trailing(e2, min, out2, TRAILING_DEPTH));
const bool are_eq = m.are_equal(out1, out2);
result = are_eq ? m.mk_true() : m.mk_eq(out1, out2);
return are_eq ? BR_DONE : BR_REWRITE2;
@ -339,6 +340,7 @@ struct bv_trailing::imp {
if (depth == 0) return;
if (m_count_cache[depth] == NULL)
m_count_cache[depth] = alloc(map);
SASSERT(!m_count_cache[depth]->contains(e));
m.inc_ref(e);
m_count_cache[depth]->insert(e, std::make_pair(min, max));
TRACE("bv-trailing", tout << "caching@" << depth <<": " << mk_ismt2_pp(e, m) << '[' << m_util.get_bv_size(e) << "]\n: " << min << '-' << max << "\n";);
@ -361,11 +363,13 @@ struct bv_trailing::imp {
return true;
}
void reset_cache(unsigned condition) {
void reset_cache(const unsigned condition) {
SASSERT(m_count_cache[0] == NULL);
for (unsigned i = 1; i <= TRAILING_DEPTH; ++i) {
if (m_count_cache[i] == NULL) continue;
if (m_count_cache[i]->size() < condition) continue;
TRACE("bv-trailing", tout << "may reset cache " << i << " " << condition << "\n";);
if (condition && m_count_cache[i]->size() < condition) continue;
TRACE("bv-trailing", tout << "reset cache " << i << "\n";);
map::iterator it = m_count_cache[i]->begin();
map::iterator end = m_count_cache[i]->end();
for (; it != end; ++it) m.dec_ref(it->m_key);

View file

@ -0,0 +1,293 @@
/*++
Copyright (c) 2016 Microsoft Corporation
Module Name:
enum2bv_rewriter.cpp
Abstract:
Conversion from enumeration types to bit-vectors.
Author:
Nikolaj Bjorner (nbjorner) 2016-10-18
Notes:
--*/
#include"rewriter.h"
#include"rewriter_def.h"
#include"enum2bv_rewriter.h"
#include"ast_util.h"
#include"ast_pp.h"
struct enum2bv_rewriter::imp {
ast_manager& m;
params_ref m_params;
obj_map<func_decl, func_decl*> m_enum2bv;
obj_map<func_decl, func_decl*> m_bv2enum;
obj_map<func_decl, expr*> m_enum2def;
expr_ref_vector m_bounds;
datatype_util m_dt;
func_decl_ref_vector m_enum_consts;
func_decl_ref_vector m_enum_bvs;
expr_ref_vector m_enum_defs;
unsigned_vector m_enum_consts_lim;
unsigned m_num_translated;
i_sort_pred* m_sort_pred;
struct rw_cfg : public default_rewriter_cfg {
imp& m_imp;
ast_manager& m;
datatype_util m_dt;
bv_util m_bv;
rw_cfg(imp& i, ast_manager & m) :
m_imp(i),
m(m),
m_dt(m),
m_bv(m)
{}
br_status reduce_app(func_decl * f, unsigned num, expr * const * args, expr_ref & result, proof_ref & result_pr) {
expr_ref a0(m), a1(m);
expr_ref_vector _args(m);
if (m.is_eq(f) && reduce_arg(args[0], a0) && reduce_arg(args[1], a1)) {
result = m.mk_eq(a0, a1);
return BR_DONE;
}
else if (m.is_distinct(f) && reduce_args(num, args, _args)) {
result = m.mk_distinct(_args.size(), _args.c_ptr());
return BR_DONE;
}
else if (m_dt.is_recognizer(f) && reduce_arg(args[0], a0)) {
unsigned idx = m_dt.get_recognizer_constructor_idx(f);
a1 = m_bv.mk_numeral(rational(idx), get_sort(a0));
result = m.mk_eq(a0, a1);
return BR_DONE;
}
else {
check_for_fd(num, args);
return BR_FAILED;
}
}
bool reduce_args(unsigned sz, expr*const* as, expr_ref_vector& result) {
expr_ref tmp(m);
for (unsigned i = 0; i < sz; ++i) {
if (!reduce_arg(as[i], tmp)) return false;
result.push_back(tmp);
}
return true;
}
void throw_non_fd(expr* e) {
std::stringstream strm;
strm << "unabled nested data-type expression " << mk_pp(e, m);
throw rewriter_exception(strm.str().c_str());
}
void check_for_fd(unsigned n, expr* const* args) {
for (unsigned i = 0; i < n; ++i) {
if (m_imp.is_fd(get_sort(args[i]))) {
throw_non_fd(args[i]);
}
}
}
bool reduce_arg(expr* a, expr_ref& result) {
sort* s = get_sort(a);
if (!m_imp.is_fd(s)) {
return false;
}
unsigned bv_size = get_bv_size(s);
if (is_var(a)) {
result = m.mk_var(to_var(a)->get_idx(), m_bv.mk_sort(bv_size));
return true;
}
SASSERT(is_app(a));
func_decl* f = to_app(a)->get_decl();
if (m_dt.is_constructor(f)) {
unsigned idx = m_dt.get_constructor_idx(f);
result = m_bv.mk_numeral(idx, bv_size);
}
else if (is_uninterp_const(a)) {
func_decl* f_fresh;
if (m_imp.m_enum2bv.find(f, f_fresh)) {
result = m.mk_const(f_fresh);
return true;
}
// create a fresh variable, add bounds constraints for it.
unsigned nc = m_dt.get_datatype_num_constructors(s);
result = m.mk_fresh_const(f->get_name().str().c_str(), m_bv.mk_sort(bv_size));
f_fresh = to_app(result)->get_decl();
if (!is_power_of_two(nc) || nc == 1) {
m_imp.m_bounds.push_back(m_bv.mk_ule(result, m_bv.mk_numeral(nc-1, bv_size)));
}
expr_ref f_def(m);
ptr_vector<func_decl> const& cs = *m_dt.get_datatype_constructors(s);
f_def = m.mk_const(cs[nc-1]);
for (unsigned i = nc - 1; i > 0; ) {
--i;
f_def = m.mk_ite(m.mk_eq(result, m_bv.mk_numeral(i,bv_size)), m.mk_const(cs[i]), f_def);
}
m_imp.m_enum2def.insert(f, f_def);
m_imp.m_enum2bv.insert(f, f_fresh);
m_imp.m_bv2enum.insert(f_fresh, f);
m_imp.m_enum_consts.push_back(f);
m_imp.m_enum_bvs.push_back(f_fresh);
m_imp.m_enum_defs.push_back(f_def);
}
else {
throw_non_fd(a);
}
++m_imp.m_num_translated;
return true;
}
ptr_buffer<sort> m_sorts;
bool reduce_quantifier(
quantifier * q,
expr * old_body,
expr * const * new_patterns,
expr * const * new_no_patterns,
expr_ref & result,
proof_ref & result_pr) {
m_sorts.reset();
expr_ref_vector bounds(m);
bool found = false;
for (unsigned i = 0; i < q->get_num_decls(); ++i) {
sort* s = q->get_decl_sort(i);
if (m_imp.is_fd(s)) {
unsigned bv_size = get_bv_size(s);
m_sorts.push_back(m_bv.mk_sort(bv_size));
unsigned nc = m_dt.get_datatype_num_constructors(s);
if (!is_power_of_two(nc) || nc == 1) {
bounds.push_back(m_bv.mk_ule(m.mk_var(q->get_num_decls()-i-1, m_sorts[i]), m_bv.mk_numeral(nc-1, bv_size)));
}
found = true;
}
else {
m_sorts.push_back(s);
}
}
if (!found) {
return false;
}
expr_ref new_body_ref(old_body, m), tmp(m);
if (!bounds.empty()) {
if (q->is_forall()) {
new_body_ref = m.mk_implies(mk_and(bounds), new_body_ref);
}
else {
bounds.push_back(new_body_ref);
new_body_ref = mk_and(bounds);
}
}
result = m.mk_quantifier(q->is_forall(), q->get_num_decls(), m_sorts.c_ptr(), q->get_decl_names(), new_body_ref,
q->get_weight(), q->get_qid(), q->get_skid(),
q->get_num_patterns(), new_patterns,
q->get_num_no_patterns(), new_no_patterns);
result_pr = 0;
return true;
}
unsigned get_bv_size(sort* s) {
unsigned nc = m_dt.get_datatype_num_constructors(s);
unsigned bv_size = 1;
while ((unsigned)(1 << bv_size) < nc) {
++bv_size;
}
return bv_size;
}
};
struct rw : public rewriter_tpl<rw_cfg> {
rw_cfg m_cfg;
rw(imp& t, ast_manager & m, params_ref const & p) :
rewriter_tpl<rw_cfg>(m, m.proofs_enabled(), m_cfg),
m_cfg(t, m) {
}
};
rw m_rw;
imp(ast_manager& m, params_ref const& p):
m(m), m_params(p), m_bounds(m),
m_dt(m),
m_enum_consts(m),
m_enum_bvs(m),
m_enum_defs(m),
m_num_translated(0),
m_sort_pred(0),
m_rw(*this, m, p) {
}
void updt_params(params_ref const & p) {}
unsigned get_num_steps() const { return m_rw.get_num_steps(); }
void cleanup() { m_rw.cleanup(); }
void operator()(expr * e, expr_ref & result, proof_ref & result_proof) {
m_rw(e, result, result_proof);
}
void push() {
m_enum_consts_lim.push_back(m_enum_consts.size());
}
void pop(unsigned num_scopes) {
SASSERT(m_bounds.empty()); // bounds must be flushed before pop.
if (num_scopes > 0) {
SASSERT(num_scopes <= m_enum_consts_lim.size());
unsigned new_sz = m_enum_consts_lim.size() - num_scopes;
unsigned lim = m_enum_consts_lim[new_sz];
for (unsigned i = m_enum_consts.size(); i > lim; ) {
--i;
func_decl* f = m_enum_consts[i].get();
func_decl* f_fresh = m_enum2bv.find(f);
m_bv2enum.erase(f_fresh);
m_enum2bv.erase(f);
m_enum2def.erase(f);
}
m_enum_consts_lim.resize(new_sz);
m_enum_consts.resize(lim);
m_enum_defs.resize(lim);
m_enum_bvs.resize(lim);
}
m_rw.reset();
}
void flush_side_constraints(expr_ref_vector& side_constraints) {
side_constraints.append(m_bounds);
m_bounds.reset();
}
bool is_fd(sort* s) {
return m_dt.is_enum_sort(s) && (!m_sort_pred || (*m_sort_pred)(s));
}
void set_is_fd(i_sort_pred* sp) {
m_sort_pred = sp;
}
};
enum2bv_rewriter::enum2bv_rewriter(ast_manager & m, params_ref const& p) { m_imp = alloc(imp, m, p); }
enum2bv_rewriter::~enum2bv_rewriter() { dealloc(m_imp); }
void enum2bv_rewriter::updt_params(params_ref const & p) { m_imp->updt_params(p); }
ast_manager & enum2bv_rewriter::m() const { return m_imp->m; }
unsigned enum2bv_rewriter::get_num_steps() const { return m_imp->get_num_steps(); }
void enum2bv_rewriter::cleanup() { ast_manager& mgr = m(); params_ref p = m_imp->m_params; dealloc(m_imp); m_imp = alloc(imp, mgr, p); }
obj_map<func_decl, func_decl*> const& enum2bv_rewriter::enum2bv() const { return m_imp->m_enum2bv; }
obj_map<func_decl, func_decl*> const& enum2bv_rewriter::bv2enum() const { return m_imp->m_bv2enum; }
obj_map<func_decl, expr*> const& enum2bv_rewriter::enum2def() const { return m_imp->m_enum2def; }
void enum2bv_rewriter::operator()(expr * e, expr_ref & result, proof_ref & result_proof) { (*m_imp)(e, result, result_proof); }
void enum2bv_rewriter::push() { m_imp->push(); }
void enum2bv_rewriter::pop(unsigned num_scopes) { m_imp->pop(num_scopes); }
void enum2bv_rewriter::flush_side_constraints(expr_ref_vector& side_constraints) { m_imp->flush_side_constraints(side_constraints); }
unsigned enum2bv_rewriter::num_translated() const { return m_imp->m_num_translated; }
void enum2bv_rewriter::set_is_fd(i_sort_pred* sp) const { m_imp->set_is_fd(sp); }

View file

@ -0,0 +1,48 @@
/*++
Copyright (c) 2016 Microsoft Corporation
Module Name:
enum2bv_rewriter.h
Abstract:
Conversion from enumeration types to bit-vectors.
Author:
Nikolaj Bjorner (nbjorner) 2016-10-18
Notes:
--*/
#ifndef ENUM_REWRITER_H_
#define ENUM_REWRITER_H_
#include"datatype_decl_plugin.h"
#include"rewriter_types.h"
#include"expr_functors.h"
class enum2bv_rewriter {
struct imp;
imp* m_imp;
public:
enum2bv_rewriter(ast_manager & m, params_ref const& p);
~enum2bv_rewriter();
void updt_params(params_ref const & p);
ast_manager & m() const;
unsigned get_num_steps() const;
void cleanup();
obj_map<func_decl, func_decl*> const& enum2bv() const;
obj_map<func_decl, func_decl*> const& bv2enum() const;
obj_map<func_decl, expr*> const& enum2def() const;
void operator()(expr * e, expr_ref & result, proof_ref & result_proof);
void push();
void pop(unsigned num_scopes);
void flush_side_constraints(expr_ref_vector& side_constraints);
unsigned num_translated() const;
void set_is_fd(i_sort_pred* sp) const;
};
#endif

View file

@ -18,11 +18,12 @@ Notes:
--*/
#include"fpa_rewriter.h"
#include"fpa_rewriter_params.hpp"
#include"ast_smt2_pp.h"
fpa_rewriter::fpa_rewriter(ast_manager & m, params_ref const & p) :
m_util(m),
m_fm(m_util.fm()),
m_hi_fp_unspecified(true) {
m_hi_fp_unspecified(false) {
updt_params(p);
}
@ -98,7 +99,7 @@ br_status fpa_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * con
case OP_FPA_INTERNAL_MIN_UNSPECIFIED:
case OP_FPA_INTERNAL_MAX_UNSPECIFIED:
SASSERT(num_args == 2); st = BR_FAILED; break;
case OP_FPA_INTERNAL_BVWRAP: SASSERT(num_args == 1); st = mk_bvwrap(args[0], result); break;
case OP_FPA_INTERNAL_BV2RM: SASSERT(num_args == 1); st = mk_bv2rm(args[0], result); break;
@ -117,34 +118,40 @@ br_status fpa_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * con
br_status fpa_rewriter::mk_to_ubv_unspecified(unsigned ebits, unsigned sbits, unsigned width, expr_ref & result) {
bv_util bu(m());
if (m_hi_fp_unspecified)
if (m_hi_fp_unspecified) {
// The "hardware interpretation" is 0.
result = bu.mk_numeral(0, width);
else
return BR_DONE;
}
else {
result = m_util.mk_internal_to_ubv_unspecified(ebits, sbits, width);
return BR_DONE;
return BR_REWRITE1;
}
}
br_status fpa_rewriter::mk_to_sbv_unspecified(unsigned ebits, unsigned sbits, unsigned width, expr_ref & result) {
bv_util bu(m());
if (m_hi_fp_unspecified)
if (m_hi_fp_unspecified) {
// The "hardware interpretation" is 0.
result = bu.mk_numeral(0, width);
else
return BR_DONE;
}
else {
result = m_util.mk_internal_to_sbv_unspecified(ebits, sbits, width);
return BR_DONE;
return BR_REWRITE1;
}
}
br_status fpa_rewriter::mk_to_real_unspecified(unsigned ebits, unsigned sbits, expr_ref & result) {
if (m_hi_fp_unspecified)
if (m_hi_fp_unspecified) {
// The "hardware interpretation" is 0.
result = m_util.au().mk_numeral(rational(0), false);
else
return BR_DONE;
}
else {
result = m_util.mk_internal_to_real_unspecified(ebits, sbits);
return BR_DONE;
return BR_REWRITE1;
}
}
br_status fpa_rewriter::mk_to_fp(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result) {
@ -776,10 +783,8 @@ br_status fpa_rewriter::mk_to_ubv(func_decl * f, expr * arg1, expr * arg2, expr_
m_util.is_numeral(arg2, v)) {
const mpf & x = v.get();
if (m_fm.is_nan(v) || m_fm.is_inf(v) || m_fm.is_neg(v)) {
mk_to_ubv_unspecified(x.get_ebits(), x.get_sbits(), bv_sz, result);
return BR_REWRITE_FULL;
}
if (m_fm.is_nan(v) || m_fm.is_inf(v) || m_fm.is_neg(v))
return mk_to_ubv_unspecified(x.get_ebits(), x.get_sbits(), bv_sz, result);
bv_util bu(m());
scoped_mpq q(m_fm.mpq_manager());
@ -789,11 +794,13 @@ br_status fpa_rewriter::mk_to_ubv(func_decl * f, expr * arg1, expr * arg2, expr_
rational ul, ll;
ul = m_fm.m_powers2.m1(bv_sz);
ll = rational(0);
if (r >= ll && r <= ul)
if (r >= ll && r <= ul) {
result = bu.mk_numeral(r, bv_sz);
return BR_DONE;
}
else
mk_to_ubv_unspecified(x.get_ebits(), x.get_sbits(), bv_sz, result);
return BR_DONE;
return mk_to_ubv_unspecified(x.get_ebits(), x.get_sbits(), bv_sz, result);
}
return BR_FAILED;
@ -810,10 +817,8 @@ br_status fpa_rewriter::mk_to_sbv(func_decl * f, expr * arg1, expr * arg2, expr_
m_util.is_numeral(arg2, v)) {
const mpf & x = v.get();
if (m_fm.is_nan(v) || m_fm.is_inf(v)) {
mk_to_sbv_unspecified(x.get_ebits(), x.get_sbits(), bv_sz, result);
return BR_REWRITE_FULL;
}
if (m_fm.is_nan(v) || m_fm.is_inf(v))
return mk_to_sbv_unspecified(x.get_ebits(), x.get_sbits(), bv_sz, result);
bv_util bu(m());
scoped_mpq q(m_fm.mpq_manager());
@ -823,46 +828,42 @@ br_status fpa_rewriter::mk_to_sbv(func_decl * f, expr * arg1, expr * arg2, expr_
rational ul, ll;
ul = m_fm.m_powers2.m1(bv_sz - 1);
ll = - m_fm.m_powers2(bv_sz - 1);
if (r >= ll && r <= ul)
if (r >= ll && r <= ul) {
result = bu.mk_numeral(r, bv_sz);
return BR_DONE;
}
else
mk_to_sbv_unspecified(x.get_ebits(), x.get_sbits(), bv_sz, result);
return BR_DONE;
return mk_to_sbv_unspecified(x.get_ebits(), x.get_sbits(), bv_sz, result);
}
return BR_FAILED;
}
br_status fpa_rewriter::mk_to_ieee_bv(func_decl * f, expr * arg, expr_ref & result) {
TRACE("fp_rewriter", tout << "to_ieee_bv of " << mk_ismt2_pp(arg, m()) << std::endl;);
scoped_mpf v(m_fm);
if (m_util.is_numeral(arg, v)) {
TRACE("fp_rewriter", tout << "to_ieee_bv numeral: " << m_fm.to_string(v) << std::endl;);
bv_util bu(m());
const mpf & x = v.get();
if (m_fm.is_nan(v)) {
if (m_hi_fp_unspecified) {
result = bu.mk_concat(bu.mk_numeral(0, 1),
bu.mk_concat(bu.mk_numeral(-1, x.get_ebits()),
bu.mk_concat(bu.mk_numeral(0, x.get_sbits() - 2),
bu.mk_numeral(1, 1))));
expr * args[4] = { bu.mk_numeral(0, 1),
bu.mk_numeral(-1, x.get_ebits()),
bu.mk_numeral(0, x.get_sbits() - 2),
bu.mk_numeral(1, 1) };
result = bu.mk_concat(4, args);
}
else {
app_ref unspec(m()), mask(m()), extra(m());
unspec = m_util.mk_internal_to_ieee_bv_unspecified(x.get_ebits(), x.get_sbits());
mask = bu.mk_concat(bu.mk_numeral(0, 1),
bu.mk_concat(bu.mk_numeral(-1, x.get_ebits()),
bu.mk_concat(bu.mk_numeral(0, x.get_sbits() - 2),
bu.mk_numeral(1, 1))));
expr * args[2] = { unspec, mask };
result = m().mk_app(bu.get_fid(), OP_BOR, 2, args);
}
return BR_REWRITE_FULL;
else
result = m_util.mk_internal_to_ieee_bv_unspecified(x.get_ebits(), x.get_sbits());
return BR_REWRITE1;
}
else {
scoped_mpz rz(m_fm.mpq_manager());
m_fm.to_ieee_bv_mpz(v, rz);
result = bu.mk_numeral(rational(rz), x.get_ebits() + x.get_sbits());
return BR_DONE;
}

View file

@ -1,5 +1,5 @@
def_module_params(module_name='rewriter',
class_name='fpa_rewriter_params',
export=True,
params=(("hi_fp_unspecified", BOOL, True, "use the 'hardware interpretation' for unspecified values in fp.to_ubv, fp.to_sbv, and fp.to_real"),
params=(("hi_fp_unspecified", BOOL, False, "use the 'hardware interpretation' for unspecified values in fp.to_ubv, fp.to_sbv, fp.to_real, and fp.to_ieee_bv"),
))

View file

@ -0,0 +1,477 @@
/*++
Copyright (c) 2016 Microsoft Corporation
Module Name:
pb2bv_rewriter.cpp
Abstract:
Conversion from pseudo-booleans to bit-vectors.
Author:
Nikolaj Bjorner (nbjorner) 2016-10-23
Notes:
--*/
#include"rewriter.h"
#include"rewriter_def.h"
#include"statistics.h"
#include"pb2bv_rewriter.h"
#include"sorting_network.h"
#include"ast_util.h"
#include"ast_pp.h"
#include"lbool.h"
struct pb2bv_rewriter::imp {
ast_manager& m;
params_ref m_params;
expr_ref_vector m_lemmas;
func_decl_ref_vector m_fresh; // all fresh variables
unsigned_vector m_fresh_lim;
unsigned m_num_translated;
struct card2bv_rewriter {
typedef expr* literal;
typedef ptr_vector<expr> literal_vector;
psort_nw<card2bv_rewriter> m_sort;
ast_manager& m;
imp& m_imp;
arith_util au;
pb_util pb;
bv_util bv;
expr_ref_vector m_trail;
expr_ref_vector m_args;
rational m_k;
vector<rational> m_coeffs;
template<lbool is_le>
expr_ref mk_le_ge(expr_ref_vector& fmls, expr* a, expr* b, expr* bound) {
expr_ref x(m), y(m), result(m);
unsigned nb = bv.get_bv_size(a);
x = bv.mk_zero_extend(1, a);
y = bv.mk_zero_extend(1, b);
result = bv.mk_bv_add(x, y);
x = bv.mk_extract(nb, nb, result);
result = bv.mk_extract(nb-1, 0, result);
if (is_le != l_false) {
fmls.push_back(m.mk_eq(x, bv.mk_numeral(rational::zero(), 1)));
fmls.push_back(bv.mk_ule(result, bound));
}
else {
fmls.push_back(m.mk_eq(x, bv.mk_numeral(rational::one(), 1)));
fmls.push_back(bv.mk_ule(bound, result));
}
return result;
}
//
// create a circuit of size sz*log(k)
// by forming a binary tree adding pairs of values that are assumed <= k,
// and in each step we check that the result is <= k by checking the overflow
// bit and that the non-overflow bits are <= k.
// The procedure for checking >= k is symmetric and checking for = k is
// achieved by checking <= k on intermediary addends and the resulting sum is = k.
//
// is_le = l_true - <=
// is_le = l_undef - =
// is_le = l_false - >=
//
template<lbool is_le>
expr_ref mk_le_ge(unsigned sz, expr * const* args, rational const & k) {
TRACE("pb",
for (unsigned i = 0; i < sz; ++i) {
tout << m_coeffs[i] << "*" << mk_pp(args[i], m) << " ";
if (i + 1 < sz && !m_coeffs[i+1].is_neg()) tout << "+ ";
}
switch (is_le) {
case l_true: tout << "<= "; break;
case l_undef: tout << "= "; break;
case l_false: tout << ">= "; break;
}
tout << m_k << "\n";);
if (k.is_zero()) {
if (is_le != l_false) {
return expr_ref(m.mk_not(mk_or(m, sz, args)), m);
}
else {
return expr_ref(m.mk_true(), m);
}
}
if (k.is_neg()) {
return expr_ref((is_le == l_false)?m.mk_true():m.mk_false(), m);
}
SASSERT(k.is_pos());
expr_ref zero(m), bound(m);
expr_ref_vector es(m), fmls(m);
unsigned nb = k.get_num_bits();
zero = bv.mk_numeral(rational(0), nb);
bound = bv.mk_numeral(k, nb);
for (unsigned i = 0; i < sz; ++i) {
SASSERT(!m_coeffs[i].is_neg());
if (m_coeffs[i] > k) {
if (is_le != l_false) {
fmls.push_back(m.mk_not(args[i]));
}
else {
fmls.push_back(args[i]);
}
}
else {
es.push_back(mk_ite(args[i], bv.mk_numeral(m_coeffs[i], nb), zero));
}
}
while (es.size() > 1) {
for (unsigned i = 0; i + 1 < es.size(); i += 2) {
es[i/2] = mk_le_ge<is_le>(fmls, es[i].get(), es[i+1].get(), bound);
}
if ((es.size() % 2) == 1) {
es[es.size()/2] = es.back();
}
es.shrink((1 + es.size())/2);
}
switch (is_le) {
case l_true:
return mk_and(fmls);
case l_false:
if (!es.empty()) {
fmls.push_back(bv.mk_ule(bound, es.back()));
}
return mk_or(fmls);
case l_undef:
if (es.empty()) {
fmls.push_back(m.mk_bool_val(k.is_zero()));
}
else {
fmls.push_back(m.mk_eq(bound, es.back()));
}
return mk_and(fmls);
default:
UNREACHABLE();
return expr_ref(m.mk_true(), m);
}
}
expr_ref mk_bv(func_decl * f, unsigned sz, expr * const* args) {
decl_kind kind = f->get_decl_kind();
rational k = pb.get_k(f);
m_coeffs.reset();
for (unsigned i = 0; i < sz; ++i) {
m_coeffs.push_back(pb.get_coeff(f, i));
}
SASSERT(!k.is_neg());
switch (kind) {
case OP_PB_GE:
case OP_AT_LEAST_K: {
expr_ref_vector nargs(m);
nargs.append(sz, args);
dualize(f, nargs, k);
SASSERT(!k.is_neg());
return mk_le_ge<l_true>(sz, nargs.c_ptr(), k);
}
case OP_PB_LE:
case OP_AT_MOST_K:
return mk_le_ge<l_true>(sz, args, k);
case OP_PB_EQ:
return mk_le_ge<l_undef>(sz, args, k);
default:
UNREACHABLE();
return expr_ref(m.mk_true(), m);
}
}
void dualize(func_decl* f, expr_ref_vector & args, rational & k) {
k.neg();
for (unsigned i = 0; i < args.size(); ++i) {
k += pb.get_coeff(f, i);
args[i] = ::mk_not(m, args[i].get());
}
}
expr* negate(expr* e) {
if (m.is_not(e, e)) return e;
return m.mk_not(e);
}
expr* mk_ite(expr* c, expr* hi, expr* lo) {
while (m.is_not(c, c)) {
std::swap(hi, lo);
}
if (hi == lo) return hi;
if (m.is_true(hi) && m.is_false(lo)) return c;
if (m.is_false(hi) && m.is_true(lo)) return negate(c);
if (m.is_true(hi)) return m.mk_or(c, lo);
if (m.is_false(lo)) return m.mk_and(c, hi);
if (m.is_false(hi)) return m.mk_and(negate(c), lo);
if (m.is_true(lo)) return m.mk_implies(c, hi);
return m.mk_ite(c, hi, lo);
}
bool is_or(func_decl* f) {
switch (f->get_decl_kind()) {
case OP_AT_MOST_K:
case OP_PB_LE:
return false;
case OP_AT_LEAST_K:
case OP_PB_GE:
return pb.get_k(f).is_one();
case OP_PB_EQ:
return false;
default:
UNREACHABLE();
return false;
}
}
public:
card2bv_rewriter(imp& i, ast_manager& m):
m_sort(*this),
m(m),
m_imp(i),
au(m),
pb(m),
bv(m),
m_trail(m),
m_args(m)
{}
bool mk_app(bool full, func_decl * f, unsigned sz, expr * const* args, expr_ref & result) {
if (f->get_family_id() == pb.get_family_id()) {
mk_pb(full, f, sz, args, result);
}
else if (au.is_le(f) && is_pb(args[0], args[1])) {
result = mk_le_ge<l_true>(m_args.size(), m_args.c_ptr(), m_k);
}
else if (au.is_lt(f) && is_pb(args[0], args[1])) {
++m_k;
result = mk_le_ge<l_true>(m_args.size(), m_args.c_ptr(), m_k);
}
else if (au.is_ge(f) && is_pb(args[1], args[0])) {
result = mk_le_ge<l_true>(m_args.size(), m_args.c_ptr(), m_k);
}
else if (au.is_gt(f) && is_pb(args[1], args[0])) {
++m_k;
result = mk_le_ge<l_true>(m_args.size(), m_args.c_ptr(), m_k);
}
else if (m.is_eq(f) && is_pb(args[0], args[1])) {
result = mk_le_ge<l_undef>(m_args.size(), m_args.c_ptr(), m_k);
}
else {
return false;
}
++m_imp.m_num_translated;
return true;
}
br_status mk_app_core(func_decl * f, unsigned sz, expr * const* args, expr_ref & result) {
if (mk_app(true, f, sz, args, result)) {
return BR_DONE;
}
else {
return BR_FAILED;
}
}
bool is_pb(expr* x, expr* y) {
m_args.reset();
m_coeffs.reset();
m_k.reset();
return is_pb(x, rational::one()) && is_pb(y, rational::minus_one());
}
bool is_pb(expr* e, rational const& mul) {
if (!is_app(e)) {
return false;
}
app* a = to_app(e);
rational r, r1, r2;
expr* c, *th, *el;
unsigned sz = a->get_num_args();
if (a->get_family_id() == au.get_family_id()) {
switch (a->get_decl_kind()) {
case OP_ADD:
for (unsigned i = 0; i < sz; ++i) {
if (!is_pb(a->get_arg(i), mul)) return false;
}
return true;
case OP_SUB: {
if (!is_pb(a->get_arg(0), mul)) return false;
r = -mul;
for (unsigned i = 1; i < sz; ++i) {
if (!is_pb(a->get_arg(1), r)) return false;
}
return true;
}
case OP_UMINUS:
return is_pb(a->get_arg(0), -mul);
case OP_NUM:
VERIFY(au.is_numeral(a, r));
m_k -= mul * r;
return true;
case OP_MUL:
if (sz != 2) {
return false;
}
if (au.is_numeral(a->get_arg(0), r)) {
r *= mul;
return is_pb(a->get_arg(1), r);
}
if (au.is_numeral(a->get_arg(1), r)) {
r *= mul;
return is_pb(a->get_arg(0), r);
}
return false;
default:
return false;
}
}
if (m.is_ite(a, c, th, el) && au.is_numeral(th, r1) && au.is_numeral(el, r2)) {
r1 *= mul;
r2 *= mul;
if (r1 < r2) {
m_args.push_back(::mk_not(m, c));
m_coeffs.push_back(r2-r1);
m_k -= r1;
}
else {
m_args.push_back(c);
m_coeffs.push_back(r1-r2);
m_k -= r2;
}
return true;
}
return false;
}
void mk_pb(bool full, func_decl * f, unsigned sz, expr * const* args, expr_ref & result) {
SASSERT(f->get_family_id() == pb.get_family_id());
if (is_or(f)) {
result = m.mk_or(sz, args);
}
else if (pb.is_at_most_k(f) && pb.get_k(f).is_unsigned()) {
result = m_sort.le(full, pb.get_k(f).get_unsigned(), sz, args);
}
else if (pb.is_at_least_k(f) && pb.get_k(f).is_unsigned()) {
result = m_sort.ge(full, pb.get_k(f).get_unsigned(), sz, args);
}
else if (pb.is_eq(f) && pb.get_k(f).is_unsigned() && pb.has_unit_coefficients(f)) {
result = m_sort.eq(full, pb.get_k(f).get_unsigned(), sz, args);
}
else if (pb.is_le(f) && pb.get_k(f).is_unsigned() && pb.has_unit_coefficients(f)) {
result = m_sort.le(full, pb.get_k(f).get_unsigned(), sz, args);
}
else if (pb.is_ge(f) && pb.get_k(f).is_unsigned() && pb.has_unit_coefficients(f)) {
result = m_sort.ge(full, pb.get_k(f).get_unsigned(), sz, args);
}
else {
result = mk_bv(f, sz, args);
}
}
// definitions used for sorting network
literal mk_false() { return m.mk_false(); }
literal mk_true() { return m.mk_true(); }
literal mk_max(literal a, literal b) { return trail(m.mk_or(a, b)); }
literal mk_min(literal a, literal b) { return trail(m.mk_and(a, b)); }
literal mk_not(literal a) { if (m.is_not(a,a)) return a; return trail(m.mk_not(a)); }
std::ostream& pp(std::ostream& out, literal lit) { return out << mk_ismt2_pp(lit, m); }
literal trail(literal l) {
m_trail.push_back(l);
return l;
}
literal fresh() {
expr_ref fr(m.mk_fresh_const("sn", m.mk_bool_sort()), m);
m_imp.m_fresh.push_back(to_app(fr)->get_decl());
return trail(fr);
}
void mk_clause(unsigned n, literal const* lits) {
m_imp.m_lemmas.push_back(mk_or(m, n, lits));
}
};
struct card2bv_rewriter_cfg : public default_rewriter_cfg {
card2bv_rewriter m_r;
bool rewrite_patterns() const { return false; }
bool flat_assoc(func_decl * f) const { return false; }
br_status reduce_app(func_decl * f, unsigned num, expr * const * args, expr_ref & result, proof_ref & result_pr) {
result_pr = 0;
return m_r.mk_app_core(f, num, args, result);
}
card2bv_rewriter_cfg(imp& i, ast_manager & m):m_r(i, m) {}
};
class card_pb_rewriter : public rewriter_tpl<card2bv_rewriter_cfg> {
public:
card2bv_rewriter_cfg m_cfg;
card_pb_rewriter(imp& i, ast_manager & m):
rewriter_tpl<card2bv_rewriter_cfg>(m, false, m_cfg),
m_cfg(i, m) {}
};
card_pb_rewriter m_rw;
imp(ast_manager& m, params_ref const& p):
m(m), m_params(p), m_lemmas(m),
m_fresh(m),
m_num_translated(0),
m_rw(*this, m) {
}
void updt_params(params_ref const & p) {}
unsigned get_num_steps() const { return m_rw.get_num_steps(); }
void cleanup() { m_rw.cleanup(); }
void operator()(expr * e, expr_ref & result, proof_ref & result_proof) {
m_rw(e, result, result_proof);
}
void push() {
m_fresh_lim.push_back(m_fresh.size());
}
void pop(unsigned num_scopes) {
SASSERT(m_lemmas.empty()); // lemmas must be flushed before pop.
if (num_scopes > 0) {
SASSERT(num_scopes <= m_fresh_lim.size());
unsigned new_sz = m_fresh_lim.size() - num_scopes;
unsigned lim = m_fresh_lim[new_sz];
m_fresh.resize(lim);
m_fresh_lim.resize(new_sz);
}
m_rw.reset();
}
void flush_side_constraints(expr_ref_vector& side_constraints) {
side_constraints.append(m_lemmas);
m_lemmas.reset();
}
void collect_statistics(statistics & st) const {
st.update("pb-aux-variables", m_fresh.size());
st.update("pb-aux-clauses", m_rw.m_cfg.m_r.m_sort.m_stats.m_num_compiled_clauses);
}
};
pb2bv_rewriter::pb2bv_rewriter(ast_manager & m, params_ref const& p) { m_imp = alloc(imp, m, p); }
pb2bv_rewriter::~pb2bv_rewriter() { dealloc(m_imp); }
void pb2bv_rewriter::updt_params(params_ref const & p) { m_imp->updt_params(p); }
ast_manager & pb2bv_rewriter::m() const { return m_imp->m; }
unsigned pb2bv_rewriter::get_num_steps() const { return m_imp->get_num_steps(); }
void pb2bv_rewriter::cleanup() { ast_manager& mgr = m(); params_ref p = m_imp->m_params; dealloc(m_imp); m_imp = alloc(imp, mgr, p); }
func_decl_ref_vector const& pb2bv_rewriter::fresh_constants() const { return m_imp->m_fresh; }
void pb2bv_rewriter::operator()(expr * e, expr_ref & result, proof_ref & result_proof) { (*m_imp)(e, result, result_proof); }
void pb2bv_rewriter::push() { m_imp->push(); }
void pb2bv_rewriter::pop(unsigned num_scopes) { m_imp->pop(num_scopes); }
void pb2bv_rewriter::flush_side_constraints(expr_ref_vector& side_constraints) { m_imp->flush_side_constraints(side_constraints); }
unsigned pb2bv_rewriter::num_translated() const { return m_imp->m_num_translated; }
void pb2bv_rewriter::collect_statistics(statistics & st) const { m_imp->collect_statistics(st); }

View file

@ -0,0 +1,46 @@
/*++
Copyright (c) 2016 Microsoft Corporation
Module Name:
pb2bv_rewriter.h
Abstract:
Conversion from pseudo-booleans to bit-vectors.
Author:
Nikolaj Bjorner (nbjorner) 2016-10-23
Notes:
--*/
#ifndef PB2BV_REWRITER_H_
#define PB2BV_REWRITER_H_
#include"pb_decl_plugin.h"
#include"rewriter_types.h"
#include"expr_functors.h"
class pb2bv_rewriter {
struct imp;
imp* m_imp;
public:
pb2bv_rewriter(ast_manager & m, params_ref const& p);
~pb2bv_rewriter();
void updt_params(params_ref const & p);
ast_manager & m() const;
unsigned get_num_steps() const;
void cleanup();
func_decl_ref_vector const& fresh_constants() const;
void operator()(expr * e, expr_ref & result, proof_ref & result_proof);
void push();
void pop(unsigned num_scopes);
void flush_side_constraints(expr_ref_vector& side_constraints);
unsigned num_translated() const;
void collect_statistics(statistics & st) const;
};
#endif

View file

@ -257,7 +257,12 @@ br_status pb_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * cons
all_unit &= m_coeffs.back().is_one();
}
if (is_eq) {
result = m_util.mk_eq(sz, m_coeffs.c_ptr(), m_args.c_ptr(), k);
if (sz == 0) {
result = k.is_zero()?m.mk_true():m.mk_false();
}
else {
result = m_util.mk_eq(sz, m_coeffs.c_ptr(), m_args.c_ptr(), k);
}
}
else if (all_unit && k.is_one()) {
result = mk_or(m, sz, m_args.c_ptr());
@ -277,6 +282,7 @@ br_status pb_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * cons
tout << tmp << "\n";
tout << result << "\n";
);
TRACE("pb_validate",
validate_rewrite(f, num_args, args, result););

View file

@ -111,7 +111,7 @@ protected:
void elim_reflex_prs(unsigned spos);
public:
rewriter_core(ast_manager & m, bool proof_gen);
~rewriter_core();
virtual ~rewriter_core();
ast_manager & m() const { return m_manager; }
void reset();
void cleanup();

View file

@ -27,7 +27,7 @@ void rewriter_tpl<Config>::process_var(var * v) {
SASSERT(v->get_sort() == m().get_sort(m_r));
if (ProofGen) {
result_pr_stack().push_back(m_pr);
m_pr = 0;
m_pr = 0;
}
set_new_child_flag(v);
TRACE("rewriter", tout << mk_ismt2_pp(v, m()) << " -> " << m_r << "\n";);
@ -39,11 +39,11 @@ void rewriter_tpl<Config>::process_var(var * v) {
unsigned idx = v->get_idx();
if (idx < m_bindings.size()) {
unsigned index = m_bindings.size() - idx - 1;
expr * r = m_bindings[index];
var * r = (var*)(m_bindings[index]);
if (r != 0) {
SASSERT(v->get_sort() == m().get_sort(r));
if (!is_ground(r) && m_shifts[index] != m_bindings.size()) {
unsigned shift_amount = m_bindings.size() - m_shifts[index];
expr_ref tmp(m());
m_shifter(r, shift_amount, tmp);
@ -103,8 +103,8 @@ template<typename Config>
template<bool ProofGen>
bool rewriter_tpl<Config>::visit(expr * t, unsigned max_depth) {
TRACE("rewriter_visit", tout << "visiting\n" << mk_ismt2_pp(t, m()) << "\n";);
expr * new_t;
proof * new_t_pr;
expr * new_t = 0;
proof * new_t_pr = 0;
if (m_cfg.get_subst(t, new_t, new_t_pr)) {
TRACE("rewriter_subst", tout << "subst\n" << mk_ismt2_pp(t, m()) << "\n---->\n" << mk_ismt2_pp(new_t, m()) << "\n";);
SASSERT(m().get_sort(t) == m().get_sort(new_t));
@ -195,9 +195,9 @@ void rewriter_tpl<Config>::process_app(app * t, frame & fr) {
// this optimization is only used when Proof generation is disabled.
if (f->is_associative() && t->get_ref_count() <= 1 && frame_stack().size() > 1) {
frame & prev_fr = frame_stack()[frame_stack().size() - 2];
if (is_app(prev_fr.m_curr) &&
to_app(prev_fr.m_curr)->get_decl() == f &&
prev_fr.m_state == PROCESS_CHILDREN &&
if (is_app(prev_fr.m_curr) &&
to_app(prev_fr.m_curr)->get_decl() == f &&
prev_fr.m_state == PROCESS_CHILDREN &&
flat_assoc(f)) {
frame_stack().pop_back();
set_new_child_flag(t);
@ -223,7 +223,7 @@ void rewriter_tpl<Config>::process_app(app * t, frame & fr) {
}
br_status st = m_cfg.reduce_app(f, new_num_args, new_args, m_r, m_pr2);
SASSERT(st != BR_DONE || m().get_sort(m_r) == m().get_sort(t));
TRACE("reduce_app",
TRACE("reduce_app",
tout << mk_ismt2_pp(t, m()) << "\n";
tout << "st: " << st;
if (m_r) tout << " --->\n" << mk_ismt2_pp(m_r, m());
@ -296,11 +296,11 @@ void rewriter_tpl<Config>::process_app(app * t, frame & fr) {
expr * def;
proof * def_pr;
quantifier * def_q;
// When get_macro succeeds, then
// When get_macro succeeds, then
// we know that:
// forall X. f(X) = def[X]
// and def_pr is a proof for this quantifier.
//
//
// Remark: def_q is only used for proof generation.
// It is the quantifier forall X. f(X) = def[X]
if (get_macro(f, def, def_q, def_pr)) {
@ -318,7 +318,7 @@ void rewriter_tpl<Config>::process_app(app * t, frame & fr) {
if (ProofGen) {
NOT_IMPLEMENTED_YET();
// We do not support the use of bindings in proof generation mode.
// Thus we have to apply the subsitution here, and
// Thus we have to apply the subsitution here, and
// beta_reducer subst(m());
// subst.set_bindings(new_num_args, new_args);
// expr_ref r2(m());
@ -333,7 +333,7 @@ void rewriter_tpl<Config>::process_app(app * t, frame & fr) {
unsigned i = num_args;
while (i > 0) {
--i;
m_bindings.push_back(new_args[i]); // num_args - i - 1]);
m_bindings.push_back(new_args[i]); // num_args - i - 1]);
m_shifts.push_back(sz);
}
result_stack().push_back(def);
@ -465,7 +465,7 @@ void rewriter_tpl<Config>::process_quantifier(quantifier * q, frame & fr) {
}
else {
new_pats = q->get_patterns();
new_no_pats = q->get_no_patterns();
new_no_pats = q->get_no_patterns();
}
if (ProofGen) {
quantifier * new_q = m().update_quantifier(q, q->get_num_patterns(), new_pats, q->get_num_no_patterns(), new_no_pats, new_body);
@ -559,7 +559,7 @@ template<typename Config>
void rewriter_tpl<Config>::display_bindings(std::ostream& out) {
out << "bindings:\n";
for (unsigned i = 0; i < m_bindings.size(); i++) {
if (m_bindings[i])
if (m_bindings[i])
out << i << ": " << mk_ismt2_pp(m_bindings[i], m()) << "\n";
}
}
@ -596,6 +596,7 @@ template<typename Config>
template<bool ProofGen>
void rewriter_tpl<Config>::main_loop(expr * t, expr_ref & result, proof_ref & result_pr) {
if (m_cancel_check && m().canceled()) {
reset();
throw rewriter_exception(m().limit().get_cancel_msg());
}
SASSERT(!ProofGen || result_stack().size() == result_pr_stack().size());
@ -630,6 +631,7 @@ void rewriter_tpl<Config>::resume_core(expr_ref & result, proof_ref & result_pr)
SASSERT(!frame_stack().empty());
while (!frame_stack().empty()) {
if (m_cancel_check && m().canceled()) {
reset();
throw rewriter_exception(m().limit().get_cancel_msg());
}
SASSERT(!ProofGen || result_stack().size() == result_pr_stack().size());

View file

@ -7,5 +7,6 @@ def_module_params('rewriter',
("push_ite_arith", BOOL, False, "push if-then-else over arithmetic terms."),
("push_ite_bv", BOOL, False, "push if-then-else over bit-vector terms."),
("pull_cheap_ite", BOOL, False, "pull if-then-else terms when cheap."),
("bv_ineq_consistency_test_max", UINT, 0, "max size of conjunctions on which to perform consistency test based on inequalities on bitvectors."),
("cache_all", BOOL, False, "cache all intermediate results.")))

View file

@ -86,20 +86,25 @@ public:
expr_ref fml(m.mk_true(), m);
return sym_expr::mk_pred(fml, m.mk_bool_sort());
}
virtual T mk_and(T x, T y) {
if (x->is_char() && y->is_char()) {
if (x->get_char() == y->get_char()) {
return x;
}
if (m.are_distinct(x->get_char(), y->get_char())) {
expr_ref fml(m.mk_false(), m);
return sym_expr::mk_pred(fml, x->get_sort());
}
}
var_ref v(m.mk_var(0, x->get_sort()), m);
expr_ref fml1 = x->accept(v);
expr_ref fml2 = y->accept(v);
if (m.is_true(fml1)) return y;
virtual T mk_and(T x, T y) {
if (x->is_char() && y->is_char()) {
if (x->get_char() == y->get_char()) {
return x;
}
if (m.are_distinct(x->get_char(), y->get_char())) {
expr_ref fml(m.mk_false(), m);
return sym_expr::mk_pred(fml, x->get_sort());
}
}
sort* s = x->get_sort();
if (m.is_bool(s)) s = y->get_sort();
var_ref v(m.mk_var(0, s), m);
expr_ref fml1 = x->accept(v);
expr_ref fml2 = y->accept(v);
if (m.is_true(fml1)) {
return y;
}
if (m.is_true(fml2)) return x;
expr_ref fml(m.mk_and(fml1, fml2), m);
return sym_expr::mk_pred(fml, x->get_sort());
@ -166,6 +171,11 @@ public:
expr_ref fml(m.mk_not(x->accept(v)), m);
return sym_expr::mk_pred(fml, x->get_sort());
}
/*virtual vector<std::pair<vector<bool>, T>> generate_min_terms(vector<T> constraints){
return 0;
}*/
};
re2automaton::re2automaton(ast_manager& m): m(m), u(m), bv(m), m_ba(0), m_sa(0) {}
@ -233,46 +243,8 @@ eautomaton* re2automaton::re2aut(expr* e) {
TRACE("seq", tout << "Range expression is not handled: " << mk_pp(e, m) << "\n";);
}
}
else if (u.re.is_complement(e, e0)) {
// TBD non-standard semantics of complementation.
if (u.re.is_range(e0, e1, e2) && u.str.is_string(e1, s1) && u.str.is_string(e2, s2) &&
s1.length() == 1 && s2.length() == 1) {
unsigned start = s1[0];
unsigned stop = s2[0];
unsigned nb = s1.num_bits();
sort_ref s(bv.mk_sort(nb), m);
expr_ref v(m.mk_var(0, s), m);
expr_ref _start(bv.mk_numeral(start, nb), m);
expr_ref _stop(bv.mk_numeral(stop, nb), m);
expr_ref _pred(m.mk_not(m.mk_and(bv.mk_ule(_start, v), bv.mk_ule(v, _stop))), m);
a = alloc(eautomaton, sm, sym_expr::mk_pred(_pred, s));
display_expr1 disp(m);
TRACE("seq", tout << mk_pp(e, m) << "\n"; a->display(tout, disp););
return a.detach();
}
else if (u.re.is_to_re(e0, e1) && u.str.is_string(e1, s1) && s1.length() == 1) {
unsigned nb = s1.num_bits();
sort_ref s(bv.mk_sort(nb), m);
expr_ref v(m.mk_var(0, s), m);
expr_ref _ch(bv.mk_numeral(s1[0], nb), m);
expr_ref _pred(m.mk_not(m.mk_eq(v, _ch)), m);
a = alloc(eautomaton, sm, sym_expr::mk_pred(_pred, s));
display_expr1 disp(m);
TRACE("seq", tout << mk_pp(e, m) << "\n"; a->display(tout, disp););
return a.detach();
}
else if (u.re.is_to_re(e0, e1) && u.str.is_unit(e1, e2)) {
sort* s = m.get_sort(e2);
expr_ref v(m.mk_var(0, s), m);
expr_ref _pred(m.mk_not(m.mk_eq(v, e2)), m);
a = alloc(eautomaton, sm, sym_expr::mk_pred(_pred, s));
display_expr1 disp(m);
TRACE("seq", tout << mk_pp(e, m) << "\n"; a->display(tout, disp););
return a.detach();
}
else {
TRACE("seq", tout << "Complement expression is not handled: " << mk_pp(e, m) << "\n";);
}
else if (u.re.is_complement(e, e0) && (a = re2aut(e0)) && m_sa) {
return m_sa->mk_complement(*a);
}
else if (u.re.is_loop(e, e1, lo, hi) && (a = re2aut(e1))) {
scoped_ptr<eautomaton> eps = eautomaton::mk_epsilon(sm);
@ -303,7 +275,7 @@ eautomaton* re2automaton::re2aut(expr* e) {
}
else if (u.re.is_full(e)) {
expr_ref tt(m.mk_true(), m);
sort* seq_s, *char_s;
sort *seq_s = 0, *char_s = 0;
VERIFY (u.is_re(m.get_sort(e), seq_s));
VERIFY (u.is_seq(seq_s, char_s));
sym_expr* _true = sym_expr::mk_pred(tt, char_s);
@ -363,6 +335,9 @@ br_status seq_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * con
SASSERT(num_args == 1);
return mk_re_opt(args[0], result);
case OP_RE_CONCAT:
if (num_args == 1) {
result = args[0]; return BR_DONE;
}
SASSERT(num_args == 2);
return mk_re_concat(args[0], args[1], result);
case OP_RE_UNION:
@ -549,7 +524,7 @@ br_status seq_rewriter::mk_seq_contains(expr* a, expr* b, expr_ref& result) {
result = m().mk_bool_val(c.contains(d));
return BR_DONE;
}
// check if subsequence of b is in a.
// check if subsequence of a is in b.
expr_ref_vector as(m()), bs(m());
m_util.str.get_concat(a, as);
m_util.str.get_concat(b, bs);
@ -612,6 +587,12 @@ br_status seq_rewriter::mk_seq_contains(expr* a, expr* b, expr_ref& result) {
SASSERT(sz > offs);
result = m_util.str.mk_contains(m_util.str.mk_concat(sz-offs, as.c_ptr()+offs), b);
return BR_REWRITE2;
}
expr* x, *y, *z;
if (m_util.str.is_extract(b, x, y, z) && x == a) {
result = m().mk_true();
return BR_DONE;
}
return BR_FAILED;
@ -665,6 +646,14 @@ br_status seq_rewriter::mk_seq_replace(expr* a, expr* b, expr* c, expr_ref& resu
result = a;
return BR_DONE;
}
if (m_util.str.is_string(b, s2) && s2.length() == 0) {
result = m_util.str.mk_concat(a, c);
return BR_REWRITE1;
}
if (m_util.str.is_string(a, s1) && s1.length() == 0) {
result = a;
return BR_DONE;
}
return BR_FAILED;
}
@ -794,7 +783,7 @@ br_status seq_rewriter::mk_seq_suffix(expr* a, expr* b, expr_ref& result) {
bool isc1 = false;
bool isc2 = false;
expr* a1, *a2, *b1, *b2;
expr *a1 = 0, *a2 = 0, *b1 = 0, *b2 = 0;
if (m_util.str.is_concat(a, a1, a2) && m_util.str.is_string(a2, s1)) {
isc1 = true;
}
@ -910,6 +899,11 @@ br_status seq_rewriter::mk_str_stoi(expr* a, expr_ref& result) {
result = m_autil.mk_numeral(r, true);
return BR_DONE;
}
expr* b;
if (m_util.str.is_itos(a, b)) {
result = b;
return BR_DONE;
}
return BR_FAILED;
}
@ -1321,7 +1315,7 @@ br_status seq_rewriter::mk_re_plus(expr* a, expr_ref& result) {
}
br_status seq_rewriter::mk_re_opt(expr* a, expr_ref& result) {
sort* s;
sort* s = 0;
VERIFY(m_util.is_re(a, s));
result = m_util.re.mk_union(m_util.re.mk_to_re(m_util.str.mk_empty(s)), a);
return BR_REWRITE1;
@ -1511,10 +1505,15 @@ bool seq_rewriter::reduce_eq(expr_ref_vector& ls, expr_ref_vector& rs, expr_ref_
lchange = true;
}
bool is_sat;
bool is_sat = true;
unsigned szl = ls.size() - head1, szr = rs.size() - head2;
expr* const* _ls = ls.c_ptr() + head1, * const* _rs = rs.c_ptr() + head2;
if (solve_itos(szl, _ls, szr, _rs, lhs, rhs, is_sat)) {
ls.reset(); rs.reset();
change = true;
return is_sat;
}
if (length_constrained(szl, _ls, szr, _rs, lhs, rhs, is_sat)) {
ls.reset(); rs.reset();
@ -1679,6 +1678,56 @@ bool seq_rewriter::min_length(unsigned n, expr* const* es, unsigned& len) {
return bounded;
}
bool seq_rewriter::is_string(unsigned n, expr* const* es, zstring& s) const {
zstring s1;
expr* e;
bv_util bv(m());
rational val;
unsigned sz;
for (unsigned i = 0; i < n; ++i) {
if (m_util.str.is_string(es[i], s1)) {
s = s + s1;
}
else if (m_util.str.is_unit(es[i], e) && bv.is_numeral(e, val, sz)) {
s = s + zstring(val.get_unsigned());
}
else {
return false;
}
}
return true;
}
bool seq_rewriter::solve_itos(unsigned szl, expr* const* ls, unsigned szr, expr* const* rs,
expr_ref_vector& lhs, expr_ref_vector& rhs, bool& is_sat) {
expr* l, *r;
is_sat = true;
if (szl == 1 && m_util.str.is_itos(ls[0], l)) {
if (szr == 1 && m_util.str.is_itos(rs[0], r)) {
lhs.push_back(l);
rhs.push_back(r);
return true;
}
zstring s;
if (is_string(szr, rs, s)) {
std::string s1 = s.encode();
rational r(s1.c_str());
if (s1 == r.to_string()) {
lhs.push_back(l);
rhs.push_back(m_autil.mk_numeral(r, true));
return true;
}
}
}
if (szr == 1 && m_util.str.is_itos(rs[0], r) && !m_util.str.is_itos(ls[0])) {
return solve_itos(szr, rs, szl, ls, rhs, lhs, is_sat);
}
return false;
}
bool seq_rewriter::length_constrained(unsigned szl, expr* const* l, unsigned szr, expr* const* r,
expr_ref_vector& lhs, expr_ref_vector& rhs, bool& is_sat) {
is_sat = true;

View file

@ -125,15 +125,20 @@ class seq_rewriter {
expr_ref_vector& lhs, expr_ref_vector& rhs, bool& is_sat);
bool length_constrained(unsigned n, expr* const* l, unsigned m, expr* const* r,
expr_ref_vector& lhs, expr_ref_vector& rhs, bool& is_sat);
bool solve_itos(unsigned n, expr* const* l, unsigned m, expr* const* r,
expr_ref_vector& lhs, expr_ref_vector& rhs, bool& is_sat);
bool min_length(unsigned n, expr* const* es, unsigned& len);
expr* concat_non_empty(unsigned n, expr* const* es);
bool is_string(unsigned n, expr* const* es, zstring& s) const;
void add_next(u_map<expr*>& next, expr_ref_vector& trail, unsigned idx, expr* cond);
bool is_sequence(expr* e, expr_ref_vector& seq);
bool is_sequence(eautomaton& aut, expr_ref_vector& seq);
bool is_epsilon(expr* e) const;
void split_units(expr_ref_vector& lhs, expr_ref_vector& rhs);
public:
seq_rewriter(ast_manager & m, params_ref const & p = params_ref()):
m_util(m), m_autil(m), m_re2aut(m), m_es(m), m_lhs(m), m_rhs(m) {
@ -144,6 +149,9 @@ public:
void updt_params(params_ref const & p) {}
static void get_param_descrs(param_descrs & r) {}
void set_solver(expr_solver* solver) { m_re2aut.set_solver(solver); }
br_status mk_app_core(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result);
br_status mk_eq_core(expr * lhs, expr * rhs, expr_ref & result);

View file

@ -194,6 +194,14 @@ struct th_rewriter_cfg : public default_rewriter_cfg {
if (st != BR_FAILED)
return st;
}
if (k == OP_ITE) {
SASSERT(num == 3);
family_id s_fid = m().get_sort(args[1])->get_family_id();
if (s_fid == m_bv_rw.get_fid())
st = m_bv_rw.mk_ite_core(args[0], args[1], args[2], result);
if (st != BR_FAILED)
return st;
}
return m_b_rw.mk_app_core(f, num, args, result);
}
if (fid == m_a_rw.get_fid())
@ -700,6 +708,7 @@ struct th_rewriter_cfg : public default_rewriter_cfg {
return false;
}
};
template class rewriter_tpl<th_rewriter_cfg>;
@ -713,6 +722,10 @@ struct th_rewriter::imp : public rewriter_tpl<th_rewriter_cfg> {
expr_ref mk_app(func_decl* f, unsigned sz, expr* const* args) {
return m_cfg.mk_app(f, sz, args);
}
void set_solver(expr_solver* solver) {
m_cfg.m_seq_rw.set_solver(solver);
}
};
th_rewriter::th_rewriter(ast_manager & m, params_ref const & p):
@ -798,3 +811,7 @@ void th_rewriter::reset_used_dependencies() {
expr_ref th_rewriter::mk_app(func_decl* f, unsigned num_args, expr* const* args) {
return m_imp->mk_app(f, num_args, args);
}
void th_rewriter::set_solver(expr_solver* solver) {
m_imp->set_solver(solver);
}

View file

@ -25,6 +25,8 @@ Notes:
class expr_substitution;
class expr_solver;
class th_rewriter {
struct imp;
imp * m_imp;
@ -58,6 +60,9 @@ public:
// Remark: reset_used_dependecies will reset the internal cache if get_used_dependencies() != 0
expr_dependency * get_used_dependencies();
void reset_used_dependencies();
void set_solver(expr_solver* solver);
};
#endif

View file

@ -144,6 +144,9 @@ zstring zstring::replace(zstring const& src, zstring const& dst) const {
if (length() < src.length()) {
return zstring(*this);
}
if (src.length() == 0) {
return zstring(*this);
}
bool found = false;
for (unsigned i = 0; i < length(); ++i) {
bool eq = !found && i + src.length() <= length();
@ -552,7 +555,7 @@ func_decl* seq_decl_plugin::mk_assoc_fun(decl_kind k, unsigned arity, sort* cons
}
match_right_assoc(*m_sigs[k], arity, domain, range, rng);
func_decl_info info(m_family_id, k_seq);
info.set_right_associative();
info.set_right_associative(true);
return m.mk_func_decl(m_sigs[(rng == m_string)?k_string:k_seq]->m_name, rng, rng, rng, info);
}
@ -598,7 +601,7 @@ func_decl * seq_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters,
match(*m_sigs[k], arity, domain, range, rng);
return m.mk_func_decl(symbol("re.allchar"), arity, domain, rng, func_decl_info(m_family_id, k));
}
return m.mk_func_decl(m_sigs[k]->m_name, arity, domain, rng, func_decl_info(m_family_id, k));
return m.mk_func_decl(m_sigs[k]->m_name, arity, domain, range, func_decl_info(m_family_id, k));
case _OP_REGEXP_EMPTY:
@ -614,7 +617,7 @@ func_decl * seq_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters,
match(*m_sigs[k], arity, domain, range, rng);
return m.mk_func_decl(symbol("re.nostr"), arity, domain, rng, func_decl_info(m_family_id, k));
}
return m.mk_func_decl(m_sigs[k]->m_name, arity, domain, rng, func_decl_info(m_family_id, k));
return m.mk_func_decl(m_sigs[k]->m_name, arity, domain, range, func_decl_info(m_family_id, k));
case OP_RE_LOOP:
switch (arity) {
@ -822,16 +825,6 @@ app* seq_util::str::mk_char(char ch) {
return mk_char(s, 0);
}
bool seq_util::str::is_char(expr* n, zstring& c) const {
if (u.is_char(n)) {
c = zstring(to_app(n)->get_decl()->get_parameter(0).get_symbol().bare_str());
return true;
}
else {
return false;
}
}
bool seq_util::str::is_string(expr const* n, zstring& s) const {
if (is_string(n)) {
s = zstring(to_app(n)->get_decl()->get_parameter(0).get_symbol().bare_str());
@ -868,7 +861,7 @@ app* seq_util::re::mk_full(sort* s) {
return m.mk_app(m_fid, OP_RE_FULL_SET, 0, 0, 0, 0, s);
}
app* seq_util::re::mk_empty(sort* s) {
app* seq_util::re::mk_empty(sort* s) {
return m.mk_app(m_fid, OP_RE_EMPTY_SET, 0, 0, 0, 0, s);
}

View file

@ -250,7 +250,6 @@ public:
}
bool is_string(expr const* n, zstring& s) const;
bool is_char(expr* n, zstring& s) const;
bool is_empty(expr const* n) const { symbol s;
return is_app_of(n, m_fid, OP_SEQ_EMPTY) || (is_string(n, s) && !s.is_numerical() && *s.bare_str() == 0);

View file

@ -24,3 +24,10 @@ void arith_simplifier_params::updt_params(params_ref const & _p) {
m_arith_expand_eqs = p.arith_expand_eqs();
m_arith_process_all_eqs = p.arith_process_all_eqs();
}
#define DISPLAY_PARAM(X) out << #X"=" << X << std::endl;
void arith_simplifier_params::display(std::ostream & out) const {
DISPLAY_PARAM(m_arith_expand_eqs);
DISPLAY_PARAM(m_arith_process_all_eqs);
}

View file

@ -30,6 +30,8 @@ struct arith_simplifier_params {
}
void updt_params(params_ref const & _p);
void display(std::ostream & out) const;
};
#endif /* ARITH_SIMPLIFIER_PARAMS_H_ */

View file

@ -43,8 +43,7 @@ bool arith_simplifier_plugin::is_neg_poly(expr * t) const {
if (m_util.is_mul(t)) {
t = to_app(t)->get_arg(0);
rational r;
bool is_int;
if (m_util.is_numeral(t, r, is_int))
if (is_numeral(t, r))
return r.is_neg();
}
return false;

View file

@ -273,7 +273,7 @@ void bit2int::visit(app* n) {
// bv2int(x) <= z - bv2int(y) -> bv2int(x) + bv2int(y) <= z
//
expr* e1, *e2;
expr* e1 = 0, *e2 = 0;
expr_ref tmp1(m_manager), tmp2(m_manager);
expr_ref tmp3(m_manager);
expr_ref pos1(m_manager), neg1(m_manager);

View file

@ -27,3 +27,10 @@ void bv_simplifier_params::updt_params(params_ref const & _p) {
m_bv2int_distribute = p.bv_bv2int_distribute();
}
#define DISPLAY_PARAM(X) out << #X"=" << X << std::endl;
void bv_simplifier_params::display(std::ostream & out) const {
DISPLAY_PARAM(m_hi_div0);
DISPLAY_PARAM(m_bv2int_distribute);
}

View file

@ -30,6 +30,8 @@ struct bv_simplifier_params {
}
void updt_params(params_ref const & _p);
void display(std::ostream & out) const;
};
#endif /* BV_SIMPLIFIER_PARAMS_H_ */

View file

@ -607,12 +607,25 @@ void poly_simplifier_plugin::append_to_monomial(expr * n, numeral & k, ptr_buffe
k *= val;
n = get_monomial_body(n);
if (is_mul(n)) {
for (unsigned i = 0; i < to_app(n)->get_num_args(); i++)
result.push_back(to_app(n)->get_arg(i));
}
else {
result.push_back(n);
unsigned hd = result.size();
result.push_back(n);
while (hd < result.size()) {
n = result[hd];
if (is_mul(n)) {
result[hd] = result.back();
result.pop_back();
for (unsigned i = 0; i < to_app(n)->get_num_args(); i++) {
result.push_back(to_app(n)->get_arg(i));
}
}
else if (is_numeral(n, val)) {
k *= val;
result[hd] = result.back();
result.pop_back();
}
else {
++hd;
}
}
}

View file

@ -650,10 +650,12 @@ void simplifier::mk_ac_congruent_term(app * n, app_ref & r, proof_ref & p) {
#define Grey 1
#define Black 2
#ifdef Z3DEBUG
static int get_color(obj_map<expr, int> & colors, expr * n) {
obj_map<expr, int>::obj_map_entry * entry = colors.insert_if_not_there2(n, White);
return entry->get_data().m_value;
}
#endif
static bool visit_ac_children(func_decl * f, expr * n, obj_map<expr, int> & colors, ptr_buffer<expr> & todo, ptr_buffer<expr> & result) {
if (is_app_of(n, f)) {

View file

@ -146,7 +146,7 @@ void substitution::apply(unsigned num_actual_offsets, unsigned const * deltas, e
bool has_new_args = false;
for (unsigned i = 0; i < num_args; i++) {
expr * arg = to_app(e)->get_arg(i);
expr * new_arg;
expr * new_arg = 0;
VERIFY(m_apply_cache.find(expr_offset(arg, off), new_arg));
new_args.push_back(new_arg);

View file

@ -44,7 +44,8 @@ struct well_sorted_proc {
void operator()(app * n) {
unsigned num_args = n->get_num_args();
func_decl * decl = n->get_decl();
if (num_args != decl->get_arity() && !decl->is_associative()) {
if (num_args != decl->get_arity() && !decl->is_associative() &&
!decl->is_right_associative() && !decl->is_left_associative()) {
TRACE("ws", tout << "unexpected number of arguments.\n" << mk_ismt2_pp(n, m_manager););
warning_msg("unexpected number of arguments.");
m_error = true;
@ -66,7 +67,7 @@ struct well_sorted_proc {
strm << "Expected sort: " << mk_pp(expected_sort, m_manager) << "\n";
strm << "Actual sort: " << mk_pp(actual_sort, m_manager) << "\n";
strm << "Function sort: " << mk_pp(decl, m_manager) << ".";
warning_msg(strm.str().c_str());
warning_msg("%s", strm.str().c_str());
m_error = true;
return;
}