From bc257211d60d04a2b2e86d483643c2c0d3281d84 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Wed, 12 Oct 2016 18:36:44 +0100 Subject: [PATCH 01/26] Whitespace --- src/ast/fpa/fpa2bv_converter.cpp | 1 - src/ast/fpa/fpa2bv_converter.h | 4 +-- src/ast/fpa_decl_plugin.h | 10 +++--- src/ast/rewriter/fpa_rewriter.cpp | 2 +- src/smt/theory_fpa.cpp | 40 +++++++++++------------ src/tactic/fpa/fpa2bv_model_converter.cpp | 18 +++++----- 6 files changed, 37 insertions(+), 38 deletions(-) diff --git a/src/ast/fpa/fpa2bv_converter.cpp b/src/ast/fpa/fpa2bv_converter.cpp index 6bba4663d..460aff29f 100644 --- a/src/ast/fpa/fpa2bv_converter.cpp +++ b/src/ast/fpa/fpa2bv_converter.cpp @@ -165,7 +165,6 @@ void fpa2bv_converter::mk_numeral(sort * s, mpf const & v, expr_ref & result) { 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;); - } } diff --git a/src/ast/fpa/fpa2bv_converter.h b/src/ast/fpa/fpa2bv_converter.h index 3f5e76c66..436f44364 100644 --- a/src/ast/fpa/fpa2bv_converter.h +++ b/src/ast/fpa/fpa2bv_converter.h @@ -71,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; diff --git a/src/ast/fpa_decl_plugin.h b/src/ast/fpa_decl_plugin.h index ee7325014..a3215dd6f 100644 --- a/src/ast/fpa_decl_plugin.h +++ b/src/ast/fpa_decl_plugin.h @@ -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; @@ -294,13 +294,13 @@ public: 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); } - 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); diff --git a/src/ast/rewriter/fpa_rewriter.cpp b/src/ast/rewriter/fpa_rewriter.cpp index b8d9c232f..92b373ca0 100644 --- a/src/ast/rewriter/fpa_rewriter.cpp +++ b/src/ast/rewriter/fpa_rewriter.cpp @@ -98,7 +98,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; diff --git a/src/smt/theory_fpa.cpp b/src/smt/theory_fpa.cpp index ee7559500..fec7922c7 100644 --- a/src/smt/theory_fpa.cpp +++ b/src/smt/theory_fpa.cpp @@ -116,15 +116,15 @@ namespace smt { SASSERT(m_trail_stack.get_num_scopes() == 0); SASSERT(m_conversions.empty()); - SASSERT(m_is_added_to_model.empty()); - } + SASSERT(m_is_added_to_model.empty()); + } void theory_fpa::init(context * ctx) { smt::theory::init(ctx); m_is_initialized = true; } app * theory_fpa::fpa_value_proc::mk_value(model_generator & mg, ptr_vector & values) { - TRACE("t_fpa_detail", + TRACE("t_fpa_detail", ast_manager & m = m_th.get_manager(); for (unsigned i = 0; i < values.size(); i++) tout << "value[" << i << "] = " << mk_ismt2_pp(values[i], m) << std::endl;); @@ -201,7 +201,7 @@ namespace smt { app * theory_fpa::fpa_rm_value_proc::mk_value(model_generator & mg, ptr_vector & values) { SASSERT(values.size() == 1); - TRACE("t_fpa_detail", + TRACE("t_fpa_detail", ast_manager & m = m_th.get_manager(); for (unsigned i = 0; i < values.size(); i++) tout << "value[" << i << "] = " << mk_ismt2_pp(values[i], m) << std::endl;); @@ -235,12 +235,12 @@ namespace smt { app_ref res(m); if (m_fpa_util.is_fp(e)) { - expr * cargs[3] = { to_app(e)->get_arg(0), to_app(e)->get_arg(1), to_app(e)->get_arg(2) }; + expr * cargs[3] = { to_app(e)->get_arg(0), to_app(e)->get_arg(1), to_app(e)->get_arg(2) }; res = m_bv_util.mk_concat(3, cargs); m_th_rw((expr_ref&)res); } else { - sort * es = m.get_sort(e); + sort * es = m.get_sort(e); sort_ref bv_srt(m); if (m_converter.is_rm(es)) @@ -264,7 +264,7 @@ namespace smt { SASSERT(!m_fpa_util.is_fp(e)); SASSERT(m_bv_util.is_bv(e)); SASSERT(m_fpa_util.is_float(s) || m_fpa_util.is_rm(s)); - ast_manager & m = get_manager(); + ast_manager & m = get_manager(); app_ref res(m); unsigned bv_sz = m_bv_util.get_bv_size(e); @@ -285,7 +285,7 @@ namespace smt { m_bv_util.mk_extract(bv_sz - 2, sbits - 1, e), m_bv_util.mk_extract(sbits - 2, 0, e)); } - + return res; } @@ -312,7 +312,7 @@ namespace smt { TRACE("t_fpa_detail", tout << "term: " << mk_ismt2_pp(e, get_manager()) << std::endl; tout << "converted term: " << mk_ismt2_pp(e_conv, get_manager()) << std::endl;); - if (m_fpa_util.is_rm(e)) { + if (m_fpa_util.is_rm(e)) { SASSERT(m_fpa_util.is_bv2rm(e_conv)); expr_ref bv_rm(m); m_th_rw(to_app(e_conv)->get_arg(0), bv_rm); @@ -329,7 +329,7 @@ namespace smt { } else UNREACHABLE(); - + return res; } @@ -362,7 +362,7 @@ namespace smt { res = convert_atom(e); else if (m_fpa_util.is_float(e) || m_fpa_util.is_rm(e)) res = convert_term(e); - else + else res = convert_conversion_term(e); TRACE("t_fpa_detail", tout << "converted; caching:" << std::endl; @@ -448,7 +448,7 @@ namespace smt { TRACE("t_fpa_internalize", tout << "internalizing term: " << mk_ismt2_pp(term, get_manager()) << "\n";); SASSERT(term->get_family_id() == get_family_id()); SASSERT(!get_context().e_internalized(term)); - + ast_manager & m = get_manager(); context & ctx = get_context(); @@ -494,7 +494,7 @@ namespace smt { SASSERT(n->get_owner()->get_decl()->get_range() == s); ast_manager & m = get_manager(); - context & ctx = get_context(); + context & ctx = get_context(); app_ref owner(n->get_owner(), m); if (!is_attached_to_var(n)) { @@ -510,7 +510,7 @@ namespace smt { assert_cnstr(valid); } } - + if (!ctx.relevancy()) relevant_eh(owner); } @@ -600,7 +600,7 @@ namespace smt { xe_eq_ye = m.mk_eq(xe, ye); not_xe_eq_ye = m.mk_not(xe_eq_ye); c_eq_iff = m.mk_iff(not_xe_eq_ye, c); - assert_cnstr(c_eq_iff); + assert_cnstr(c_eq_iff); assert_cnstr(mk_side_conditions()); return; @@ -689,10 +689,10 @@ namespace smt { pop_scope_eh(m_trail_stack.get_num_scopes()); m_converter.reset(); m_rw.reset(); - m_th_rw.reset(); - m_trail_stack.pop_scope(m_trail_stack.get_num_scopes()); + m_th_rw.reset(); + m_trail_stack.pop_scope(m_trail_stack.get_num_scopes()); if (m_factory) { - dealloc(m_factory); + dealloc(m_factory); m_factory = 0; } ast_manager & m = get_manager(); @@ -862,8 +862,8 @@ namespace smt { } bool theory_fpa::include_func_interp(func_decl * f) { - TRACE("t_fpa", tout << "f = " << mk_ismt2_pp(f, get_manager()) << std::endl;); - + TRACE("t_fpa", tout << "f = " << mk_ismt2_pp(f, get_manager()) << std::endl;); + if (f->get_family_id() == get_family_id()) { bool include = m_fpa_util.is_min_unspecified(f) || diff --git a/src/tactic/fpa/fpa2bv_model_converter.cpp b/src/tactic/fpa/fpa2bv_model_converter.cpp index 20d8bbbcc..05fedb37f 100644 --- a/src/tactic/fpa/fpa2bv_model_converter.cpp +++ b/src/tactic/fpa/fpa2bv_model_converter.cpp @@ -234,7 +234,7 @@ fpa2bv_model_converter::array_model fpa2bv_model_converter::convert_array_func_i array_util arr_util(m); array_model am(m); - sort_ref_vector array_domain(m); + sort_ref_vector array_domain(m); unsigned arity = f->get_range()->get_num_parameters()-1; expr_ref as_arr_mdl(m); @@ -245,21 +245,21 @@ fpa2bv_model_converter::array_model fpa2bv_model_converter::convert_array_func_i 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(am.new_float_fd, bv_f, bv_mdl); + am.new_float_fi = convert_func_interp(am.new_float_fd, bv_f, bv_mdl); am.bv_fd = bv_f; am.result = arr_util.mk_as_array(f->get_range(), am.new_float_fd); return am; } -func_interp * fpa2bv_model_converter::convert_func_interp(func_decl * f, func_decl * bv_f, model * bv_mdl) { +func_interp * fpa2bv_model_converter::convert_func_interp(func_decl * f, func_decl * bv_f, model * bv_mdl) { SASSERT(f->get_arity() > 0); func_interp * result = 0; sort * rng = f->get_range(); - sort * const * dmn = f->get_domain(); + sort * const * dmn = f->get_domain(); unsigned arity = bv_f->get_arity(); func_interp * bv_fi = bv_mdl->get_func_interp(bv_f); @@ -276,7 +276,7 @@ func_interp * fpa2bv_model_converter::convert_func_interp(func_decl * f, func_de for (unsigned j = 0; j < arity; j++) { sort * ft_dj = dmn[j]; - expr * bv_aj = bv_args[j]; + expr * bv_aj = bv_args[j]; ai = rebuild_floats(bv_mdl, ft_dj, bv_aj); m_th_rw(ai); new_args.push_back(ai); @@ -293,7 +293,7 @@ func_interp * fpa2bv_model_converter::convert_func_interp(func_decl * f, func_de bv_els = bv_fi->get_else(); ft_els = rebuild_floats(bv_mdl, rng, bv_els); m_th_rw(ft_els); - result->set_else(ft_els); + result->set_else(ft_els); } return result; @@ -409,7 +409,7 @@ void fpa2bv_model_converter::convert(model * bv_mdl, model * float_mdl) { it++) { seen.insert(it->m_value); - func_decl * f = it->m_key; + func_decl * f = it->m_key; if (f->get_arity() == 0) { array_util au(m); @@ -426,7 +426,7 @@ void fpa2bv_model_converter::convert(model * bv_mdl, model * float_mdl) { bv_mdl->eval(it->m_value, val); if (val) float_mdl->register_decl(f, val); } - } + } else { func_interp * fmv = convert_func_interp(f, it->m_value, bv_mdl); if (fmv) float_mdl->register_decl(f, fmv); From 7e705a2d3287cc800a5fd871d0deca757b4c0075 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Wed, 12 Oct 2016 18:37:41 +0100 Subject: [PATCH 02/26] Bug fixes for underspecified FP operations. --- src/ast/fpa/fpa2bv_converter.cpp | 79 ++++++++++++--------- src/ast/fpa/fpa2bv_converter.h | 4 +- src/ast/fpa/fpa2bv_rewriter.cpp | 4 +- src/ast/fpa_decl_plugin.h | 40 +++++------ src/ast/rewriter/fpa_rewriter.cpp | 87 ++++++++++++------------ src/ast/rewriter/fpa_rewriter_params.pyg | 2 +- src/smt/theory_fpa.cpp | 30 ++++++-- 7 files changed, 139 insertions(+), 107 deletions(-) diff --git a/src/ast/fpa/fpa2bv_converter.cpp b/src/ast/fpa/fpa2bv_converter.cpp index 460aff29f..8db839e24 100644 --- a/src/ast/fpa/fpa2bv_converter.cpp +++ b/src/ast/fpa/fpa2bv_converter.cpp @@ -3072,13 +3072,57 @@ 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 { + expr_ref unspec_bits(m); + unspec_bits = m_util.mk_internal_to_ieee_bv_unspecified(ebits, sbits); + nanv = m_bv_util.mk_concat(m_bv_util.mk_extract(sbits-1, sbits-1, unspec_bits), + m_bv_util.mk_concat(m_bv_util.mk_numeral(-1, ebits), + m_bv_util.mk_extract(sbits-2, 0, unspec_bits))); + } 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)); } @@ -3308,41 +3352,10 @@ expr_ref fpa2bv_converter::mk_to_real_unspecified(unsigned ebits, unsigned sbits 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; -} - void fpa2bv_converter::mk_fp(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { SASSERT(num == 3); SASSERT(m_bv_util.get_bv_size(args[0]) == 1); diff --git a/src/ast/fpa/fpa2bv_converter.h b/src/ast/fpa/fpa2bv_converter.h index 436f44364..4fcfe42f6 100644 --- a/src/ast/fpa/fpa2bv_converter.h +++ b/src/ast/fpa/fpa2bv_converter.h @@ -133,6 +133,7 @@ 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); @@ -152,13 +153,12 @@ public: 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; - + 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; }; diff --git a/src/ast/fpa/fpa2bv_rewriter.cpp b/src/ast/fpa/fpa2bv_rewriter.cpp index 5f89e12db..6d4f24856 100644 --- a/src/ast/fpa/fpa2bv_rewriter.cpp +++ b/src/ast/fpa/fpa2bv_rewriter.cpp @@ -145,7 +145,8 @@ br_status fpa2bv_rewriter_cfg::reduce_app(func_decl * f, unsigned num, expr * co case OP_FPA_TO_UBV: m_conv.mk_to_ubv(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_TO_REAL: m_conv.mk_to_real(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_TO_IEEE_BV: m_conv.mk_to_ieee_bv(f, num, args, result); return BR_REWRITE_FULL; + 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; @@ -161,7 +162,6 @@ br_status fpa2bv_rewriter_cfg::reduce_app(func_decl * f, unsigned num, expr * co 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"; diff --git a/src/ast/fpa_decl_plugin.h b/src/ast/fpa_decl_plugin.h index a3215dd6f..c00bed7ae 100644 --- a/src/ast/fpa_decl_plugin.h +++ b/src/ast/fpa_decl_plugin.h @@ -377,28 +377,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); }; diff --git a/src/ast/rewriter/fpa_rewriter.cpp b/src/ast/rewriter/fpa_rewriter.cpp index 92b373ca0..26487c5a4 100644 --- a/src/ast/rewriter/fpa_rewriter.cpp +++ b/src/ast/rewriter/fpa_rewriter.cpp @@ -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); } @@ -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; } diff --git a/src/ast/rewriter/fpa_rewriter_params.pyg b/src/ast/rewriter/fpa_rewriter_params.pyg index 85973e744..f0cfbdf55 100644 --- a/src/ast/rewriter/fpa_rewriter_params.pyg +++ b/src/ast/rewriter/fpa_rewriter_params.pyg @@ -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"), )) diff --git a/src/smt/theory_fpa.cpp b/src/smt/theory_fpa.cpp index fec7922c7..288b61748 100644 --- a/src/smt/theory_fpa.cpp +++ b/src/smt/theory_fpa.cpp @@ -715,14 +715,14 @@ namespace smt { fpa2bv_converter::uf2bvuf_t const & uf2bvuf = m_converter.get_uf2bvuf(); for (fpa2bv_converter::uf2bvuf_t::iterator it = uf2bvuf.begin(); - it != uf2bvuf.end(); - it++) { - mg.hide(it->m_value); + it != uf2bvuf.end(); + it++) { + //mg.hide(it->m_value); } fpa2bv_converter::special_t const & specials = m_converter.get_min_max_specials(); for (fpa2bv_converter::special_t::iterator it = specials.begin(); - it != specials.end(); - it++) { + it != specials.end(); + it++) { mg.hide(it->m_value.first->get_decl()); mg.hide(it->m_value.second->get_decl()); } @@ -811,7 +811,25 @@ namespace smt { return res; } - void theory_fpa::finalize_model(model_generator & mg) {} + void theory_fpa::finalize_model(model_generator & mg) { + ast_manager & m = get_manager(); + proto_model & mdl = mg.get_model(); + + fpa2bv_converter::uf2bvuf_t const & uf2bvuf = m_converter.get_uf2bvuf(); + for (fpa2bv_converter::uf2bvuf_t::iterator it = uf2bvuf.begin(); + it != uf2bvuf.end(); + it++) { + func_decl * bv_fd = it->m_value; + if (bv_fd->get_arity() == 0) { + expr_ref bve(m), v(m); + bve = m.mk_const(bv_fd); + mdl.eval(bve, v, true); + mdl.register_decl(it->m_key, v); + } + else + NOT_IMPLEMENTED_YET(); + } + } void theory_fpa::display(std::ostream & out) const { From 58af4cae1452ef1da104122b4fe1f491d19ad08a Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Sat, 15 Oct 2016 17:40:22 +0200 Subject: [PATCH 03/26] More consistent fp.* operators. --- src/ast/fpa_decl_plugin.cpp | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/ast/fpa_decl_plugin.cpp b/src/ast/fpa_decl_plugin.cpp index 6c8b7ac6f..d8bf70e80 100644 --- a/src/ast/fpa_decl_plugin.cpp +++ b/src/ast/fpa_decl_plugin.cpp @@ -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 & 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 & sort_names, symbol const & logic) { From ab4bb8194ec612f1231c8364c97f15b45f54f1e2 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Sat, 15 Oct 2016 17:40:42 +0200 Subject: [PATCH 04/26] Added unregister_decl to model_core --- src/model/model_core.cpp | 16 ++++++++++++++++ src/model/model_core.h | 1 + 2 files changed, 17 insertions(+) diff --git a/src/model/model_core.cpp b/src/model/model_core.cpp index 3c10f8704..bef2e6494 100644 --- a/src/model/model_core.cpp +++ b/src/model/model_core.cpp @@ -87,3 +87,19 @@ void model_core::register_decl(func_decl * d, func_interp * fi) { } } +void model_core::unregister_decl(func_decl * d) { + decl2expr::obj_map_entry * ec = m_interp.find_core(d); + if (ec && ec->get_data().m_value != 0) { + m_manager.dec_ref(ec->get_data().m_key); + m_manager.dec_ref(ec->get_data().m_value); + m_interp.remove(d); + return; + } + + decl2finterp::obj_map_entry * ef = m_finterp.find_core(d); + if (ef && ef->get_data().m_value != 0) { + m_manager.dec_ref(ef->get_data().m_key); + dealloc(ef->get_data().m_value); + m_finterp.remove(d); + } +} \ No newline at end of file diff --git a/src/model/model_core.h b/src/model/model_core.h index 8527a0bca..371106b05 100644 --- a/src/model/model_core.h +++ b/src/model/model_core.h @@ -60,6 +60,7 @@ public: void register_decl(func_decl * d, expr * v); void register_decl(func_decl * f, func_interp * fi); + void unregister_decl(func_decl * d); virtual expr * get_some_value(sort * s) = 0; From 009af4455d60e0affb376e36f48e3ab42fcf67d0 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Sat, 15 Oct 2016 18:16:44 +0200 Subject: [PATCH 05/26] Refactored and fixed model conversion for fpa2bv conversion of unspecified values via theory_fpa. --- scripts/mk_project.py | 2 +- src/ast/fpa/bv2fpa_converter.cpp | 543 ++++++++++++++++++++++ src/ast/fpa/bv2fpa_converter.h | 74 +++ src/ast/fpa/fpa2bv_converter.cpp | 190 ++++---- src/ast/fpa/fpa2bv_converter.h | 13 +- src/ast/fpa/fpa2bv_rewriter.cpp | 10 +- src/smt/theory_fpa.cpp | 69 ++- src/tactic/fpa/fpa2bv_model_converter.cpp | 468 ++----------------- src/tactic/fpa/fpa2bv_model_converter.h | 92 +--- 9 files changed, 817 insertions(+), 644 deletions(-) create mode 100644 src/ast/fpa/bv2fpa_converter.cpp create mode 100644 src/ast/fpa/bv2fpa_converter.h diff --git a/scripts/mk_project.py b/scripts/mk_project.py index 00b5cdef5..c03d76b5f 100644 --- a/scripts/mk_project.py +++ b/scripts/mk_project.py @@ -45,7 +45,7 @@ def init_project_def(): # Simplifier module will be deleted in the future. # It has been replaced with rewriter module. add_lib('simplifier', ['rewriter'], 'ast/simplifier') - add_lib('fpa', ['ast', 'util', 'simplifier'], 'ast/fpa') + add_lib('fpa', ['ast', 'util', 'simplifier', 'model'], 'ast/fpa') add_lib('macros', ['simplifier'], 'ast/macros') add_lib('pattern', ['normal_forms', 'smt2parser', 'simplifier'], 'ast/pattern') add_lib('bit_blaster', ['rewriter', 'simplifier'], 'ast/rewriter/bit_blaster') diff --git a/src/ast/fpa/bv2fpa_converter.cpp b/src/ast/fpa/bv2fpa_converter.cpp new file mode 100644 index 000000000..fb3af396c --- /dev/null +++ b/src/ast/fpa/bv2fpa_converter.cpp @@ -0,0 +1,543 @@ +/*++ + Copyright (c) 2012 Microsoft Corporation + +Module Name: + + bv2fpa_converter.cpp + +Abstract: + + Model conversion for fpa2bv_converter + +Author: + + Christoph (cwinter) 2016-10-15 + +Notes: + +--*/ +#include + +#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::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::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::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 >::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 >::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 & seen) { + for (obj_map::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)); + app * a1 = to_app(val->get_arg(1)); + app * a2 = to_app(val->get_arg(2)); + + expr_ref v0(m), v1(m), v2(m); + v0 = mc->get_const_interp(a0->get_decl()); + v1 = mc->get_const_interp(a1->get_decl()); + v2 = mc->get_const_interp(a2->get_decl()); + + 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 & seen) { + for (obj_map::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 & seen) { + for (obj_map >::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 & seen) { + for (obj_map::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::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::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::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 >::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::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::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::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 >::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(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; + }); + +} \ No newline at end of file diff --git a/src/ast/fpa/bv2fpa_converter.h b/src/ast/fpa/bv2fpa_converter.h new file mode 100644 index 000000000..c441ea6ff --- /dev/null +++ b/src/ast/fpa/bv2fpa_converter.h @@ -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 m_const2bv; + obj_map m_rm_const2bv; + obj_map m_uf2bvuf; + obj_map > 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 & seen); + void convert_rm_consts(model_core * mc, model_core * target_model, obj_hashtable & seen); + void convert_min_max_specials(model_core * mc, model_core * target_model, obj_hashtable & seen); + void convert_uf2bvuf(model_core * mc, model_core * target_model, obj_hashtable & 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 \ No newline at end of file diff --git a/src/ast/fpa/fpa2bv_converter.cpp b/src/ast/fpa/fpa2bv_converter.cpp index 8db839e24..05c45c925 100644 --- a/src/ast/fpa/fpa2bv_converter.cpp +++ b/src/ast/fpa/fpa2bv_converter.cpp @@ -23,6 +23,7 @@ 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); } @@ -32,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()), @@ -2771,6 +2771,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); @@ -3073,11 +3074,9 @@ void fpa2bv_converter::mk_to_ieee_bv(func_decl * f, unsigned num, expr * const * m_bv_util.mk_concat(m_bv_util.mk_numeral(0, sbits - 2), m_bv_util.mk_numeral(1, 1)))); else { - expr_ref unspec_bits(m); - unspec_bits = m_util.mk_internal_to_ieee_bv_unspecified(ebits, sbits); - nanv = m_bv_util.mk_concat(m_bv_util.mk_extract(sbits-1, sbits-1, unspec_bits), - m_bv_util.mk_concat(m_bv_util.mk_numeral(-1, ebits), - m_bv_util.mk_extract(sbits-2, 0, unspec_bits))); + 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); @@ -3127,39 +3126,42 @@ void fpa2bv_converter::mk_to_ieee_bv_unspecified(func_decl * f, unsigned num, ex } void fpa2bv_converter::mk_to_bv(func_decl * f, unsigned num, expr * const * args, bool is_signed, expr_ref & result) { - TRACE("fpa2bv_to_bv", for (unsigned i = 0; i < num; i++) - tout << "arg" << i << " = " << mk_ismt2_pp(args[i], m) << std::endl;); + TRACE("fpa2bv_to_bv", for (unsigned i = 0; i < num; i++) + tout << "arg" << i << " = " << mk_ismt2_pp(args[i], m) << std::endl;); - SASSERT(num == 2); - SASSERT(m_util.is_bv2rm(args[0])); - SASSERT(m_util.is_float(args[1])); + SASSERT(num == 2); + SASSERT(m_util.is_bv2rm(args[0])); + SASSERT(m_util.is_float(args[1])); - expr * rm = to_app(args[0])->get_arg(0); - expr * x = args[1]; - sort * xs = m.get_sort(x); - sort * bv_srt = f->get_range(); + expr * rm = to_app(args[0])->get_arg(0); + expr * x = args[1]; + sort * xs = m.get_sort(x); + sort * bv_srt = f->get_range(); - unsigned ebits = m_util.get_ebits(xs); - unsigned sbits = m_util.get_sbits(xs); - unsigned bv_sz = (unsigned)f->get_parameter(0).get_int(); + unsigned ebits = m_util.get_ebits(xs); + unsigned sbits = m_util.get_sbits(xs); + unsigned bv_sz = (unsigned)f->get_parameter(0).get_int(); - expr_ref bv0(m), bv1(m); - bv1 = m_bv_util.mk_numeral(1, 1); + expr_ref bv0(m), bv1(m); + bv1 = m_bv_util.mk_numeral(1, 1); - expr_ref x_is_nan(m), x_is_inf(m), x_is_zero(m), x_is_neg(m), x_is_nzero(m); - mk_is_nan(x, x_is_nan); - mk_is_inf(x, x_is_inf); - mk_is_zero(x, x_is_zero); - mk_is_neg(x, x_is_neg); - mk_is_nzero(x, x_is_nzero); + expr_ref x_is_nan(m), x_is_inf(m), x_is_zero(m), x_is_neg(m), x_is_nzero(m); + mk_is_nan(x, x_is_nan); + mk_is_inf(x, x_is_inf); + mk_is_zero(x, x_is_zero); + mk_is_neg(x, x_is_neg); + mk_is_nzero(x, x_is_nzero); - // NaN, Inf, or negative (except -0) -> unspecified - expr_ref c1(m), v1(m); - 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 - c1 = m.mk_or(x_is_nan, x_is_inf); - v1 = mk_to_ubv_unspecified(ebits, sbits, bv_sz); + // NaN, Inf, or negative (except -0) -> unspecified + expr_ref c1(m), v1(m); + 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))); + v1 = mk_to_ubv_unspecified(ebits, sbits, bv_sz); + } + else { + c1 = m.mk_or(x_is_nan, x_is_inf); + v1 = mk_to_sbv_unspecified(ebits, sbits, bv_sz); + } dbg_decouple("fpa2bv_to_bv_c1", c1); // +-Zero -> 0 @@ -3269,7 +3271,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); @@ -3290,70 +3293,89 @@ void fpa2bv_converter::mk_to_sbv(func_decl * f, unsigned num, expr * const * arg mk_to_bv(f, num, args, true, result); } +void fpa2bv_converter::mk_to_ubv_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(); + 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_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 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_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); - 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_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 ebits = f->get_parameter(0).get_int(); + unsigned sbits = f->get_parameter(1).get_int(); + 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); } - 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) { diff --git a/src/ast/fpa/fpa2bv_converter.h b/src/ast/fpa/fpa2bv_converter.h index 4fcfe42f6..247cfcacb 100644 --- a/src/ast/fpa/fpa2bv_converter.h +++ b/src/ast/fpa/fpa2bv_converter.h @@ -43,7 +43,6 @@ protected: 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; @@ -57,6 +56,7 @@ protected: special_t m_min_max_specials; friend class fpa2bv_model_converter; + friend class bv2fpa_converter; public: fpa2bv_converter(ast_manager & m); @@ -138,8 +138,11 @@ public: 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; } @@ -150,10 +153,6 @@ 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); - void reset(void); void dbg_decouple(const char * prefix, expr_ref & e); @@ -227,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 diff --git a/src/ast/fpa/fpa2bv_rewriter.cpp b/src/ast/fpa/fpa2bv_rewriter.cpp index 6d4f24856..725c0b043 100644 --- a/src/ast/fpa/fpa2bv_rewriter.cpp +++ b/src/ast/fpa/fpa2bv_rewriter.cpp @@ -143,9 +143,12 @@ 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_TO_IEEE_BV: m_conv.mk_to_ieee_bv(f, num, args, result); return BR_REWRITE_FULL; + 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; @@ -158,11 +161,8 @@ 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: 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;); diff --git a/src/smt/theory_fpa.cpp b/src/smt/theory_fpa.cpp index 288b61748..248d5b84d 100644 --- a/src/smt/theory_fpa.cpp +++ b/src/smt/theory_fpa.cpp @@ -21,6 +21,7 @@ Revision History: #include"theory_fpa.h" #include"theory_bv.h" #include"smt_model_generator.h" +#include"bv2fpa_converter.h" namespace smt { @@ -83,15 +84,15 @@ namespace smt { } } - theory_fpa::theory_fpa(ast_manager & m) : - theory(m.mk_family_id("fpa")), - m_converter(m, this), - m_rw(m, m_converter, params_ref()), - m_th_rw(m), - m_trail_stack(*this), - m_fpa_util(m_converter.fu()), - m_bv_util(m_converter.bu()), - m_arith_util(m_converter.au()), + theory_fpa::theory_fpa(ast_manager & m) : + theory(m.mk_family_id("fpa")), + m_converter(m, this), + m_rw(m, m_converter, params_ref()), + m_th_rw(m), + m_trail_stack(*this), + m_fpa_util(m_converter.fu()), + m_bv_util(m_converter.bu()), + m_arith_util(m_converter.au()), m_is_initialized(false) { params_ref p; @@ -712,20 +713,6 @@ namespace smt { ast_manager & m = get_manager(); m_factory = alloc(fpa_value_factory, m, get_family_id()); mg.register_factory(m_factory); - - fpa2bv_converter::uf2bvuf_t const & uf2bvuf = m_converter.get_uf2bvuf(); - for (fpa2bv_converter::uf2bvuf_t::iterator it = uf2bvuf.begin(); - it != uf2bvuf.end(); - it++) { - //mg.hide(it->m_value); - } - fpa2bv_converter::special_t const & specials = m_converter.get_min_max_specials(); - for (fpa2bv_converter::special_t::iterator it = specials.begin(); - it != specials.end(); - it++) { - mg.hide(it->m_value.first->get_decl()); - mg.hide(it->m_value.second->get_decl()); - } } model_value_proc * theory_fpa::mk_value(enode * n, model_generator & mg) { @@ -814,21 +801,29 @@ namespace smt { void theory_fpa::finalize_model(model_generator & mg) { ast_manager & m = get_manager(); proto_model & mdl = mg.get_model(); + proto_model new_model(m); - fpa2bv_converter::uf2bvuf_t const & uf2bvuf = m_converter.get_uf2bvuf(); - for (fpa2bv_converter::uf2bvuf_t::iterator it = uf2bvuf.begin(); - it != uf2bvuf.end(); - it++) { - func_decl * bv_fd = it->m_value; - if (bv_fd->get_arity() == 0) { - expr_ref bve(m), v(m); - bve = m.mk_const(bv_fd); - mdl.eval(bve, v, true); - mdl.register_decl(it->m_key, v); - } - else - NOT_IMPLEMENTED_YET(); - } + bv2fpa_converter bv2fp(m, m_converter); + + obj_hashtable seen; + bv2fp.convert_min_max_specials(&mdl, &new_model, seen); + bv2fp.convert_uf2bvuf(&mdl, &new_model, seen); + + for (obj_hashtable::iterator it = seen.begin(); + it != seen.end(); + it++) + mdl.unregister_decl(*it); + + for (unsigned i = 0; i < new_model.get_num_constants(); i++) { + func_decl * f = new_model.get_constant(i); + mdl.register_decl(f, new_model.get_const_interp(f)); + } + + for (unsigned i = 0; i < new_model.get_num_functions(); i++) { + func_decl * f = new_model.get_function(i); + func_interp * fi = new_model.get_func_interp(f)->copy(); + mdl.register_decl(f, fi); + } } void theory_fpa::display(std::ostream & out) const diff --git a/src/tactic/fpa/fpa2bv_model_converter.cpp b/src/tactic/fpa/fpa2bv_model_converter.cpp index 05fedb37f..9b95cf921 100644 --- a/src/tactic/fpa/fpa2bv_model_converter.cpp +++ b/src/tactic/fpa/fpa2bv_model_converter.cpp @@ -22,448 +22,54 @@ Notes: void fpa2bv_model_converter::display(std::ostream & out) { out << "(fpa2bv-model-converter"; - for (obj_map::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::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::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 >::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) << ")"; - } + m_bv2fp->display(out); out << ")"; } model_converter * fpa2bv_model_converter::translate(ast_translation & translator) { - fpa2bv_model_converter * res = alloc(fpa2bv_model_converter, translator.to()); - for (obj_map::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::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::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 >::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(v1, v2)); - translator.to().inc_ref(k); - translator.to().inc_ref(v1); - translator.to().inc_ref(v2); - } + fpa2bv_model_converter * res = alloc(fpa2bv_model_converter, translator.to()); + res->m_bv2fp = m_bv2fp->translate(translator); return res; } -expr_ref fpa2bv_model_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(); +void fpa2bv_model_converter::convert(model_core * mc, model * float_mdl) { + obj_hashtable seen; + m_bv2fp->convert_consts(mc, float_mdl, seen); + m_bv2fp->convert_rm_consts(mc, float_mdl, seen); + m_bv2fp->convert_min_max_specials(mc, float_mdl, seen); + m_bv2fp->convert_uf2bvuf(mc, float_mdl, seen); - expr_ref res(m); - mpf fp_val; + // Keep all the non-float constants. + unsigned sz = mc->get_num_constants(); + for (unsigned i = 0; i < sz; i++) + { + func_decl * c = mc->get_constant(i); + if (!seen.contains(c)) + float_mdl->register_decl(c, mc->get_const_interp(c)); + } - unsigned ebits = m_fpa_util.get_ebits(s); - unsigned sbits = m_fpa_util.get_sbits(s); + // And keep everything else + sz = mc->get_num_functions(); + for (unsigned i = 0; i < sz; i++) + { + func_decl * f = mc->get_function(i); + if (!seen.contains(f)) + { + TRACE("fpa2bv_mc", tout << "Keeping: " << mk_ismt2_pp(f, m) << std::endl;); + func_interp * val = mc->get_func_interp(f)->copy(); + float_mdl->register_decl(f, val); + } + } - 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("fpa2bv_mc", 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; + sz = mc->get_num_uninterpreted_sorts(); + for (unsigned i = 0; i < sz; i++) + { + sort * s = mc->get_uninterpreted_sort(i); + ptr_vector u = mc->get_universe(s); + float_mdl->register_usort(s, u.size(), u.c_ptr()); + } } -expr_ref fpa2bv_model_converter::convert_bv2fp(model * bv_mdl, sort * s, expr * 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 sgn(m), exp(m), sig(m); - sgn = m_bv_util.mk_extract(bv_sz - 1, bv_sz - 1, bv); - exp = m_bv_util.mk_extract(bv_sz - 2, sbits - 1, bv); - sig = m_bv_util.mk_extract(sbits - 2, 0, bv); - - expr_ref v_sgn(m), v_exp(m), v_sig(m); - bv_mdl->eval(sgn, v_sgn); - bv_mdl->eval(exp, v_exp); - bv_mdl->eval(sig, v_sig); - - return convert_bv2fp(s, v_sgn, v_exp, v_sig); -} - -expr_ref fpa2bv_model_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 fpa2bv_model_converter::convert_bv2rm(model * bv_mdl, expr * val) { - expr_ref res(m); - expr_ref eval_v(m); - - if (val && bv_mdl->eval(val, eval_v, true)) - res = convert_bv2rm(eval_v); - - return res; -} - -expr_ref fpa2bv_model_converter::rebuild_floats(model * bv_mdl, sort * s, expr * e) { - expr_ref result(m); - TRACE("fpa2bv_mc", tout << "rebuild floats in " << mk_ismt2_pp(s, m) << " for " << mk_ismt2_pp(e, m) << std::endl;); - - if (m_fpa_util.is_float(s)) { - 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(bv_mdl, s, e); - } - } - else if (m_fpa_util.is_rm(s)) { - 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(bv_mdl, 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(bv_mdl, a->get_decl()->get_domain()[i], a->get_arg(i))); - result = m.mk_app(a->get_decl(), new_args.size(), new_args.c_ptr()); - } - - return result; -} - -fpa2bv_model_converter::array_model fpa2bv_model_converter::convert_array_func_interp(func_decl * f, func_decl * bv_f, model * bv_mdl) { - 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 = bv_mdl->get_const_interp(bv_f); - if (as_arr_mdl == 0) return am; - TRACE("fpa2bv_mc", 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(am.new_float_fd, bv_f, bv_mdl); - am.bv_fd = bv_f; - am.result = arr_util.mk_as_array(f->get_range(), am.new_float_fd); - return am; -} - -func_interp * fpa2bv_model_converter::convert_func_interp(func_decl * f, func_decl * bv_f, model * bv_mdl) { - 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 = bv_mdl->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(bv_mdl, ft_dj, 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(bv_mdl, rng, bv_fres); - m_th_rw(ft_fres); - result->insert_new_entry(new_args.c_ptr(), ft_fres); - } - - expr_ref bv_els(m), ft_els(m); - bv_els = bv_fi->get_else(); - ft_els = rebuild_floats(bv_mdl, rng, bv_els); - m_th_rw(ft_els); - result->set_else(ft_els); - } - - return result; -} - -void fpa2bv_model_converter::convert(model * bv_mdl, model * float_mdl) { - TRACE("fpa2bv_mc", tout << "BV Model: " << std::endl; - for (unsigned i = 0; i < bv_mdl->get_num_constants(); i++) - tout << bv_mdl->get_constant(i)->get_name() << " --> " << - mk_ismt2_pp(bv_mdl->get_const_interp(bv_mdl->get_constant(i)), m) << std::endl; - for (unsigned i = 0; i < bv_mdl->get_num_functions(); i++) { - func_decl * f = bv_mdl->get_function(i); - tout << f->get_name() << "(...) := " << std::endl; - func_interp * fi = bv_mdl->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; - }); - - obj_hashtable seen; - - for (obj_map >::iterator it = m_specials.begin(); - it != m_specials.end(); - it++) { - func_decl * f = it->m_key; - 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); - bv_mdl->eval(it->m_value.first, pn, true); - bv_mdl->eval(it->m_value.second, np, true); - seen.insert(it->m_value.first->get_decl()); - seen.insert(it->m_value.second->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); - - float_mdl->register_decl(f, flt_fi); - TRACE("fpa2bv_mc", tout << "fp.min/fp.max special: " << std::endl << - mk_ismt2_pp(f, m) << " == " << mk_ismt2_pp(flt_fi->get_interp(), m) << std::endl;); - } - - for (obj_map::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); - - expr_ref sgn(m), sig(m), exp(m); - bv_mdl->eval(val->get_arg(0), sgn, true); - bv_mdl->eval(val->get_arg(1), exp, true); - bv_mdl->eval(val->get_arg(2), sig, true); - - 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); - float_mdl->register_decl(var, cv); - - TRACE("fpa2bv_mc", tout << var->get_name() << " == " << mk_ismt2_pp(cv, m) << std::endl;); - } - - for (obj_map::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(bv_mdl, bvval); - TRACE("fpa2bv_mc", tout << var->get_name() << " == " << mk_ismt2_pp(fv, m) << ")" << std::endl;); - float_mdl->register_decl(var, fv); - seen.insert(to_app(bvval)->get_decl()); - } - - for (obj_map::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(f, it->m_value, bv_mdl); - if (am.new_float_fd) float_mdl->register_decl(am.new_float_fd, am.new_float_fi); - if (am.result) float_mdl->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 val(m); - bv_mdl->eval(it->m_value, val); - if (val) float_mdl->register_decl(f, val); - } - } - else { - func_interp * fmv = convert_func_interp(f, it->m_value, bv_mdl); - if (fmv) float_mdl->register_decl(f, fmv); - } - } - - // Keep all the non-float constants. - unsigned sz = bv_mdl->get_num_constants(); - for (unsigned i = 0; i < sz; i++) - { - func_decl * c = bv_mdl->get_constant(i); - if (!seen.contains(c)) - float_mdl->register_decl(c, bv_mdl->get_const_interp(c)); - } - - // And keep everything else - sz = bv_mdl->get_num_functions(); - for (unsigned i = 0; i < sz; i++) - { - func_decl * f = bv_mdl->get_function(i); - if (!seen.contains(f)) - { - TRACE("fpa2bv_mc", tout << "Keeping: " << mk_ismt2_pp(f, m) << std::endl;); - func_interp * val = bv_mdl->get_func_interp(f)->copy(); - float_mdl->register_decl(f, val); - } - } - - sz = bv_mdl->get_num_uninterpreted_sorts(); - for (unsigned i = 0; i < sz; i++) - { - sort * s = bv_mdl->get_uninterpreted_sort(i); - ptr_vector u = bv_mdl->get_universe(s); - float_mdl->register_usort(s, u.size(), u.c_ptr()); - } -} - -model_converter * mk_fpa2bv_model_converter(ast_manager & m, fpa2bv_converter const & conv) { +model_converter * mk_fpa2bv_model_converter(ast_manager & m, fpa2bv_converter & conv) { return alloc(fpa2bv_model_converter, m, conv); } diff --git a/src/tactic/fpa/fpa2bv_model_converter.h b/src/tactic/fpa/fpa2bv_model_converter.h index 909a7cb78..7a39c0fba 100644 --- a/src/tactic/fpa/fpa2bv_model_converter.h +++ b/src/tactic/fpa/fpa2bv_model_converter.h @@ -19,79 +19,29 @@ Notes: #ifndef FPA2BV_MODEL_CONVERTER_H_ #define FPA2BV_MODEL_CONVERTER_H_ -#include"th_rewriter.h" #include"fpa2bv_converter.h" #include"model_converter.h" +#include"bv2fpa_converter.h" class fpa2bv_model_converter : public model_converter { ast_manager & m; - fpa_util m_fpa_util; - bv_util m_bv_util; - th_rewriter m_th_rw; + bv2fpa_converter * m_bv2fp; - obj_map m_const2bv; - obj_map m_rm_const2bv; - obj_map m_uf2bvuf; - obj_map > m_specials; - public: - fpa2bv_model_converter(ast_manager & m, fpa2bv_converter const & conv) : - m(m), - m_fpa_util(m), - m_bv_util(m), - m_th_rw(m) { - for (obj_map::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::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::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 >::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); - } + fpa2bv_model_converter(ast_manager & m, fpa2bv_converter & conv) : + m(m) { + m_bv2fp = alloc(bv2fpa_converter, m, conv); } virtual ~fpa2bv_model_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 >::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); - } + if (m_bv2fp) dealloc(m_bv2fp); + m_bv2fp = 0; } virtual void operator()(model_ref & md, unsigned goal_idx) { SASSERT(goal_idx == 0); model * new_model = alloc(model, m); - obj_hashtable bits; - convert(md.get(), new_model); + convert(md.get(), new_model); md = new_model; } @@ -106,32 +56,12 @@ public: protected: fpa2bv_model_converter(ast_manager & m) : m(m), - m_fpa_util(m), - m_bv_util(m), - m_th_rw(m) {} + m_bv2fp(0) {} - void convert(model * bv_mdl, model * float_mdl); - expr_ref convert_bv2fp(sort * s, expr * sgn, expr * exp, expr * sig); - expr_ref convert_bv2fp(model * bv_mdl, sort * s, expr * bv); - expr_ref convert_bv2rm(expr * eval_v); - expr_ref convert_bv2rm(model * bv_mdl, expr * val); - - func_interp * convert_func_interp(func_decl * f, func_decl * bv_f, model * bv_mdl); - expr_ref rebuild_floats(model * bv_mdl, sort * s, expr * 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(func_decl * f, func_decl * bv_f, model * bv_mdl); + void convert(model_core * mc, model * float_mdl); }; -model_converter * mk_fpa2bv_model_converter(ast_manager & m, fpa2bv_converter const & conv); +model_converter * mk_fpa2bv_model_converter(ast_manager & m, fpa2bv_converter & conv); #endif From b2381acceb345b85f9dd03d2213bc24b08b16ea2 Mon Sep 17 00:00:00 2001 From: Dan Liew Date: Sat, 15 Oct 2016 21:42:20 +0100 Subject: [PATCH 06/26] Unbreak the CMake build broken by 009af4455d60e0affb376e36f48e3ab42fcf67d0 The commit added an additional source file and dependency but the corresponding changes weren't added to the CMake build. --- contrib/cmake/src/ast/fpa/CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/contrib/cmake/src/ast/fpa/CMakeLists.txt b/contrib/cmake/src/ast/fpa/CMakeLists.txt index 7369a9b3d..4a9506d16 100644 --- a/contrib/cmake/src/ast/fpa/CMakeLists.txt +++ b/contrib/cmake/src/ast/fpa/CMakeLists.txt @@ -1,10 +1,12 @@ z3_add_component(fpa SOURCES + bv2fpa_converter.cpp fpa2bv_converter.cpp fpa2bv_rewriter.cpp COMPONENT_DEPENDENCIES ast simplifier + model util PYG_FILES fpa2bv_rewriter_params.pyg From aec59e4ff77b5389e377a5df2336491cd99ed84e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 16 Oct 2016 15:43:28 -0400 Subject: [PATCH 07/26] add consequence finding to inc-sat-solver Signed-off-by: Nikolaj Bjorner --- contrib/cmake/src/test/CMakeLists.txt | 1 + src/ast/pb_decl_plugin.cpp | 50 +++++---- src/ast/pb_decl_plugin.h | 1 + src/ast/rewriter/pb_rewriter.cpp | 16 +++ src/sat/sat_solver.cpp | 46 ++++---- src/sat/sat_solver.h | 3 + src/sat/sat_solver/inc_sat_solver.cpp | 144 +++++++++++++++++++++++++- src/sat/sat_types.h | 12 +++ src/test/get_consequences.cpp | 50 +++++++++ src/test/main.cpp | 1 + 10 files changed, 283 insertions(+), 41 deletions(-) create mode 100644 src/test/get_consequences.cpp diff --git a/contrib/cmake/src/test/CMakeLists.txt b/contrib/cmake/src/test/CMakeLists.txt index 427cedcdb..acaf186ba 100644 --- a/contrib/cmake/src/test/CMakeLists.txt +++ b/contrib/cmake/src/test/CMakeLists.txt @@ -42,6 +42,7 @@ add_executable(test-z3 factor_rewriter.cpp fixed_bit_vector.cpp for_each_file.cpp + get_consequences.cpp get_implied_equalities.cpp "${CMAKE_CURRENT_BINARY_DIR}/gparams_register_modules.cpp" hashtable.cpp diff --git a/src/ast/pb_decl_plugin.cpp b/src/ast/pb_decl_plugin.cpp index e87bc15ac..18a652859 100644 --- a/src/ast/pb_decl_plugin.cpp +++ b/src/ast/pb_decl_plugin.cpp @@ -101,35 +101,47 @@ void pb_decl_plugin::get_op_names(svector & op_names, symbol const } void pb_util::normalize(unsigned num_args, rational const* coeffs, rational const& k) { - rational d(1); - for (unsigned i = 0; i < num_args; ++i) { - d = lcm(d, denominator(coeffs[i])); - } m_coeffs.reset(); - for (unsigned i = 0; i < num_args; ++i) { - m_coeffs.push_back(d*coeffs[i]); + bool all_ones = true; + for (unsigned i = 0; i < num_args && all_ones; ++i) { + all_ones = denominator(coeffs[i]).is_one(); + } + 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; } - 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); - vector params; - params.push_back(parameter(floor(m_k))); + m_params.reset(); + m_params.push_back(parameter(floor(m_k))); for (unsigned i = 0; i < num_args; ++i) { - params.push_back(parameter(m_coeffs[i])); + m_params.push_back(parameter(m_coeffs[i])); } - return m.mk_app(m_fid, OP_PB_LE, params.size(), params.c_ptr(), num_args, args, m.mk_bool_sort()); + 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) { normalize(num_args, coeffs, k); - vector params; - params.push_back(parameter(ceil(m_k))); + m_params.reset(); + m_params.push_back(parameter(ceil(m_k))); for (unsigned i = 0; i < num_args; ++i) { - params.push_back(parameter(m_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) { @@ -137,12 +149,12 @@ app * pb_util::mk_eq(unsigned num_args, rational const * coeffs, expr * const * if (!m_k.is_int()) { return m.mk_false(); } - vector params; - params.push_back(parameter(m_k)); + m_params.reset(); + m_params.push_back(parameter(m_k)); for (unsigned i = 0; i < num_args; ++i) { - params.push_back(parameter(m_coeffs[i])); + m_params.push_back(parameter(m_coeffs[i])); } - return m.mk_app(m_fid, OP_PB_EQ, params.size(), params.c_ptr(), num_args, args, m.mk_bool_sort()); + 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 diff --git a/src/ast/pb_decl_plugin.h b/src/ast/pb_decl_plugin.h index e1b16f0c9..2ed14a4ce 100644 --- a/src/ast/pb_decl_plugin.h +++ b/src/ast/pb_decl_plugin.h @@ -80,6 +80,7 @@ class pb_util { ast_manager & m; family_id m_fid; vector m_coeffs; + vector m_params; rational m_k; void normalize(unsigned num_args, rational const* coeffs, rational const& k); public: diff --git a/src/ast/rewriter/pb_rewriter.cpp b/src/ast/rewriter/pb_rewriter.cpp index eb85f8ec9..74062fbfa 100644 --- a/src/ast/rewriter/pb_rewriter.cpp +++ b/src/ast/rewriter/pb_rewriter.cpp @@ -277,6 +277,22 @@ br_status pb_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * cons tout << tmp << "\n"; tout << result << "\n"; ); + +#if 0 + static unsigned num_changes = 0; + static unsigned num_calls = 0; + static unsigned inc = 1; + { + expr_ref tmp(m); + tmp = m.mk_app(f, num_args, args); + num_calls++; + if (tmp != result) ++num_changes; + if (num_calls > inc) { + std::cout << num_calls << " " << num_changes << "\n"; + inc *= 2; + } + } +#endif TRACE("pb_validate", validate_rewrite(f, num_args, args, result);); diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index f2279b3c4..915080c4a 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -3075,45 +3075,51 @@ namespace sat { m_binary_clause_graph[l1.index()].push_back(l2); m_binary_clause_graph[l2.index()].push_back(l1); } - while (!ps.empty()) { + bool non_empty = true; + m_seen[0].reset(); + while (non_empty) { literal_vector mutex; - literal_set other(ps); - while (!other.empty()) { - literal_set conseq; - literal p = other.pop(); + bool turn = false; + m_reachable[turn] = ps; + while (!m_reachable[turn].empty()) { + literal p = m_reachable[turn].pop(); + if (m_seen[0].contains(p)) { + continue; + } + m_reachable[turn].remove(p); + m_seen[0].insert(p); mutex.push_back(p); - if (other.empty()) { + if (m_reachable[turn].empty()) { break; } - get_reachable(p, other, conseq); - other = conseq; + m_reachable[!turn].reset(); + get_reachable(p, m_reachable[turn], m_reachable[!turn]); + turn = !turn; } if (mutex.size() > 1) { mutexes.push_back(mutex); } - for (unsigned i = 0; i < mutex.size(); ++i) { - ps.erase(mutex[i]); - } + non_empty = !mutex.empty(); } return l_true; } void solver::get_reachable(literal p, literal_set const& goal, literal_set& reachable) { - literal_set seen; - literal_vector todo; - todo.push_back(p); - while (!todo.empty()) { - p = todo.back(); - todo.pop_back(); - if (seen.contains(p)) { + m_seen[1].reset(); + m_todo.reset(); + m_todo.push_back(p); + while (!m_todo.empty()) { + p = m_todo.back(); + m_todo.pop_back(); + if (m_seen[1].contains(p)) { continue; } - seen.insert(p); + m_seen[1].insert(p); literal np = ~p; if (goal.contains(np)) { reachable.insert(np); } - todo.append(m_binary_clause_graph[np.index()]); + m_todo.append(m_binary_clause_graph[np.index()]); } } diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index 785bc6856..85836b889 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -447,6 +447,9 @@ namespace sat { u_map m_antecedents; vector m_binary_clause_graph; + literal_set m_reachable[2]; + literal_set m_seen[2]; + literal_vector m_todo; void extract_assumptions(literal lit, index_set& s); diff --git a/src/sat/sat_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp index 6139b3e22..83ccfcac4 100644 --- a/src/sat/sat_solver/inc_sat_solver.cpp +++ b/src/sat/sat_solver/inc_sat_solver.cpp @@ -33,6 +33,7 @@ Notes: #include "filter_model_converter.h" #include "bit_blaster_model_converter.h" #include "ast_translation.h" +#include "ast_util.h" // incremental SAT solver. class inc_sat_solver : public solver { @@ -232,6 +233,41 @@ public: return 0; } + virtual lbool get_consequences_core(expr_ref_vector const& assumptions, expr_ref_vector const& vars, expr_ref_vector& conseq) { + TRACE("sat", tout << assumptions << "\n" << vars << "\n";); + sat::literal_vector asms; + sat::bool_var_vector bvars; + vector lconseq; + dep2asm_t dep2asm; + m_solver.pop_to_base_level(); + lbool r = internalize_formulas(); + if (r != l_true) return r; + r = internalize_assumptions(assumptions.size(), assumptions.c_ptr(), dep2asm); + if (r != l_true) return r; + r = internalize_vars(vars, bvars); + + r = m_solver.get_consequences(m_asms, bvars, lconseq); + if (r != l_true) return r; + + // build map from bound variables to + // the consequences that cover them. + u_map bool_var2conseq; + for (unsigned i = 0; i < lconseq.size(); ++i) { + TRACE("sat", tout << lconseq[i] << "\n";); + bool_var2conseq.insert(lconseq[i][0].var(), i); + } + + // extract original fixed variables + for (unsigned i = 0; i < vars.size(); ++i) { + expr_ref cons(m); + if (extract_fixed_variable(dep2asm, vars[i], bool_var2conseq, lconseq, cons)) { + conseq.push_back(cons); + } + } + + return r; + } + virtual lbool find_mutexes(expr_ref_vector const& vars, vector& mutexes) { sat::literal_vector ls; u_map lit2var; @@ -359,6 +395,106 @@ private: return res; } + lbool internalize_vars(expr_ref_vector const& vars, sat::bool_var_vector& bvars) { + for (unsigned i = 0; i < vars.size(); ++i) { + internalize_var(vars[i], bvars); + } + return l_true; + } + + bool internalize_var(expr* v, sat::bool_var_vector& bvars) { + obj_map const& const2bits = m_bb_rewriter->const2bits(); + expr* bv; + bv_util bvutil(m); + bool internalized = false; + if (is_uninterp_const(v) && m.is_bool(v)) { + sat::bool_var b = m_map.to_bool_var(v); + + if (b != sat::null_bool_var) { + bvars.push_back(b); + internalized = true; + } + } + else if (is_uninterp_const(v) && const2bits.find(to_app(v)->get_decl(), bv)) { + SASSERT(bvutil.is_bv(bv)); + app* abv = to_app(bv); + internalized = true; + unsigned sz = abv->get_num_args(); + for (unsigned j = 0; j < sz; ++j) { + SASSERT(is_uninterp_const(abv->get_arg(j))); + sat::bool_var b = m_map.to_bool_var(abv->get_arg(j)); + if (b == sat::null_bool_var) { + internalized = false; + } + else { + bvars.push_back(b); + } + } + CTRACE("sat", internalized, tout << "var: "; for (unsigned j = 0; j < sz; ++j) tout << bvars[bvars.size()-sz+j] << " "; tout << "\n";); + } + else if (is_uninterp_const(v) && bvutil.is_bv(v)) { + // variable does not occur in assertions, so is unconstrained. + } + CTRACE("sat", !internalized, tout << "unhandled variable " << mk_pp(v, m) << "\n";); + return internalized; + } + + bool extract_fixed_variable(dep2asm_t& dep2asm, expr* v, u_map const& bool_var2conseq, vector const& lconseq, expr_ref& conseq) { + u_map asm2dep; + extract_asm2dep(dep2asm, asm2dep); + + sat::bool_var_vector bvars; + if (!internalize_var(v, bvars)) { + return false; + } + sat::literal_vector value; + sat::literal_set premises; + for (unsigned i = 0; i < bvars.size(); ++i) { + unsigned index; + if (bool_var2conseq.find(bvars[i], index)) { + value.push_back(lconseq[index][0]); + for (unsigned j = 1; j < lconseq[index].size(); ++j) { + premises.insert(lconseq[index][j]); + } + } + else { + TRACE("sat", tout << "variable is not bound " << mk_pp(v, m) << "\n";); + return false; + } + } + expr_ref val(m); + expr_ref_vector conj(m); + internalize_value(value, v, val); + while (!premises.empty()) { + expr* e = 0; + VERIFY(asm2dep.find(premises.pop().index(), e)); + conj.push_back(e); + } + conseq = m.mk_implies(mk_and(conj), val); + return true; + } + + void internalize_value(sat::literal_vector const& value, expr* v, expr_ref& val) { + bv_util bvutil(m); + if (is_uninterp_const(v) && m.is_bool(v)) { + SASSERT(value.size() == 1); + val = value[0].sign() ? m.mk_not(v) : v; + } + else if (is_uninterp_const(v) && bvutil.is_bv_sort(m.get_sort(v))) { + SASSERT(value.size() == bvutil.get_bv_size(v)); + rational r(0); + for (unsigned i = 0; i < value.size(); ++i) { + if (!value[i].sign()) { + r += rational(2).expt(i); + } + } + val = m.mk_eq(v, bvutil.mk_numeral(r, value.size())); + } + else { + UNREACHABLE(); + } + } + lbool internalize_formulas() { if (m_fmls_head == m_fmls.size()) { return l_true; @@ -395,13 +531,17 @@ private: SASSERT(dep2asm.size() == m_asms.size()); } - void extract_core(dep2asm_t& dep2asm) { - u_map asm2dep; + void extract_asm2dep(dep2asm_t const& dep2asm, u_map& asm2dep) { dep2asm_t::iterator it = dep2asm.begin(), end = dep2asm.end(); for (; it != end; ++it) { expr* e = it->m_key; asm2dep.insert(it->m_value.index(), e); } + } + + void extract_core(dep2asm_t& dep2asm) { + u_map asm2dep; + extract_asm2dep(dep2asm, asm2dep); sat::literal_vector const& core = m_solver.get_core(); TRACE("sat", dep2asm_t::iterator it2 = dep2asm.begin(); diff --git a/src/sat/sat_types.h b/src/sat/sat_types.h index 697af2e2d..93109a74f 100644 --- a/src/sat/sat_types.h +++ b/src/sat/sat_types.h @@ -239,6 +239,18 @@ namespace sat { } return result; } + literal_set& operator=(literal_vector const& v) { + reset(); + for (unsigned i = 0; i < v.size(); ++i) insert(v[i]); + return *this; + } + literal_set& operator=(literal_set const& other) { + if (this != &other) { + m_set = other.m_set; + } + return *this; + } + void insert(literal l) { m_set.insert(l.index()); } void remove(literal l) { m_set.remove(l.index()); } literal pop() { return to_literal(m_set.erase()); } diff --git a/src/test/get_consequences.cpp b/src/test/get_consequences.cpp new file mode 100644 index 000000000..8bd6bccba --- /dev/null +++ b/src/test/get_consequences.cpp @@ -0,0 +1,50 @@ +/*++ +Copyright (c) 2016 Microsoft Corporation + +--*/ + +#include "inc_sat_solver.h" +#include "bv_decl_plugin.h" +#include "reg_decl_plugins.h" +#include "ast_pp.h" +//include + +static expr_ref mk_const(ast_manager& m, char const* name, sort* s) { + return expr_ref(m.mk_const(symbol(name), s), m); +} + +static expr_ref mk_bool(ast_manager& m, char const* name) { + return expr_ref(m.mk_const(symbol(name), m.mk_bool_sort()), m); +} + +static expr_ref mk_bv(ast_manager& m, char const* name, unsigned sz) { + bv_util bv(m); + return expr_ref(m.mk_const(symbol(name), bv.mk_sort(sz)), m); +} + +void tst_get_consequences() { + ast_manager m; + reg_decl_plugins(m); + bv_util bv(m); + params_ref p; + + ref solver = mk_inc_sat_solver(m, p); + expr_ref a = mk_bool(m, "a"), b = mk_bool(m, "b"), c = mk_bool(m, "c"); + expr_ref ba = mk_bv(m, "ba", 3), bb = mk_bv(m, "bb", 3), bc = mk_bv(m, "bc", 3); + + solver->assert_expr(m.mk_implies(a, b)); + solver->assert_expr(m.mk_implies(b, c)); + expr_ref_vector asms(m), vars(m), conseq(m); + asms.push_back(a); + vars.push_back(b); + vars.push_back(c); + vars.push_back(bb); + vars.push_back(bc); + solver->assert_expr(m.mk_eq(ba, bc)); + solver->assert_expr(m.mk_eq(bv.mk_numeral(2, 3), ba)); + solver->get_consequences(asms, vars, conseq); + + std::cout << conseq << "\n"; + + +} diff --git a/src/test/main.cpp b/src/test/main.cpp index 8fc0a2de6..9c6cdd668 100644 --- a/src/test/main.cpp +++ b/src/test/main.cpp @@ -228,6 +228,7 @@ int main(int argc, char ** argv) { TST(pdr); TST_ARGV(ddnf); TST(model_evaluator); + TST(get_consequences); //TST_ARGV(hs); } From 58198d7cb69df67b0c7974f55109613839975300 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 16 Oct 2016 15:45:39 -0400 Subject: [PATCH 08/26] add consequence finding to inc-sat-solver Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/pb_rewriter.cpp | 15 --------------- src/smt/theory_pb.cpp | 2 +- 2 files changed, 1 insertion(+), 16 deletions(-) diff --git a/src/ast/rewriter/pb_rewriter.cpp b/src/ast/rewriter/pb_rewriter.cpp index 74062fbfa..d233604f9 100644 --- a/src/ast/rewriter/pb_rewriter.cpp +++ b/src/ast/rewriter/pb_rewriter.cpp @@ -278,21 +278,6 @@ br_status pb_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * cons tout << result << "\n"; ); -#if 0 - static unsigned num_changes = 0; - static unsigned num_calls = 0; - static unsigned inc = 1; - { - expr_ref tmp(m); - tmp = m.mk_app(f, num_args, args); - num_calls++; - if (tmp != result) ++num_changes; - if (num_calls > inc) { - std::cout << num_calls << " " << num_changes << "\n"; - inc *= 2; - } - } -#endif TRACE("pb_validate", validate_rewrite(f, num_args, args, result);); diff --git a/src/smt/theory_pb.cpp b/src/smt/theory_pb.cpp index 2461a9db2..90cd020c3 100644 --- a/src/smt/theory_pb.cpp +++ b/src/smt/theory_pb.cpp @@ -519,7 +519,7 @@ namespace smt { c->m_compilation_threshold = th; IF_VERBOSE(2, verbose_stream() << "(smt.pb setting compilation threhshold to " << th << ")\n";); TRACE("pb", tout << "compilation threshold: " << th << "\n";); - compile_ineq(*c); + //compile_ineq(*c); } else { c->m_compilation_threshold = UINT_MAX; From fe14a22baacb8185e701a5d321226ba387cab76e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 16 Oct 2016 22:19:59 -0400 Subject: [PATCH 09/26] adding enumeration tests Signed-off-by: Nikolaj Bjorner --- src/test/get_consequences.cpp | 36 +++++++++++++++++++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/src/test/get_consequences.cpp b/src/test/get_consequences.cpp index 8bd6bccba..9dc0b43f9 100644 --- a/src/test/get_consequences.cpp +++ b/src/test/get_consequences.cpp @@ -5,6 +5,7 @@ Copyright (c) 2016 Microsoft Corporation #include "inc_sat_solver.h" #include "bv_decl_plugin.h" +#include "datatype_decl_plugin.h" #include "reg_decl_plugins.h" #include "ast_pp.h" //include @@ -22,7 +23,7 @@ static expr_ref mk_bv(ast_manager& m, char const* name, unsigned sz) { return expr_ref(m.mk_const(symbol(name), bv.mk_sort(sz)), m); } -void tst_get_consequences() { +static void test1() { ast_manager m; reg_decl_plugins(m); bv_util bv(m); @@ -45,6 +46,37 @@ void tst_get_consequences() { solver->get_consequences(asms, vars, conseq); std::cout << conseq << "\n"; - +} + +static void test2() { + ast_manager m; + reg_decl_plugins(m); + bv_util bv(m); + + datatype_decl_plugin& dt = static_cast(*m.get_plugin(m.get_family_id("datatype"))); + sort_ref_vector new_sorts(m); + constructor_decl* R = mk_constructor_decl(symbol("R"), symbol("is-R"), 0, 0); + constructor_decl* G = mk_constructor_decl(symbol("G"), symbol("is-G"), 0, 0); + constructor_decl* B = mk_constructor_decl(symbol("B"), symbol("is-B"), 0, 0); + constructor_decl* constrs[3] = { R, G, B }; + datatype_decl const* enum_sort = mk_datatype_decl(symbol("RGB"), 3, constrs); + VERIFY(dt.mk_datatypes(1, &enum_sort, new_sorts)); + del_constructor_decls(3, constrs); + sort* rgb = new_sorts[0].get(); + + expr_ref x = mk_const(m, "x", rgb), y = mk_const(m, "y", rgb), z = mk_const(m, "z", rgb); + ptr_vector const& enums = dt.geet_datatype_constructors(rgb); + expr_ref r = expr_ref(m.mk_const(enums[0], m), m), g = expr_ref(m.mk_const(enums[1], m), m), b = expr_ref(m.mk_const(enums[2], m), m); + + goal_ref g = alloc(goal, m); + g->assert_expr(m.mk_not(m.mk_eq(x, r))); + g->assert_expr(m.mk_not(m.mk_eq(x, b))); + g->display(std::cout); +} + +void tst_get_consequences() { + test1(); + test2(); + } From 4cae91b0965954b1e495b3b3e641381b45578069 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 17 Oct 2016 08:07:23 -0400 Subject: [PATCH 10/26] spacing, unit test Signed-off-by: Nikolaj Bjorner --- src/ast/fpa/fpa2bv_converter.h | 14 ++--- src/smt/theory_fpa.cpp | 68 ++++++++++----------- src/tactic/fpa/fpa2bv_model_converter.cpp | 72 +++++++++++------------ src/tactic/fpa/fpa2bv_model_converter.h | 19 +++--- src/test/get_consequences.cpp | 13 ++++ 5 files changed, 98 insertions(+), 88 deletions(-) diff --git a/src/ast/fpa/fpa2bv_converter.h b/src/ast/fpa/fpa2bv_converter.h index 247cfcacb..34417b7fc 100644 --- a/src/ast/fpa/fpa2bv_converter.h +++ b/src/ast/fpa/fpa2bv_converter.h @@ -56,7 +56,7 @@ protected: special_t m_min_max_specials; friend class fpa2bv_model_converter; - friend class bv2fpa_converter; + friend class bv2fpa_converter; public: fpa2bv_converter(ast_manager & m); @@ -138,11 +138,11 @@ public: 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_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_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 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; } @@ -227,9 +227,9 @@ private: 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); + 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 diff --git a/src/smt/theory_fpa.cpp b/src/smt/theory_fpa.cpp index 248d5b84d..3a45e1876 100644 --- a/src/smt/theory_fpa.cpp +++ b/src/smt/theory_fpa.cpp @@ -84,15 +84,15 @@ namespace smt { } } - theory_fpa::theory_fpa(ast_manager & m) : - theory(m.mk_family_id("fpa")), - m_converter(m, this), - m_rw(m, m_converter, params_ref()), - m_th_rw(m), - m_trail_stack(*this), - m_fpa_util(m_converter.fu()), - m_bv_util(m_converter.bu()), - m_arith_util(m_converter.au()), + theory_fpa::theory_fpa(ast_manager & m) : + theory(m.mk_family_id("fpa")), + m_converter(m, this), + m_rw(m, m_converter, params_ref()), + m_th_rw(m), + m_trail_stack(*this), + m_fpa_util(m_converter.fu()), + m_bv_util(m_converter.bu()), + m_arith_util(m_converter.au()), m_is_initialized(false) { params_ref p; @@ -799,33 +799,35 @@ namespace smt { } void theory_fpa::finalize_model(model_generator & mg) { +#if 0 ast_manager & m = get_manager(); proto_model & mdl = mg.get_model(); - proto_model new_model(m); - - bv2fpa_converter bv2fp(m, m_converter); - - obj_hashtable seen; - bv2fp.convert_min_max_specials(&mdl, &new_model, seen); - bv2fp.convert_uf2bvuf(&mdl, &new_model, seen); - - for (obj_hashtable::iterator it = seen.begin(); - it != seen.end(); - it++) - mdl.unregister_decl(*it); - - for (unsigned i = 0; i < new_model.get_num_constants(); i++) { - func_decl * f = new_model.get_constant(i); - mdl.register_decl(f, new_model.get_const_interp(f)); - } - - for (unsigned i = 0; i < new_model.get_num_functions(); i++) { - func_decl * f = new_model.get_function(i); - func_interp * fi = new_model.get_func_interp(f)->copy(); - mdl.register_decl(f, fi); - } + proto_model new_model(m); + + bv2fpa_converter bv2fp(m, m_converter); + + obj_hashtable seen; + bv2fp.convert_min_max_specials(&mdl, &new_model, seen); + bv2fp.convert_uf2bvuf(&mdl, &new_model, seen); + + for (obj_hashtable::iterator it = seen.begin(); + it != seen.end(); + it++) + mdl.unregister_decl(*it); + + for (unsigned i = 0; i < new_model.get_num_constants(); i++) { + func_decl * f = new_model.get_constant(i); + mdl.register_decl(f, new_model.get_const_interp(f)); + } + + for (unsigned i = 0; i < new_model.get_num_functions(); i++) { + func_decl * f = new_model.get_function(i); + func_interp * fi = new_model.get_func_interp(f)->copy(); + mdl.register_decl(f, fi); + } +#endif } - + void theory_fpa::display(std::ostream & out) const { ast_manager & m = get_manager(); diff --git a/src/tactic/fpa/fpa2bv_model_converter.cpp b/src/tactic/fpa/fpa2bv_model_converter.cpp index 9b95cf921..88224d2f2 100644 --- a/src/tactic/fpa/fpa2bv_model_converter.cpp +++ b/src/tactic/fpa/fpa2bv_model_converter.cpp @@ -22,52 +22,48 @@ Notes: void fpa2bv_model_converter::display(std::ostream & out) { out << "(fpa2bv-model-converter"; - m_bv2fp->display(out); + m_bv2fp->display(out); out << ")"; } model_converter * fpa2bv_model_converter::translate(ast_translation & translator) { - fpa2bv_model_converter * res = alloc(fpa2bv_model_converter, translator.to()); - res->m_bv2fp = m_bv2fp->translate(translator); + fpa2bv_model_converter * res = alloc(fpa2bv_model_converter, translator.to()); + res->m_bv2fp = m_bv2fp->translate(translator); return res; } void fpa2bv_model_converter::convert(model_core * mc, model * float_mdl) { - obj_hashtable seen; - m_bv2fp->convert_consts(mc, float_mdl, seen); - m_bv2fp->convert_rm_consts(mc, float_mdl, seen); - m_bv2fp->convert_min_max_specials(mc, float_mdl, seen); - m_bv2fp->convert_uf2bvuf(mc, float_mdl, seen); - - // Keep all the non-float constants. - unsigned sz = mc->get_num_constants(); - for (unsigned i = 0; i < sz; i++) - { - func_decl * c = mc->get_constant(i); - if (!seen.contains(c)) - float_mdl->register_decl(c, mc->get_const_interp(c)); - } - - // And keep everything else - sz = mc->get_num_functions(); - for (unsigned i = 0; i < sz; i++) - { - func_decl * f = mc->get_function(i); - if (!seen.contains(f)) - { - TRACE("fpa2bv_mc", tout << "Keeping: " << mk_ismt2_pp(f, m) << std::endl;); - func_interp * val = mc->get_func_interp(f)->copy(); - float_mdl->register_decl(f, val); - } - } - - sz = mc->get_num_uninterpreted_sorts(); - for (unsigned i = 0; i < sz; i++) - { - sort * s = mc->get_uninterpreted_sort(i); - ptr_vector u = mc->get_universe(s); - float_mdl->register_usort(s, u.size(), u.c_ptr()); - } + obj_hashtable seen; + m_bv2fp->convert_consts(mc, float_mdl, seen); + m_bv2fp->convert_rm_consts(mc, float_mdl, seen); + m_bv2fp->convert_min_max_specials(mc, float_mdl, seen); + m_bv2fp->convert_uf2bvuf(mc, float_mdl, seen); + + // Keep all the non-float constants. + unsigned sz = mc->get_num_constants(); + for (unsigned i = 0; i < sz; i++) { + func_decl * c = mc->get_constant(i); + if (!seen.contains(c)) + float_mdl->register_decl(c, mc->get_const_interp(c)); + } + + // And keep everything else + sz = mc->get_num_functions(); + for (unsigned i = 0; i < sz; i++) { + func_decl * f = mc->get_function(i); + if (!seen.contains(f)) { + TRACE("fpa2bv_mc", tout << "Keeping: " << mk_ismt2_pp(f, m) << std::endl;); + func_interp * val = mc->get_func_interp(f)->copy(); + float_mdl->register_decl(f, val); + } + } + + sz = mc->get_num_uninterpreted_sorts(); + for (unsigned i = 0; i < sz; i++) { + sort * s = mc->get_uninterpreted_sort(i); + ptr_vector u = mc->get_universe(s); + float_mdl->register_usort(s, u.size(), u.c_ptr()); + } } model_converter * mk_fpa2bv_model_converter(ast_manager & m, fpa2bv_converter & conv) { diff --git a/src/tactic/fpa/fpa2bv_model_converter.h b/src/tactic/fpa/fpa2bv_model_converter.h index 7a39c0fba..1f482478b 100644 --- a/src/tactic/fpa/fpa2bv_model_converter.h +++ b/src/tactic/fpa/fpa2bv_model_converter.h @@ -25,23 +25,22 @@ Notes: class fpa2bv_model_converter : public model_converter { ast_manager & m; - bv2fpa_converter * m_bv2fp; + bv2fpa_converter * m_bv2fp; public: - fpa2bv_model_converter(ast_manager & m, fpa2bv_converter & conv) : - m(m) { - m_bv2fp = alloc(bv2fpa_converter, m, conv); + fpa2bv_model_converter(ast_manager & m, fpa2bv_converter & conv): + m(m), + m_bv2fp(alloc(bv2fpa_converter, m, conv)) { } virtual ~fpa2bv_model_converter() { - if (m_bv2fp) dealloc(m_bv2fp); - m_bv2fp = 0; + dealloc(m_bv2fp); } virtual void operator()(model_ref & md, unsigned goal_idx) { SASSERT(goal_idx == 0); model * new_model = alloc(model, m); - convert(md.get(), new_model); + convert(md.get(), new_model); md = new_model; } @@ -56,9 +55,9 @@ public: protected: fpa2bv_model_converter(ast_manager & m) : m(m), - m_bv2fp(0) {} - - void convert(model_core * mc, model * float_mdl); + m_bv2fp(0) {} + + void convert(model_core * mc, model * float_mdl); }; diff --git a/src/test/get_consequences.cpp b/src/test/get_consequences.cpp index 9dc0b43f9..f35a12ede 100644 --- a/src/test/get_consequences.cpp +++ b/src/test/get_consequences.cpp @@ -8,6 +8,7 @@ Copyright (c) 2016 Microsoft Corporation #include "datatype_decl_plugin.h" #include "reg_decl_plugins.h" #include "ast_pp.h" +#include "dt2bv.h" //include static expr_ref mk_const(ast_manager& m, char const* name, sort* s) { @@ -72,6 +73,18 @@ static void test2() { g->assert_expr(m.mk_not(m.mk_eq(x, r))); g->assert_expr(m.mk_not(m.mk_eq(x, b))); g->display(std::cout); + tactic_ref dt2bv = mk_dt2bv_tactic(m); + goal_ref_buffer result; + model_converter_ref mc; + proof_converter_ref pc; + expr_dependency_ref core; + (*dt2bv)(g, result, mc, pc, core); + model_ref mdl1 = alloc(model, m); + model_ref mdl2 = (*mc)(*mdl1); + expr_ref val(m); + mdl2->eval(x, val); + std::cout << val << "\n"; + } void tst_get_consequences() { From 707dbd4173a6dff25d4b4212df64240406c01824 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Mon, 17 Oct 2016 16:19:27 +0100 Subject: [PATCH 11/26] Bugfix for bv2fpa (model) conversion. Relates to #740 --- src/ast/fpa/bv2fpa_converter.cpp | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/ast/fpa/bv2fpa_converter.cpp b/src/ast/fpa/bv2fpa_converter.cpp index fb3af396c..50f13aeee 100644 --- a/src/ast/fpa/bv2fpa_converter.cpp +++ b/src/ast/fpa/bv2fpa_converter.cpp @@ -316,13 +316,21 @@ void bv2fpa_converter::convert_consts(model_core * mc, model_core * target_model app * a2 = to_app(val->get_arg(2)); expr_ref v0(m), v1(m), v2(m); +#ifdef Z3DEBUG 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()); + 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); + 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); From 2f6ef0f3be4ba96dd09c7f1c7c13d88bc77f19c7 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Mon, 17 Oct 2016 16:33:09 +0100 Subject: [PATCH 12/26] Removed unnecessary variables. --- src/ast/fpa/fpa2bv_converter.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/ast/fpa/fpa2bv_converter.cpp b/src/ast/fpa/fpa2bv_converter.cpp index 05c45c925..da473f993 100644 --- a/src/ast/fpa/fpa2bv_converter.cpp +++ b/src/ast/fpa/fpa2bv_converter.cpp @@ -3295,8 +3295,6 @@ void fpa2bv_converter::mk_to_sbv(func_decl * f, unsigned num, expr * const * arg void fpa2bv_converter::mk_to_ubv_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(); unsigned width = m_bv_util.get_bv_size(f->get_range()); if (m_hi_fp_unspecified) @@ -3326,8 +3324,6 @@ expr_ref fpa2bv_converter::mk_to_ubv_unspecified(unsigned ebits, unsigned sbits, void fpa2bv_converter::mk_to_sbv_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(); unsigned width = m_bv_util.get_bv_size(f->get_range()); if (m_hi_fp_unspecified) @@ -3339,7 +3335,7 @@ void fpa2bv_converter::mk_to_sbv_unspecified(func_decl * f, unsigned num, expr * m_uf2bvuf.insert(f, fd); m.inc_ref(f); m.inc_ref(fd); - } + } result = m.mk_const(fd); } From 4ef55505e7f8ca5b35b88ec1c2e1a2c331460d40 Mon Sep 17 00:00:00 2001 From: Dan Liew Date: Mon, 17 Oct 2016 17:12:04 +0100 Subject: [PATCH 13/26] [CMake] Fix #763 reported by @jirislaby. `INTERFACE` was the not appropriate usage requirement to use. However it only caused a problem when USE_LIB_GMP was enabled. With `INTERFACE` `-lgmp` was not specified on the link line so `libz3.so` did not have a reference to the library and linking against `libz3.so` by clients would fail with missing references to symbols in `libgmp`. --- contrib/cmake/src/CMakeLists.txt | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/contrib/cmake/src/CMakeLists.txt b/contrib/cmake/src/CMakeLists.txt index cba30c46f..f12c56f8e 100644 --- a/contrib/cmake/src/CMakeLists.txt +++ b/contrib/cmake/src/CMakeLists.txt @@ -136,9 +136,10 @@ if (NOT MSVC) set_target_properties(libz3 PROPERTIES OUTPUT_NAME z3) endif() -# Using INTERFACE means that targets that try link against libz3 will -# automatically link against the libs in Z3_DEPENDENT_LIBS -target_link_libraries(libz3 INTERFACE ${Z3_DEPENDENT_LIBS}) +# The `PRIVATE` usage requirement is specified so that when building Z3 as a +# shared library the dependent libraries are specified on the link command line +# so that if those are also shared libraries they are referenced by `libz3.so`. +target_link_libraries(libz3 PRIVATE ${Z3_DEPENDENT_LIBS}) z3_append_linker_flag_list_to_target(libz3 ${Z3_DEPENDENT_EXTRA_CXX_LINK_FLAGS}) From 03071db3eda047743442f1160af28f223ddb6608 Mon Sep 17 00:00:00 2001 From: Dan Liew Date: Mon, 17 Oct 2016 18:00:08 +0100 Subject: [PATCH 14/26] [CMake] Fix building the examples when libz3 is built as a static library. --- contrib/cmake/examples/c++/CMakeLists.txt | 5 +++++ contrib/cmake/examples/c/CMakeLists.txt | 6 ++++++ 2 files changed, 11 insertions(+) diff --git a/contrib/cmake/examples/c++/CMakeLists.txt b/contrib/cmake/examples/c++/CMakeLists.txt index 85bbd77c7..fdc5cf387 100644 --- a/contrib/cmake/examples/c++/CMakeLists.txt +++ b/contrib/cmake/examples/c++/CMakeLists.txt @@ -1,4 +1,9 @@ +# FIXME: We should build this as an external project and consume +# Z3 as `find_package(z3 CONFIG)`. add_executable(cpp_example EXCLUDE_FROM_ALL example.cpp) target_link_libraries(cpp_example PRIVATE libz3) target_include_directories(cpp_example PRIVATE "${CMAKE_SOURCE_DIR}/src/api") target_include_directories(cpp_example PRIVATE "${CMAKE_SOURCE_DIR}/src/api/c++") +if (NOT BUILD_LIBZ3_SHARED) + z3_append_linker_flag_list_to_target(cpp_example ${Z3_DEPENDENT_EXTRA_CXX_LINK_FLAGS}) +endif() diff --git a/contrib/cmake/examples/c/CMakeLists.txt b/contrib/cmake/examples/c/CMakeLists.txt index 1a14573ac..fc6eaee18 100644 --- a/contrib/cmake/examples/c/CMakeLists.txt +++ b/contrib/cmake/examples/c/CMakeLists.txt @@ -1,3 +1,9 @@ +# FIXME: We should build this as an external project and consume +# Z3 as `find_package(z3 CONFIG)`. add_executable(c_example EXCLUDE_FROM_ALL test_capi.c) target_link_libraries(c_example PRIVATE libz3) target_include_directories(c_example PRIVATE "${CMAKE_SOURCE_DIR}/src/api") +# This is needed for when libz3 is built as a static library +if (NOT BUILD_LIBZ3_SHARED) + z3_append_linker_flag_list_to_target(c_example ${Z3_DEPENDENT_EXTRA_C_LINK_FLAGS}) +endif() From 462d3e8e8b6ac0f8319bd0f8e73aa82e85d02e1a Mon Sep 17 00:00:00 2001 From: Dan Liew Date: Mon, 17 Oct 2016 18:15:31 +0100 Subject: [PATCH 15/26] [CMake] Unbreak building the .NET bindings. 7fefe40f210300dc073c93b2889be274bd92da62 broke building the .NET bindings by renaming the signing key without updating the CMake build. --- contrib/cmake/src/api/dotnet/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/cmake/src/api/dotnet/CMakeLists.txt b/contrib/cmake/src/api/dotnet/CMakeLists.txt index 7440f021b..93f5929d9 100644 --- a/contrib/cmake/src/api/dotnet/CMakeLists.txt +++ b/contrib/cmake/src/api/dotnet/CMakeLists.txt @@ -156,7 +156,7 @@ elseif (DOTNET_TOOLCHAIN_IS_MONO) # We need to give the assembly a strong name so that it can be installed # into the GAC. list(APPEND CSC_FLAGS - "/keyfile:${CMAKE_CURRENT_SOURCE_DIR}/Microsoft.Z3.mono.snk" + "/keyfile:${CMAKE_CURRENT_SOURCE_DIR}/Microsoft.Z3.snk" ) else() message(FATAL_ERROR "Unknown .NET toolchain") From 289e51f4557baebb08ea37f951bf92fc01b3c1ef Mon Sep 17 00:00:00 2001 From: Dan Liew Date: Mon, 17 Oct 2016 18:30:49 +0100 Subject: [PATCH 16/26] [CMake] Fix building the Java bindings. This was broken due to 495ef0f055f300089ec57f7aa71c2cc48d0fd402 and a914822346179531cf36c79809e5f01842267c84 adding and removing source files without updating the CMake build. --- contrib/cmake/src/api/java/CMakeLists.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/contrib/cmake/src/api/java/CMakeLists.txt b/contrib/cmake/src/api/java/CMakeLists.txt index 6e16ddb74..b34277266 100644 --- a/contrib/cmake/src/api/java/CMakeLists.txt +++ b/contrib/cmake/src/api/java/CMakeLists.txt @@ -110,7 +110,9 @@ set(Z3_JAVA_JAR_SOURCE_FILES BitVecSort.java BoolExpr.java BoolSort.java + ConstructorDecRefQueue.java Constructor.java + ConstructorListDecRefQueue.java ConstructorList.java Context.java DatatypeExpr.java @@ -136,7 +138,6 @@ set(Z3_JAVA_JAR_SOURCE_FILES GoalDecRefQueue.java Goal.java IDecRefQueue.java - IDisposable.java InterpolationContext.java IntExpr.java IntNum.java From 9e4450228eb4537e7cf87192c53ba4bcb69107bb Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 17 Oct 2016 14:52:37 -0400 Subject: [PATCH 17/26] adding unit test for enumeration types Signed-off-by: Nikolaj Bjorner --- src/ast/ast_smt2_pp.cpp | 5 ++- src/tactic/bv/dt2bv_tactic.cpp | 16 +++++--- src/tactic/bv/dt2bv_tactic.h | 3 +- src/test/get_consequences.cpp | 74 ++++++++++++++++++++++++++-------- 4 files changed, 74 insertions(+), 24 deletions(-) diff --git a/src/ast/ast_smt2_pp.cpp b/src/ast/ast_smt2_pp.cpp index 2e2d99a38..98c3b7962 100644 --- a/src/ast/ast_smt2_pp.cpp +++ b/src/ast/ast_smt2_pp.cpp @@ -1205,13 +1205,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); diff --git a/src/tactic/bv/dt2bv_tactic.cpp b/src/tactic/bv/dt2bv_tactic.cpp index e8763475b..ab9df78ad 100644 --- a/src/tactic/bv/dt2bv_tactic.cpp +++ b/src/tactic/bv/dt2bv_tactic.cpp @@ -43,6 +43,7 @@ class dt2bv_tactic : public tactic { ref m_ext; ref m_filter; unsigned m_num_translated; + obj_map* m_translate; struct rw_cfg : public default_rewriter_cfg { dt2bv_tactic& m_t; @@ -117,7 +118,7 @@ class dt2bv_tactic : public tactic { unsigned nc = m_t.m_dt.get_datatype_num_constructors(s); result = m.mk_fresh_const(f->get_name().str().c_str(), m_t.m_bv.mk_sort(bv_size)); if (!is_power_of_two(nc)) { - m_t.m_bounds.push_back(m_t.m_bv.mk_ule(result, m_t.m_bv.mk_numeral(nc, bv_size))); + m_t.m_bounds.push_back(m_t.m_bv.mk_ule(result, m_t.m_bv.mk_numeral(nc-1, bv_size))); } expr_ref f_def(m); ptr_vector const& cs = *m_t.m_dt.get_datatype_constructors(s); @@ -129,6 +130,9 @@ class dt2bv_tactic : public tactic { // update model converters. m_t.m_ext->insert(f, f_def); m_t.m_filter->insert(to_app(result)->get_decl()); + if (m_t.m_translate) { + m_t.m_translate->insert(f, result); + } } else { return false; @@ -253,11 +257,11 @@ class dt2bv_tactic : public tactic { public: - dt2bv_tactic(ast_manager& m, params_ref const& p): - m(m), m_params(p), m_dt(m), m_bv(m), m_bounds(m) {} + dt2bv_tactic(ast_manager& m, params_ref const& p, obj_map* tr): + m(m), m_params(p), m_dt(m), m_bv(m), m_bounds(m), m_translate(tr) {} virtual tactic * translate(ast_manager & m) { - return alloc(dt2bv_tactic, m, m_params); + return alloc(dt2bv_tactic, m, m_params, 0); } virtual void updt_params(params_ref const & p) { @@ -320,6 +324,6 @@ public: }; -tactic * mk_dt2bv_tactic(ast_manager & m, params_ref const & p) { - return alloc(dt2bv_tactic, m, p); +tactic * mk_dt2bv_tactic(ast_manager & m, params_ref const & p, obj_map* tr) { + return alloc(dt2bv_tactic, m, p, tr); } diff --git a/src/tactic/bv/dt2bv_tactic.h b/src/tactic/bv/dt2bv_tactic.h index 64d1d5497..a8fb33fe8 100644 --- a/src/tactic/bv/dt2bv_tactic.h +++ b/src/tactic/bv/dt2bv_tactic.h @@ -20,10 +20,11 @@ Revision History: #define DT2BV_TACTIC_H_ #include"params.h" +#include"obj_hashtable.h" class ast_manager; class tactic; -tactic * mk_dt2bv_tactic(ast_manager & m, params_ref const & p = params_ref()); +tactic * mk_dt2bv_tactic(ast_manager & m, params_ref const & p = params_ref(), obj_map* tr = 0); /* ADD_TACTIC("dt2bv", "eliminate finite domain data-types. Replace by bit-vectors.", "mk_dt2bv_tactic(m, p)") diff --git a/src/test/get_consequences.cpp b/src/test/get_consequences.cpp index f35a12ede..24f3a5d38 100644 --- a/src/test/get_consequences.cpp +++ b/src/test/get_consequences.cpp @@ -8,7 +8,9 @@ Copyright (c) 2016 Microsoft Corporation #include "datatype_decl_plugin.h" #include "reg_decl_plugins.h" #include "ast_pp.h" -#include "dt2bv.h" +#include "dt2bv_tactic.h" +#include "tactic.h" +#include "model_smt2_pp.h" //include static expr_ref mk_const(ast_manager& m, char const* name, sort* s) { @@ -53,38 +55,78 @@ static void test2() { ast_manager m; reg_decl_plugins(m); bv_util bv(m); + datatype_util dtutil(m); + params_ref p; - datatype_decl_plugin& dt = static_cast(*m.get_plugin(m.get_family_id("datatype"))); + datatype_decl_plugin & dt = *(static_cast(m.get_plugin(m.get_family_id("datatype")))); sort_ref_vector new_sorts(m); constructor_decl* R = mk_constructor_decl(symbol("R"), symbol("is-R"), 0, 0); constructor_decl* G = mk_constructor_decl(symbol("G"), symbol("is-G"), 0, 0); constructor_decl* B = mk_constructor_decl(symbol("B"), symbol("is-B"), 0, 0); constructor_decl* constrs[3] = { R, G, B }; - datatype_decl const* enum_sort = mk_datatype_decl(symbol("RGB"), 3, constrs); + datatype_decl * enum_sort = mk_datatype_decl(symbol("RGB"), 3, constrs); VERIFY(dt.mk_datatypes(1, &enum_sort, new_sorts)); del_constructor_decls(3, constrs); sort* rgb = new_sorts[0].get(); expr_ref x = mk_const(m, "x", rgb), y = mk_const(m, "y", rgb), z = mk_const(m, "z", rgb); - ptr_vector const& enums = dt.geet_datatype_constructors(rgb); - expr_ref r = expr_ref(m.mk_const(enums[0], m), m), g = expr_ref(m.mk_const(enums[1], m), m), b = expr_ref(m.mk_const(enums[2], m), m); + ptr_vector const& enums = *dtutil.get_datatype_constructors(rgb); + expr_ref r = expr_ref(m.mk_const(enums[0]), m); + expr_ref g = expr_ref(m.mk_const(enums[1]), m); + expr_ref b = expr_ref(m.mk_const(enums[2]), m); + expr_ref val(m); - goal_ref g = alloc(goal, m); - g->assert_expr(m.mk_not(m.mk_eq(x, r))); - g->assert_expr(m.mk_not(m.mk_eq(x, b))); - g->display(std::cout); - tactic_ref dt2bv = mk_dt2bv_tactic(m); + // Eliminate enumeration data-types: + goal_ref gl = alloc(goal, m); + gl->assert_expr(m.mk_not(m.mk_eq(x, r))); + gl->assert_expr(m.mk_not(m.mk_eq(x, b))); + gl->display(std::cout); + obj_map tr; + obj_map rev_tr; + ref dt2bv = mk_dt2bv_tactic(m, p, &tr); goal_ref_buffer result; model_converter_ref mc; proof_converter_ref pc; - expr_dependency_ref core; - (*dt2bv)(g, result, mc, pc, core); - model_ref mdl1 = alloc(model, m); - model_ref mdl2 = (*mc)(*mdl1); - expr_ref val(m); - mdl2->eval(x, val); + expr_dependency_ref core(m); + (*dt2bv)(gl, result, mc, pc, core); + + // Collect translations from enumerations to bit-vectors + obj_map::iterator it = tr.begin(), end = tr.end(); + for (; it != end; ++it) { + rev_tr.insert(it->m_value, it->m_key); + } + + // Create bit-vector implication problem + val = tr.find(to_app(x)->get_decl()); std::cout << val << "\n"; + ptr_vector fmls; + result[0]->get_formulas(fmls); + ref solver = mk_inc_sat_solver(m, p); + for (unsigned i = 0; i < fmls.size(); ++i) { + solver->assert_expr(fmls[i]); + } + expr_ref_vector asms(m), vars(m), conseq(m); + vars.push_back(val); + + // retrieve consequences + solver->get_consequences(asms, vars, conseq); + // Convert consequences over bit-vectors to enumeration types. + std::cout << conseq << "\n"; + for (unsigned i = 0; i < conseq.size(); ++i) { + expr* a, *b, *u, *v; + func_decl* f; + rational num; + unsigned bvsize; + VERIFY(m.is_implies(conseq[i].get(), a, b)); + if (m.is_eq(b, u, v) && rev_tr.find(u, f) && bv.is_numeral(v, num, bvsize)) { + SASSERT(num.is_unsigned()); + expr_ref head(m); + head = m.mk_eq(m.mk_const(f), m.mk_const(enums[num.get_unsigned()])); + conseq[i] = m.mk_implies(a, head); + } + } + std::cout << conseq << "\n"; } void tst_get_consequences() { From 5ac3bb04eef80de3edf9d495612228055e02857e Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Tue, 18 Oct 2016 13:18:59 +0100 Subject: [PATCH 18/26] Tabs --- src/ast/fpa/bv2fpa_converter.cpp | 826 +++++++++++++++---------------- src/ast/fpa/bv2fpa_converter.h | 74 +-- src/ast/fpa/fpa2bv_converter.cpp | 162 +++--- 3 files changed, 531 insertions(+), 531 deletions(-) diff --git a/src/ast/fpa/bv2fpa_converter.cpp b/src/ast/fpa/bv2fpa_converter.cpp index 50f13aeee..07a24e40a 100644 --- a/src/ast/fpa/bv2fpa_converter.cpp +++ b/src/ast/fpa/bv2fpa_converter.cpp @@ -1,17 +1,17 @@ /*++ - Copyright (c) 2012 Microsoft Corporation + Copyright (c) 2012 Microsoft Corporation Module Name: - bv2fpa_converter.cpp + bv2fpa_converter.cpp Abstract: - Model conversion for fpa2bv_converter + Model conversion for fpa2bv_converter Author: - Christoph (cwinter) 2016-10-15 + Christoph (cwinter) 2016-10-15 Notes: @@ -27,299 +27,299 @@ Notes: bv2fpa_converter::bv2fpa_converter(ast_manager & m) : - m(m), - m_fpa_util(m), - m_bv_util(m), - m_th_rw(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::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::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::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 >::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); - } + m(m), + m_fpa_util(m), + m_bv_util(m), + m_th_rw(m) { + for (obj_map::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::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::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 >::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 >::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); - } + 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 >::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(); + 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; + expr_ref res(m); + mpf fp_val; - unsigned ebits = m_fpa_util.get_ebits(s); - unsigned sbits = m_fpa_util.get_sbits(s); + 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; + unsigned sgn_sz = 1; + unsigned exp_sz = ebits; + unsigned sig_sz = sbits - 1; - rational sgn_q(0), sig_q(0), exp_q(0); + 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); + 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); + // 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()); + 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); + m_fpa_util.fm().set(fp_val, ebits, sbits, !mpqm.is_zero(sgn_q.to_mpq()), exp_z, sig_z); - mpzm.del(sig_z); + mpzm.del(sig_z); - res = m_fpa_util.mk_value(fp_val); + 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); + 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; + return res; } expr_ref bv2fpa_converter::convert_bv2fp(model_core * mc, sort * s, app * bv) { - SASSERT(m_bv_util.is_bv(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; + 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 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 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); + 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); + 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; + 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(); - } - } + 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; + return res; } expr_ref bv2fpa_converter::convert_bv2rm(model_core * mc, app * val) { - expr_ref res(m); + 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(); - } + 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; + 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; ); + 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()); - } + 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; + 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); + 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; + 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()); + 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)); + 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; + 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(); + 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); + 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); + 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 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); - } + 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); - } + 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); - } + 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; + return result; } void bv2fpa_converter::convert_consts(model_core * mc, model_core * target_model, obj_hashtable & seen) { - for (obj_map::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()); + for (obj_map::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)); - app * a1 = to_app(val->get_arg(1)); - app * a2 = to_app(val->get_arg(2)); + app * a0 = to_app(val->get_arg(0)); + app * a1 = to_app(val->get_arg(1)); + app * a2 = to_app(val->get_arg(2)); - expr_ref v0(m), v1(m), v2(m); + expr_ref v0(m), v1(m), v2(m); #ifdef Z3DEBUG - v0 = mc->get_const_interp(a0->get_decl()); - v1 = mc->get_const_interp(a1->get_decl()); - v2 = mc->get_const_interp(a2->get_decl()); + 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()); unsigned bv_sz = m_bv_util.get_bv_size(bv); @@ -332,220 +332,220 @@ void bv2fpa_converter::convert_consts(model_core * mc, model_core * target_model 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); + 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)); + 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()); + 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()); + 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; + if (!sgn && !sig && !exp) + continue; - expr_ref cv(m); - cv = convert_bv2fp(var->get_range(), sgn, exp, sig); - target_model->register_decl(var, cv); + 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;); - } + 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 & seen) { - for (obj_map::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()); - } + for (obj_map::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 & seen) { - for (obj_map >::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; + for (obj_map >::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 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()); + 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); + 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); + 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;); - } + 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 & seen) { - for (obj_map::iterator it = m_uf2bvuf.begin(); - it != m_uf2bvuf.end(); - it++) { - seen.insert(it->m_value); + for (obj_map::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); - } - } + 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::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::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::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 >::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 << ")"; + out << "(fpa2bv-model-converter"; + for (obj_map::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::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::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 >::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::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::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::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 >::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(v1, v2)); - translator.to().inc_ref(k); - translator.to().inc_ref(v1); - translator.to().inc_ref(v2); - } - return res; + bv2fpa_converter * res = alloc(bv2fpa_converter, translator.to()); + for (obj_map::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::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::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 >::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(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; - }); + 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; + }); } \ No newline at end of file diff --git a/src/ast/fpa/bv2fpa_converter.h b/src/ast/fpa/bv2fpa_converter.h index c441ea6ff..5150056c4 100644 --- a/src/ast/fpa/bv2fpa_converter.h +++ b/src/ast/fpa/bv2fpa_converter.h @@ -1,17 +1,17 @@ /*++ - Copyright (c) 2016 Microsoft Corporation + Copyright (c) 2016 Microsoft Corporation Module Name: - bv2fpa_converter.h + bv2fpa_converter.h Abstract: - Model conversion for fpa2bv_converter + Model conversion for fpa2bv_converter Author: - Christoph (cwinter) 2016-10-15 + Christoph (cwinter) 2016-10-15 Notes: @@ -27,48 +27,48 @@ Notes: class bv2fpa_converter { - ast_manager & m; - fpa_util m_fpa_util; - bv_util m_bv_util; - th_rewriter m_th_rw; + ast_manager & m; + fpa_util m_fpa_util; + bv_util m_bv_util; + th_rewriter m_th_rw; - obj_map m_const2bv; - obj_map m_rm_const2bv; - obj_map m_uf2bvuf; - obj_map > m_specials; + obj_map m_const2bv; + obj_map m_rm_const2bv; + obj_map m_uf2bvuf; + obj_map > m_specials; public: - bv2fpa_converter(ast_manager & m); - bv2fpa_converter(ast_manager & m, fpa2bv_converter & conv); - virtual ~bv2fpa_converter(); + 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); + 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); + 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 & seen); - void convert_rm_consts(model_core * mc, model_core * target_model, obj_hashtable & seen); - void convert_min_max_specials(model_core * mc, model_core * target_model, obj_hashtable & seen); - void convert_uf2bvuf(model_core * mc, model_core * target_model, obj_hashtable & seen); + void convert(model_core * mc, model_core * float_mdl); + void convert_consts(model_core * mc, model_core * target_model, obj_hashtable & seen); + void convert_rm_consts(model_core * mc, model_core * target_model, obj_hashtable & seen); + void convert_min_max_specials(model_core * mc, model_core * target_model, obj_hashtable & seen); + void convert_uf2bvuf(model_core * mc, model_core * target_model, obj_hashtable & 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); + 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) {} - }; + 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); + array_model convert_array_func_interp(model_core * mc, func_decl * f, func_decl * bv_f); }; #endif \ No newline at end of file diff --git a/src/ast/fpa/fpa2bv_converter.cpp b/src/ast/fpa/fpa2bv_converter.cpp index da473f993..ba6d436cc 100644 --- a/src/ast/fpa/fpa2bv_converter.cpp +++ b/src/ast/fpa/fpa2bv_converter.cpp @@ -3074,9 +3074,9 @@ void fpa2bv_converter::mk_to_ieee_bv(func_decl * f, unsigned num, expr * const * m_bv_util.mk_concat(m_bv_util.mk_numeral(0, sbits - 2), m_bv_util.mk_numeral(1, 1)))); 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); + 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); @@ -3126,42 +3126,42 @@ void fpa2bv_converter::mk_to_ieee_bv_unspecified(func_decl * f, unsigned num, ex } void fpa2bv_converter::mk_to_bv(func_decl * f, unsigned num, expr * const * args, bool is_signed, expr_ref & result) { - TRACE("fpa2bv_to_bv", for (unsigned i = 0; i < num; i++) - tout << "arg" << i << " = " << mk_ismt2_pp(args[i], m) << std::endl;); + TRACE("fpa2bv_to_bv", for (unsigned i = 0; i < num; i++) + tout << "arg" << i << " = " << mk_ismt2_pp(args[i], m) << std::endl;); - SASSERT(num == 2); - SASSERT(m_util.is_bv2rm(args[0])); - SASSERT(m_util.is_float(args[1])); + SASSERT(num == 2); + SASSERT(m_util.is_bv2rm(args[0])); + SASSERT(m_util.is_float(args[1])); - expr * rm = to_app(args[0])->get_arg(0); - expr * x = args[1]; - sort * xs = m.get_sort(x); - sort * bv_srt = f->get_range(); + expr * rm = to_app(args[0])->get_arg(0); + expr * x = args[1]; + sort * xs = m.get_sort(x); + sort * bv_srt = f->get_range(); - unsigned ebits = m_util.get_ebits(xs); - unsigned sbits = m_util.get_sbits(xs); - unsigned bv_sz = (unsigned)f->get_parameter(0).get_int(); + unsigned ebits = m_util.get_ebits(xs); + unsigned sbits = m_util.get_sbits(xs); + unsigned bv_sz = (unsigned)f->get_parameter(0).get_int(); - expr_ref bv0(m), bv1(m); - bv1 = m_bv_util.mk_numeral(1, 1); + expr_ref bv0(m), bv1(m); + bv1 = m_bv_util.mk_numeral(1, 1); - expr_ref x_is_nan(m), x_is_inf(m), x_is_zero(m), x_is_neg(m), x_is_nzero(m); - mk_is_nan(x, x_is_nan); - mk_is_inf(x, x_is_inf); - mk_is_zero(x, x_is_zero); - mk_is_neg(x, x_is_neg); - mk_is_nzero(x, x_is_nzero); + expr_ref x_is_nan(m), x_is_inf(m), x_is_zero(m), x_is_neg(m), x_is_nzero(m); + mk_is_nan(x, x_is_nan); + mk_is_inf(x, x_is_inf); + mk_is_zero(x, x_is_zero); + mk_is_neg(x, x_is_neg); + mk_is_nzero(x, x_is_nzero); - // NaN, Inf, or negative (except -0) -> unspecified - expr_ref c1(m), v1(m); - 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))); - v1 = mk_to_ubv_unspecified(ebits, sbits, bv_sz); - } - else { - c1 = m.mk_or(x_is_nan, x_is_inf); - v1 = mk_to_sbv_unspecified(ebits, sbits, bv_sz); - } + // NaN, Inf, or negative (except -0) -> unspecified + expr_ref c1(m), v1(m); + 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))); + v1 = mk_to_ubv_unspecified(ebits, sbits, bv_sz); + } + else { + c1 = m.mk_or(x_is_nan, x_is_inf); + v1 = mk_to_sbv_unspecified(ebits, sbits, bv_sz); + } dbg_decouple("fpa2bv_to_bv_c1", c1); // +-Zero -> 0 @@ -3272,7 +3272,7 @@ void fpa2bv_converter::mk_to_bv(func_decl * f, unsigned num, expr * const * args expr_ref unspec(m); unspec = is_signed ? mk_to_sbv_unspecified(ebits, sbits, bv_sz) : - mk_to_ubv_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); @@ -3294,61 +3294,61 @@ void fpa2bv_converter::mk_to_sbv(func_decl * f, unsigned num, expr * const * arg } 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()); + 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); - } + 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_ubv_unspecified", tout << "result=" << mk_ismt2_pp(result, m) << std::endl;); - SASSERT(is_well_sorted(m, 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; + 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()); + 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); - } + 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)); + 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 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 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; } void fpa2bv_converter::mk_to_real_unspecified(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { @@ -3367,11 +3367,11 @@ void fpa2bv_converter::mk_to_real_unspecified(func_decl * f, unsigned num, expr } 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; + 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) { From 948a1e600e453a76f5293d54a807d630650da5b9 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 18 Oct 2016 10:27:47 -0400 Subject: [PATCH 19/26] undo breaking commit Signed-off-by: Nikolaj Bjorner --- src/smt/theory_fpa.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/smt/theory_fpa.cpp b/src/smt/theory_fpa.cpp index 3a45e1876..b0b8ffff5 100644 --- a/src/smt/theory_fpa.cpp +++ b/src/smt/theory_fpa.cpp @@ -799,7 +799,6 @@ namespace smt { } void theory_fpa::finalize_model(model_generator & mg) { -#if 0 ast_manager & m = get_manager(); proto_model & mdl = mg.get_model(); proto_model new_model(m); @@ -825,7 +824,6 @@ namespace smt { func_interp * fi = new_model.get_func_interp(f)->copy(); mdl.register_decl(f, fi); } -#endif } void theory_fpa::display(std::ostream & out) const From 9fef51553c728b02b0de2f17f4be588608ee1e44 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Tue, 18 Oct 2016 17:15:43 +0100 Subject: [PATCH 20/26] Whitespace --- src/smt/theory_arith_nl.h | 390 +++++++++++++++++++------------------- 1 file changed, 195 insertions(+), 195 deletions(-) diff --git a/src/smt/theory_arith_nl.h b/src/smt/theory_arith_nl.h index 311a62a38..c3ae8c99b 100644 --- a/src/smt/theory_arith_nl.h +++ b/src/smt/theory_arith_nl.h @@ -23,9 +23,9 @@ Revision History: namespace smt { - template + template expr * theory_arith::mk_nary_mul(unsigned sz, expr * const * args, bool is_int) { - if (sz == 0) + if (sz == 0) return m_util.mk_numeral(rational(1), is_int); if (sz == 1) return args[0]; @@ -36,21 +36,21 @@ namespace smt { return m_util.mk_mul(sz, args); } - template + template expr * theory_arith::mk_nary_add(unsigned sz, expr * const * args, bool is_int) { - if (sz == 0) + if (sz == 0) return m_util.mk_numeral(rational(0), is_int); if (sz == 1) return args[0]; return m_util.mk_add(sz, args); } - template + template expr * theory_arith::mk_nary_add(unsigned sz, expr * const * args) { SASSERT(sz != 0); return mk_nary_add(sz, args, false); } - + /** \brief Insert v into vars and already_found if v is not already in already_found. */ @@ -92,21 +92,21 @@ namespace smt { theory_var s = r.get_base_var(); // ignore quasi base vars... actually they should not be used if the problem is non linear... if (is_quasi_base(s)) - continue; + continue; // If s is a base variable different from v and it is free, then this row can be ignored. // It doesn't need to be part of the non linear cluster. For all purposes, this variable // was eliminated by substitution. if (is_free(s) && s != v) - continue; + continue; typename vector::const_iterator it2 = r.begin_entries(); typename vector::const_iterator end2 = r.end_entries(); - for (; it2 != end2; ++it2) { - if (!it2->is_dead() && !is_fixed(it2->m_var)) + for (; it2 != end2; ++it2) { + if (!it2->is_dead() && !is_fixed(it2->m_var)) mark_var(it2->m_var, vars, already_found); } } } - + /** \brief Store in vars the variables that are in the non linear cluster of constraints, and are not satisfied by the current assignment. @@ -123,7 +123,7 @@ namespace smt { for (; it != end; ++it) { theory_var v = *it; expr * n = var2expr(v); - if (ctx.is_relevant(n)) + if (ctx.is_relevant(n)) mark_var(v, vars, already_found); } for (unsigned idx = 0; idx < vars.size(); idx++) { @@ -134,7 +134,7 @@ namespace smt { svector::const_iterator it = vars.begin(); svector::const_iterator end = vars.end(); for (; it != end; ++it) tout << "v" << *it << " "; - tout << "\n";); + tout << "\n";); } /** @@ -148,7 +148,7 @@ namespace smt { \remark if a variables has an even number of occurrences, then I consider that it has a bound associated with it. - + Examples: 1) Assume x1, x4 have bounds: analyze_monomial(x1 * x2 * x2 * x3 * x3 * x3 * x4) @@ -168,24 +168,24 @@ namespace smt { int idx = 0; for (unsigned i = 0; i < to_app(m)->get_num_args(); i++) { expr * arg = to_app(m)->get_arg(i); - if (var == 0) { - var = arg; - power = 1; - } - else if (arg == var) { - power++; - } - else { - if (power % 2 == 1 && is_free(var)) { - c++; - free_var_idx = idx; - if (c > 1) - return std::make_pair(2, free_var_idx); - } - var = arg; - power = 1; - idx++; - } + if (var == 0) { + var = arg; + power = 1; + } + else if (arg == var) { + power++; + } + else { + if (power % 2 == 1 && is_free(var)) { + c++; + free_var_idx = idx; + if (c > 1) + return std::make_pair(2, free_var_idx); + } + var = arg; + power = 1; + idx++; + } } if (power % 2 == 1 && is_free(var)) { c++; @@ -257,17 +257,17 @@ namespace smt { unsigned j; for (j = 0; j < to_app(m)->get_num_args(); j++) { expr * arg = to_app(m)->get_arg(j); - if (var == 0) { - var = arg; - power = 1; - } - else if (var == arg) { - power++; - } - else { - if (curr_idx == i) - return var_power_pair(var, power); - curr_idx++; + if (var == 0) { + var = arg; + power = 1; + } + else if (var == arg) { + power++; + } + else { + if (curr_idx == i) + return var_power_pair(var, power); + curr_idx++; var = arg; power = 1; } @@ -289,24 +289,24 @@ namespace smt { bound * l = lower(v); bound * u = upper(v); if (l && u) { - return interval(m_dep_manager, - l->get_value().get_rational().to_rational(), + return interval(m_dep_manager, + l->get_value().get_rational().to_rational(), !l->get_value().get_infinitesimal().to_rational().is_zero(), m_dep_manager.mk_leaf(l), - u->get_value().get_rational().to_rational(), + u->get_value().get_rational().to_rational(), !u->get_value().get_infinitesimal().to_rational().is_zero(), m_dep_manager.mk_leaf(u)); } else if (l) { return interval(m_dep_manager, - l->get_value().get_rational().to_rational(), + l->get_value().get_rational().to_rational(), !l->get_value().get_infinitesimal().to_rational().is_zero(), true, m_dep_manager.mk_leaf(l)); } else if (u) { return interval(m_dep_manager, - u->get_value().get_rational().to_rational(), + u->get_value().get_rational().to_rational(), !u->get_value().get_infinitesimal().to_rational().is_zero(), false, m_dep_manager.mk_leaf(u)); @@ -333,12 +333,12 @@ namespace smt { void theory_arith::mul_bound_of(expr * var, unsigned power, interval & target) { theory_var v = expr2var(var); interval i = mk_interval_for(v); - - TRACE("non_linear", + + TRACE("non_linear", display_interval(tout << "bound: ",i); tout << i << "\n"; tout << mk_pp(var, get_manager()) << "\n"; tout << "power " << power << ": " << expt(i, power) << "\n"; - display_interval(tout << "target before: ", target); tout << "\n";); + display_interval(tout << "target before: ", target); tout << "\n";); i.expt(power); target *= i; TRACE("non_linear", display_interval(tout << "target after: ", target); tout << "\n";); @@ -348,7 +348,7 @@ namespace smt { \brief Evaluate the given expression using interval arithmetic. - If a subexpression is internalized, then mk_interval_for is used to - compute its interval. + compute its interval. - Only +, *, and numerals are handled. */ @@ -382,7 +382,7 @@ namespace smt { interval it = evaluate_as_interval(var); it.expt(power); r *= it; - } + } TRACE("cross_nested_eval_bug", display_nested_form(tout, n); tout << "\ninterval: " << r << "\n";); return r; } @@ -424,7 +424,7 @@ namespace smt { ptr_vector::const_iterator end = bounds.end(); for (; it != end; ++it) { bound * b = static_cast(*it); - accumulate_justification(*b, new_bound, numeral::zero(), m_tmp_lit_set, m_tmp_eq_set); + accumulate_justification(*b, new_bound, numeral::zero(), m_tmp_lit_set, m_tmp_eq_set); } } @@ -476,7 +476,7 @@ namespace smt { } return r; } - + template bool theory_arith::update_bounds_using_interval(expr * n, interval const & i) { SASSERT(expr2var(n) != null_theory_var); @@ -510,7 +510,7 @@ namespace smt { } /** - \brief Propagate a bound to the i-th variable of the given monomial + \brief Propagate a bound to the i-th variable of the given monomial using the bounds of m and other variables in m. \remark We do not support roots in interval... so, if the i-th var has power != 1 @@ -523,7 +523,7 @@ namespace smt { var_power_pair p = get_var_and_degree(m, i); expr * v = p.first; unsigned power = p.second; - TRACE("propagate_nl_downward", tout << "m: " << mk_ismt2_pp(m, get_manager()) << "\nv: " << mk_ismt2_pp(v, get_manager()) << + TRACE("propagate_nl_downward", tout << "m: " << mk_ismt2_pp(m, get_manager()) << "\nv: " << mk_ismt2_pp(v, get_manager()) << "\npower: " << power << "\n";); if (power != 1) return false; // TODO: remove, when the n-th root is implemented in interval. @@ -556,7 +556,7 @@ namespace smt { template bool theory_arith::propagate_nl_bound(expr * m, int i) { TRACE("propagate_nl_bound", tout << "propagate using i: " << i << "\n"; display_monomial(tout, m); tout << "\n";); - if (i == -1) + if (i == -1) return propagate_nl_upward(m); else return propagate_nl_downward(m, i); @@ -657,13 +657,13 @@ namespace smt { rational val(1); for (unsigned i = 0; i < to_app(m)->get_num_args(); i++) { expr * arg = to_app(m)->get_arg(i); - theory_var curr = expr2var(arg); - SASSERT(curr != null_theory_var); - val *= get_value(curr, computed_epsilon); + theory_var curr = expr2var(arg); + SASSERT(curr != null_theory_var); + val *= get_value(curr, computed_epsilon); } return get_value(v, computed_epsilon) == val; } - + /** \brief Return true if for every monomial x_1 * ... * x_n, @@ -691,11 +691,11 @@ namespace smt { /** \brief Try to find an integer variable for performing branching in the non linear cluster. - + The idea is select a variable in a monomial with an invalid assignment. I give preference to variables with small ranges. If no variable is bounded, then select a random one. - + Free variables are not considered. */ template @@ -705,44 +705,44 @@ namespace smt { theory_var target = null_theory_var; bool bounded = false; unsigned n = 0; - numeral range; + numeral range; svector::const_iterator it = m_nl_monomials.begin(); svector::const_iterator end = m_nl_monomials.end(); for (; it != end; ++it) { theory_var v = *it; - if (is_real(v)) + if (is_real(v)) continue; bool computed_epsilon = false; - bool r = check_monomial_assignment(v, computed_epsilon); + bool r = check_monomial_assignment(v, computed_epsilon); SASSERT(!computed_epsilon); // integer variables do not use epsilon if (!r) { expr * m = get_enode(v)->get_owner(); SASSERT(is_pure_monomial(m)); for (unsigned i = 0; i < to_app(m)->get_num_args(); i++) { expr * arg = to_app(m)->get_arg(i); - theory_var curr = ctx.get_enode(arg)->get_th_var(get_id()); - TRACE("nl_branching", tout << "target: v" << target << ", curr: v" << curr << "\n";); - if (!is_fixed(curr) && is_int(curr)) { - if (is_bounded(curr)) { - numeral new_range; - new_range = upper_bound(curr).get_rational(); - new_range -= lower_bound(curr).get_rational(); - if (!bounded || new_range < range) { - target = curr; - range = new_range; - bounded = true; - } - } - else if (!bounded) { - n++; - TRACE("nl_branching", tout << "n: " << n << "\n";); - if (m_random()%n == 0) - target = curr; - SASSERT(target != null_theory_var); - } - SASSERT(target != null_theory_var); - } - TRACE("nl_branching", tout << "after target: v" << target << "\n";); + theory_var curr = ctx.get_enode(arg)->get_th_var(get_id()); + TRACE("nl_branching", tout << "target: v" << target << ", curr: v" << curr << "\n";); + if (!is_fixed(curr) && is_int(curr)) { + if (is_bounded(curr)) { + numeral new_range; + new_range = upper_bound(curr).get_rational(); + new_range -= lower_bound(curr).get_rational(); + if (!bounded || new_range < range) { + target = curr; + range = new_range; + bounded = true; + } + } + else if (!bounded) { + n++; + TRACE("nl_branching", tout << "n: " << n << "\n";); + if (m_random()%n == 0) + target = curr; + SASSERT(target != null_theory_var); + } + SASSERT(target != null_theory_var); + } + TRACE("nl_branching", tout << "after target: v" << target << "\n";); } } } @@ -762,7 +762,7 @@ namespace smt { m_stats.m_nl_branching++; SASSERT(is_int(v)); expr * bound = 0; - if (lower(v)) + if (lower(v)) bound = m_util.mk_le(var2expr(v), m_util.mk_numeral(lower_bound(v).get_rational().to_rational(), true)); else if (upper(v)) bound = m_util.mk_ge(var2expr(v), m_util.mk_numeral(upper_bound(v).get_rational().to_rational(), true)); @@ -787,14 +787,14 @@ namespace smt { unsigned num_nl_vars = 0; for (unsigned i = 0; i < to_app(m)->get_num_args(); i++) { expr * arg = to_app(m)->get_arg(i); - theory_var _var = expr2var(arg); - if (!is_fixed(_var)) { - num_nl_vars++; - } - else { - if (lower_bound(_var).is_zero()) - return true; - } + theory_var _var = expr2var(arg); + if (!is_fixed(_var)) { + num_nl_vars++; + } + else { + if (lower_bound(_var).is_zero()) + return true; + } } return num_nl_vars <= 1; } @@ -809,9 +809,9 @@ namespace smt { numeral r(1); for (unsigned i = 0; i < to_app(m)->get_num_args(); i++) { expr * arg = to_app(m)->get_arg(i); - theory_var _var = expr2var(arg); - if (is_fixed(_var)) - r *= lower_bound(_var).get_rational(); + theory_var _var = expr2var(arg); + if (is_fixed(_var)) + r *= lower_bound(_var).get_rational(); } return r; } @@ -825,9 +825,9 @@ namespace smt { SASSERT(is_pure_monomial(m)); for (unsigned i = 0; i < to_app(m)->get_num_args(); i++) { expr * arg = to_app(m)->get_arg(i); - theory_var _var = expr2var(arg); - if (!is_fixed(_var)) - return arg; + theory_var _var = expr2var(arg); + if (!is_fixed(_var)) + return arg; } return 0; } @@ -886,7 +886,7 @@ namespace smt { } else { // One of the x_i variables is zero, - // or all of them are assigned. + // or all of them are assigned. // Assert the equality // (= (* x_1 ... x_n) k) @@ -908,45 +908,45 @@ namespace smt { SASSERT(is_pure_monomial(m)); bool found_zero = false; - for (unsigned i = 0; !found_zero && i < to_app(m)->get_num_args(); i++) { - expr * arg = to_app(m)->get_arg(i); - theory_var _var = expr2var(arg); - if (is_fixed(_var)) { - bound * l = lower(_var); - bound * u = upper(_var); - if (l->get_value().is_zero()) { - /* if zero was found, then it is the explanation */ - SASSERT(k.is_zero()); - found_zero = true; - m_tmp_lit_set.reset(); - m_tmp_eq_set.reset(); - new_lower->m_lits.reset(); - new_lower->m_eqs.reset(); - } + for (unsigned i = 0; !found_zero && i < to_app(m)->get_num_args(); i++) { + expr * arg = to_app(m)->get_arg(i); + theory_var _var = expr2var(arg); + if (is_fixed(_var)) { + bound * l = lower(_var); + bound * u = upper(_var); + if (l->get_value().is_zero()) { + /* if zero was found, then it is the explanation */ + SASSERT(k.is_zero()); + found_zero = true; + m_tmp_lit_set.reset(); + m_tmp_eq_set.reset(); + new_lower->m_lits.reset(); + new_lower->m_eqs.reset(); + } accumulate_justification(*l, *new_lower, numeral::zero(), m_tmp_lit_set, m_tmp_eq_set); - - TRACE("non_linear", + + TRACE("non_linear", for (unsigned j = 0; j < new_lower->m_lits.size(); ++j) { ctx.display_detailed_literal(tout, new_lower->m_lits[j]); tout << " "; } tout << "\n";); - + accumulate_justification(*u, *new_lower, numeral::zero(), m_tmp_lit_set, m_tmp_eq_set); - - TRACE("non_linear", + + TRACE("non_linear", for (unsigned j = 0; j < new_lower->m_lits.size(); ++j) { ctx.display_detailed_literal(tout, new_lower->m_lits[j]); tout << " "; } tout << "\n";); - - } - } + + } + } new_upper->m_lits.append(new_lower->m_lits); new_upper->m_eqs.append(new_lower->m_eqs); - TRACE("non_linear", + TRACE("non_linear", tout << "lower: " << new_lower << " upper: " << new_upper << "\n"; for (unsigned j = 0; j < new_upper->m_lits.size(); ++j) { ctx.display_detailed_literal(tout, new_upper->m_lits[j]); @@ -979,9 +979,9 @@ namespace smt { /* Interval arithmetic does not satisfy distributivity. Actually, it satisfies the sub-distributivity property: - + x*(y + z) \subseteq x*y + x*z - + The sub-distributivity property only holds if condensation is not used. For example: @@ -995,11 +995,11 @@ namespace smt { x*(x^3+1) = [-7, 14] x^4 + x = [-2, 17] - + This weakness of AI is known as the "dependency problem", which comes from the decorrelation of the multiple occurrences of one variable during interval evaluation. - + Given a polynomial: p(x) = a_0 + a_1 * x + ... + a_n * x^n The horner extension is: @@ -1009,13 +1009,13 @@ namespace smt { h_p(x) = x(2 + x^3(1 + x)) The horner extension evaluates tighter intervals when - condensation is not used. + condensation is not used. Remark: there is no guarantee that horner extension will provide a tighter interval than a sum of monomials when condensation is used. - For multivariate polynomials nested (or cross nested) forms + For multivariate polynomials nested (or cross nested) forms are used. The idea is to select one variable, and pretend the other are parameters. The horner form is computed for the selected variable, and the computation continues for the polynomials on the @@ -1027,13 +1027,13 @@ namespace smt { p(x) = a*x^n + b*x^{n+m} for n >= m is equivalent to - + b*x^{n-m}*[(x^{m} + a/(2b))^2 - (a/2b)^2] - + This polynomial provides tight bound when n and m have the same parity and: 1) a*b > 0 and (lower(x) >= 0 or upper(x)^m <= -a/b) 2) a*b < 0 and (upper(x) <= 0 or lower(x)^m >= a/b) - + This polynomial also provides tight bounds when n = m, and the polynomial is simplified to, and n and m may have arbitrary parities: @@ -1047,7 +1047,7 @@ namespace smt { If we compute the bounds for x^2 - x we obtain (-oo, oo). - On the other hand, if we compute the bounds for + On the other hand, if we compute the bounds for (x - 1/2)^2 - 1/4 we obtain the bounds (0, oo), and the inconsistency is detected. @@ -1055,8 +1055,8 @@ namespace smt { Remark: In Z3, I condensate multiple occurrences of a variable when evaluating monomials. So, the interval for a monomial is always tight. - - Remark: M1*(M2 + M3) is more precise than M1 * M2 + M1 * M3, + + Remark: M1*(M2 + M3) is more precise than M1 * M2 + M1 * M3, if intersection(Vars(M1), union(Vars(M2), Vars(M3))) = empty-set, Remark: A trivial consequence of Moore's theorem for interval @@ -1066,7 +1066,7 @@ namespace smt { /** \brief Check whether the same variable occurs in two different monomials. - + \remark Fixed variables are ignored. \remark A trivial consequence of Moore's theorem for interval @@ -1208,7 +1208,7 @@ namespace smt { UNREACHABLE(); } } - + // Update the number of occurrences in the result vector. typename var2num_occs::iterator it2 = m_var2num_occs.begin(); typename var2num_occs::iterator end2 = m_var2num_occs.end(); @@ -1263,14 +1263,14 @@ namespace smt { m_nl_new_exprs.push_back(r); return r; } - + /** \brief Return true if var only occurs in two monovariate monomials, and return its power and coefficients and these monomials. The arguments i1 and i2 contain the position in p of the two monomials. */ template - bool theory_arith::in_monovariate_monomials(sbuffer & p, expr * var, + bool theory_arith::in_monovariate_monomials(sbuffer & p, expr * var, unsigned & i1, rational & c1, unsigned & n1, unsigned & i2, rational & c2, unsigned & n2) { int idx = 0; #define SET_RESULT(POWER) { \ @@ -1289,7 +1289,7 @@ namespace smt { else \ return false; \ } - + typename sbuffer::const_iterator it = p.begin(); typename sbuffer::const_iterator end = p.end(); for (unsigned i = 0; it != end; ++it, ++i) { @@ -1396,7 +1396,7 @@ namespace smt { SASSERT(d != UINT_MAX); return d; } - + /** \brief Divide m by var^d. */ @@ -1416,19 +1416,19 @@ namespace smt { ptr_buffer new_args; for (unsigned i = 0; i < to_app(m)->get_num_args(); i++) { expr * arg = to_app(m)->get_arg(i); - if (arg == var) { - if (idx < d) - idx++; - else - new_args.push_back(arg); - } - else { - new_args.push_back(arg); - } + if (arg == var) { + if (idx < d) + idx++; + else + new_args.push_back(arg); + } + else { + new_args.push_back(arg); + } } SASSERT(idx == d); TRACE("factor_bug", tout << "new_args:\n"; for(unsigned i = 0; i < new_args.size(); i++) tout << mk_pp(new_args[i], get_manager()) << "\n";); - expr * result = mk_nary_mul(new_args.size(), new_args.c_ptr(), m_util.is_int(var)); + expr * result = mk_nary_mul(new_args.size(), new_args.c_ptr(), m_util.is_int(var)); m_nl_new_exprs.push_back(result); TRACE("factor", tout << "result: " << mk_pp(result, get_manager()) << "\n";); return result; @@ -1442,7 +1442,7 @@ namespace smt { SASSERT(!p.empty()); SASSERT(var != 0); unsigned d = get_min_degree(p, var); - TRACE("horner_bug", tout << "poly:\n"; + TRACE("horner_bug", tout << "poly:\n"; for (unsigned i = 0; i < p.size(); i++) { if (i > 0) tout << " + "; tout << p[i].first << "*" << mk_pp(p[i].second, get_manager()); } tout << "\n"; tout << "var: " << mk_pp(var, get_manager()) << "\n"; tout << "min_degree: " << d << "\n";); @@ -1467,7 +1467,7 @@ namespace smt { // TODO: improve here s = m_util.mk_add(q, s); } - + expr * result = s; if (d != 0) { expr * xd = power(var, d); @@ -1513,9 +1513,9 @@ namespace smt { unsigned nm = UINT_MAX; if (in_monovariate_monomials(p, var, i1, a, n, i2, b, nm)) { CTRACE("in_monovariate_monomials", n == nm, - for (unsigned i = 0; i < p.size(); i++) { - if (i > 0) tout << " + "; tout << p[i].first << "*" << mk_pp(p[i].second, get_manager()); - } + for (unsigned i = 0; i < p.size(); i++) { + if (i > 0) tout << " + "; tout << p[i].first << "*" << mk_pp(p[i].second, get_manager()); + } tout << "\n"; tout << "var: " << mk_pp(var, get_manager()) << "\n"; tout << "i1: " << i1 << "\n"; @@ -1556,7 +1556,7 @@ namespace smt { sbuffer rest; unsigned sz = p.size(); for (unsigned i = 0; i < sz; i++) { - if (i != i1 && i != i2) + if (i != i1 && i != i2) rest.push_back(p[i]); } if (rest.empty()) @@ -1620,7 +1620,7 @@ namespace smt { /** \brief Check whether the polynomial represented by the current row is - consistent with respect to the known bound when converted into a + consistent with respect to the known bound when converted into a equivalent cross nested form. */ template @@ -1630,17 +1630,17 @@ namespace smt { return true; TRACE("cross_nested", tout << "problematic...\n";); - + /* The method is_cross_nested converts rows back to expressions. The conversion back to expressions may create sort incorrect expressions. - This is in some sense ok, since these expressions are temporary, but + This is in some sense ok, since these expressions are temporary, but the sort incorrect expressions may generate assertion violations. - + Sort incorrect expressions may be created in the following cases: - + 1) mixed real int rows. - + 2) int rows that contain non integer coefficients. 3) int rows that when converted to cross nested form use non integer coefficients. @@ -1654,10 +1654,10 @@ namespace smt { c) Disable the assertions temporally. This sounds like a big HACK. d) Use a different data-structure to represent polynomials in cross-nested form. Disadvantage: code duplication, the data-structure - is essentially identical to the ASTs we are using right now. + is essentially identical to the ASTs we are using right now. e) Disable the test when we cannot create a well-sorted expression. - I'm temporally using this solution. + I'm temporally using this solution. I implemented the following logic: 1) (mixed real int) Disable the test. Most benchmarks do not contain mixed int real variables. 2) (int coeffs) I multiply the row by a constant to force it to have only integer coefficients. @@ -1696,7 +1696,7 @@ namespace smt { svector::const_iterator end = nl_cluster.end(); for (; it != end; ++it) { theory_var v = *it; - if (!is_base(v)) + if (!is_base(v)) continue; m_stats.m_nl_cross_nested++; row const & r = m_rows[get_var_row(v)]; @@ -1719,8 +1719,8 @@ namespace smt { /** \brief Initialize variable order for grobner basis computation. Make: - "quoted free vars" > "free vars" > "quoted variables with lower or upper bounds" > - "variables with lower or upper bounds" > "quoted bounded variables" > + "quoted free vars" > "free vars" > "quoted variables with lower or upper bounds" > + "variables with lower or upper bounds" > "quoted bounded variables" > "bounded variables" > "quoted fixed variables" > "fixed variables" */ template @@ -1801,7 +1801,7 @@ namespace smt { } if (!coeff.is_zero()) return gb.mk_monomial(coeff, vars.size(), vars.c_ptr()); - else + else return 0; } @@ -1918,7 +1918,7 @@ namespace smt { derived_bound b(null_theory_var, inf_numeral(0), B_LOWER); dependency2new_bound(d, b); set_conflict(b, ante, "arith_nl"); - TRACE("non_linear", + TRACE("non_linear", for (unsigned i = 0; i < b.m_lits.size(); ++i) { tout << b.m_lits[i] << " "; }); @@ -2027,7 +2027,7 @@ namespace smt { unsigned num1 = m1_sq->get_degree(); unsigned num2 = m2_sq->get_degree(); unsigned num12 = m1m2->get_degree(); - if (num1 + num2 != num12 * 2) + if (num1 + num2 != num12 * 2) return false; unsigned i1, i2, i12; i1 = i2 = i12 = 0; @@ -2072,8 +2072,8 @@ namespace smt { */ template bool theory_arith::is_inconsistent2(grobner::equation const * eq, grobner & gb) { - // TODO: a possible improvement: create a quotation for (M1 - M2)^2 - // instead of trying to find it in a specific equation. + // TODO: a possible improvement: create a quotation for (M1 - M2)^2 + // instead of trying to find it in a specific equation. // This approach is more precise, but more expensive // since a new row must be created. buffer intervals; @@ -2117,7 +2117,7 @@ namespace smt { continue; // m1, m2, and m1m2 form a perfect square. // check if [0, oo) provides a better lowerbound than adding the intervals of m1, m2 and m1m2; - TRACE("non_linear", tout << "found perfect square (M1-M2)^2:\n"; + TRACE("non_linear", tout << "found perfect square (M1-M2)^2:\n"; gb.display_monomial(tout, *m1); tout << "\n"; gb.display_monomial(tout, *m2); tout << "\n"; gb.display_monomial(tout, *m1m2); tout << "\n";); @@ -2131,7 +2131,7 @@ namespace smt { deleted[i] = true; deleted[j] = true; deleted[k] = true; - break; + break; } } if (k < num) @@ -2184,7 +2184,7 @@ namespace smt { grobner::monomial const * m = eq->get_monomial(i); if (m->get_degree() == 0) k -= m->get_coeff(); - else + else args.push_back(monomial2expr(eq->get_monomial(i), is_int)); } context & ctx = get_context(); @@ -2213,7 +2213,7 @@ namespace smt { TRACE("non_linear", tout << "inserted new equation into the tableau\n"; display_var(tout, v);); return true; } - + /** \brief Compute Grobner basis, return true if a conflict or new fixed variables were detected. */ @@ -2227,7 +2227,7 @@ namespace smt { bool warn = false; unsigned next_weight = MAX_DEFAULT_WEIGHT + 1; // next weight using during perturbation phase. ptr_vector eqs; - + while (true) { TRACE("non_linear_gb", tout << "before:\n"; gb.display(tout);); bool r = false; @@ -2267,7 +2267,7 @@ namespace smt { if (is_inconsistent2(eq, gb)) return GB_PROGRESS; } - // Scan the grobner basis eqs for equations of the form x - k = 0 or x = 0 is found, and x is not fixed, + // Scan the grobner basis eqs for equations of the form x - k = 0 or x = 0 is found, and x is not fixed, // then assert bounds for x, and continue gb_result result = GB_FAIL; if (m_params.m_nl_arith_gb_eqs) { @@ -2277,7 +2277,7 @@ namespace smt { if (!eq->is_linear_combination()) { TRACE("non_linear", tout << "processing new equality:\n"; gb.display_equation(tout, *eq);); TRACE("non_linear_bug", tout << "processing new equality:\n"; gb.display_equation(tout, *eq);); - if (internalize_gb_eq(eq)) + if (internalize_gb_eq(eq)) result = GB_NEW_EQ; } } @@ -2372,10 +2372,10 @@ namespace smt { IF_VERBOSE(3, verbose_stream() << "Max. non linear arithmetic rounds. Increase threshold using NL_ARITH_ROUNDS=\n";); return FC_GIVEUP; } - + get_context().push_trail(value_trail(m_nl_rounds)); m_nl_rounds++; - + elim_quasi_base_rows(); move_non_base_vars_to_bounds(); TRACE("non_linear", tout << "processing non linear constraints...\n"; get_context().display(tout);); @@ -2384,8 +2384,8 @@ namespace smt { failed(); return FC_CONTINUE; } - - if (!max_min_nl_vars()) + + if (!max_min_nl_vars()) return FC_CONTINUE; if (check_monomial_assignments()) { @@ -2409,20 +2409,20 @@ namespace smt { } break; case 1: - if (!is_cross_nested_consistent(vars)) + if (!is_cross_nested_consistent(vars)) progress = true; break; case 2: if (m_params.m_nl_arith_gb) { switch(compute_grobner(vars)) { - case GB_PROGRESS: + case GB_PROGRESS: progress = true; break; - case GB_NEW_EQ: + case GB_NEW_EQ: progress = true; propagate_core(); break; - case GB_FAIL: + case GB_FAIL: break; } } From 45469152387b8f89ba386c770bd8a7028fc152af Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Tue, 18 Oct 2016 17:17:19 +0100 Subject: [PATCH 21/26] Fixed iterator invalidation bug in theory_arith_nl. Indirectly relates to #740 --- src/smt/theory_arith_nl.h | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/smt/theory_arith_nl.h b/src/smt/theory_arith_nl.h index c3ae8c99b..04b974d6e 100644 --- a/src/smt/theory_arith_nl.h +++ b/src/smt/theory_arith_nl.h @@ -965,10 +965,19 @@ namespace smt { bool theory_arith::propagate_linear_monomials() { TRACE("non_linear", tout << "propagating linear monomials...\n";); bool p = false; - svector::const_iterator it = m_nl_monomials.begin(); - svector::const_iterator end = m_nl_monomials.end(); - for (; it != end; ++it) { - theory_var v = *it; + // CMW: m_nl_monomials is sometimes modified while executing + // propagate_linear_monomial(...), invalidating the iterator `it'. + // (Via the relevancy propagation that internalizes a new axiom + // in mk_div_axiom and possibly others.) I'm replacing the iterator + // with an index `i'. + + // Was previously: + // svector::const_iterator it = m_nl_monomials.begin(); + // svector::const_iterator end = m_nl_monomials.end(); + // for (; it != end; ++it) { + // theory_var v = *it; + for (unsigned i = 0; i < m_nl_monomials.size(); i++) { + theory_var v = m_nl_monomials[i]; if (propagate_linear_monomial(v)) p = true; } From d060359f01b06c19bd4d65c4ba73d0f5c2393fc7 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 18 Oct 2016 22:34:34 -0400 Subject: [PATCH 22/26] add fd solver for finite domain queries Signed-off-by: Nikolaj Bjorner --- contrib/cmake/src/ast/rewriter/CMakeLists.txt | 1 + .../cmake/src/tactic/portfolio/CMakeLists.txt | 1 + src/ast/expr_functors.h | 8 + src/ast/rewriter/fd_rewriter.cpp | 292 ++++++++++++++++++ src/ast/rewriter/fd_rewriter.h | 48 +++ src/cmd_context/check_logic.cpp | 17 +- src/cmd_context/cmd_context.cpp | 5 +- src/sat/sat_solver.cpp | 9 +- src/sat/sat_solver/inc_sat_solver.cpp | 2 +- src/tactic/bv/dt2bv_tactic.cpp | 228 +++----------- src/tactic/bv/dt2bv_tactic.h | 2 +- src/tactic/extension_model_converter.cpp | 2 +- src/tactic/portfolio/fd_solver.cpp | 161 ++++++++++ src/tactic/portfolio/fd_solver.h | 29 ++ src/tactic/portfolio/smt_strategic_solver.cpp | 4 +- src/test/get_consequences.cpp | 71 ++++- 16 files changed, 676 insertions(+), 204 deletions(-) create mode 100644 src/ast/rewriter/fd_rewriter.cpp create mode 100644 src/ast/rewriter/fd_rewriter.h create mode 100644 src/tactic/portfolio/fd_solver.cpp create mode 100644 src/tactic/portfolio/fd_solver.h diff --git a/contrib/cmake/src/ast/rewriter/CMakeLists.txt b/contrib/cmake/src/ast/rewriter/CMakeLists.txt index 47323d821..b01a0e016 100644 --- a/contrib/cmake/src/ast/rewriter/CMakeLists.txt +++ b/contrib/cmake/src/ast/rewriter/CMakeLists.txt @@ -12,6 +12,7 @@ z3_add_component(rewriter expr_replacer.cpp expr_safe_replace.cpp factor_rewriter.cpp + fd_rewriter.cpp fpa_rewriter.cpp label_rewriter.cpp mk_simplified_app.cpp diff --git a/contrib/cmake/src/tactic/portfolio/CMakeLists.txt b/contrib/cmake/src/tactic/portfolio/CMakeLists.txt index d20af772b..201cdcf0f 100644 --- a/contrib/cmake/src/tactic/portfolio/CMakeLists.txt +++ b/contrib/cmake/src/tactic/portfolio/CMakeLists.txt @@ -1,6 +1,7 @@ z3_add_component(portfolio SOURCES default_tactic.cpp + fd_solver.cpp smt_strategic_solver.cpp COMPONENT_DEPENDENCIES aig_tactic diff --git a/src/ast/expr_functors.h b/src/ast/expr_functors.h index 32560e139..da2b43dea 100644 --- a/src/ast/expr_functors.h +++ b/src/ast/expr_functors.h @@ -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. diff --git a/src/ast/rewriter/fd_rewriter.cpp b/src/ast/rewriter/fd_rewriter.cpp new file mode 100644 index 000000000..026387e22 --- /dev/null +++ b/src/ast/rewriter/fd_rewriter.cpp @@ -0,0 +1,292 @@ +/*++ +Copyright (c) 2016 Microsoft Corporation + +Module Name: + + fd_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"fd_rewriter.h" +#include"ast_util.h" +#include"ast_pp.h" + +struct fd_rewriter::imp { + ast_manager& m; + params_ref m_params; + obj_map m_enum2bv; + obj_map m_bv2enum; + obj_map 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)) { + 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 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 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)) { + 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 m_cfg; + + rw(imp& t, ast_manager & m, params_ref const & p) : + rewriter_tpl(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); + } + } + + 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; + } +}; + + +fd_rewriter::fd_rewriter(ast_manager & m, params_ref const& p) { m_imp = alloc(imp, m, p); } +fd_rewriter::~fd_rewriter() { dealloc(m_imp); } +void fd_rewriter::updt_params(params_ref const & p) { m_imp->updt_params(p); } +ast_manager & fd_rewriter::m() const { return m_imp->m; } +unsigned fd_rewriter::get_num_steps() const { return m_imp->get_num_steps(); } +void fd_rewriter::cleanup() { ast_manager& mgr = m(); params_ref p = m_imp->m_params; dealloc(m_imp); m_imp = alloc(imp, mgr, p); } +obj_map const& fd_rewriter::enum2bv() const { return m_imp->m_enum2bv; } +obj_map const& fd_rewriter::bv2enum() const { return m_imp->m_bv2enum; } +obj_map const& fd_rewriter::enum2def() const { return m_imp->m_enum2def; } +void fd_rewriter::operator()(expr * e, expr_ref & result, proof_ref & result_proof) { (*m_imp)(e, result, result_proof); } +void fd_rewriter::push() { m_imp->push(); } +void fd_rewriter::pop(unsigned num_scopes) { m_imp->pop(num_scopes); } +void fd_rewriter::flush_side_constraints(expr_ref_vector& side_constraints) { m_imp->flush_side_constraints(side_constraints); } +unsigned fd_rewriter::num_translated() const { return m_imp->m_num_translated; } +void fd_rewriter::set_is_fd(i_sort_pred* sp) const { m_imp->set_is_fd(sp); } diff --git a/src/ast/rewriter/fd_rewriter.h b/src/ast/rewriter/fd_rewriter.h new file mode 100644 index 000000000..3d4ecae9c --- /dev/null +++ b/src/ast/rewriter/fd_rewriter.h @@ -0,0 +1,48 @@ +/*++ +Copyright (c) 2016 Microsoft Corporation + +Module Name: + + fd_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 fd_rewriter { + struct imp; + imp* m_imp; +public: + fd_rewriter(ast_manager & m, params_ref const& p); + ~fd_rewriter(); + + void updt_params(params_ref const & p); + ast_manager & m() const; + unsigned get_num_steps() const; + void cleanup(); + obj_map const& enum2bv() const; + obj_map const& bv2enum() const; + obj_map 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 diff --git a/src/cmd_context/check_logic.cpp b/src/cmd_context/check_logic.cpp index 733689ac9..7a49f8fd0 100644 --- a/src/cmd_context/check_logic.cpp +++ b/src/cmd_context/check_logic.cpp @@ -21,8 +21,10 @@ Revision History: #include"array_decl_plugin.h" #include"bv_decl_plugin.h" #include"seq_decl_plugin.h" +#include"datatype_decl_plugin.h" #include"ast_pp.h" #include"for_each_expr.h" +#include struct check_logic::imp { ast_manager & m; @@ -31,6 +33,7 @@ struct check_logic::imp { bv_util m_bv_util; array_util m_ar_util; seq_util m_seq_util; + datatype_util m_dt_util; bool m_uf; // true if the logic supports uninterpreted functions bool m_arrays; // true if the logic supports arbitrary arrays bool m_bv_arrays; // true if the logic supports only bv arrays @@ -42,7 +45,7 @@ struct check_logic::imp { bool m_quantifiers; // true if the logic supports quantifiers bool m_unknown_logic; - imp(ast_manager & _m):m(_m), m_a_util(m), m_bv_util(m), m_ar_util(m), m_seq_util(m) { + imp(ast_manager & _m):m(_m), m_a_util(m), m_bv_util(m), m_ar_util(m), m_seq_util(m), m_dt_util(m) { reset(); } @@ -178,6 +181,11 @@ struct check_logic::imp { m_reals = true; m_quantifiers = false; } + else if (logic == "QF_FD") { + m_bvs = true; + m_uf = true; + m_ints = true; + } else { m_unknown_logic = true; } @@ -432,8 +440,13 @@ struct check_logic::imp { else if (fid == m_seq_util.get_family_id()) { // nothing to check } + else if (fid == m_dt_util.get_family_id() && m_logic == "QF_FD") { + // nothing to check + } else { - fail("logic does not support theory"); + std::stringstream strm; + strm << "logic does not support theory " << m.get_family_name(fid); + fail(strm.str().c_str()); } } diff --git a/src/cmd_context/cmd_context.cpp b/src/cmd_context/cmd_context.cpp index 3260f02b0..1df28b8e5 100644 --- a/src/cmd_context/cmd_context.cpp +++ b/src/cmd_context/cmd_context.cpp @@ -568,6 +568,7 @@ bool cmd_context::logic_has_bv_core(symbol const & s) const { s == "QF_FPBV" || s == "QF_BVFP" || s == "ALL" || + s == "QF_FD" || s == "HORN"; } @@ -622,7 +623,7 @@ bool cmd_context::logic_has_array() const { } bool cmd_context::logic_has_datatype() const { - return !has_logic(); + return !has_logic() || m_logic == "QF_FD"; } void cmd_context::init_manager_core(bool new_manager) { @@ -705,7 +706,7 @@ void cmd_context::init_external_manager() { } bool cmd_context::supported_logic(symbol const & s) const { - return s == "QF_UF" || s == "UF" || s == "ALL" || + return s == "QF_UF" || s == "UF" || s == "ALL" || s == "QF_FD" || logic_has_arith_core(s) || logic_has_bv_core(s) || logic_has_array_core(s) || logic_has_seq_core(s) || logic_has_horn(s) || logic_has_fpa_core(s); diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 915080c4a..1e667eccc 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -3135,6 +3135,7 @@ namespace sat { if (is_sat != l_true) { return is_sat; } + model mdl = get_model(); for (unsigned i = 0; i < vars.size(); ++i) { bool_var v = vars[i]; switch (get_model()[v]) { @@ -3143,7 +3144,9 @@ namespace sat { default: break; } } - return get_consequences(asms, lits, conseq); + is_sat = get_consequences(asms, lits, conseq); + set_model(mdl); + return is_sat; } lbool solver::get_consequences(literal_vector const& asms, literal_vector const& lits, vector& conseq) { @@ -3164,13 +3167,11 @@ namespace sat { while (!unfixed.empty()) { checkpoint(); literal_set::iterator it = unfixed.begin(), end = unfixed.end(); - unsigned chunk_size = 100; - for (; it != end && chunk_size > 0; ++it) { + for (; it != end; ++it) { literal lit = *it; if (value(lit) != l_undef) { continue; } - --chunk_size; push(); assign(~lit, justification()); propagate(false); diff --git a/src/sat/sat_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp index 83ccfcac4..349b60f55 100644 --- a/src/sat/sat_solver/inc_sat_solver.cpp +++ b/src/sat/sat_solver/inc_sat_solver.cpp @@ -580,7 +580,7 @@ private: } void extract_model() { - TRACE("sat", tout << "retrieve model\n";); + TRACE("sat", tout << "retrieve model " << (m_solver.model_is_current()?"present":"absent") << "\n";); if (!m_solver.model_is_current()) { m_model = 0; return; diff --git a/src/tactic/bv/dt2bv_tactic.cpp b/src/tactic/bv/dt2bv_tactic.cpp index ab9df78ad..d7d6c9811 100644 --- a/src/tactic/bv/dt2bv_tactic.cpp +++ b/src/tactic/bv/dt2bv_tactic.cpp @@ -29,6 +29,7 @@ Revision History: #include "extension_model_converter.h" #include "var_subst.h" #include "ast_util.h" +#include "fd_rewriter.h" class dt2bv_tactic : public tactic { @@ -39,177 +40,8 @@ class dt2bv_tactic : public tactic { bv_util m_bv; obj_hashtable m_fd_sorts; obj_hashtable m_non_fd_sorts; - expr_ref_vector m_bounds; - ref m_ext; - ref m_filter; - unsigned m_num_translated; - obj_map* m_translate; - - struct rw_cfg : public default_rewriter_cfg { - dt2bv_tactic& m_t; - ast_manager& m; - params_ref m_params; - obj_map m_cache; - expr_ref_vector m_trail; - - rw_cfg(dt2bv_tactic& t, ast_manager & m, params_ref const & p) : - m_t(t), - m(m), - m_params(p), - m_trail(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_t.m_dt.is_recognizer(f) && reduce_arg(args[0], a0)) { - unsigned idx = m_t.m_dt.get_recognizer_constructor_idx(f); - a1 = m_t.m_bv.mk_numeral(rational(idx), get_sort(a0)); - result = m.mk_eq(a0, a1); - return BR_DONE; - } - else { - 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; - } - - bool reduce_arg(expr* a, expr_ref& result) { - expr* b; - if (m_cache.find(a, b)) { - result = b; - return true; - } - - sort* s = get_sort(a); - if (!m_t.m_fd_sorts.contains(s)) { - return false; - } - unsigned bv_size = get_bv_size(s); - - if (is_var(a)) { - result = m.mk_var(to_var(a)->get_idx(), m_t.m_bv.mk_sort(bv_size)); - return true; - } - SASSERT(is_app(a)); - func_decl* f = to_app(a)->get_decl(); - if (m_t.m_dt.is_constructor(f)) { - unsigned idx = m_t.m_dt.get_constructor_idx(f); - result = m_t.m_bv.mk_numeral(idx, bv_size); - } - else if (is_uninterp_const(a)) { - // create a fresh variable, add bounds constraints for it. - unsigned nc = m_t.m_dt.get_datatype_num_constructors(s); - result = m.mk_fresh_const(f->get_name().str().c_str(), m_t.m_bv.mk_sort(bv_size)); - if (!is_power_of_two(nc)) { - m_t.m_bounds.push_back(m_t.m_bv.mk_ule(result, m_t.m_bv.mk_numeral(nc-1, bv_size))); - } - expr_ref f_def(m); - ptr_vector const& cs = *m_t.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_t.m_bv.mk_numeral(i,bv_size)), m.mk_const(cs[i]), f_def); - } - // update model converters. - m_t.m_ext->insert(f, f_def); - m_t.m_filter->insert(to_app(result)->get_decl()); - if (m_t.m_translate) { - m_t.m_translate->insert(f, result); - } - } - else { - return false; - } - m_cache.insert(a, result); - ++m_t.m_num_translated; - return true; - } - - ptr_buffer 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_t.m_fd_sorts.contains(s)) { - unsigned bv_size = get_bv_size(s); - m_sorts.push_back(m_t.m_bv.mk_sort(bv_size)); - unsigned nc = m_t.m_dt.get_datatype_num_constructors(s); - if (!is_power_of_two(nc)) { - bounds.push_back(m_t.m_bv.mk_ule(m.mk_var(q->get_num_decls()-i-1, m_sorts[i]), m_t.m_bv.mk_numeral(nc, 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_t.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 m_cfg; - - rw(dt2bv_tactic& t, ast_manager & m, params_ref const & p) : - rewriter_tpl(m, m.proofs_enabled(), m_cfg), - m_cfg(t, m, p) { - } - }; - - + obj_map* m_translate; + bool is_fd(expr* a) { return is_fd(get_sort(a)); } bool is_fd(sort* a) { return m_dt.is_enum_sort(a); } @@ -255,10 +87,20 @@ class dt2bv_tactic : public tactic { void operator()(quantifier* q) {} }; + struct sort_pred : public i_sort_pred { + dt2bv_tactic& m_t; + sort_pred(dt2bv_tactic& t): m_t(t) {} + virtual ~sort_pred() {} + virtual bool operator()(sort* s) { + return m_t.m_fd_sorts.contains(s); + } + }; + + sort_pred m_is_fd; public: - dt2bv_tactic(ast_manager& m, params_ref const& p, obj_map* tr): - m(m), m_params(p), m_dt(m), m_bv(m), m_bounds(m), m_translate(tr) {} + dt2bv_tactic(ast_manager& m, params_ref const& p, obj_map* tr): + m(m), m_params(p), m_dt(m), m_bv(m), m_translate(tr), m_is_fd(*this) {} virtual tactic * translate(ast_manager & m) { return alloc(dt2bv_tactic, m, m_params, 0); @@ -289,26 +131,43 @@ public: m_fd_sorts.remove(*it); } if (!m_fd_sorts.empty()) { - m_bounds.reset(); - m_num_translated = 0; - m_ext = alloc(extension_model_converter, m); - m_filter = alloc(filter_model_converter, m); - scoped_ptr r = alloc(rw, *this, m, m_params); + ref ext = alloc(extension_model_converter, m); + ref filter = alloc(filter_model_converter, m); + fd_rewriter rw(m, m_params); + rw.set_is_fd(&m_is_fd); expr_ref new_curr(m); proof_ref new_pr(m); for (unsigned idx = 0; idx < size; idx++) { - (*r)(g->form(idx), new_curr, new_pr); + rw(g->form(idx), new_curr, new_pr); if (produce_proofs) { proof * pr = g->pr(idx); new_pr = m.mk_modus_ponens(pr, new_pr); } g->update(idx, new_curr, new_pr, g->dep(idx)); } - for (unsigned i = 0; i < m_bounds.size(); ++i) { - g->assert_expr(m_bounds[i].get()); + expr_ref_vector bounds(m); + rw.flush_side_constraints(bounds); + for (unsigned i = 0; i < bounds.size(); ++i) { + g->assert_expr(bounds[i].get()); } - mc = concat(m_filter.get(), m_ext.get()); - report_tactic_progress(":fd-num-translated", m_num_translated); + { + obj_map::iterator it = rw.enum2bv().begin(), end = rw.enum2bv().end(); + for (; it != end; ++it) { + filter->insert(it->m_value); + if (m_translate) { + m_translate->insert(it->m_key, it->m_value); + } + } + } + { + obj_map::iterator it = rw.enum2def().begin(), end = rw.enum2def().end(); + for (; it != end; ++it) { + ext->insert(it->m_key, it->m_value); + } + } + + mc = concat(filter.get(), ext.get()); + report_tactic_progress(":fd-num-translated", rw.num_translated()); } g->inc_depth(); result.push_back(g.get()); @@ -319,11 +178,10 @@ public: virtual void cleanup() { m_fd_sorts.reset(); m_non_fd_sorts.reset(); - m_bounds.reset(); } }; -tactic * mk_dt2bv_tactic(ast_manager & m, params_ref const & p, obj_map* tr) { +tactic * mk_dt2bv_tactic(ast_manager & m, params_ref const & p, obj_map* tr) { return alloc(dt2bv_tactic, m, p, tr); } diff --git a/src/tactic/bv/dt2bv_tactic.h b/src/tactic/bv/dt2bv_tactic.h index a8fb33fe8..fd5aacda6 100644 --- a/src/tactic/bv/dt2bv_tactic.h +++ b/src/tactic/bv/dt2bv_tactic.h @@ -24,7 +24,7 @@ Revision History: class ast_manager; class tactic; -tactic * mk_dt2bv_tactic(ast_manager & m, params_ref const & p = params_ref(), obj_map* tr = 0); +tactic * mk_dt2bv_tactic(ast_manager & m, params_ref const & p = params_ref(), obj_map* tr = 0); /* ADD_TACTIC("dt2bv", "eliminate finite domain data-types. Replace by bit-vectors.", "mk_dt2bv_tactic(m, p)") diff --git a/src/tactic/extension_model_converter.cpp b/src/tactic/extension_model_converter.cpp index cdd096455..345ea5cc9 100644 --- a/src/tactic/extension_model_converter.cpp +++ b/src/tactic/extension_model_converter.cpp @@ -71,7 +71,7 @@ void extension_model_converter::operator()(model_ref & md, unsigned goal_idx) { void extension_model_converter::insert(func_decl * v, expr * def) { m_vars.push_back(v); - m_defs.push_back(def); + m_defs.push_back(def); } diff --git a/src/tactic/portfolio/fd_solver.cpp b/src/tactic/portfolio/fd_solver.cpp new file mode 100644 index 000000000..9447c158c --- /dev/null +++ b/src/tactic/portfolio/fd_solver.cpp @@ -0,0 +1,161 @@ +/*++ +Copyright (c) 2016 Microsoft Corporation + +Module Name: + + fd_solver.cpp + +Abstract: + + Finite domain solver. + + Enumeration data-types are translated into bit-vectors, and then + the incremental sat-solver is applied to the resulting assertions. + +Author: + + Nikolaj Bjorner (nbjorner) 2016-10-17 + +Notes: + +--*/ + +#include "fd_solver.h" +#include "solver_na2as.h" +#include "tactic.h" +#include "inc_sat_solver.h" +#include "bv_decl_plugin.h" +#include "datatype_decl_plugin.h" +#include "fd_rewriter.h" +#include "extension_model_converter.h" +#include "filter_model_converter.h" +#include "ast_pp.h" +#include "model_smt2_pp.h" + +class fd_solver : public solver_na2as { + ast_manager& m; + params_ref m_params; + ref m_solver; + fd_rewriter m_rewriter; + +public: + + fd_solver(ast_manager& m, params_ref const& p): + solver_na2as(m), + m(m), + m_params(p), + m_solver(mk_inc_sat_solver(m, p)), + m_rewriter(m, p) + { + } + + virtual ~fd_solver() {} + + virtual solver* translate(ast_manager& m, params_ref const& p) { + return alloc(fd_solver, m, p); + } + + virtual void assert_expr(expr * t) { + expr_ref tmp(t, m); + expr_ref_vector bounds(m); + proof_ref tmp_proof(m); + m_rewriter(t, tmp, tmp_proof); + m_solver->assert_expr(tmp); + m_rewriter.flush_side_constraints(bounds); + m_solver->assert_expr(bounds); + } + + virtual void push_core() { + m_rewriter.push(); + m_solver->push(); + } + + virtual void pop_core(unsigned n) { + m_solver->pop(n); + m_rewriter.pop(n); + } + + virtual lbool check_sat_core(unsigned num_assumptions, expr * const * assumptions) { + return m_solver->check_sat(num_assumptions, assumptions); + } + + virtual void updt_params(params_ref const & p) { m_solver->updt_params(p); } + virtual void collect_param_descrs(param_descrs & r) { m_solver->collect_param_descrs(r); } + virtual void set_produce_models(bool f) { m_solver->set_produce_models(f); } + virtual void set_progress_callback(progress_callback * callback) { m_solver->set_progress_callback(callback); } + virtual void collect_statistics(statistics & st) const { m_solver->collect_statistics(st); } + virtual void get_unsat_core(ptr_vector & r) { m_solver->get_unsat_core(r); } + virtual void get_model(model_ref & mdl) { + m_solver->get_model(mdl); + if (mdl) { + extend_model(mdl); + filter_model(mdl); + } + } + virtual proof * get_proof() { return m_solver->get_proof(); } + virtual std::string reason_unknown() const { return m_solver->reason_unknown(); } + virtual void set_reason_unknown(char const* msg) { m_solver->set_reason_unknown(msg); } + virtual void get_labels(svector & r) { m_solver->get_labels(r); } + virtual ast_manager& get_manager() const { return m; } + virtual lbool find_mutexes(expr_ref_vector const& vars, vector& mutexes) { return m_solver->find_mutexes(vars, mutexes); } + + virtual lbool get_consequences_core(expr_ref_vector const& asms, expr_ref_vector const& vars, expr_ref_vector& consequences) { + + datatype_util dt(m); + bv_util bv(m); + + // translate enumeration constants to bit-vectors. + expr_ref_vector bvars(m), conseq(m); + for (unsigned i = 0; i < vars.size(); ++i) { + func_decl* f; + if (is_app(vars[i]) && is_uninterp_const(vars[i]) && m_rewriter.enum2bv().find(to_app(vars[i])->get_decl(), f)) { + bvars.push_back(m.mk_const(f)); + } + else { + bvars.push_back(vars[i]); + } + } + lbool r = m_solver->get_consequences(asms, bvars, consequences); + + // translate bit-vector consequences back to enumeration types + for (unsigned i = 0; i < consequences.size(); ++i) { + expr* a, *b, *u, *v; + func_decl* f; + rational num; + unsigned bvsize; + VERIFY(m.is_implies(consequences[i].get(), a, b)); + if (m.is_eq(b, u, v) && is_uninterp_const(u) && m_rewriter.bv2enum().find(to_app(u)->get_decl(), f) && bv.is_numeral(v, num, bvsize)) { + SASSERT(num.is_unsigned()); + expr_ref head(m); + ptr_vector const& enums = *dt.get_datatype_constructors(f->get_range()); + head = m.mk_eq(m.mk_const(f), m.mk_const(enums[num.get_unsigned()])); + consequences[i] = m.mk_implies(a, head); + } + } + return r; + } + + void filter_model(model_ref& mdl) { + filter_model_converter filter(m); + obj_map::iterator it = m_rewriter.enum2bv().begin(), end = m_rewriter.enum2bv().end(); + for (; it != end; ++it) { + filter.insert(it->m_value); + } + filter(mdl, 0); + } + + void extend_model(model_ref& mdl) { + extension_model_converter ext(m); + obj_map::iterator it = m_rewriter.enum2def().begin(), end = m_rewriter.enum2def().end(); + for (; it != end; ++it) { + ext.insert(it->m_key, it->m_value); + + } + ext(mdl, 0); + } + +}; + +solver * mk_fd_solver(ast_manager & m, params_ref const & p) { + return alloc(fd_solver, m, p); +} diff --git a/src/tactic/portfolio/fd_solver.h b/src/tactic/portfolio/fd_solver.h new file mode 100644 index 000000000..51abb087f --- /dev/null +++ b/src/tactic/portfolio/fd_solver.h @@ -0,0 +1,29 @@ +/*++ +Copyright (c) 2016 Microsoft Corporation + +Module Name: + + fd_solver.h + +Abstract: + + Finite domain solver. + +Author: + + Nikolaj Bjorner (nbjorner) 2016-10-17 + +Notes: + +--*/ +#ifndef FD_SOLVER_H_ +#define FD_SOLVER_H_ + +#include"ast.h" +#include"params.h" + +class solver; + +solver * mk_fd_solver(ast_manager & m, params_ref const & p); + +#endif diff --git a/src/tactic/portfolio/smt_strategic_solver.cpp b/src/tactic/portfolio/smt_strategic_solver.cpp index f9334bcb2..81825221e 100644 --- a/src/tactic/portfolio/smt_strategic_solver.cpp +++ b/src/tactic/portfolio/smt_strategic_solver.cpp @@ -38,6 +38,7 @@ Notes: #include"horn_tactic.h" #include"smt_solver.h" #include"inc_sat_solver.h" +#include"fd_solver.h" #include"bv_rewriter.h" @@ -98,6 +99,8 @@ static solver* mk_solver_for_logic(ast_manager & m, params_ref const & p, symbol bv_rewriter rw(m); if (logic == "QF_BV" && rw.hi_div0()) return mk_inc_sat_solver(m, p); + if (logic == "QF_FD") + return mk_fd_solver(m, p); return mk_smt_solver(m, p, logic); } @@ -116,7 +119,6 @@ public: tactic * t = mk_tactic_for_logic(m, p, l); return mk_combined_solver(mk_tactic2solver(m, t, p, proofs_enabled, models_enabled, unsat_core_enabled, l), mk_solver_for_logic(m, p, l), - //mk_smt_solver(m, p, l), p); } }; diff --git a/src/test/get_consequences.cpp b/src/test/get_consequences.cpp index 24f3a5d38..8c35bcfb1 100644 --- a/src/test/get_consequences.cpp +++ b/src/test/get_consequences.cpp @@ -11,7 +11,7 @@ Copyright (c) 2016 Microsoft Corporation #include "dt2bv_tactic.h" #include "tactic.h" #include "model_smt2_pp.h" -//include +#include "fd_solver.h" static expr_ref mk_const(ast_manager& m, char const* name, sort* s) { return expr_ref(m.mk_const(symbol(name), s), m); @@ -81,8 +81,8 @@ static void test2() { gl->assert_expr(m.mk_not(m.mk_eq(x, r))); gl->assert_expr(m.mk_not(m.mk_eq(x, b))); gl->display(std::cout); - obj_map tr; - obj_map rev_tr; + obj_map tr; + obj_map rev_tr; ref dt2bv = mk_dt2bv_tactic(m, p, &tr); goal_ref_buffer result; model_converter_ref mc; @@ -91,13 +91,13 @@ static void test2() { (*dt2bv)(gl, result, mc, pc, core); // Collect translations from enumerations to bit-vectors - obj_map::iterator it = tr.begin(), end = tr.end(); + obj_map::iterator it = tr.begin(), end = tr.end(); for (; it != end; ++it) { rev_tr.insert(it->m_value, it->m_key); } // Create bit-vector implication problem - val = tr.find(to_app(x)->get_decl()); + val = m.mk_const(tr.find(to_app(x)->get_decl())); std::cout << val << "\n"; ptr_vector fmls; result[0]->get_formulas(fmls); @@ -119,7 +119,7 @@ static void test2() { rational num; unsigned bvsize; VERIFY(m.is_implies(conseq[i].get(), a, b)); - if (m.is_eq(b, u, v) && rev_tr.find(u, f) && bv.is_numeral(v, num, bvsize)) { + if (m.is_eq(b, u, v) && rev_tr.find(to_app(u)->get_decl(), f) && bv.is_numeral(v, num, bvsize)) { SASSERT(num.is_unsigned()); expr_ref head(m); head = m.mk_eq(m.mk_const(f), m.mk_const(enums[num.get_unsigned()])); @@ -129,9 +129,66 @@ static void test2() { std::cout << conseq << "\n"; } +void test3() { + ast_manager m; + reg_decl_plugins(m); + bv_util bv(m); + datatype_util dtutil(m); + params_ref p; + + datatype_decl_plugin & dt = *(static_cast(m.get_plugin(m.get_family_id("datatype")))); + sort_ref_vector new_sorts(m); + constructor_decl* R = mk_constructor_decl(symbol("R"), symbol("is-R"), 0, 0); + constructor_decl* G = mk_constructor_decl(symbol("G"), symbol("is-G"), 0, 0); + constructor_decl* B = mk_constructor_decl(symbol("B"), symbol("is-B"), 0, 0); + constructor_decl* constrs[3] = { R, G, B }; + datatype_decl * enum_sort = mk_datatype_decl(symbol("RGB"), 3, constrs); + VERIFY(dt.mk_datatypes(1, &enum_sort, new_sorts)); + del_constructor_decls(3, constrs); + sort* rgb = new_sorts[0].get(); + + expr_ref x = mk_const(m, "x", rgb), y = mk_const(m, "y", rgb), z = mk_const(m, "z", rgb); + ptr_vector const& enums = *dtutil.get_datatype_constructors(rgb); + expr_ref r = expr_ref(m.mk_const(enums[0]), m); + expr_ref g = expr_ref(m.mk_const(enums[1]), m); + expr_ref b = expr_ref(m.mk_const(enums[2]), m); + + ref fd_solver = mk_fd_solver(m, p); + fd_solver->assert_expr(m.mk_not(m.mk_eq(x, r))); + fd_solver->assert_expr(m.mk_not(m.mk_eq(x, b))); + + expr_ref_vector asms(m), vars(m), conseq(m); + vars.push_back(x); + vars.push_back(y); + + VERIFY(l_true == fd_solver->get_consequences(asms, vars, conseq)); + std::cout << conseq << "\n"; + conseq.reset(); + + fd_solver->push(); + fd_solver->assert_expr(m.mk_not(m.mk_eq(x, g))); + VERIFY(l_false == fd_solver->check_sat(0,0)); + fd_solver->pop(1); + + VERIFY(l_true == fd_solver->get_consequences(asms, vars, conseq)); + + std::cout << conseq << "\n"; + conseq.reset(); + + model_ref mr; + fd_solver->get_model(mr); + model_smt2_pp(std::cout << "model:\n", m, *mr.get(), 0); + + VERIFY(l_true == fd_solver->check_sat(0,0)); + fd_solver->get_model(mr); + SASSERT(mr.get()); + model_smt2_pp(std::cout, m, *mr.get(), 0); + +} + void tst_get_consequences() { test1(); test2(); - + test3(); } From 11997afb5d1c0dd816bcd43dfa8298031e4ee743 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Wed, 19 Oct 2016 12:00:34 +0100 Subject: [PATCH 23/26] Fixed potential problems with invalidated iterators. --- src/smt/theory_arith_nl.h | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/src/smt/theory_arith_nl.h b/src/smt/theory_arith_nl.h index 04b974d6e..df9a71aaa 100644 --- a/src/smt/theory_arith_nl.h +++ b/src/smt/theory_arith_nl.h @@ -589,10 +589,8 @@ namespace smt { m_dep_manager.reset(); bool propagated = false; context & ctx = get_context(); - svector::const_iterator it = m_nl_monomials.begin(); - svector::const_iterator end = m_nl_monomials.end(); - for (; it != end; ++it) { - theory_var v = *it; + for (unsigned i = 0; i < m_nl_monomials.size(); i++) { + theory_var v = m_nl_monomials.size(); expr * m = var2expr(v); if (!ctx.is_relevant(m)) continue; @@ -706,10 +704,8 @@ namespace smt { bool bounded = false; unsigned n = 0; numeral range; - svector::const_iterator it = m_nl_monomials.begin(); - svector::const_iterator end = m_nl_monomials.end(); - for (; it != end; ++it) { - theory_var v = *it; + for (unsigned i = 0; i < m_nl_monomials.size(); i++) { + theory_var v = m_nl_monomials.size(); if (is_real(v)) continue; bool computed_epsilon = false; @@ -2340,10 +2336,8 @@ namespace smt { bool theory_arith::max_min_nl_vars() { var_set already_found; svector vars; - svector::const_iterator it = m_nl_monomials.begin(); - svector::const_iterator end = m_nl_monomials.end(); - for (; it != end; ++it) { - theory_var v = *it; + for (unsigned i = 0; i < m_nl_monomials.size(); i++) { + theory_var v = m_nl_monomials.size(); mark_var(v, vars, already_found); expr * n = var2expr(v); SASSERT(is_pure_monomial(n)); From 948bf9540f92a32da1450360a0e33e10dabbd7d2 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Wed, 19 Oct 2016 12:07:33 +0100 Subject: [PATCH 24/26] Fix for previous commit. --- src/smt/theory_arith_nl.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/smt/theory_arith_nl.h b/src/smt/theory_arith_nl.h index df9a71aaa..d47ecaa4e 100644 --- a/src/smt/theory_arith_nl.h +++ b/src/smt/theory_arith_nl.h @@ -590,7 +590,7 @@ namespace smt { bool propagated = false; context & ctx = get_context(); for (unsigned i = 0; i < m_nl_monomials.size(); i++) { - theory_var v = m_nl_monomials.size(); + theory_var v = m_nl_monomials[i]; expr * m = var2expr(v); if (!ctx.is_relevant(m)) continue; @@ -705,7 +705,7 @@ namespace smt { unsigned n = 0; numeral range; for (unsigned i = 0; i < m_nl_monomials.size(); i++) { - theory_var v = m_nl_monomials.size(); + theory_var v = m_nl_monomials[i]; if (is_real(v)) continue; bool computed_epsilon = false; @@ -2337,7 +2337,7 @@ namespace smt { var_set already_found; svector vars; for (unsigned i = 0; i < m_nl_monomials.size(); i++) { - theory_var v = m_nl_monomials.size(); + theory_var v = m_nl_monomials[i]; mark_var(v, vars, already_found); expr * n = var2expr(v); SASSERT(is_pure_monomial(n)); From f9bd8f674dd9d1783cee13c96d8caecbd0d72a55 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Wed, 19 Oct 2016 12:31:06 +0100 Subject: [PATCH 25/26] whitespace --- src/sat/sat_types.h | 66 ++++++++++++++++++++++----------------------- 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/src/sat/sat_types.h b/src/sat/sat_types.h index 93109a74f..8e3460179 100644 --- a/src/sat/sat_types.h +++ b/src/sat/sat_types.h @@ -40,9 +40,9 @@ namespace sat { typedef unsigned bool_var; typedef svector bool_var_vector; - + const bool_var null_bool_var = UINT_MAX >> 1; - + /** \brief The literal b is represented by the value 2*b, and the literal (not b) by the value 2*b + 1 @@ -54,33 +54,33 @@ namespace sat { literal():m_val(null_bool_var << 1) { SASSERT(var() == null_bool_var && !sign()); } - + literal(bool_var v, bool _sign): m_val((v << 1) + static_cast(_sign)) { SASSERT(var() == v); SASSERT(sign() == _sign); } - - bool_var var() const { - return m_val >> 1; + + bool_var var() const { + return m_val >> 1; } - + bool sign() const { - return m_val & 1; + return m_val & 1; } literal unsign() const { return literal(m_val & ~1); } - + unsigned index() const { return m_val; } - + void neg() { m_val = m_val ^ 1; } - + friend literal operator~(literal l) { return literal(l.m_val ^ 1); } @@ -116,7 +116,7 @@ namespace sat { typedef approx_set_tpl literal_approx_set; typedef approx_set_tpl var_approx_set; - + enum phase { POS_PHASE, NEG_PHASE, PHASE_NOT_AVAILABLE }; @@ -128,7 +128,7 @@ namespace sat { typedef ptr_vector clause_vector; class solver_exception : public default_exception { - public: + public: solver_exception(char const * msg):default_exception(msg) {} }; @@ -138,7 +138,7 @@ namespace sat { inline lbool value_at(bool_var v, model const & m) { return m[v]; } inline lbool value_at(literal l, model const & m) { lbool r = value_at(l.var(), m); return l.sign() ? ~r : r; } - + inline std::ostream & operator<<(std::ostream & out, model const & m) { bool first = true; for (bool_var v = 0; v < m.size(); v++) { @@ -154,12 +154,12 @@ namespace sat { svector m_set; public: typedef svector::const_iterator iterator; - void insert(unsigned v) { + void insert(unsigned v) { m_in_set.reserve(v+1, false); - if (m_in_set[v]) - return; - m_in_set[v] = true; - m_set.push_back(v); + if (m_in_set[v]) + return; + m_in_set[v] = true; + m_set.push_back(v); } void remove(unsigned v) { @@ -178,22 +178,22 @@ namespace sat { m_set = other.m_set; return *this; } - - bool contains(unsigned v) const { - return v < m_in_set.size() && m_in_set[v] != 0; + + bool contains(unsigned v) const { + return v < m_in_set.size() && m_in_set[v] != 0; } - - bool empty() const { - return m_set.empty(); + + bool empty() const { + return m_set.empty(); } // erase some variable from the set - unsigned erase() { - SASSERT(!empty()); - unsigned v = m_set.back(); - m_set.pop_back(); - m_in_set[v] = false; - return v; + unsigned erase() { + SASSERT(!empty()); + unsigned v = m_set.back(); + m_set.pop_back(); + m_in_set[v] = false; + return v; } unsigned size() const { return m_set.size(); } iterator begin() const { return m_set.begin(); } @@ -280,10 +280,10 @@ namespace sat { return *this; } }; - + struct mem_stat { }; - + inline std::ostream & operator<<(std::ostream & out, mem_stat const & m) { double mem = static_cast(memory::get_allocation_size())/static_cast(1024*1024); out << " :memory " << std::fixed << std::setprecision(2) << mem; From f97ffce479e3283e59f5352d001e9ab4cd1dafc9 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Wed, 19 Oct 2016 12:31:35 +0100 Subject: [PATCH 26/26] Silenced GCC warning about empty loop body. --- src/sat/sat_types.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sat/sat_types.h b/src/sat/sat_types.h index 8e3460179..00edaa593 100644 --- a/src/sat/sat_types.h +++ b/src/sat/sat_types.h @@ -166,7 +166,8 @@ namespace sat { if (contains(v)) { m_in_set[v] = false; unsigned i = 0; - for (i = 0; i < m_set.size() && m_set[i] != v; ++i); + for (i = 0; i < m_set.size() && m_set[i] != v; ++i) + ; SASSERT(i < m_set.size()); m_set[i] = m_set.back(); m_set.pop_back();