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:
commit
235ea79043
588 changed files with 21784 additions and 15202 deletions
|
@ -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_ */
|
||||
|
||||
|
|
|
@ -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));
|
||||
|
|
123
src/ast/ast.cpp
123
src/ast/ast.cpp
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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); }
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
|
558
src/ast/fpa/bv2fpa_converter.cpp
Normal file
558
src/ast/fpa/bv2fpa_converter.cpp
Normal 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;
|
||||
});
|
||||
|
||||
}
|
74
src/ast/fpa/bv2fpa_converter.h
Normal file
74
src/ast/fpa/bv2fpa_converter.h
Normal 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
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)) {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) <<
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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_ */
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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; }
|
||||
|
|
|
@ -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')))
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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_ */
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)) {
|
||||
|
|
|
@ -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; }
|
||||
|
|
664
src/ast/rewriter/bv_bounds.cpp
Normal file
664
src/ast/rewriter/bv_bounds.cpp
Normal 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;
|
||||
}
|
130
src/ast/rewriter/bv_bounds.h
Normal file
130
src/ast/rewriter/bv_bounds.h
Normal 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 */
|
|
@ -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>;
|
||||
|
||||
|
|
|
@ -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; }
|
||||
|
||||
|
|
|
@ -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")
|
||||
))
|
||||
|
|
|
@ -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);
|
||||
|
|
293
src/ast/rewriter/enum2bv_rewriter.cpp
Normal file
293
src/ast/rewriter/enum2bv_rewriter.cpp
Normal 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); }
|
48
src/ast/rewriter/enum2bv_rewriter.h
Normal file
48
src/ast/rewriter/enum2bv_rewriter.h
Normal 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
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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"),
|
||||
))
|
||||
|
|
477
src/ast/rewriter/pb2bv_rewriter.cpp
Normal file
477
src/ast/rewriter/pb2bv_rewriter.cpp
Normal 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); }
|
46
src/ast/rewriter/pb2bv_rewriter.h
Normal file
46
src/ast/rewriter/pb2bv_rewriter.h
Normal 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
|
|
@ -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););
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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.")))
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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_ */
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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_ */
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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)) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue