From a7c66356aec006dd5740074e2a6dc806f608758b Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Tue, 3 May 2016 18:20:18 +0100 Subject: [PATCH 01/61] mpf partial remainder draft --- src/util/mpf.cpp | 214 ++++++++++++++++++++++++++++++++++++++--------- src/util/mpf.h | 10 ++- 2 files changed, 182 insertions(+), 42 deletions(-) diff --git a/src/util/mpf.cpp b/src/util/mpf.cpp index de215c95834..ceb40778156 100644 --- a/src/util/mpf.cpp +++ b/src/util/mpf.cpp @@ -1214,6 +1214,154 @@ void mpf_manager::to_ieee_bv_mpz(const mpf & x, scoped_mpz & o) { } } +void mpf_manager::prem(scoped_mpf & x, scoped_mpf const & y, mpf_exp_t const & exp_diff, bool partial) { + unsigned ebits = x.get().ebits; + unsigned sbits = x.get().sbits; + bool sign = x.get().sign; + + signed int D = (unsigned)(partial ? 0 : exp_diff); + mpf_exp_t N = sbits/2; + + TRACE("mpf_dbg_rem", tout << "x=" << to_string(x) << std::endl; + tout << "y=" << to_string(y) << std::endl; + tout << "d=" << D << std::endl; + tout << "partial=" << partial << std::endl;); + + // 1. Compute a/b + unsigned extra_bits = sbits + 2; + scoped_mpz x_sig_shifted(m_mpz_manager), x_div_y_sig_lrg(m_mpz_manager); + scoped_mpz x_div_y_sig(m_mpz_manager), x_rem_y_sig(m_mpz_manager); + m_mpz_manager.mul2k(x.significand(), sbits + extra_bits, x_sig_shifted); + m_mpz_manager.machine_div(x_sig_shifted, y.significand(), x_div_y_sig_lrg); + m_mpz_manager.machine_div_rem(x_div_y_sig_lrg, m_powers2(extra_bits-2), x_div_y_sig, x_rem_y_sig); + TRACE("mpf_dbg_rem", tout << "X/Y_sig=" << m_mpz_manager.to_string(x_div_y_sig) << std::endl; + tout << "X%Y_sig=" << m_mpz_manager.to_string(x_rem_y_sig) << std::endl; + tout << "X/Y=" << to_string_hexfloat( + to_packed_mpf(x.sign(), D, x_div_y_sig, ebits, sbits, 3)) << std::endl;); + SASSERT(m_mpz_manager.lt(x_div_y_sig, m_powers2(sbits + 3))); // 3 extra bits in x_div_y_sig. + SASSERT(m_mpz_manager.ge(x_div_y_sig, m_powers2(sbits - 1 + 3))); + // Bug: a_rem_b_sig is not used. + + // 2. Round a/b to integer Q/QQ + mpf_exp_t Q_exp = partial ? N : D; + scoped_mpz Q_sig(m_mpz_manager), Q_rem(m_mpz_manager); + if (partial) { + // Round according to MPF_ROUND_TOWARD_ZERO + SASSERT(N < D && D < INT_MAX); + unsigned D_N = (unsigned)(D-N); + unsigned Q_shft = (sbits - 1) - D_N; + m_mpz_manager.machine_div_rem(x_div_y_sig, m_powers2(Q_shft+3), Q_sig, Q_rem); + m_mpz_manager.mul2k(Q_sig, Q_shft); + } + else { + // Round according to MPF_ROUND_NEAREST_TEVEN + unsigned Q_shft = (sbits - 1) - D; + m_mpz_manager.machine_div_rem(x_div_y_sig, m_powers2(Q_shft+3), Q_sig, Q_rem); + const mpz & shiftm1_p = m_powers2(Q_shft-1); + bool tie = m_mpz_manager.eq(Q_rem, shiftm1_p); + bool more_than_tie = m_mpz_manager.gt(Q_rem, shiftm1_p); + TRACE("mpf_dbg_rem", tout << "tie= " << tie << "; >tie= " << more_than_tie << std::endl;); + if ((tie && m_mpz_manager.is_odd(Q_sig)) || more_than_tie) + m_mpz_manager.inc(Q_sig); + m_mpz_manager.mul2k(Q_sig, Q_shft); + SASSERT(m_mpz_manager.ge(Q_sig, m_powers2(sbits-1))); + } + TRACE("mpf_dbg_rem", tout << "Q_sig'=" << m_mpz_manager.to_string(Q_sig) << std::endl; + tout << "Q_rem=" << m_mpz_manager.to_string(Q_rem) << std::endl; ); + + // re-normalize Q + while (m_mpz_manager.ge(Q_sig, m_powers2(sbits))) { + m_mpz_manager.machine_div2k(Q_sig, 1); + Q_exp++; + } + + TRACE("mpf_dbg_rem", tout << "Q_exp=" << Q_exp << std::endl; + tout << "Q_sig=" << m_mpz_manager.to_string(Q_sig) << std::endl; + scoped_mpf & Q = to_packed_mpf(x.sign(), Q_exp, Q_sig, ebits, sbits, 0); + tout << "Q=" << to_string_hexfloat(Q) << std::endl;); + + // 3. Compute Y*Q / Y*QQ*2^{D-N} + scoped_mpz YQ_sig(m_mpz_manager); + mpf_exp_t YQ_exp = (Q_exp + y.exponent()) + (partial ? D-N : 0); + m_mpz_manager.mul(y.significand(), Q_sig, YQ_sig); + + if (sbits >= 7) { + scoped_mpz sticky_rem(m_mpz_manager); + m_mpz_manager.machine_div_rem(YQ_sig, m_powers2(sbits-7), YQ_sig, sticky_rem); + if (!m_mpz_manager.is_zero(sticky_rem) && m_mpz_manager.is_even(YQ_sig)) + m_mpz_manager.inc(YQ_sig); + } + else + m_mpz_manager.mul2k(YQ_sig, 7-sbits, YQ_sig); + + TRACE("mpf_dbg_rem", tout << "YQ_exp=" << YQ_exp << std::endl; + tout << "YQ_sig=" << m_mpz_manager.to_string(YQ_sig) << std::endl; + scoped_mpf & YQ = to_packed_mpf(x.sign(), YQ_exp, YQ_sig, ebits, sbits, 6); + tout << "YQ=" << to_string_hexfloat(YQ) << std::endl;); + + // 4. Compute X-Y*Q + bool YQ_sgn = !x.sign(); + mpf_exp_t X_YQ_exp = x.exponent() - 3; + scoped_mpz X_YQ_sig(m_mpz_manager); + mpf_exp_t exp_delta = exp(x) - YQ_exp; + TRACE("mpf_dbg_rem", tout << "exp_delta=" << exp_delta << std::endl;); + scoped_mpz minuend(m_mpz_manager), subtrahend(m_mpz_manager); + + if (exp_delta >= 0) { + m_mpz_manager.set(minuend, x.significand()); + m_mpz_manager.set(subtrahend, YQ_sig); + } + else if (exp_delta < 0) { + m_mpz_manager.set(minuend, YQ_sig); + m_mpz_manager.set(subtrahend, x.significand()); + YQ_sgn = !YQ_sgn; + exp_delta = -exp_delta; + } + + if (exp_delta != 0) { + scoped_mpz sticky_rem(m_mpz_manager); + if (exp_delta > sbits+5) { + m_mpz_manager.set(sticky_rem, 0); + sticky_rem.swap(subtrahend); + } + else + m_mpz_manager.machine_div_rem(subtrahend, m_powers2((unsigned)exp_delta), subtrahend, sticky_rem); + if (!m_mpz_manager.is_zero(sticky_rem) && m_mpz_manager.is_even(subtrahend)) + m_mpz_manager.inc(subtrahend); + TRACE("mpf_dbg_rem", tout << "aligned subtrahend=" << m_mpz_manager.to_string(subtrahend) << std::endl;); + } + + scoped_mpz minuend_lrg(m_mpz_manager); + m_mpz_manager.mul2k(minuend, 6, minuend_lrg); // + 6 extra bits into X + m_mpz_manager.sub(minuend_lrg, subtrahend, X_YQ_sig); + + TRACE("mpf_dbg_rem", tout << "minuend=" << m_mpz_manager.to_string(minuend) << std::endl; + tout << "subtrahend=" << m_mpz_manager.to_string(subtrahend) << std::endl; + tout << "X_YQ_exp=" << X_YQ_exp << std::endl; + tout << "X_YQ_sig=" << m_mpz_manager.to_string(X_YQ_sig) << std::endl; + scoped_mpf & X_YQ = to_packed_mpf(YQ_sgn, X_YQ_exp, X_YQ_sig, ebits, sbits, 3); + tout << "X-YQ=" << to_string_hexfloat(X_YQ) << std::endl;); + + SASSERT(m_mpz_manager.lt(X_YQ_sig, m_powers2(sbits+5))); + + // 5. Rounding + if (m_mpz_manager.is_zero(X_YQ_sig)) { + TRACE("mpf_dbg_rem", tout << "sig zero" << std::endl;); + mk_zero(ebits, sbits, x.sign(), x); + } + else { + bool neg = m_mpz_manager.is_neg(X_YQ_sig); + if (neg) m_mpz_manager.neg(X_YQ_sig); + bool X_YQ_sgn = ((!x.sign() && YQ_sgn && neg) || + (x.sign() && !YQ_sgn && !neg) || + (x.sign() && YQ_sgn)); + set(x, ebits, sbits, X_YQ_sgn, X_YQ_exp, X_YQ_sig); + round(MPF_ROUND_NEAREST_TEVEN, x); + } + + TRACE("mpf_dbg_rem", tout << "partial remainder = " << to_string_hexfloat(x) << std::endl;); +} + void mpf_manager::rem(mpf const & x, mpf const & y, mpf & o) { SASSERT(x.sbits == y.sbits && x.ebits == y.ebits); @@ -1231,54 +1379,32 @@ void mpf_manager::rem(mpf const & x, mpf const & y, mpf & o) { else if (is_zero(x)) set(o, x); else { - // This is a generalized version of the algorithm for FPREM1 in the Intel + SASSERT(is_regular(x) && is_regular(y)); + SASSERT(x.exponent >= y.exponent); + + // This is a generalized version of the algorithm for FPREM1 in the `Intel // 64 and IA-32 Architectures Software Developer's Manual', - // Section 3-402 Vol. 2A FPREM1-Partial Remainder'. + // Section 3-402 Vol. 2A `FPREM1-Partial Remainder'. scoped_mpf ST0(*this), ST1(*this); set(ST0, x); set(ST1, y); + unpack(ST0, true); + unpack(ST1, true); - const mpf_exp_t B = x.sbits-1; // max bits per iteration. + const mpf_exp_t B = x.sbits; // max bits per iteration. mpf_exp_t D; do { D = ST0.exponent() - ST1.exponent(); - TRACE("mpf_dbg_rem", tout << "st0=" << to_string_hexfloat(ST0) << std::endl; - tout << "st1=" << to_string_hexfloat(ST1) << std::endl; - tout << "D=" << D << std::endl;); + SASSERT(0 <= D && D < INT64_MAX); - if (D < B) { - scoped_mpf ST0_DIV_ST1(*this), Q(*this), ST1_MUL_Q(*this), ST0p(*this); - div(MPF_ROUND_NEAREST_TEVEN, ST0, ST1, ST0_DIV_ST1); - round_to_integral(MPF_ROUND_NEAREST_TEVEN, ST0_DIV_ST1, Q); - mul(MPF_ROUND_NEAREST_TEVEN, ST1, Q, ST1_MUL_Q); - sub(MPF_ROUND_NEAREST_TEVEN, ST0, ST1_MUL_Q, ST0p); - TRACE("mpf_dbg_rem", tout << "ST0/ST1=" << to_string_hexfloat(ST0_DIV_ST1) << std::endl; - tout << "Q=" << to_string_hexfloat(Q) << std::endl; - tout << "ST1*Q=" << to_string_hexfloat(ST1_MUL_Q) << std::endl; - tout << "ST0'=" << to_string_hexfloat(ST0p) << std::endl;); - set(ST0, ST0p); - } - else { - const mpf_exp_t N = B; - scoped_mpf ST0_DIV_ST1(*this), QQ(*this), ST1_MUL_QQ(*this), ST0p(*this); - div(MPF_ROUND_TOWARD_ZERO, ST0, ST1, ST0_DIV_ST1); - ST0_DIV_ST1.get().exponent -= D - N; - round_to_integral(MPF_ROUND_TOWARD_ZERO, ST0_DIV_ST1, QQ); - mul(MPF_ROUND_NEAREST_TEVEN, ST1, QQ, ST1_MUL_QQ); - ST1_MUL_QQ.get().exponent += D - N; - sub(MPF_ROUND_NEAREST_TEVEN, ST0, ST1_MUL_QQ, ST0p); - TRACE("mpf_dbg_rem", tout << "ST0/ST1/2^{D-N}=" << to_string_hexfloat(ST0_DIV_ST1) << std::endl; - tout << "QQ=" << to_string_hexfloat(QQ) << std::endl; - tout << "ST1*QQ*2^{D-N}=" << to_string_hexfloat(ST1_MUL_QQ) << std::endl; - tout << "ST0'=" << to_string_hexfloat(ST0p) << std::endl;); - SASSERT(!eq(ST0, ST0p)); - set(ST0, ST0p); - } + TRACE("mpf_dbg_rem", tout << "ST0=" << to_string_raw(ST0) << "=" << to_string_hexfloat(ST0) << std::endl; + tout << "ST1=" << to_string_raw(ST1) << "=" << to_string_hexfloat(ST1) << std::endl; + tout << "D=" << D << std::endl;); - SASSERT(ST0.exponent() - ST1.exponent() <= D); + prem(ST0, ST1, D, (D >= B)); } while (D >= B); - set(o, ST0); + set(o, x.ebits, x.sbits, MPF_ROUND_TOWARD_ZERO, ST0); if (is_zero(o)) o.sign = x.sign; } @@ -1364,9 +1490,9 @@ std::string mpf_manager::to_string(mpf const & x) { } } - //DEBUG_CODE( - // res += " " + to_string_hexfloat(x); - //); + DEBUG_CODE( + res += " " + to_string_raw(x); + ); return res; } @@ -1407,6 +1533,16 @@ std::string mpf_manager::to_string_raw(mpf const & x) { return res; } +scoped_mpf mpf_manager::to_packed_mpf(bool sgn, mpf_exp_t exp, scoped_mpz const & sig, unsigned ebits, unsigned sbits, unsigned rbits) { + scoped_mpf q(*this); + scoped_mpz q_sig(m_mpz_manager); + m_mpz_manager.set(q_sig, sig); + if (rbits != 0) m_mpz_manager.div(q_sig, m_powers2(rbits), q_sig); // restore scale + m_mpz_manager.sub(q_sig, m_powers2(sbits-1), q_sig); // strip hidden bit + set(q, ebits, sbits, sgn, exp, q_sig); + return q; +} + std::string mpf_manager::to_string_hexfloat(mpf const & x) { std::stringstream ss(""); std::ios::fmtflags ff = ss.setf(std::ios_base::hex | std::ios_base::uppercase | diff --git a/src/util/mpf.h b/src/util/mpf.h index 1bd0ac95235..e6bf3cd271e 100644 --- a/src/util/mpf.h +++ b/src/util/mpf.h @@ -185,9 +185,6 @@ class mpf_manager { void mk_pinf(unsigned ebits, unsigned sbits, mpf & o); void mk_ninf(unsigned ebits, unsigned sbits, mpf & o); - std::string to_string_raw(mpf const & a); - std::string to_string_hexfloat(mpf const & a); - unsynch_mpz_manager & mpz_manager(void) { return m_mpz_manager; } unsynch_mpq_manager & mpq_manager(void) { return m_mpq_manager; } @@ -226,6 +223,8 @@ class mpf_manager { void round(mpf_rounding_mode rm, mpf & o); void round_sqrt(mpf_rounding_mode rm, mpf & o); + void prem(scoped_mpf & x, scoped_mpf const & y, mpf_exp_t const & exp_diff, bool partial); + void mk_round_inf(mpf_rounding_mode rm, mpf & o); // Convert x into a mpz numeral. zm is the manager that owns o. @@ -284,6 +283,10 @@ class mpf_manager { } }; + std::string to_string_raw(mpf const & a); + std::string to_string_hexfloat(mpf const & a); + scoped_mpf to_packed_mpf(bool sgn, mpf_exp_t exp, scoped_mpz const & sig, unsigned ebits, unsigned sbits, unsigned rbits); + public: powers2 m_powers2; }; @@ -291,6 +294,7 @@ class mpf_manager { class scoped_mpf : public _scoped_numeral { friend class mpf_manager; mpz & significand() { return get().significand; } + const mpz & significand() const { return get().significand; } bool sign() const { return get().sign; } mpf_exp_t exponent() const { return get().exponent; } unsigned sbits() const { return get().sbits; } From 91af947863fe279f4672c3c0554c9a1b81e0d1a3 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 3 May 2016 11:09:05 -0700 Subject: [PATCH 02/61] adding checks for #570 Signed-off-by: Nikolaj Bjorner --- src/sat/sat_clause_set.cpp | 8 +++++++- src/smt/theory_arith_core.h | 26 ++++++++++++++++++-------- 2 files changed, 25 insertions(+), 9 deletions(-) diff --git a/src/sat/sat_clause_set.cpp b/src/sat/sat_clause_set.cpp index ca8e9d84140..29c761130e6 100644 --- a/src/sat/sat_clause_set.cpp +++ b/src/sat/sat_clause_set.cpp @@ -35,6 +35,8 @@ namespace sat { unsigned id = c.id(); if (id >= m_id2pos.size()) return; + if (empty()) + return; unsigned pos = m_id2pos[id]; if (pos == UINT_MAX) return; @@ -52,7 +54,11 @@ namespace sat { clause & clause_set::erase() { SASSERT(!empty()); clause & c = *m_set.back(); - m_id2pos[c.id()] = UINT_MAX; + SASSERT(c.id() < m_id2pos.size()); + SASSERT(m_id2pos[c.id()] == m_set.size()-1); + if (c.id() < m_id2pos.size()) { + m_id2pos[c.id()] = UINT_MAX; + } m_set.pop_back(); return c; } diff --git a/src/smt/theory_arith_core.h b/src/smt/theory_arith_core.h index 8a83b93bdf3..95c7fdfad50 100644 --- a/src/smt/theory_arith_core.h +++ b/src/smt/theory_arith_core.h @@ -1866,7 +1866,7 @@ namespace smt { template template void theory_arith::pivot(theory_var x_i, theory_var x_j, numeral const & a_ij, bool apply_gcd_test) { - TRACE("arith_pivot", tout << "pivoting: v" << x_i << ", v" << x_j << "\n";); + TRACE("arith_pivoting", tout << "pivoting: v" << x_i << ", v" << x_j << "\n";); m_stats.m_pivots++; SASSERT(is_base(x_i) || is_quasi_base(x_i)); SASSERT(x_i != x_j); @@ -2067,14 +2067,14 @@ namespace smt { theory_var max = get_num_vars(); theory_var result = max; row const & r = m_rows[get_var_row(x_i)]; - int n; int best_col_sz = INT_MAX; int best_so_far = INT_MAX; - - typename vector::const_iterator it = r.begin_entries(); + int n = 0; + typename vector::const_iterator it = r.begin_entries(); typename vector::const_iterator end = r.end_entries(); - - for (; it != end; ++it) { + + for (; it != end; ++it) { + if (!it->is_dead()) { theory_var x_j = it->m_var; numeral const & a_ij = it->m_coeff; @@ -2090,14 +2090,14 @@ namespace smt { best_so_far = num; best_col_sz = col_sz; n = 1; - } + } else if (num == best_so_far && col_sz == best_col_sz) { n++; if (m_random()%n == 0) { result = x_j; out_a_ij = a_ij; } - } + } } } } @@ -2174,6 +2174,7 @@ namespace smt { inf_numeral curr_error; typename var_heap::iterator it = m_to_patch.begin(); typename var_heap::iterator end = m_to_patch.end(); + //unsigned n = 0; for (; it != end; ++it) { theory_var v = *it; if (below_lower(v)) @@ -2188,7 +2189,16 @@ namespace smt { << ", best_error: " << best_error << ", curr_error: " << curr_error << "\n";); best = v; best_error = curr_error; + //n = 2; + } +#if 0 + else if (false && n > 0 && curr_error == best_error) { + n++; + if (m_random()%n == 0) { + best = v; + } } +#endif } if (best == null_theory_var) m_to_patch.clear(); // all variables are satisfied From d11d9bd1de1d90dbca9db865ee6d5b4e52a5888a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 3 May 2016 16:24:12 -0700 Subject: [PATCH 03/61] avoid crash on quantifiers + sequences Signed-off-by: Nikolaj Bjorner --- src/smt/theory_seq.cpp | 6 ++++-- src/smt/theory_seq_empty.h | 25 +++++++++++++++++++++---- 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index a8811b1793a..86761412f7b 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -2380,7 +2380,7 @@ void theory_seq::init_model(expr_ref_vector const& es) { } void theory_seq::init_model(model_generator & mg) { - m_factory = alloc(seq_factory, get_manager(), get_family_id()); + m_factory = alloc(seq_factory, get_manager(), get_family_id(), mg.get_model()); mg.register_factory(m_factory); for (unsigned j = 0; j < m_nqs.size(); ++j) { ne const& n = m_nqs[j]; @@ -2469,7 +2469,9 @@ model_value_proc * theory_seq::mk_value(enode * n, model_generator & mg) { for (unsigned i = 0; i < concats.size(); ++i) { expr* c = concats[i], *c1; if (m_util.str.is_unit(c, c1)) { - sv->add_dependency(ctx.get_enode(c1)); + if (ctx.e_internalized(c1)) { + sv->add_dependency(ctx.get_enode(c1)); + } } else if (m_util.str.is_string(c)) { sv->add_string(c); diff --git a/src/smt/theory_seq_empty.h b/src/smt/theory_seq_empty.h index be17fe5ac69..27c72cc974d 100644 --- a/src/smt/theory_seq_empty.h +++ b/src/smt/theory_seq_empty.h @@ -25,6 +25,7 @@ Revision History: namespace smt { class seq_factory : public value_factory { typedef hashtable symbol_set; + proto_model& m_model; ast_manager& m; seq_util u; symbol_set m_strings; @@ -34,8 +35,9 @@ namespace smt { expr_ref_vector m_trail; public: - seq_factory(ast_manager & m, family_id fid): + seq_factory(ast_manager & m, family_id fid, proto_model& md): value_factory(m, fid), + m_model(md), m(m), u(m), m_next(0), @@ -78,6 +80,17 @@ namespace smt { v2 = u.str.mk_string(symbol("b")); return true; } + sort* ch; + if (u.is_seq(s, ch)) { + if (m_model.get_some_values(ch, v1, v2)) { + v1 = u.str.mk_unit(v1); + v2 = u.str.mk_unit(v2); + return true; + } + else { + return false; + } + } NOT_IMPLEMENTED_YET(); return false; } @@ -92,7 +105,7 @@ namespace smt { return u.str.mk_string(sym); } } - sort* seq = 0; + sort* seq = 0, *ch = 0; if (u.is_re(s, seq)) { expr* v0 = get_fresh_value(seq); return u.re.mk_to_re(v0); @@ -102,7 +115,11 @@ namespace smt { //return u.str.mk_char(zstring(s), 0); return u.str.mk_char(zstring("a"), 0); } - NOT_IMPLEMENTED_YET(); + if (u.is_seq(s, ch)) { + expr* v = m_model.get_fresh_value(ch); + return u.str.mk_unit(v); + } + UNREACHABLE(); return 0; } virtual void register_value(expr* n) { @@ -126,7 +143,7 @@ namespace smt { public: theory_seq_empty(ast_manager& m):theory(m.mk_family_id("seq")), m_used(false) {} virtual void init_model(model_generator & mg) { - mg.register_factory(alloc(seq_factory, get_manager(), get_family_id())); + mg.register_factory(alloc(seq_factory, get_manager(), get_family_id(), mg.get_model())); } }; From 044e08a11467b9f3e3712f90129ad8b2b7bccf5b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 4 May 2016 11:17:09 -0700 Subject: [PATCH 04/61] adding unit tests for qe_arith/mbo Signed-off-by: Nikolaj Bjorner --- src/qe/qe_arith.cpp | 91 ++++++++++++++---------- src/test/qe_arith.cpp | 160 +++++++++++++++++++++++++++++++++++++++++- 2 files changed, 214 insertions(+), 37 deletions(-) diff --git a/src/qe/qe_arith.cpp b/src/qe/qe_arith.cpp index 60111a47306..58a290c0b7f 100644 --- a/src/qe/qe_arith.cpp +++ b/src/qe/qe_arith.cpp @@ -51,13 +51,6 @@ namespace qe { } return is_divides(a, e1, e2, k, t) || is_divides(a, e2, e1, k, t); } - - -#if 0 - obj_map m_expr2var; - ptr_vector m_var2expr; - -#endif struct arith_project_plugin::imp { @@ -88,18 +81,23 @@ namespace qe { } } - void insert_mul(expr* x, rational const& v, obj_map& ts) - { + void insert_mul(expr* x, rational const& v, obj_map& ts) { rational w; if (ts.find(x, w)) { ts.insert(x, w + v); } else { + TRACE("qe", tout << "Adding variable " << mk_pp(x, m) << "\n";); ts.insert(x, v); } } - void linearize(model& model, opt::model_based_opt& mbo, expr* lit, obj_map& tids) { + // + // extract linear inequalities from literal 'lit' into the model-based optimization manager 'mbo'. + // It uses the current model to choose values for conditionals and it primes mbo with the current + // interpretation of sub-expressions that are treated as variables for mbo. + // + void linearize(opt::model_based_opt& mbo, model& model, expr* lit, obj_map& tids) { obj_map ts; rational c(0), mul(1); expr_ref t(m); @@ -112,19 +110,19 @@ namespace qe { SASSERT(!m.is_not(lit)); if (a.is_le(lit, e1, e2) || a.is_ge(lit, e2, e1)) { if (is_not) mul.neg(); - linearize(model, mul, e1, c, ts); - linearize(model, -mul, e2, c, ts); + linearize(mbo, model, mul, e1, c, ts, tids); + linearize(mbo, model, -mul, e2, c, ts, tids); ty = is_not ? opt::t_lt : opt::t_le; } else if (a.is_lt(lit, e1, e2) || a.is_gt(lit, e2, e1)) { if (is_not) mul.neg(); - linearize(model, mul, e1, c, ts); - linearize(model, -mul, e2, c, ts); + linearize(mbo, model, mul, e1, c, ts, tids); + linearize(mbo, model, -mul, e2, c, ts, tids); ty = is_not ? opt::t_le: opt::t_lt; } else if (m.is_eq(lit, e1, e2) && !is_not && is_arith(e1)) { - linearize(model, mul, e1, c, ts); - linearize(model, -mul, e2, c, ts); + linearize(mbo, model, mul, e1, c, ts, tids); + linearize(mbo, model, -mul, e2, c, ts, tids); ty = opt::t_eq; } else if (m.is_distinct(lit) && !is_not && is_arith(to_app(lit)->get_arg(0))) { @@ -137,55 +135,63 @@ namespace qe { UNREACHABLE(); } else { + TRACE("qe", tout << "Skipping " << mk_pp(lit, m) << "\n";); return; } - if (ty == opt::t_lt && is_int()) { +#if 0 + TBD for integers + if (ty == opt::t_lt && false) { c += rational(1); ty = opt::t_le; } +#endif vars coeffs; - extract_coefficients(ts, tids, coeffs); + extract_coefficients(mbo, model, ts, tids, coeffs); mbo.add_constraint(coeffs, c, ty); } - void linearize(model& model, rational const& mul, expr* t, rational& c, obj_map& ts) { + // + // convert linear arithmetic term into an inequality for mbo. + // + void linearize(opt::model_based_opt& mbo, model& model, rational const& mul, expr* t, rational& c, + obj_map& ts, obj_map& tids) { expr* t1, *t2, *t3; rational mul1; expr_ref val(m); if (a.is_mul(t, t1, t2) && is_numeral(model, t1, mul1)) { - linearize(model, mul* mul1, t2, c, ts); + linearize(mbo, model, mul* mul1, t2, c, ts, tids); } else if (a.is_mul(t, t1, t2) && is_numeral(model, t2, mul1)) { - linearize(model, mul* mul1, t1, c, ts); + linearize(mbo, model, mul* mul1, t1, c, ts, tids); } else if (a.is_add(t)) { app* ap = to_app(t); for (unsigned i = 0; i < ap->get_num_args(); ++i) { - linearize(model, mul, ap->get_arg(i), c, ts); + linearize(mbo, model, mul, ap->get_arg(i), c, ts, tids); } } else if (a.is_sub(t, t1, t2)) { - linearize(model, mul, t1, c, ts); - linearize(model, -mul, t2, c, ts); + linearize(mbo, model, mul, t1, c, ts, tids); + linearize(mbo, model, -mul, t2, c, ts, tids); } else if (a.is_uminus(t, t1)) { - linearize(model, -mul, t1, c, ts); + linearize(mbo, model, -mul, t1, c, ts, tids); } else if (a.is_numeral(t, mul1)) { c += mul*mul1; } - else if (extract_mod(model, t, val)) { - insert_mul(val, mul, ts); - } else if (m.is_ite(t, t1, t2, t3)) { VERIFY(model.eval(t1, val)); SASSERT(m.is_true(val) || m.is_false(val)); TRACE("qe", tout << mk_pp(t1, m) << " := " << val << "\n";); if (m.is_true(val)) { - linearize(model, mul, t2, c, ts); + linearize(mbo, model, mul, t2, c, ts, tids); + linearize(mbo, model, t1, tids); } else { - linearize(model, mul, t3, c, ts); + expr_ref not_t1(mk_not(m, t1), m); + linearize(mbo, model, mul, t3, c, ts, tids); + linearize(mbo, model, not_t1, tids); } } else { @@ -193,6 +199,9 @@ namespace qe { } } + // + // extract linear terms from t into c and ts. + // void is_linear(model& model, rational const& mul, expr* t, rational& c, expr_ref_vector& ts) { expr* t1, *t2, *t3; rational mul1; @@ -245,7 +254,9 @@ namespace qe { } } - + // + // extract linear inequalities from literal lit. + // bool is_linear(model& model, expr* lit, bool& found_eq) { rational c(0), mul(1); expr_ref t(m); @@ -977,13 +988,13 @@ namespace qe { // extract objective function. vars coeffs; rational c(0), mul(1); - linearize(mdl, mul, t, c, ts); - extract_coefficients(ts, tids, coeffs); + linearize(mbo, mdl, mul, t, c, ts, tids); + extract_coefficients(mbo, mdl, ts, tids, coeffs); mbo.set_objective(coeffs, c); // extract linear constraints for (unsigned i = 0; i < fmls.size(); ++i) { - linearize(mdl, mbo, fmls[i], tids); + linearize(mbo, mdl, fmls[i], tids); } // find optimal value @@ -1021,13 +1032,21 @@ namespace qe { return value; } - void extract_coefficients(obj_map const& ts, obj_map& tids, vars& coeffs) { + void extract_coefficients(opt::model_based_opt& mbo, model& model, obj_map const& ts, obj_map& tids, vars& coeffs) { coeffs.reset(); obj_map::iterator it = ts.begin(), end = ts.end(); for (; it != end; ++it) { unsigned id; if (!tids.find(it->m_key, id)) { - id = tids.size(); + rational r; + expr_ref val(m); + if (model.eval(it->m_key, val) && a.is_numeral(val, r)) { + id = mbo.add_var(r); + } + else { + TRACE("qe", tout << "extraction of coefficients cancelled\n";); + return; + } tids.insert(it->m_key, id); } coeffs.push_back(var(id, it->m_value)); diff --git a/src/test/qe_arith.cpp b/src/test/qe_arith.cpp index a1b5c28598f..f14ccf3e2e2 100644 --- a/src/test/qe_arith.cpp +++ b/src/test/qe_arith.cpp @@ -280,12 +280,170 @@ static void test2(char const *ex) { ctx.assert_expr(pr1); ctx.assert_expr(npr2); VERIFY(l_false == ctx.check()); - ctx.pop(1); + ctx.pop(1); +} + +typedef opt::model_based_opt::var var_t; + +static void mk_var(unsigned x, app_ref& v) { + ast_manager& m = v.get_manager(); + arith_util a(m); + std::ostringstream strm; + strm << "v" << x; + v = m.mk_const(symbol(strm.str().c_str()), a.mk_real()); +} + +static void mk_term(vector const& vars, rational const& coeff, app_ref& term) { + ast_manager& m = term.get_manager(); + expr_ref_vector ts(m); + arith_util a(m); + + for (unsigned i = 0; i < vars.size(); ++i) { + app_ref var(m); + mk_var(vars[i].m_id, var); + rational coeff = vars[i].m_coeff; + ts.push_back(a.mk_mul(a.mk_numeral(coeff, false), var)); + } + ts.push_back(a.mk_numeral(coeff, a.mk_real())); + term = a.mk_add(ts.size(), ts.c_ptr()); +} + +static void add_random_ineq( + expr_ref_vector& fmls, + opt::model_based_opt& mbo, + random_gen& r, + svector const& values, + unsigned max_vars, + unsigned max_coeff) +{ + ast_manager& m = fmls.get_manager(); + arith_util a(m); + + unsigned num_vars = values.size(); + uint_set used_vars; + vector vars; + int value = 0; + for (unsigned i = 0; i < max_vars; ++i) { + unsigned x = r(num_vars); + if (used_vars.contains(x)) { + continue; + } + used_vars.insert(x); + int coeff = r(max_coeff + 1); + if (coeff == 0) { + continue; + } + unsigned sign = r(2); + coeff = sign == 0 ? coeff : -coeff; + vars.push_back(var_t(x, rational(coeff))); + value += coeff*values[x]; + } + unsigned abs_value = value < 0 ? - value : value; + // value + k <= 0 + // k <= - value + // range for k is 2*|value| + // k <= - value - range + opt::ineq_type rel = opt::t_le; + + int coeff = 0; + if (r(4) == 0) { + rel = opt::t_eq; + coeff = -value; + } + else { + if (abs_value > 0) { + coeff = -value - r(2*abs_value); + } + else { + coeff = 0; + } + if (coeff != -value && r(3) == 0) { + rel = opt::t_lt; + } + } + expr_ref fml(m); + app_ref t1(m); + app_ref t2(a.mk_numeral(rational(0), a.mk_real()), m); + mk_term(vars, rational(coeff), t1); + switch (rel) { + case opt::t_eq: + fml = m.mk_eq(t1, t2); + break; + case opt::t_lt: + fml = a.mk_lt(t1, t2); + break; + case opt::t_le: + fml = a.mk_le(t1, t2); + break; + } + fmls.push_back(fml); + mbo.add_constraint(vars, rational(coeff), rel); +} + +static void test_maximize(opt::model_based_opt& mbo, ast_manager& m, unsigned num_vars, expr_ref_vector const& fmls, app* t) { + qe::arith_project_plugin plugin(m); + model mdl(m); + expr_ref bound(m); + arith_util a(m); + for (unsigned i = 0; i < num_vars; ++i) { + app_ref var(m); + mk_var(i, var); + rational val = mbo.get_value(i); + mdl.register_decl(var->get_decl(), a.mk_numeral(val, false)); + } + opt::inf_eps value1 = plugin.maximize(fmls, mdl, t, bound); + opt::inf_eps value2 = mbo.maximize(); + std::cout << "optimal: " << value1 << " " << value2 << "\n"; + mbo.display(std::cout); +} + +static void check_random_ineqs(random_gen& r, ast_manager& m, unsigned num_vars, unsigned max_value, unsigned num_ineqs, unsigned max_vars, unsigned max_coeff) { + opt::model_based_opt mbo; + expr_ref_vector fmls(m); + + svector values; + for (unsigned i = 0; i < num_vars; ++i) { + values.push_back(r(max_value + 1)); + mbo.add_var(rational(values.back())); + } + for (unsigned i = 0; i < num_ineqs; ++i) { + add_random_ineq(fmls, mbo, r, values, max_vars, max_coeff); + } + + vector vars; + vars.reset(); + vars.push_back(var_t(0, rational(2))); + vars.push_back(var_t(1, rational(-2))); + mbo.set_objective(vars, rational(0)); + + + mbo.display(std::cout); + app_ref t(m); + mk_term(vars, rational(0), t); + test_maximize(mbo, m, num_vars, fmls, t); + for (unsigned i = 0; i < values.size(); ++i) { + std::cout << i << ": " << values[i] << " -> " << mbo.get_value(i) << "\n"; + } +} + +static void check_random_ineqs() { + random_gen r(1); + ast_manager m; + reg_decl_plugins(m); + + for (unsigned i = 0; i < 100; ++i) { + check_random_ineqs(r, m, 4, 5, 5, 3, 6); + } } + + + void tst_qe_arith() { + check_random_ineqs(); + return; // enable_trace("qe"); testI(example8); testR(example7); From 0286cee45026a1cf97ae9f001b4049496267f691 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Thu, 5 May 2016 11:00:21 +0100 Subject: [PATCH 05/61] simplify th_rewriter::mk_eq_value() --- src/ast/rewriter/th_rewriter.cpp | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/ast/rewriter/th_rewriter.cpp b/src/ast/rewriter/th_rewriter.cpp index ab711dde760..6f6daf8dfb4 100644 --- a/src/ast/rewriter/th_rewriter.cpp +++ b/src/ast/rewriter/th_rewriter.cpp @@ -212,14 +212,11 @@ struct th_rewriter_cfg : public default_rewriter_cfg { // auxiliary function for pull_ite_core expr * mk_eq_value(expr * lhs, expr * value) { - SASSERT(m().is_value(value)); - if (m().is_value(lhs)) { - if (m().are_equal(lhs, value)) { - return m().mk_true(); - } - else if (m().are_distinct(lhs, value)) { - return m().mk_false(); - } + if (m().are_equal(lhs, value)) { + return m().mk_true(); + } + else if (m().are_distinct(lhs, value)) { + return m().mk_false(); } return m().mk_eq(lhs, value); } From 5b31f5450170e29910b7d5535c9126d768ddc478 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 5 May 2016 14:11:13 -0700 Subject: [PATCH 06/61] max/min Signed-off-by: Nikolaj Bjorner --- src/opt/opt_cmds.cpp | 15 ++- src/opt/opt_context.cpp | 8 +- src/qe/qsat.cpp | 243 ++++++++++++++-------------------------- src/qe/qsat.h | 11 ++ 4 files changed, 110 insertions(+), 167 deletions(-) diff --git a/src/opt/opt_cmds.cpp b/src/opt/opt_cmds.cpp index f5d98e498ba..f8f78835cc1 100644 --- a/src/opt/opt_cmds.cpp +++ b/src/opt/opt_cmds.cpp @@ -141,6 +141,13 @@ class alternate_min_max_cmd : public cmd { app_ref_vector* m_vars; svector m_is_max; unsigned m_position; + + app_ref_vector& vars(cmd_context& ctx) { + if (!m_vars) { + m_vars = alloc(app_ref_vector, ctx.m()); + } + return *m_vars; + } public: alternate_min_max_cmd(): cmd("min-max"), @@ -150,6 +157,7 @@ class alternate_min_max_cmd : public cmd { virtual void reset(cmd_context & ctx) { dealloc(m_vars); + m_vars = 0; m_is_max.reset(); m_position = 0; } @@ -176,8 +184,7 @@ class alternate_min_max_cmd : public cmd { } else { m_is_max.push_back(is_max); - if (!m_vars) m_vars = alloc(app_ref_vector, ctx.m()); - m_vars->push_back(ctx.m().mk_const(ctx.find_func_decl(slist[i]))); + vars(ctx).push_back(ctx.m().mk_const(ctx.find_func_decl(slist[i]))); } } ++m_position; @@ -188,8 +195,8 @@ class alternate_min_max_cmd : public cmd { throw cmd_exception("malformed objective term: it cannot be a quantifier or bound variable"); } ++m_position; - if (!m_vars) m_vars = alloc(app_ref_vector, ctx.m()); - get_opt(ctx).min_max(to_app(t), *m_vars, m_is_max); + get_opt(ctx).min_max(to_app(t), vars(ctx), m_is_max); + reset(ctx); } virtual void failure_cleanup(cmd_context & ctx) { diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 4d65b9a2503..0c19e7987c6 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -218,11 +218,9 @@ namespace opt { import_scoped_state(); normalize(); internalize(); - update_solver(); - solver& s = get_solver(); - s.assert_expr(m_hard_constraints); - std::cout << "min-max is TBD\n"; - return l_undef; + qe::max_min_opt max_min(m, m_params); + max_min.add(m_hard_constraints); + return max_min.check(is_max, vars, t); } diff --git a/src/qe/qsat.cpp b/src/qe/qsat.cpp index 74b1101fe1a..c7e20b73390 100644 --- a/src/qe/qsat.cpp +++ b/src/qe/qsat.cpp @@ -550,8 +550,7 @@ namespace qe { unsigned m_num_rounds; stats() { reset(); } void reset() { memset(this, 0, sizeof(*this)); } - }; - + }; ast_manager& m; params_ref m_params; @@ -706,96 +705,7 @@ namespace qe { for (unsigned i = 0; i < vars.size(); ++i) { m_pred_abs.fmc()->insert(vars[i]->get_decl()); } - } - -#if 0 - void hoist_ite(expr_ref& fml) { - app* ite; - scoped_ptr replace = mk_default_expr_replacer(m); - th_rewriter rewriter(m); - while (find_ite(fml, ite)) { - expr* cond, *th, *el; - VERIFY(m.is_ite(ite, cond, th, el)); - expr_ref tmp1(fml, m), tmp2(fml, m); - replace->apply_substitution(cond, m.mk_true(), tmp1); - replace->apply_substitution(cond, m.mk_false(), tmp2); - fml = m.mk_ite(cond, tmp1, tmp2); - rewriter(fml); - } - } - - bool find_ite(expr* e, app*& ite) { - ptr_vector todo; - todo.push_back(e); - ast_mark visited; - while(!todo.empty()) { - e = todo.back(); - todo.pop_back(); - if (visited.is_marked(e)) { - continue; - } - visited.mark(e, true); - if (m.is_ite(e) && !m.is_bool(e)) { - ite = to_app(e); - return true; - } - if (is_app(e)) { - app* a = to_app(e); - todo.append(a->get_num_args(), a->get_args()); - } - } - return false; - } - - // slower - void hoist_ite2(expr_ref& fml) { - obj_map result; - expr_ref_vector trail(m); - ptr_vector todo, args; - todo.push_back(fml); - - while (!todo.empty()) { - expr* e = todo.back(); - if (result.contains(e)) { - todo.pop_back(); - continue; - } - if (!is_app(e)) { - todo.pop_back(); - result.insert(e, e); - continue; - } - app* a = to_app(e); - expr* r; - unsigned sz = a->get_num_args(); - args.reset(); - for (unsigned i = 0; i < sz; ++i) { - if (result.find(a->get_arg(i), r)) { - args.push_back(r); - } - else { - todo.push_back(a->get_arg(i)); - } - } - if (sz == args.size()) { - r = m.mk_app(a->get_decl(), args.size(), args.c_ptr()); - trail.push_back(r); - if (m.is_bool(e) && m.get_basic_family_id() != a->get_family_id()) { - expr_ref fml(r, m); - hoist_ite(fml); - trail.push_back(fml); - r = fml; - } - result.insert(e, r); - todo.pop_back(); - } - } - fml = result.find(fml); - } -#endif - - - + } void initialize_levels() { // initialize levels. @@ -1162,7 +1072,8 @@ namespace qe { m_level(0), m_mode(mode), m_avars(m), - m_free_vars(m) + m_free_vars(m), + m_kernel(m) { reset(); } @@ -1328,67 +1239,14 @@ namespace qe { m_ex.assert_expr(bound); } - }; - lbool maximize(expr_ref_vector const& fmls, app* t, opt::inf_eps& value, model_ref& mdl, params_ref const& p) { - ast_manager& m = fmls.get_manager(); - qsat qs(m, p, qsat_maximize); - return qs.maximize(fmls, t, mdl, value); - } -}; - -tactic * mk_qsat_tactic(ast_manager& m, params_ref const& p) { - return alloc(qe::qsat, m, p, qe::qsat_sat); -} - -tactic * mk_qe2_tactic(ast_manager& m, params_ref const& p) { - return alloc(qe::qsat, m, p, qe::qsat_qe); -} - -tactic * mk_qe_rec_tactic(ast_manager& m, params_ref const& p) { - return alloc(qe::qsat, m, p, qe::qsat_qe_rec); -} - - - - -#if 0 - - class min_max_opt { - struct imp; - imp* m_imp; - public: - min_max_opt(ast_manager& m); - ~min_max_opt(); - void add(expr* e); - void add(expr_ref_vector const& fmls); - lbool check(svector const& is_max, app_ref_vector const& vars, app* t); - }; - - struct min_max_opt::imp { - ast_manager& m; - expr_ref_vector m_fmls; - pred_abs m_pred_abs; - qe::mbp m_mbp; kernel m_kernel; - vector m_vars; - - imp(ast_manager& m): - m(m), - m_fmls(m), - m_pred_abs(m), - m_mbp(m), - m_kernel(m) {} - void add(expr* e) { - m_fmls.push_back(e); - } - - lbool check(svector const& is_max, app_ref_vector const& vars, app* t) { + lbool max_min(expr_ref_vector const& fmls, svector const& is_max, app_ref_vector const& vars, app* t) { // Assume this is the only call to check. expr_ref_vector defs(m); app_ref_vector free_vars(m), vars1(m); - expr_ref fml = mk_and(m_fmls); + expr_ref fml = mk_and(fmls); m_pred_abs.get_free_vars(fml, free_vars); m_pred_abs.abstract_atoms(fml, defs); fml = m_pred_abs.mk_abstract(fml); @@ -1404,7 +1262,11 @@ tactic * mk_qe_rec_tactic(ast_manager& m, params_ref const& p) { vars1.push_back(v); } } - bool is_m = is_max[0]; + // + // Insert all variables in alternating list of max/min objectives. + // By convention, the outer-most level is max. + // + bool is_m = true; for (unsigned i = 0; i < vars.size(); ++i) { if (is_m != is_max[i]) { m_vars.push_back(vars1); @@ -1413,33 +1275,98 @@ tactic * mk_qe_rec_tactic(ast_manager& m, params_ref const& p) { } vars1.push_back(vars[i]); } - - // TBD + m_vars.push_back(vars1); + return max_min(); + + // return l_undef; + } + + lbool max_min() { + while (true) { + ++m_stats.m_num_rounds; + check_cancel(); + expr_ref_vector asms(m_asms); + m_pred_abs.get_assumptions(m_model.get(), asms); + smt::kernel& k = get_kernel(m_level).k(); + lbool res = k.check(asms); + switch (res) { + case l_true: + break; + case l_false: + break; + case l_undef: + break; + } + } return l_undef; } + }; - min_max_opt::min_max_opt(ast_manager& m) { - m_imp = alloc(imp, m); + lbool maximize(expr_ref_vector const& fmls, app* t, opt::inf_eps& value, model_ref& mdl, params_ref const& p) { + ast_manager& m = fmls.get_manager(); + qsat qs(m, p, qsat_maximize); + return qs.maximize(fmls, t, mdl, value); + } + + + struct max_min_opt::imp { + + expr_ref_vector m_fmls; + qsat m_qsat; + + imp(ast_manager& m, params_ref const& p): + m_fmls(m), + m_qsat(m, p, qsat_maximize) + {} + + void add(expr* e) { + m_fmls.push_back(e); + } + + lbool check(svector const& is_max, app_ref_vector const& vars, app* t) { + return m_qsat.max_min(m_fmls, is_max, vars, t); + } + + }; + + max_min_opt::max_min_opt(ast_manager& m, params_ref const& p) { + m_imp = alloc(imp, m, p); } - min_max_opt::~min_max_opt() { + max_min_opt::~max_min_opt() { dealloc(m_imp); } - void min_max_opt::add(expr* e) { + void max_min_opt::add(expr* e) { m_imp->add(e); } - void min_max_opt::add(expr_ref_vector const& fmls) { + void max_min_opt::add(expr_ref_vector const& fmls) { for (unsigned i = 0; i < fmls.size(); ++i) { add(fmls[i]); } } - lbool min_max_opt::check(svector const& is_max, app_ref_vector const& vars, app* t) { + lbool max_min_opt::check(svector const& is_max, app_ref_vector const& vars, app* t) { return m_imp->check(is_max, vars, t); } -#endif +}; + +tactic * mk_qsat_tactic(ast_manager& m, params_ref const& p) { + return alloc(qe::qsat, m, p, qe::qsat_sat); +} + +tactic * mk_qe2_tactic(ast_manager& m, params_ref const& p) { + return alloc(qe::qsat, m, p, qe::qsat_qe); +} + +tactic * mk_qe_rec_tactic(ast_manager& m, params_ref const& p) { + return alloc(qe::qsat, m, p, qe::qsat_qe_rec); +} + + + + diff --git a/src/qe/qsat.h b/src/qe/qsat.h index 456711c4f3b..59cf6d8a081 100644 --- a/src/qe/qsat.h +++ b/src/qe/qsat.h @@ -114,6 +114,17 @@ namespace qe { void collect_statistics(statistics& st) const; }; + class max_min_opt { + struct imp; + imp* m_imp; + public: + max_min_opt(ast_manager& m, params_ref const& p = params_ref()); + ~max_min_opt(); + void add(expr* e); + void add(expr_ref_vector const& fmls); + lbool check(svector const& is_max, app_ref_vector const& vars, app* t); + }; + lbool maximize(expr_ref_vector const& fmls, app* t, opt::inf_eps& value, model_ref& mdl, params_ref const& p); } From 4d11e57a33e573fc73a536952c18f6da46264e1e Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Fri, 6 May 2016 18:28:08 +0100 Subject: [PATCH 07/61] Added param descrs collection to ackermannize_bv_tactic --- src/ackermannization/ackermannize_bv_tactic.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/ackermannization/ackermannize_bv_tactic.cpp b/src/ackermannization/ackermannize_bv_tactic.cpp index f9c48c2bdca..70230e346b8 100644 --- a/src/ackermannization/ackermannize_bv_tactic.cpp +++ b/src/ackermannization/ackermannize_bv_tactic.cpp @@ -74,6 +74,10 @@ class ackermannize_bv_tactic : public tactic { m_lemma_limit = p.div0_ackermann_limit(); } + virtual void collect_param_descrs(param_descrs & r) { + ackermannize_bv_tactic_params::collect_param_descrs(r); + } + virtual void collect_statistics(statistics & st) const { st.update("ackr-constraints", m_st.m_ackrs_sz); } From 88f92660f01ce3227fe92868e4411319b9bceca4 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Fri, 6 May 2016 18:29:19 +0100 Subject: [PATCH 08/61] Added param descrs collection to ackermannize_bv_tactic --- src/ackermannization/ackermannize_bv_tactic.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/ackermannization/ackermannize_bv_tactic.cpp b/src/ackermannization/ackermannize_bv_tactic.cpp index f9c48c2bdca..70230e346b8 100644 --- a/src/ackermannization/ackermannize_bv_tactic.cpp +++ b/src/ackermannization/ackermannize_bv_tactic.cpp @@ -74,6 +74,10 @@ class ackermannize_bv_tactic : public tactic { m_lemma_limit = p.div0_ackermann_limit(); } + virtual void collect_param_descrs(param_descrs & r) { + ackermannize_bv_tactic_params::collect_param_descrs(r); + } + virtual void collect_statistics(statistics & st) const { st.update("ackr-constraints", m_st.m_ackrs_sz); } From f8795f35222faa72ef1c56d97cd108898b66ebae Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Mon, 9 May 2016 14:16:51 +0100 Subject: [PATCH 09/61] Added term ITEs to bvarray2uf rewriter. --- src/tactic/bv/bvarray2uf_rewriter.cpp | 53 +++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/src/tactic/bv/bvarray2uf_rewriter.cpp b/src/tactic/bv/bvarray2uf_rewriter.cpp index d4e738ed71e..db60f3fcd40 100644 --- a/src/tactic/bv/bvarray2uf_rewriter.cpp +++ b/src/tactic/bv/bvarray2uf_rewriter.cpp @@ -163,6 +163,59 @@ br_status bvarray2uf_rewriter_cfg::reduce_app(func_decl * f, unsigned num, expr result = m_manager.mk_distinct_expanded(num, args); res = BR_REWRITE1; } + else if (m_manager.is_term_ite(f) && is_bv_array(f->get_range())) { + expr_ref c(args[0], m_manager); + func_decl_ref f_t(mk_uf_for_array(args[1]), m_manager); + func_decl_ref f_f(mk_uf_for_array(args[2]), m_manager); + + TRACE("bvarray2uf_rw", tout << "(ite " << c << ", " << f_t->get_name() + << ", " << f_f->get_name() << ")" << std::endl;); + + sort * sorts[1] = { get_index_sort(m_manager.get_sort(args[1])) }; + symbol names[1] = { symbol("x") }; + var_ref x(m_manager.mk_var(0, sorts[0]), m_manager); + + app_ref f_a(m_manager), f_ta(m_manager), f_fa(m_manager); + f_a = m_manager.mk_app(f, num, args); + f_ta = m_manager.mk_app(f_t, x.get()); + f_fa = m_manager.mk_app(f_f, x.get()); + + app_ref e(m_manager); + func_decl_ref itefd(m_manager); + e = m_manager.mk_ite(c, f_ta, f_fa); + + func_decl * bv_f = 0; + if (!m_arrays_fs.find(f_a, bv_f)) { + sort * domain = get_index_sort(args[1]); + sort * range = get_value_sort(args[1]); + bv_f = m_manager.mk_fresh_func_decl("f_t", "", 1, &domain, range); + TRACE("bvarray2uf_rw", tout << mk_ismt2_pp(e, m_manager) << " -> " << bv_f->get_name() << std::endl; ); + if (is_uninterp_const(e)) { + if (m_emc) + m_emc->insert(e->get_decl(), + m_array_util.mk_as_array(m_manager.get_sort(e), bv_f)); + } + else if (m_fmc) + m_fmc->insert(bv_f); + m_arrays_fs.insert(e, bv_f); + m_manager.inc_ref(e); + m_manager.inc_ref(bv_f); + } + + expr_ref q(m_manager), body(m_manager); + body = m_manager.mk_eq(m_manager.mk_app(bv_f, x), e); + q = m_manager.mk_forall(1, sorts, names, body); + extra_assertions.push_back(q); + + result = m_array_util.mk_as_array(f->get_range(), bv_f); + + TRACE("bvarray2uf_rw", tout << "result: " << mk_ismt2_pp(result, m_manager) << ")" << std::endl;); + res = BR_DONE; + + } + else if (f->get_family_id() == m_manager.get_basic_family_id() && is_bv_array(f->get_range())) { + NOT_IMPLEMENTED_YET(); + } else if (f->get_family_id() == null_family_id) { TRACE("bvarray2uf_rw", tout << "UF APP: " << f->get_name() << std::endl; ); From d30ba3f1adfb84d00b5db660d30da4748a28ff6a Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Wed, 11 May 2016 14:30:37 +0100 Subject: [PATCH 10/61] change Z3_get_decl_kind API to correctly identify OP_B*_I and OP_B*_NO_OVFL instead of returning Z3_OP_UNINTERPRETED --- src/api/api_ast.cpp | 17 ++++++++--------- src/api/z3_api.h | 9 +++++++++ 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/src/api/api_ast.cpp b/src/api/api_ast.cpp index 34dab3ed697..9aea9d6f474 100644 --- a/src/api/api_ast.cpp +++ b/src/api/api_ast.cpp @@ -1066,15 +1066,14 @@ extern "C" { case OP_BV2INT: return Z3_OP_BV2INT; case OP_CARRY: return Z3_OP_CARRY; case OP_XOR3: return Z3_OP_XOR3; - case OP_BSMUL_NO_OVFL: - case OP_BUMUL_NO_OVFL: - case OP_BSMUL_NO_UDFL: - case OP_BSDIV_I: - case OP_BUDIV_I: - case OP_BSREM_I: - case OP_BUREM_I: - case OP_BSMOD_I: - return Z3_OP_UNINTERPRETED; + case OP_BSMUL_NO_OVFL: return Z3_OP_BSMUL_NO_OVFL; + case OP_BUMUL_NO_OVFL: return Z3_OP_BUMUL_NO_OVFL; + case OP_BSMUL_NO_UDFL: return Z3_OP_BSMUL_NO_UDFL; + case OP_BSDIV_I: return Z3_OP_BSDIV_I; + case OP_BUDIV_I: return Z3_OP_BUDIV_I; + case OP_BSREM_I: return Z3_OP_BSREM_I; + case OP_BUREM_I: return Z3_OP_BUREM_I; + case OP_BSMOD_I: return Z3_OP_BSMOD_I; default: UNREACHABLE(); return Z3_OP_UNINTERPRETED; diff --git a/src/api/z3_api.h b/src/api/z3_api.h index 7c846cc99be..9d89bc9572a 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -1060,6 +1060,15 @@ typedef enum { Z3_OP_CARRY, Z3_OP_XOR3, + Z3_OP_BSMUL_NO_OVFL, + Z3_OP_BUMUL_NO_OVFL, + Z3_OP_BSMUL_NO_UDFL, + Z3_OP_BSDIV_I, + Z3_OP_BUDIV_I, + Z3_OP_BSREM_I, + Z3_OP_BUREM_I, + Z3_OP_BSMOD_I, + // Proofs Z3_OP_PR_UNDEF = 0x500, Z3_OP_PR_TRUE, From d1f8b06ec4e5cc0c9e3b022c52a3e8662d0f2f71 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Wed, 11 May 2016 22:33:41 -0400 Subject: [PATCH 11/61] bug fix in model_evaluator for array equality --- src/model/model_evaluator.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/model/model_evaluator.cpp b/src/model/model_evaluator.cpp index e67e3cb5ecf..5cc3d27abf7 100644 --- a/src/model/model_evaluator.cpp +++ b/src/model/model_evaluator.cpp @@ -150,7 +150,7 @@ struct evaluator_cfg : public default_rewriter_cfg { st = m_f_rw.mk_eq_core(args[0], args[1], result); else if (s_fid == m_seq_rw.get_fid()) st = m_seq_rw.mk_eq_core(args[0], args[1], result); - else if (fid == m_ar_rw.get_fid()) + else if (s_fid == m_ar_rw.get_fid()) st = mk_array_eq(args[0], args[1], result); if (st != BR_FAILED) return st; From dd83495d5d0cf686c3a0a86791b7a341517a7667 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Thu, 12 May 2016 14:15:24 +0100 Subject: [PATCH 12/61] New implementation of mpf_manager::rem. Partially addresses #561 --- src/util/mpf.cpp | 255 ++++++++++++++++++++++++++++------------------- src/util/mpf.h | 3 +- 2 files changed, 152 insertions(+), 106 deletions(-) diff --git a/src/util/mpf.cpp b/src/util/mpf.cpp index ceb40778156..32932522c86 100644 --- a/src/util/mpf.cpp +++ b/src/util/mpf.cpp @@ -1214,149 +1214,192 @@ void mpf_manager::to_ieee_bv_mpz(const mpf & x, scoped_mpz & o) { } } -void mpf_manager::prem(scoped_mpf & x, scoped_mpf const & y, mpf_exp_t const & exp_diff, bool partial) { +void mpf_manager::renormalize(unsigned ebits, unsigned sbits, mpf_exp_t & exp, mpz & sig) { + if (m_mpz_manager.is_zero(sig)) + return; + + mpf_exp_t max_e = mk_max_exp(ebits); + mpf_exp_t min_e = mk_min_exp(ebits); + + const mpz & pg = m_powers2(sbits); + while (m_mpz_manager.ge(sig, pg)) { + m_mpz_manager.machine_div2k(sig, 1); + exp++; + } + + const mpz & pl = m_powers2(sbits-1); + while (m_mpz_manager.lt(sig, pl)) { + m_mpz_manager.mul2k(sig, 1); + exp--; + } +} + +void mpf_manager::partial_remainder(scoped_mpf & x, scoped_mpf const & y, mpf_exp_t const & exp_diff, bool partial) { unsigned ebits = x.get().ebits; unsigned sbits = x.get().sbits; bool sign = x.get().sign; - signed int D = (unsigned)(partial ? 0 : exp_diff); - mpf_exp_t N = sbits/2; + SASSERT(-1 <= exp_diff && exp_diff < INT64_MAX); + SASSERT(exp_diff < ebits+sbits || partial); + + signed int D = (signed int)(exp_diff); + mpf_exp_t N = (sbits+ebits)/2; TRACE("mpf_dbg_rem", tout << "x=" << to_string(x) << std::endl; tout << "y=" << to_string(y) << std::endl; tout << "d=" << D << std::endl; tout << "partial=" << partial << std::endl;); - // 1. Compute a/b - unsigned extra_bits = sbits + 2; - scoped_mpz x_sig_shifted(m_mpz_manager), x_div_y_sig_lrg(m_mpz_manager); - scoped_mpz x_div_y_sig(m_mpz_manager), x_rem_y_sig(m_mpz_manager); - m_mpz_manager.mul2k(x.significand(), sbits + extra_bits, x_sig_shifted); - m_mpz_manager.machine_div(x_sig_shifted, y.significand(), x_div_y_sig_lrg); - m_mpz_manager.machine_div_rem(x_div_y_sig_lrg, m_powers2(extra_bits-2), x_div_y_sig, x_rem_y_sig); - TRACE("mpf_dbg_rem", tout << "X/Y_sig=" << m_mpz_manager.to_string(x_div_y_sig) << std::endl; - tout << "X%Y_sig=" << m_mpz_manager.to_string(x_rem_y_sig) << std::endl; - tout << "X/Y=" << to_string_hexfloat( - to_packed_mpf(x.sign(), D, x_div_y_sig, ebits, sbits, 3)) << std::endl;); - SASSERT(m_mpz_manager.lt(x_div_y_sig, m_powers2(sbits + 3))); // 3 extra bits in x_div_y_sig. - SASSERT(m_mpz_manager.ge(x_div_y_sig, m_powers2(sbits - 1 + 3))); - // Bug: a_rem_b_sig is not used. + SASSERT(m_mpz_manager.lt(x.significand(), m_powers2(sbits))); + SASSERT(m_mpz_manager.ge(x.significand(), m_powers2(sbits - 1))); + SASSERT(m_mpz_manager.lt(y.significand(), m_powers2(sbits))); + SASSERT(m_mpz_manager.ge(y.significand(), m_powers2(sbits - 1))); + + // 1. Compute a/b + bool x_div_y_sgn = x.sign() ^ y.sign(); + mpf_exp_t x_div_y_exp = D; + scoped_mpz x_sig_shifted(m_mpz_manager), x_div_y_sig_lrg(m_mpz_manager), x_div_y_rem(m_mpz_manager); + scoped_mpz x_rem_y_sig(m_mpz_manager); + m_mpz_manager.mul2k(x.significand(), 2*sbits + 2, x_sig_shifted); + m_mpz_manager.machine_div_rem(x_sig_shifted, y.significand(), x_div_y_sig_lrg, x_div_y_rem); // rem useful? + // x/y is in x_diuv_y_sig_lrg and has sbits+3 extra bits. + + TRACE("mpf_dbg_rem", tout << "X/Y_exp=" << x_div_y_exp << std::endl; + tout << "X/Y_sig_lrg=" << m_mpz_manager.to_string(x_div_y_sig_lrg) << std::endl; + tout << "X/Y_rem=" << m_mpz_manager.to_string(x_div_y_rem) << std::endl; + scoped_mpf & XdY = to_packed_mpf(x_div_y_sgn, x_div_y_exp, x_div_y_sig_lrg, ebits, sbits, sbits+3); + tout << "X/Y~=" << to_string_hexfloat(XdY) << std::endl;); // 2. Round a/b to integer Q/QQ - mpf_exp_t Q_exp = partial ? N : D; + bool Q_sgn = x_div_y_sgn; + mpf_exp_t Q_exp = x_div_y_exp; scoped_mpz Q_sig(m_mpz_manager), Q_rem(m_mpz_manager); - if (partial) { + unsigned Q_shft = (sbits-1) + (sbits+3) - (unsigned) (partial ? N :Q_exp); + if (partial) { // Round according to MPF_ROUND_TOWARD_ZERO - SASSERT(N < D && D < INT_MAX); - unsigned D_N = (unsigned)(D-N); - unsigned Q_shft = (sbits - 1) - D_N; - m_mpz_manager.machine_div_rem(x_div_y_sig, m_powers2(Q_shft+3), Q_sig, Q_rem); - m_mpz_manager.mul2k(Q_sig, Q_shft); + SASSERT(0 < N && N < Q_exp && Q_exp < INT_MAX); + m_mpz_manager.machine_div2k(x_div_y_sig_lrg, Q_shft, Q_sig); } else { // Round according to MPF_ROUND_NEAREST_TEVEN - unsigned Q_shft = (sbits - 1) - D; - m_mpz_manager.machine_div_rem(x_div_y_sig, m_powers2(Q_shft+3), Q_sig, Q_rem); + m_mpz_manager.machine_div_rem(x_div_y_sig_lrg, m_powers2(Q_shft), Q_sig, Q_rem); const mpz & shiftm1_p = m_powers2(Q_shft-1); bool tie = m_mpz_manager.eq(Q_rem, shiftm1_p); bool more_than_tie = m_mpz_manager.gt(Q_rem, shiftm1_p); TRACE("mpf_dbg_rem", tout << "tie= " << tie << "; >tie= " << more_than_tie << std::endl;); if ((tie && m_mpz_manager.is_odd(Q_sig)) || more_than_tie) m_mpz_manager.inc(Q_sig); - m_mpz_manager.mul2k(Q_sig, Q_shft); - SASSERT(m_mpz_manager.ge(Q_sig, m_powers2(sbits-1))); - } - TRACE("mpf_dbg_rem", tout << "Q_sig'=" << m_mpz_manager.to_string(Q_sig) << std::endl; - tout << "Q_rem=" << m_mpz_manager.to_string(Q_rem) << std::endl; ); - - // re-normalize Q - while (m_mpz_manager.ge(Q_sig, m_powers2(sbits))) { - m_mpz_manager.machine_div2k(Q_sig, 1); - Q_exp++; } + m_mpz_manager.mul2k(Q_sig, Q_shft); + m_mpz_manager.machine_div2k(Q_sig, sbits+3); + renormalize(ebits, sbits, Q_exp, Q_sig); TRACE("mpf_dbg_rem", tout << "Q_exp=" << Q_exp << std::endl; tout << "Q_sig=" << m_mpz_manager.to_string(Q_sig) << std::endl; - scoped_mpf & Q = to_packed_mpf(x.sign(), Q_exp, Q_sig, ebits, sbits, 0); + scoped_mpf & Q = to_packed_mpf(Q_sgn, Q_exp, Q_sig, ebits, sbits, 0); tout << "Q=" << to_string_hexfloat(Q) << std::endl;); + + if ((D == -1 || partial) && m_mpz_manager.is_zero(Q_sig)) + return; // This means x % y = x. + + // no extra bits in Q_sig. + SASSERT(!m_mpz_manager.is_zero(Q_sig)); + SASSERT(m_mpz_manager.lt(Q_sig, m_powers2(sbits))); + SASSERT(m_mpz_manager.ge(Q_sig, m_powers2(sbits - 1))); + // 3. Compute Y*Q / Y*QQ*2^{D-N} + bool YQ_sgn = y.sign() ^ Q_sgn; scoped_mpz YQ_sig(m_mpz_manager); - mpf_exp_t YQ_exp = (Q_exp + y.exponent()) + (partial ? D-N : 0); - m_mpz_manager.mul(y.significand(), Q_sig, YQ_sig); + mpf_exp_t YQ_exp = Q_exp + y.exponent(); + m_mpz_manager.mul(y.significand(), Q_sig, YQ_sig); + renormalize(ebits, 2*sbits-1, YQ_exp, YQ_sig); // YQ_sig has `sbits-1' extra bits. - if (sbits >= 7) { - scoped_mpz sticky_rem(m_mpz_manager); - m_mpz_manager.machine_div_rem(YQ_sig, m_powers2(sbits-7), YQ_sig, sticky_rem); - if (!m_mpz_manager.is_zero(sticky_rem) && m_mpz_manager.is_even(YQ_sig)) - m_mpz_manager.inc(YQ_sig); - } - else - m_mpz_manager.mul2k(YQ_sig, 7-sbits, YQ_sig); - - TRACE("mpf_dbg_rem", tout << "YQ_exp=" << YQ_exp << std::endl; + TRACE("mpf_dbg_rem", tout << "YQ_sgn=" << YQ_sgn << std::endl; + tout << "YQ_exp=" << YQ_exp << std::endl; tout << "YQ_sig=" << m_mpz_manager.to_string(YQ_sig) << std::endl; - scoped_mpf & YQ = to_packed_mpf(x.sign(), YQ_exp, YQ_sig, ebits, sbits, 6); + scoped_mpf & YQ = to_packed_mpf(YQ_sgn, YQ_exp, YQ_sig, ebits, sbits, sbits-1); tout << "YQ=" << to_string_hexfloat(YQ) << std::endl;); - // 4. Compute X-Y*Q - bool YQ_sgn = !x.sign(); - mpf_exp_t X_YQ_exp = x.exponent() - 3; + // `sbits-1' extra bits in YQ_sig. + SASSERT(m_mpz_manager.lt(YQ_sig, m_powers2(2*sbits-1))); + SASSERT(m_mpz_manager.ge(YQ_sig, m_powers2(2*sbits-2)) || YQ_exp <= mk_bot_exp(ebits)); + + // 4. Compute X-Y*Q + mpf_exp_t X_YQ_exp = x.exponent(); scoped_mpz X_YQ_sig(m_mpz_manager); mpf_exp_t exp_delta = exp(x) - YQ_exp; TRACE("mpf_dbg_rem", tout << "exp_delta=" << exp_delta << std::endl;); + SASSERT(INT_MIN < exp_delta && exp_delta <= INT_MAX); scoped_mpz minuend(m_mpz_manager), subtrahend(m_mpz_manager); - if (exp_delta >= 0) { - m_mpz_manager.set(minuend, x.significand()); - m_mpz_manager.set(subtrahend, YQ_sig); - } - else if (exp_delta < 0) { - m_mpz_manager.set(minuend, YQ_sig); - m_mpz_manager.set(subtrahend, x.significand()); - YQ_sgn = !YQ_sgn; - exp_delta = -exp_delta; - } + scoped_mpz x_sig_lrg(m_mpz_manager); + m_mpz_manager.mul2k(x.significand(), sbits-1, x_sig_lrg); // sbits-1 extra bits into x + + m_mpz_manager.set(minuend, x_sig_lrg); + m_mpz_manager.set(subtrahend, YQ_sig); + SASSERT(m_mpz_manager.lt(minuend, m_powers2(2*sbits-1))); + SASSERT(m_mpz_manager.ge(minuend, m_powers2(2*sbits-2))); + SASSERT(m_mpz_manager.lt(subtrahend, m_powers2(2*sbits-1))); + SASSERT(m_mpz_manager.ge(subtrahend, m_powers2(2*sbits-2))); + if (exp_delta != 0) { scoped_mpz sticky_rem(m_mpz_manager); - if (exp_delta > sbits+5) { - m_mpz_manager.set(sticky_rem, 0); - sticky_rem.swap(subtrahend); + m_mpz_manager.set(sticky_rem, 0); + if (exp_delta > sbits+5) + sticky_rem.swap(subtrahend); + else if (exp_delta > 0) + m_mpz_manager.machine_div_rem(subtrahend, m_powers2((unsigned)exp_delta), subtrahend, sticky_rem); + else { + SASSERT(exp_delta < 0); + exp_delta = -exp_delta; + m_mpz_manager.mul2k(subtrahend, (int)exp_delta); } - else - m_mpz_manager.machine_div_rem(subtrahend, m_powers2((unsigned)exp_delta), subtrahend, sticky_rem); if (!m_mpz_manager.is_zero(sticky_rem) && m_mpz_manager.is_even(subtrahend)) m_mpz_manager.inc(subtrahend); TRACE("mpf_dbg_rem", tout << "aligned subtrahend=" << m_mpz_manager.to_string(subtrahend) << std::endl;); } + + m_mpz_manager.sub(minuend, subtrahend, X_YQ_sig); + TRACE("mpf_dbg_rem", tout << "X_YQ_sig'=" << m_mpz_manager.to_string(X_YQ_sig) << std::endl;); - scoped_mpz minuend_lrg(m_mpz_manager); - m_mpz_manager.mul2k(minuend, 6, minuend_lrg); // + 6 extra bits into X - m_mpz_manager.sub(minuend_lrg, subtrahend, X_YQ_sig); - - TRACE("mpf_dbg_rem", tout << "minuend=" << m_mpz_manager.to_string(minuend) << std::endl; - tout << "subtrahend=" << m_mpz_manager.to_string(subtrahend) << std::endl; - tout << "X_YQ_exp=" << X_YQ_exp << std::endl; - tout << "X_YQ_sig=" << m_mpz_manager.to_string(X_YQ_sig) << std::endl; - scoped_mpf & X_YQ = to_packed_mpf(YQ_sgn, X_YQ_exp, X_YQ_sig, ebits, sbits, 3); - tout << "X-YQ=" << to_string_hexfloat(X_YQ) << std::endl;); - - SASSERT(m_mpz_manager.lt(X_YQ_sig, m_powers2(sbits+5))); + bool neg = m_mpz_manager.is_neg(X_YQ_sig); + if (neg) m_mpz_manager.neg(X_YQ_sig); + bool X_YQ_sgn = ((!x.sign() && !YQ_sgn && neg) || + (x.sign() && YQ_sgn && !neg) || + (x.sign() && !YQ_sgn)); // 5. Rounding - if (m_mpz_manager.is_zero(X_YQ_sig)) { - TRACE("mpf_dbg_rem", tout << "sig zero" << std::endl;); + if (m_mpz_manager.is_zero(X_YQ_sig)) mk_zero(ebits, sbits, x.sign(), x); - } else { - bool neg = m_mpz_manager.is_neg(X_YQ_sig); - if (neg) m_mpz_manager.neg(X_YQ_sig); - bool X_YQ_sgn = ((!x.sign() && YQ_sgn && neg) || - (x.sign() && !YQ_sgn && !neg) || - (x.sign() && YQ_sgn)); + renormalize(ebits, 2*sbits-1, X_YQ_exp, X_YQ_sig); + + TRACE("mpf_dbg_rem", tout << "minuend=" << m_mpz_manager.to_string(minuend) << std::endl; + tout << "subtrahend=" << m_mpz_manager.to_string(subtrahend) << std::endl; + tout << "X_YQ_sgn=" << X_YQ_sgn << std::endl; + tout << "X_YQ_exp=" << X_YQ_exp << std::endl; + tout << "X_YQ_sig=" << m_mpz_manager.to_string(X_YQ_sig) << std::endl; + scoped_mpf & X_YQ = to_packed_mpf(X_YQ_sgn, X_YQ_exp, X_YQ_sig, ebits, sbits, sbits-1); + tout << "X-YQ=" << to_string_hexfloat(X_YQ) << std::endl;); + + // `sbits-1' extra bits in X_YQ_sig + SASSERT(m_mpz_manager.lt(X_YQ_sig, m_powers2(2*sbits-1))); + scoped_mpz rnd_bits(m_mpz_manager); + m_mpz_manager.machine_div_rem(X_YQ_sig, m_powers2(sbits-1), X_YQ_sig, rnd_bits); + TRACE("mpf_dbg_rem", tout << "final sticky=" << m_mpz_manager.to_string(rnd_bits) << std::endl; ); + + // Round to nearest, ties to even. + if (m_mpz_manager.eq(rnd_bits, mpz(32))) { // tie. + if (m_mpz_manager.is_odd(X_YQ_sig)) { + m_mpz_manager.inc(X_YQ_sig); + } + } + else if (m_mpz_manager.gt(rnd_bits, mpz(32))) + m_mpz_manager.inc(X_YQ_sig); + set(x, ebits, sbits, X_YQ_sgn, X_YQ_exp, X_YQ_sig); - round(MPF_ROUND_NEAREST_TEVEN, x); } TRACE("mpf_dbg_rem", tout << "partial remainder = " << to_string_hexfloat(x) << std::endl;); @@ -1365,8 +1408,8 @@ void mpf_manager::prem(scoped_mpf & x, scoped_mpf const & y, mpf_exp_t const & e void mpf_manager::rem(mpf const & x, mpf const & y, mpf & o) { SASSERT(x.sbits == y.sbits && x.ebits == y.ebits); - TRACE("mpf_dbg", tout << "X = " << to_string(x) << std::endl;); - TRACE("mpf_dbg", tout << "Y = " << to_string(y) << std::endl;); + TRACE("mpf_dbg_rem", tout << "X = " << to_string(x) << "=" << to_string_hexfloat(x) << std::endl; + tout << "Y = " << to_string(y) << "=" << to_string_hexfloat(y) << std::endl;); if (is_nan(x) || is_nan(y)) mk_nan(x.ebits, x.sbits, o); @@ -1380,7 +1423,6 @@ void mpf_manager::rem(mpf const & x, mpf const & y, mpf & o) { set(o, x); else { SASSERT(is_regular(x) && is_regular(y)); - SASSERT(x.exponent >= y.exponent); // This is a generalized version of the algorithm for FPREM1 in the `Intel // 64 and IA-32 Architectures Software Developer's Manual', @@ -1391,24 +1433,24 @@ void mpf_manager::rem(mpf const & x, mpf const & y, mpf & o) { unpack(ST0, true); unpack(ST1, true); - const mpf_exp_t B = x.sbits; // max bits per iteration. + const mpf_exp_t B = x.sbits+x.ebits; mpf_exp_t D; do { - D = ST0.exponent() - ST1.exponent(); - SASSERT(0 <= D && D < INT64_MAX); - - TRACE("mpf_dbg_rem", tout << "ST0=" << to_string_raw(ST0) << "=" << to_string_hexfloat(ST0) << std::endl; - tout << "ST1=" << to_string_raw(ST1) << "=" << to_string_hexfloat(ST1) << std::endl; - tout << "D=" << D << std::endl;); - - prem(ST0, ST1, D, (D >= B)); - } while (D >= B); + if (ST0.exponent() < (ST1.exponent()) - 1) { + D = 0; + } + else { + D = ST0.exponent() - ST1.exponent(); + partial_remainder(ST0, ST1, D, (D >= B)); + } + } while (D >= B && !ST0.is_zero()); + m_mpz_manager.mul2k(ST0.significand(), 3); set(o, x.ebits, x.sbits, MPF_ROUND_TOWARD_ZERO, ST0); - if (is_zero(o)) - o.sign = x.sign; + round(MPF_ROUND_NEAREST_TEVEN, o); } + TRACE("mpf_dbg_rem", tout << "R = " << to_string(o) << "=" << to_string_hexfloat(o) << std::endl; ); TRACE("mpf_dbg", tout << "REMAINDER = " << to_string(o) << std::endl;); } @@ -1538,7 +1580,10 @@ scoped_mpf mpf_manager::to_packed_mpf(bool sgn, mpf_exp_t exp, scoped_mpz const scoped_mpz q_sig(m_mpz_manager); m_mpz_manager.set(q_sig, sig); if (rbits != 0) m_mpz_manager.div(q_sig, m_powers2(rbits), q_sig); // restore scale - m_mpz_manager.sub(q_sig, m_powers2(sbits-1), q_sig); // strip hidden bit + if (m_mpz_manager.ge(q_sig, m_powers2(sbits-1))) + m_mpz_manager.sub(q_sig, m_powers2(sbits-1), q_sig); // strip hidden bit + else if (exp == mk_min_exp(ebits)) + exp = mk_bot_exp(ebits); set(q, ebits, sbits, sgn, exp, q_sig); return q; } diff --git a/src/util/mpf.h b/src/util/mpf.h index e6bf3cd271e..ca2e3c60527 100644 --- a/src/util/mpf.h +++ b/src/util/mpf.h @@ -223,7 +223,8 @@ class mpf_manager { void round(mpf_rounding_mode rm, mpf & o); void round_sqrt(mpf_rounding_mode rm, mpf & o); - void prem(scoped_mpf & x, scoped_mpf const & y, mpf_exp_t const & exp_diff, bool partial); + void renormalize(unsigned ebits, unsigned sbits, mpf_exp_t & exp, mpz & sig); + void partial_remainder(scoped_mpf & x, scoped_mpf const & y, mpf_exp_t const & exp_diff, bool partial); void mk_round_inf(mpf_rounding_mode rm, mpf & o); From 12a8d0d02ba8b49ce2b5a4b202a343d748b92d65 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Thu, 12 May 2016 15:12:46 +0100 Subject: [PATCH 13/61] mpf debug cleanup --- src/util/mpf.cpp | 70 +++++++++++++++++++++++------------------------- src/util/mpf.h | 7 +++-- 2 files changed, 36 insertions(+), 41 deletions(-) diff --git a/src/util/mpf.cpp b/src/util/mpf.cpp index 32932522c86..085814734b9 100644 --- a/src/util/mpf.cpp +++ b/src/util/mpf.cpp @@ -1234,41 +1234,40 @@ void mpf_manager::renormalize(unsigned ebits, unsigned sbits, mpf_exp_t & exp, m } } -void mpf_manager::partial_remainder(scoped_mpf & x, scoped_mpf const & y, mpf_exp_t const & exp_diff, bool partial) { - unsigned ebits = x.get().ebits; - unsigned sbits = x.get().sbits; - bool sign = x.get().sign; +void mpf_manager::partial_remainder(mpf & x, mpf const & y, mpf_exp_t const & exp_diff, bool partial) { + unsigned ebits = x.ebits; + unsigned sbits = x.sbits; + bool sign = x.sign; SASSERT(-1 <= exp_diff && exp_diff < INT64_MAX); SASSERT(exp_diff < ebits+sbits || partial); signed int D = (signed int)(exp_diff); - mpf_exp_t N = (sbits+ebits)/2; + mpf_exp_t N = sbits-1; TRACE("mpf_dbg_rem", tout << "x=" << to_string(x) << std::endl; tout << "y=" << to_string(y) << std::endl; tout << "d=" << D << std::endl; tout << "partial=" << partial << std::endl;); - SASSERT(m_mpz_manager.lt(x.significand(), m_powers2(sbits))); - SASSERT(m_mpz_manager.ge(x.significand(), m_powers2(sbits - 1))); - SASSERT(m_mpz_manager.lt(y.significand(), m_powers2(sbits))); - SASSERT(m_mpz_manager.ge(y.significand(), m_powers2(sbits - 1))); + SASSERT(m_mpz_manager.lt(x.significand, m_powers2(sbits))); + SASSERT(m_mpz_manager.ge(x.significand, m_powers2(sbits - 1))); + SASSERT(m_mpz_manager.lt(y.significand, m_powers2(sbits))); + SASSERT(m_mpz_manager.ge(y.significand, m_powers2(sbits - 1))); // 1. Compute a/b - bool x_div_y_sgn = x.sign() ^ y.sign(); + bool x_div_y_sgn = x.sign != y.sign; mpf_exp_t x_div_y_exp = D; scoped_mpz x_sig_shifted(m_mpz_manager), x_div_y_sig_lrg(m_mpz_manager), x_div_y_rem(m_mpz_manager); scoped_mpz x_rem_y_sig(m_mpz_manager); - m_mpz_manager.mul2k(x.significand(), 2*sbits + 2, x_sig_shifted); - m_mpz_manager.machine_div_rem(x_sig_shifted, y.significand(), x_div_y_sig_lrg, x_div_y_rem); // rem useful? + m_mpz_manager.mul2k(x.significand, 2*sbits + 2, x_sig_shifted); + m_mpz_manager.machine_div_rem(x_sig_shifted, y.significand, x_div_y_sig_lrg, x_div_y_rem); // rem useful? // x/y is in x_diuv_y_sig_lrg and has sbits+3 extra bits. TRACE("mpf_dbg_rem", tout << "X/Y_exp=" << x_div_y_exp << std::endl; tout << "X/Y_sig_lrg=" << m_mpz_manager.to_string(x_div_y_sig_lrg) << std::endl; tout << "X/Y_rem=" << m_mpz_manager.to_string(x_div_y_rem) << std::endl; - scoped_mpf & XdY = to_packed_mpf(x_div_y_sgn, x_div_y_exp, x_div_y_sig_lrg, ebits, sbits, sbits+3); - tout << "X/Y~=" << to_string_hexfloat(XdY) << std::endl;); + tout << "X/Y~=" << to_string_hexfloat(x_div_y_sgn, x_div_y_exp, x_div_y_sig_lrg, ebits, sbits, sbits+3) << std::endl;); // 2. Round a/b to integer Q/QQ bool Q_sgn = x_div_y_sgn; @@ -1296,8 +1295,7 @@ void mpf_manager::partial_remainder(scoped_mpf & x, scoped_mpf const & y, mpf_ex TRACE("mpf_dbg_rem", tout << "Q_exp=" << Q_exp << std::endl; tout << "Q_sig=" << m_mpz_manager.to_string(Q_sig) << std::endl; - scoped_mpf & Q = to_packed_mpf(Q_sgn, Q_exp, Q_sig, ebits, sbits, 0); - tout << "Q=" << to_string_hexfloat(Q) << std::endl;); + tout << "Q=" << to_string_hexfloat(Q_sgn, Q_exp, Q_sig, ebits, sbits, 0) << std::endl;); if ((D == -1 || partial) && m_mpz_manager.is_zero(Q_sig)) return; // This means x % y = x. @@ -1309,24 +1307,23 @@ void mpf_manager::partial_remainder(scoped_mpf & x, scoped_mpf const & y, mpf_ex // 3. Compute Y*Q / Y*QQ*2^{D-N} - bool YQ_sgn = y.sign() ^ Q_sgn; + bool YQ_sgn = y.sign ^ Q_sgn; scoped_mpz YQ_sig(m_mpz_manager); - mpf_exp_t YQ_exp = Q_exp + y.exponent(); - m_mpz_manager.mul(y.significand(), Q_sig, YQ_sig); + mpf_exp_t YQ_exp = Q_exp + y.exponent; + m_mpz_manager.mul(y.significand, Q_sig, YQ_sig); renormalize(ebits, 2*sbits-1, YQ_exp, YQ_sig); // YQ_sig has `sbits-1' extra bits. TRACE("mpf_dbg_rem", tout << "YQ_sgn=" << YQ_sgn << std::endl; tout << "YQ_exp=" << YQ_exp << std::endl; tout << "YQ_sig=" << m_mpz_manager.to_string(YQ_sig) << std::endl; - scoped_mpf & YQ = to_packed_mpf(YQ_sgn, YQ_exp, YQ_sig, ebits, sbits, sbits-1); - tout << "YQ=" << to_string_hexfloat(YQ) << std::endl;); + tout << "YQ=" << to_string_hexfloat(YQ_sgn, YQ_exp, YQ_sig, ebits, sbits, sbits-1) << std::endl;); // `sbits-1' extra bits in YQ_sig. SASSERT(m_mpz_manager.lt(YQ_sig, m_powers2(2*sbits-1))); SASSERT(m_mpz_manager.ge(YQ_sig, m_powers2(2*sbits-2)) || YQ_exp <= mk_bot_exp(ebits)); // 4. Compute X-Y*Q - mpf_exp_t X_YQ_exp = x.exponent(); + mpf_exp_t X_YQ_exp = x.exponent; scoped_mpz X_YQ_sig(m_mpz_manager); mpf_exp_t exp_delta = exp(x) - YQ_exp; TRACE("mpf_dbg_rem", tout << "exp_delta=" << exp_delta << std::endl;); @@ -1334,7 +1331,7 @@ void mpf_manager::partial_remainder(scoped_mpf & x, scoped_mpf const & y, mpf_ex scoped_mpz minuend(m_mpz_manager), subtrahend(m_mpz_manager); scoped_mpz x_sig_lrg(m_mpz_manager); - m_mpz_manager.mul2k(x.significand(), sbits-1, x_sig_lrg); // sbits-1 extra bits into x + m_mpz_manager.mul2k(x.significand, sbits-1, x_sig_lrg); // sbits-1 extra bits into x m_mpz_manager.set(minuend, x_sig_lrg); m_mpz_manager.set(subtrahend, YQ_sig); @@ -1366,23 +1363,22 @@ void mpf_manager::partial_remainder(scoped_mpf & x, scoped_mpf const & y, mpf_ex bool neg = m_mpz_manager.is_neg(X_YQ_sig); if (neg) m_mpz_manager.neg(X_YQ_sig); - bool X_YQ_sgn = ((!x.sign() && !YQ_sgn && neg) || - (x.sign() && YQ_sgn && !neg) || - (x.sign() && !YQ_sgn)); + bool X_YQ_sgn = ((!x.sign && !YQ_sgn && neg) || + (x.sign && YQ_sgn && !neg) || + (x.sign && !YQ_sgn)); // 5. Rounding if (m_mpz_manager.is_zero(X_YQ_sig)) - mk_zero(ebits, sbits, x.sign(), x); + mk_zero(ebits, sbits, x.sign, x); else { renormalize(ebits, 2*sbits-1, X_YQ_exp, X_YQ_sig); TRACE("mpf_dbg_rem", tout << "minuend=" << m_mpz_manager.to_string(minuend) << std::endl; - tout << "subtrahend=" << m_mpz_manager.to_string(subtrahend) << std::endl; - tout << "X_YQ_sgn=" << X_YQ_sgn << std::endl; - tout << "X_YQ_exp=" << X_YQ_exp << std::endl; - tout << "X_YQ_sig=" << m_mpz_manager.to_string(X_YQ_sig) << std::endl; - scoped_mpf & X_YQ = to_packed_mpf(X_YQ_sgn, X_YQ_exp, X_YQ_sig, ebits, sbits, sbits-1); - tout << "X-YQ=" << to_string_hexfloat(X_YQ) << std::endl;); + tout << "subtrahend=" << m_mpz_manager.to_string(subtrahend) << std::endl; + tout << "X_YQ_sgn=" << X_YQ_sgn << std::endl; + tout << "X_YQ_exp=" << X_YQ_exp << std::endl; + tout << "X_YQ_sig=" << m_mpz_manager.to_string(X_YQ_sig) << std::endl; + tout << "X-YQ=" << to_string_hexfloat(X_YQ_sgn, X_YQ_exp, X_YQ_sig, ebits, sbits, sbits-1) << std::endl;); // `sbits-1' extra bits in X_YQ_sig SASSERT(m_mpz_manager.lt(X_YQ_sig, m_powers2(2*sbits-1))); @@ -1433,7 +1429,7 @@ void mpf_manager::rem(mpf const & x, mpf const & y, mpf & o) { unpack(ST0, true); unpack(ST1, true); - const mpf_exp_t B = x.sbits+x.ebits; + const mpf_exp_t B = x.sbits; mpf_exp_t D; do { if (ST0.exponent() < (ST1.exponent()) - 1) { @@ -1441,7 +1437,7 @@ void mpf_manager::rem(mpf const & x, mpf const & y, mpf & o) { } else { D = ST0.exponent() - ST1.exponent(); - partial_remainder(ST0, ST1, D, (D >= B)); + partial_remainder(ST0.get(), ST1.get(), D, (D >= B)); } } while (D >= B && !ST0.is_zero()); @@ -1575,7 +1571,7 @@ std::string mpf_manager::to_string_raw(mpf const & x) { return res; } -scoped_mpf mpf_manager::to_packed_mpf(bool sgn, mpf_exp_t exp, scoped_mpz const & sig, unsigned ebits, unsigned sbits, unsigned rbits) { +std::string mpf_manager::to_string_hexfloat(bool sgn, mpf_exp_t exp, scoped_mpz const & sig, unsigned ebits, unsigned sbits, unsigned rbits) { scoped_mpf q(*this); scoped_mpz q_sig(m_mpz_manager); m_mpz_manager.set(q_sig, sig); @@ -1585,7 +1581,7 @@ scoped_mpf mpf_manager::to_packed_mpf(bool sgn, mpf_exp_t exp, scoped_mpz const else if (exp == mk_min_exp(ebits)) exp = mk_bot_exp(ebits); set(q, ebits, sbits, sgn, exp, q_sig); - return q; + return to_string(q.get()); } std::string mpf_manager::to_string_hexfloat(mpf const & x) { diff --git a/src/util/mpf.h b/src/util/mpf.h index ca2e3c60527..31523c3ed2b 100644 --- a/src/util/mpf.h +++ b/src/util/mpf.h @@ -224,7 +224,7 @@ class mpf_manager { void round_sqrt(mpf_rounding_mode rm, mpf & o); void renormalize(unsigned ebits, unsigned sbits, mpf_exp_t & exp, mpz & sig); - void partial_remainder(scoped_mpf & x, scoped_mpf const & y, mpf_exp_t const & exp_diff, bool partial); + void partial_remainder(mpf & x, mpf const & y, mpf_exp_t const & exp_diff, bool partial); void mk_round_inf(mpf_rounding_mode rm, mpf & o); @@ -285,9 +285,8 @@ class mpf_manager { }; std::string to_string_raw(mpf const & a); - std::string to_string_hexfloat(mpf const & a); - scoped_mpf to_packed_mpf(bool sgn, mpf_exp_t exp, scoped_mpz const & sig, unsigned ebits, unsigned sbits, unsigned rbits); - + std::string to_string_hexfloat(mpf const & a); + std::string to_string_hexfloat(bool sgn, mpf_exp_t exp, scoped_mpz const & sig, unsigned ebits, unsigned sbits, unsigned rbits); public: powers2 m_powers2; }; From 0ddf2d92fec40487c6433dabe046661cdbb1e114 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Thu, 12 May 2016 15:20:50 +0100 Subject: [PATCH 14/61] removed unused variables --- src/util/mpf.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/util/mpf.cpp b/src/util/mpf.cpp index 085814734b9..48d2f976573 100644 --- a/src/util/mpf.cpp +++ b/src/util/mpf.cpp @@ -1218,9 +1218,6 @@ void mpf_manager::renormalize(unsigned ebits, unsigned sbits, mpf_exp_t & exp, m if (m_mpz_manager.is_zero(sig)) return; - mpf_exp_t max_e = mk_max_exp(ebits); - mpf_exp_t min_e = mk_min_exp(ebits); - const mpz & pg = m_powers2(sbits); while (m_mpz_manager.ge(sig, pg)) { m_mpz_manager.machine_div2k(sig, 1); @@ -1237,8 +1234,7 @@ void mpf_manager::renormalize(unsigned ebits, unsigned sbits, mpf_exp_t & exp, m void mpf_manager::partial_remainder(mpf & x, mpf const & y, mpf_exp_t const & exp_diff, bool partial) { unsigned ebits = x.ebits; unsigned sbits = x.sbits; - bool sign = x.sign; - + SASSERT(-1 <= exp_diff && exp_diff < INT64_MAX); SASSERT(exp_diff < ebits+sbits || partial); From 7e3dfb46173e4d7e2e69bbead080cb3881ca0875 Mon Sep 17 00:00:00 2001 From: Manuel Jacob Date: Fri, 13 May 2016 23:11:15 +0200 Subject: [PATCH 15/61] Expose Z3_mk_bv2int's is_signed parameter in Python API. --- src/api/python/z3.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/api/python/z3.py b/src/api/python/z3.py index 848883ba391..624cd18f239 100644 --- a/src/api/python/z3.py +++ b/src/api/python/z3.py @@ -3468,7 +3468,7 @@ def is_bv_value(a): """ return is_bv(a) and _is_numeral(a.ctx, a.as_ast()) -def BV2Int(a): +def BV2Int(a, is_signed=False): """Return the Z3 expression BV2Int(a). >>> b = BitVec('b', 3) @@ -3477,6 +3477,10 @@ def BV2Int(a): >>> x = Int('x') >>> x > BV2Int(b) x > BV2Int(b) + >>> x > BV2Int(b, is_signed=False) + x > BV2Int(b) + >>> x > BV2Int(b, is_signed=True) + x > If(b < 0, BV2Int(b) - 8, BV2Int(b)) >>> solve(x > BV2Int(b), b == 1, x < 3) [b = 1, x = 2] """ @@ -3484,7 +3488,7 @@ def BV2Int(a): _z3_assert(is_bv(a), "Z3 bit-vector expression expected") ctx = a.ctx ## investigate problem with bv2int - return ArithRef(Z3_mk_bv2int(ctx.ref(), a.as_ast(), 0), ctx) + return ArithRef(Z3_mk_bv2int(ctx.ref(), a.as_ast(), is_signed), ctx) def BitVecSort(sz, ctx=None): """Return a Z3 bit-vector sort of the given size. If `ctx=None`, then the global context is used. From 3fde81aea6d895a2fe9337c79ae27a1fbdea527f Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Sat, 14 May 2016 14:29:13 +0100 Subject: [PATCH 16/61] Style --- src/util/mpf.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util/mpf.cpp b/src/util/mpf.cpp index 48d2f976573..14fb1c535b8 100644 --- a/src/util/mpf.cpp +++ b/src/util/mpf.cpp @@ -1428,7 +1428,7 @@ void mpf_manager::rem(mpf const & x, mpf const & y, mpf & o) { const mpf_exp_t B = x.sbits; mpf_exp_t D; do { - if (ST0.exponent() < (ST1.exponent()) - 1) { + if (ST0.exponent() < ST1.exponent() - 1) { D = 0; } else { From bb2c5972c7117fe695ee75f3fc0eaf70b9273c98 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Sat, 14 May 2016 18:21:53 +0100 Subject: [PATCH 17/61] Bugfixes for UFs in theory_fpa. Fixes #591, but performance issues remain. --- src/ast/fpa/fpa2bv_converter.cpp | 27 ++--- src/ast/fpa/fpa2bv_converter.h | 5 + src/smt/theory_fpa.cpp | 171 ++++++++++++++++++------------- src/smt/theory_fpa.h | 5 +- 4 files changed, 121 insertions(+), 87 deletions(-) diff --git a/src/ast/fpa/fpa2bv_converter.cpp b/src/ast/fpa/fpa2bv_converter.cpp index aefa6294ae0..8220e64ae71 100644 --- a/src/ast/fpa/fpa2bv_converter.cpp +++ b/src/ast/fpa/fpa2bv_converter.cpp @@ -2235,14 +2235,17 @@ void fpa2bv_converter::mk_to_fp(func_decl * f, unsigned num, expr * const * args SASSERT(is_well_sorted(m, result)); } + void fpa2bv_converter::mk_to_fp_float(func_decl * f, sort * s, expr * rm, expr * x, expr_ref & result) { + SASSERT(is_app_of(rm, m_util.get_family_id(), OP_FPA_INTERNAL_RM)); + mk_to_fp_float(s, to_app(rm)->get_arg(0), x, result); +} + +void fpa2bv_converter::mk_to_fp_float(sort * to_srt, expr * rm, expr * x, expr_ref & result) { unsigned from_sbits = m_util.get_sbits(m.get_sort(x)); unsigned from_ebits = m_util.get_ebits(m.get_sort(x)); - unsigned to_sbits = m_util.get_sbits(s); - unsigned to_ebits = m_util.get_ebits(s); - - SASSERT(is_app_of(rm, m_util.get_family_id(), OP_FPA_INTERNAL_RM)); - expr * bv_rm = to_app(rm)->get_arg(0); + unsigned to_sbits = m_util.get_sbits(to_srt); + unsigned to_ebits = m_util.get_ebits(to_srt); if (from_sbits == to_sbits && from_ebits == to_ebits) result = x; @@ -2253,20 +2256,20 @@ void fpa2bv_converter::mk_to_fp_float(func_decl * f, sort * s, expr * rm, expr * one1 = m_bv_util.mk_numeral(1, 1); expr_ref ninf(m), pinf(m); - mk_pinf(f, pinf); - mk_ninf(f, ninf); + mk_pinf(to_srt, pinf); + mk_ninf(to_srt, ninf); // NaN -> NaN mk_is_nan(x, c1); - mk_nan(f, v1); + mk_nan(to_srt, v1); // +0 -> +0 mk_is_pzero(x, c2); - mk_pzero(f, v2); + mk_pzero(to_srt, v2); // -0 -> -0 mk_is_nzero(x, c3); - mk_nzero(f, v3); + mk_nzero(to_srt, v3); // +oo -> +oo mk_is_pinf(x, c4); @@ -2380,8 +2383,8 @@ void fpa2bv_converter::mk_to_fp_float(func_decl * f, sort * s, expr * rm, expr * dbg_decouple("fpa2bv_to_float_res_exp", res_exp); expr_ref rounded(m); - expr_ref rm_e(bv_rm, m); - round(s, rm_e, res_sgn, res_sig, res_exp, rounded); + expr_ref rm_e(rm, m); + round(to_srt, rm_e, res_sgn, res_sig, res_exp, rounded); expr_ref is_neg(m), sig_inf(m); m_simp.mk_eq(sgn, one1, is_neg); diff --git a/src/ast/fpa/fpa2bv_converter.h b/src/ast/fpa/fpa2bv_converter.h index b6a6bdbb37f..32c3124dba1 100644 --- a/src/ast/fpa/fpa2bv_converter.h +++ b/src/ast/fpa/fpa2bv_converter.h @@ -144,6 +144,9 @@ class fpa2bv_converter { void dbg_decouple(const char * prefix, expr_ref & e); expr_ref_vector m_extra_assertions; + bool is_special(func_decl * f) { return m_specials.contains(f); } + bool is_uf2bvuf(func_decl * f) { return m_uf2bvuf.contains(f); } + protected: void mk_one(func_decl *f, expr_ref & sign, expr_ref & result); @@ -201,6 +204,8 @@ class fpa2bv_converter { void mk_div(sort * s, expr_ref & bv_rm, expr_ref & x, expr_ref & y, expr_ref & result); void mk_rem(sort * s, expr_ref & x, expr_ref & y, expr_ref & result); 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); }; #endif diff --git a/src/smt/theory_fpa.cpp b/src/smt/theory_fpa.cpp index 23e1f746d01..543b1348e56 100644 --- a/src/smt/theory_fpa.cpp +++ b/src/smt/theory_fpa.cpp @@ -85,8 +85,63 @@ namespace smt { } void theory_fpa::fpa2bv_converter_wrapped::mk_uninterpreted_function(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { - // TODO: This introduces temporary variables/func_decls that should be filtered in the end. - fpa2bv_converter::mk_uninterpreted_function(f, num, args, result); + // TODO: This introduces temporary func_decls that should be filtered in the end. + + TRACE("t_fpa", tout << "UF: " << mk_ismt2_pp(f, m) << std::endl; ); + SASSERT(f->get_arity() == num); + + expr_ref_buffer new_args(m); + + for (unsigned i = 0; i < num; i++) { + if (is_float(args[i]) || is_rm(args[i])) { + expr_ref ai(m), wrapped(m); + ai = args[i]; + wrapped = m_th.wrap(ai); + new_args.push_back(wrapped); + m_extra_assertions.push_back(m.mk_eq(m_th.unwrap(wrapped, m.get_sort(ai)), ai)); + } + else + new_args.push_back(args[i]); + } + + func_decl * fd; + if (m_uf2bvuf.find(f, fd)) + mk_uninterpreted_output(f->get_range(), fd, new_args, result); + else { + sort_ref_buffer new_domain(m); + + for (unsigned i = 0; i < f->get_arity(); i++) { + sort * di = f->get_domain()[i]; + if (is_float(di)) + new_domain.push_back(m_bv_util.mk_sort(m_util.get_sbits(di) + m_util.get_ebits(di))); + else if (is_rm(di)) + new_domain.push_back(m_bv_util.mk_sort(3)); + else + new_domain.push_back(di); + } + + sort * frng = f->get_range(); + sort_ref rng(frng, m); + if (m_util.is_float(frng)) + rng = m_bv_util.mk_sort(m_util.get_ebits(frng) + m_util.get_sbits(frng)); + else if (m_util.is_rm(frng)) + rng = m_bv_util.mk_sort(3); + + func_decl_ref fbv(m); + fbv = m.mk_fresh_func_decl(new_domain.size(), new_domain.c_ptr(), rng); + TRACE("t_fpa", tout << "New UF func_decl : " << mk_ismt2_pp(fbv, m) << std::endl;); + + m_uf2bvuf.insert(f, fbv); + m.inc_ref(f); + m.inc_ref(fbv); + + mk_uninterpreted_output(frng, fbv, new_args, result); + } + + expr_ref fapp(m); + fapp = m.mk_app(f, num, args); + m_extra_assertions.push_back(m.mk_eq(fapp, result)); + TRACE("t_fpa", tout << "UF result: " << mk_ismt2_pp(result, m) << std::endl; ); } expr_ref theory_fpa::fpa2bv_converter_wrapped::mk_min_unspecified(func_decl * f, expr * x, expr * y) { @@ -284,30 +339,40 @@ namespace smt { app_ref theory_fpa::wrap(expr * e) { SASSERT(!m_fpa_util.is_wrap(e)); ast_manager & m = get_manager(); - sort * e_srt = m.get_sort(e); + app_ref res(m); - func_decl *w; + if (is_app(e) && + to_app(e)->get_family_id() == get_family_id() && + to_app(e)->get_decl_kind() == OP_FPA_FP) { + 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 * e_srt = m.get_sort(e); + func_decl * w; - if (!m_wraps.find(e_srt, w)) { - SASSERT(!m_wraps.contains(e_srt)); + if (!m_wraps.find(e_srt, w)) { + SASSERT(!m_wraps.contains(e_srt)); - sort * bv_srt; - if (m_converter.is_rm(e_srt)) - bv_srt = m_bv_util.mk_sort(3); - else { - SASSERT(m_converter.is_float(e_srt)); - unsigned ebits = m_fpa_util.get_ebits(e_srt); - unsigned sbits = m_fpa_util.get_sbits(e_srt); - bv_srt = m_bv_util.mk_sort(ebits + sbits); + sort * bv_srt; + if (m_converter.is_rm(e_srt)) + bv_srt = m_bv_util.mk_sort(3); + else { + SASSERT(m_converter.is_float(e_srt)); + unsigned ebits = m_fpa_util.get_ebits(e_srt); + unsigned sbits = m_fpa_util.get_sbits(e_srt); + bv_srt = m_bv_util.mk_sort(ebits + sbits); + } + + w = m.mk_func_decl(get_family_id(), OP_FPA_INTERNAL_BVWRAP, 0, 0, 1, &e_srt, bv_srt); + m_wraps.insert(e_srt, w); + m.inc_ref(w); } - w = m.mk_func_decl(get_family_id(), OP_FPA_INTERNAL_BVWRAP, 0, 0, 1, &e_srt, bv_srt); - m_wraps.insert(e_srt, w); - m.inc_ref(w); + res = m.mk_app(w, e); } - - app_ref res(m); - res = m.mk_app(w, e); + return res; } @@ -389,59 +454,6 @@ namespace smt { return res; } -#if 0 - expr_ref theory_fpa::convert_uf(expr * e) { - SASSERT(is_app(e)); - ast_manager & m = get_manager(); - expr_ref res(m); - - app * a = to_app(e); - func_decl * f = a->get_decl(); - sort * const * domain = f->get_domain(); - unsigned arity = f->get_arity(); - - expr_ref_buffer new_args(m); - expr_ref unwrapped(m); - - for (unsigned i = 0; i < arity; i++) { - expr * ai = a->get_arg(i); - if (m_fpa_util.is_float(ai) || m_fpa_util.is_rm(ai)) { - if (m_fpa_util.is_unwrap(ai)) - unwrapped = ai; - else { - // unwrapped = unwrap(wrap(ai), domain[i]); - // assert_cnstr(m.mk_eq(unwrapped, ai)); - // assert_cnstr(); - unwrapped = convert_term(ai); - } - - new_args.push_back(unwrapped); - TRACE("t_fpa_detail", tout << "UF arg(" << i << ") = " << mk_ismt2_pp(unwrapped, get_manager()) << "\n";); - } - else - new_args.push_back(ai); - } - - sort * rng = f->get_range(); - if (m_fpa_util.is_float(rng)) { - unsigned sbits = m_fpa_util.get_sbits(rng); - unsigned bv_sz = m_fpa_util.get_ebits(rng) + sbits; - expr_ref wrapped(m); - wrapped = wrap(m.mk_app(f, new_args.size(), new_args.c_ptr())); - - m_converter.mk_fp(m_bv_util.mk_extract(bv_sz - 1, bv_sz - 1, wrapped), - m_bv_util.mk_extract(bv_sz - 2, sbits - 1, wrapped), - m_bv_util.mk_extract(sbits - 2, 0, wrapped), - res); - } - else - res = m.mk_app(f, new_args.size(), new_args.c_ptr()); - - TRACE("t_fpa_detail", tout << "UF call = " << mk_ismt2_pp(res, get_manager()) << "\n";); - return res; - } -#endif - expr_ref theory_fpa::convert_conversion_term(expr * e) { /* This is for the conversion functions fp.to_* */ ast_manager & m = get_manager(); @@ -606,6 +618,7 @@ namespace smt { // Therefore, we translate and assert them here. fpa_op_kind k = (fpa_op_kind)term->get_decl_kind(); switch (k) { + case OP_FPA_TO_FP: case OP_FPA_TO_UBV: case OP_FPA_TO_SBV: case OP_FPA_TO_REAL: @@ -966,4 +979,16 @@ namespace smt { out << r->get_id() << " --> " << mk_ismt2_pp(n, m) << std::endl; } } + + bool theory_fpa::include_func_interp(func_decl * f) { + TRACE("t_fpa", tout << "f = " << mk_ismt2_pp(f, get_manager()) << std::endl;); + func_decl * wt; + + if (m_wraps.find(f->get_range(), wt) || m_unwraps.find(f->get_range(), wt)) + return wt == f; + else if (m_converter.is_uf2bvuf(f) || m_converter.is_special(f)) + return false; + else + return true; + } }; diff --git a/src/smt/theory_fpa.h b/src/smt/theory_fpa.h index 1b0fc6c54a4..d693e3ede20 100644 --- a/src/smt/theory_fpa.h +++ b/src/smt/theory_fpa.h @@ -83,7 +83,7 @@ namespace smt { virtual ~fpa2bv_converter_wrapped() {} virtual void mk_const(func_decl * f, expr_ref & result); virtual void mk_rm_const(func_decl * f, expr_ref & result); - virtual void mk_uninterpreted_function(func_decl * f, unsigned num, expr * const * args, expr_ref & result); + virtual void mk_uninterpreted_function(func_decl * f, unsigned num, expr * const * args, expr_ref & result); virtual expr_ref mk_min_unspecified(func_decl * f, expr * x, expr * y); virtual expr_ref mk_max_unspecified(func_decl * f, expr * x, expr * y); @@ -112,7 +112,7 @@ namespace smt { result.append(m_deps); } - virtual app * mk_value(model_generator & mg, ptr_vector & values); + virtual app * mk_value(model_generator & mg, ptr_vector & values); }; class fpa_rm_value_proc : public model_value_proc { @@ -163,6 +163,7 @@ namespace smt { virtual char const * get_name() const { return "fpa"; } virtual model_value_proc * mk_value(enode * n, model_generator & mg); + virtual bool include_func_interp(func_decl * f); void assign_eh(bool_var v, bool is_true); virtual void relevant_eh(app * n); From 44b0a6ddbcc75c2252c21965c8f473136784acf7 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Sat, 14 May 2016 18:42:10 +0100 Subject: [PATCH 18/61] Tentative fix for #586. --- src/ast/fpa/fpa2bv_converter.cpp | 3 +-- src/util/mpf.cpp | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/ast/fpa/fpa2bv_converter.cpp b/src/ast/fpa/fpa2bv_converter.cpp index 8220e64ae71..e6b9dda07b5 100644 --- a/src/ast/fpa/fpa2bv_converter.cpp +++ b/src/ast/fpa/fpa2bv_converter.cpp @@ -1928,8 +1928,7 @@ void fpa2bv_converter::mk_round_to_integral(sort * s, expr_ref & rm, expr_ref & tie_pttrn = m_bv_util.mk_concat(one_1, m_bv_util.mk_numeral(0, sbits-1)); m_simp.mk_eq(rem, tie_pttrn, tie2); div_last = m_bv_util.mk_extract(0, 0, div); - tie2_c = m.mk_ite(tie2, m.mk_or(m.mk_and(rm_is_rte, m.mk_eq(div_last, one_1)), - m.mk_and(rm_is_rta, m.mk_eq(div_last, zero_1))), + tie2_c = m.mk_ite(tie2, m.mk_or(m.mk_and(rm_is_rte, m.mk_eq(div_last, one_1)), rm_is_rta), m_bv_util.mk_ule(tie_pttrn, rem)); m_simp.mk_ite(tie2_c, div_p1, div, v51); diff --git a/src/util/mpf.cpp b/src/util/mpf.cpp index 14fb1c535b8..2a1f0362c0a 100644 --- a/src/util/mpf.cpp +++ b/src/util/mpf.cpp @@ -1095,7 +1095,7 @@ void mpf_manager::round_to_integral(mpf_rounding_mode rm, mpf const & x, mpf & o TRACE("mpf_dbg", tout << "tie= " << tie << "; tie = " << more_than_tie << std::endl;); if (tie) { if ((rm == MPF_ROUND_NEAREST_TEVEN && m_mpz_manager.is_odd(div)) || - (rm == MPF_ROUND_NEAREST_TAWAY && m_mpz_manager.is_even(div))) { + (rm == MPF_ROUND_NEAREST_TAWAY)) { TRACE("mpf_dbg", tout << "div++ (1)" << std::endl;); m_mpz_manager.inc(div); } From 42726171b54b3eb4704cf7a055cb3578d0453033 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 15 May 2016 11:34:48 -0700 Subject: [PATCH 19/61] add limit checks in Grobner. Issue #599 Signed-off-by: Nikolaj Bjorner --- src/math/grobner/grobner.cpp | 17 +++++++++------ src/math/grobner/grobner.h | 2 +- src/model/model_evaluator.cpp | 3 ++- src/qe/qsat.cpp | 39 ++++++++++++++++++++++++++++------- 4 files changed, 45 insertions(+), 16 deletions(-) diff --git a/src/math/grobner/grobner.cpp b/src/math/grobner/grobner.cpp index 309e0c777b0..2bf4d5ba3ad 100644 --- a/src/math/grobner/grobner.cpp +++ b/src/math/grobner/grobner.cpp @@ -670,7 +670,7 @@ grobner::equation * grobner::simplify(equation const * source, equation * target simplify(target); } } - while (simplified); + while (simplified && !m_manager.canceled()); TRACE("grobner", tout << "result: "; display_equation(tout, *target);); return result ? target : 0; } @@ -697,7 +697,10 @@ grobner::equation * grobner::simplify_using_processed(equation * eq) { simplified = true; eq = new_eq; } - } + if (m_manager.canceled()) { + return 0; + } + } } while (simplified); TRACE("grobner", tout << "simplification result: "; display_equation(tout, *eq);); @@ -749,13 +752,13 @@ grobner::equation * grobner::pick_next() { /** \brief Use the given equation to simplify processed terms. */ -void grobner::simplify_processed(equation * eq) { +bool grobner::simplify_processed(equation * eq) { ptr_buffer to_insert; ptr_buffer to_remove; ptr_buffer to_delete; equation_set::iterator it = m_processed.begin(); equation_set::iterator end = m_processed.end(); - for (; it != end; ++it) { + for (; it != end && !m_manager.canceled(); ++it) { equation * curr = *it; m_changed_leading_term = false; // if the leading term is simplified, then the equation has to be moved to m_to_process @@ -795,6 +798,7 @@ void grobner::simplify_processed(equation * eq) { end1 = to_delete.end(); for (; it1 != end1; ++it1) del_equation(*it1); + return !m_manager.canceled(); } /** @@ -944,7 +948,8 @@ bool grobner::compute_basis_step() { m_equations_to_unfreeze.push_back(eq); eq = new_eq; } - simplify_processed(eq); + if (m_manager.canceled()) return false; + if (!simplify_processed(eq)) return false; superpose(eq); m_processed.insert(eq); simplify_to_process(eq); @@ -954,7 +959,7 @@ bool grobner::compute_basis_step() { bool grobner::compute_basis(unsigned threshold) { compute_basis_init(); - while (m_num_new_equations < threshold) { + while (m_num_new_equations < threshold && !m_manager.canceled()) { if (compute_basis_step()) return true; } return false; diff --git a/src/math/grobner/grobner.h b/src/math/grobner/grobner.h index 6084bf77d63..770f0a538bd 100644 --- a/src/math/grobner/grobner.h +++ b/src/math/grobner/grobner.h @@ -175,7 +175,7 @@ class grobner { equation * pick_next(); - void simplify_processed(equation * eq); + bool simplify_processed(equation * eq); void simplify_to_process(equation * eq); diff --git a/src/model/model_evaluator.cpp b/src/model/model_evaluator.cpp index e67e3cb5ecf..f8c7198523e 100644 --- a/src/model/model_evaluator.cpp +++ b/src/model/model_evaluator.cpp @@ -114,7 +114,8 @@ struct evaluator_cfg : public default_rewriter_cfg { br_status reduce_app(func_decl * f, unsigned num, expr * const * args, expr_ref & result, proof_ref & result_pr) { result_pr = 0; family_id fid = f->get_family_id(); - if (num == 0 && (fid == null_family_id || m().get_plugin(f->get_family_id())->is_considered_uninterpreted(f))) { + bool is_uninterp = fid != null_family_id && m().get_plugin(fid)->is_considered_uninterpreted(f); + if (num == 0 && (fid == null_family_id || is_uninterp)) { expr * val = m_model.get_const_interp(f); if (val != 0) { result = val; diff --git a/src/qe/qsat.cpp b/src/qe/qsat.cpp index c7e20b73390..e50821256c3 100644 --- a/src/qe/qsat.cpp +++ b/src/qe/qsat.cpp @@ -620,7 +620,7 @@ namespace qe { } kernel& get_kernel(unsigned j) { - if (is_exists(j)) { + if (m_kernel_ex || is_exists(j)) { return m_ex; } else { @@ -1073,7 +1073,7 @@ namespace qe { m_mode(mode), m_avars(m), m_free_vars(m), - m_kernel(m) + m_kernel_ex(false) { reset(); } @@ -1240,9 +1240,10 @@ namespace qe { } - kernel m_kernel; + bool m_kernel_ex; lbool max_min(expr_ref_vector const& fmls, svector const& is_max, app_ref_vector const& vars, app* t) { + m_kernel_ex = true; // Assume this is the only call to check. expr_ref_vector defs(m); app_ref_vector free_vars(m), vars1(m); @@ -1250,8 +1251,8 @@ namespace qe { m_pred_abs.get_free_vars(fml, free_vars); m_pred_abs.abstract_atoms(fml, defs); fml = m_pred_abs.mk_abstract(fml); - m_kernel.assert_expr(mk_and(defs)); - m_kernel.assert_expr(fml); + get_kernel(0).k().assert_expr(mk_and(defs)); + get_kernel(0).k().assert_expr(fml); obj_hashtable var_set; for (unsigned i = 0; i < vars.size(); ++i) { var_set.insert(vars[i]); @@ -1278,8 +1279,6 @@ namespace qe { m_vars.push_back(vars1); return max_min(); - - // return l_undef; } lbool max_min() { @@ -1288,15 +1287,39 @@ namespace qe { check_cancel(); expr_ref_vector asms(m_asms); m_pred_abs.get_assumptions(m_model.get(), asms); + // + // TBD: add bound to asms. + // smt::kernel& k = get_kernel(m_level).k(); lbool res = k.check(asms); switch (res) { case l_true: + k.get_model(m_model); + SASSERT(validate_model(asms)); + TRACE("qe", k.display(tout); display(tout << "\n", *m_model.get()); display(tout, asms); ); + // + // TBD: compute new bound on objective. + // + push(); break; case l_false: + switch (m_level) { + case 0: return l_false; + case 1: + // TBD + break; + default: + if (m_model.get()) { + project(asms); + } + else { + pop(1); + } + break; + } break; case l_undef: - break; + return res; } } return l_undef; From 10cdd527caa220c0d13dc6c30641cf567ea2fc13 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 15 May 2016 12:27:04 -0700 Subject: [PATCH 20/61] strengthening length properties for int.to.str. Issue #589 Signed-off-by: Nikolaj Bjorner --- src/smt/theory_seq.cpp | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index 86761412f7b..239ba742021 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -2823,6 +2823,7 @@ void theory_seq::add_elim_string_axiom(expr* n) { - len(unit(u)) = 1 if x = unit(u) - len(str) = str.length() if x = str - len(empty) = 0 if x = empty + - len(int.to.str(i)) >= 1 if x = int.to.str(i) and more generally if i = 0 then 1 else 1+floor(log(|i|)) - len(x) >= 0 otherwise */ void theory_seq::add_length_axiom(expr* n) { @@ -2837,16 +2838,17 @@ void theory_seq::add_length_axiom(expr* n) { m_rewrite(len); SASSERT(n != len); add_axiom(mk_eq(len, n, false)); - if (!ctx.at_base_level()) { - m_trail_stack.push(push_replay(alloc(replay_axiom, m, n))); - } + } + else if (m_util.str.is_itos(x)) { + add_axiom(mk_literal(m_autil.mk_ge(n, m_autil.mk_int(1)))); } else { add_axiom(mk_literal(m_autil.mk_ge(n, m_autil.mk_int(0)))); - if (!ctx.at_base_level()) { - m_trail_stack.push(push_replay(alloc(replay_axiom, m, n))); - } } + if (!ctx.at_base_level()) { + m_trail_stack.push(push_replay(alloc(replay_axiom, m, n))); + } + } From 886759a58cfd2a39a4b2a87193c4019b54cef273 Mon Sep 17 00:00:00 2001 From: Teodor Vlasov Date: Sun, 15 May 2016 22:36:12 +0300 Subject: [PATCH 21/61] add DOTNET_ENABLED in parser_options of mk_*_dist --- scripts/mk_unix_dist.py | 2 +- scripts/mk_win_dist.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/mk_unix_dist.py b/scripts/mk_unix_dist.py index 999d495a329..0c28058ed18 100644 --- a/scripts/mk_unix_dist.py +++ b/scripts/mk_unix_dist.py @@ -58,7 +58,7 @@ def display_help(): # Parse configuration option for mk_make script def parse_options(): - global FORCE_MK, JAVA_ENABLED, GIT_HASH + global FORCE_MK, JAVA_ENABLED, GIT_HASH, DOTNET_ENABLED path = BUILD_DIR options, remainder = getopt.gnu_getopt(sys.argv[1:], 'b:hsf', ['build=', 'help', diff --git a/scripts/mk_win_dist.py b/scripts/mk_win_dist.py index 454bba7cae1..cee8c0460ec 100644 --- a/scripts/mk_win_dist.py +++ b/scripts/mk_win_dist.py @@ -63,7 +63,7 @@ def display_help(): # Parse configuration option for mk_make script def parse_options(): - global FORCE_MK, JAVA_ENABLED, GIT_HASH + global FORCE_MK, JAVA_ENABLED, GIT_HASH, DOTNET_ENABLED path = BUILD_DIR options, remainder = getopt.gnu_getopt(sys.argv[1:], 'b:hsf', ['build=', 'help', From 7fb30c38aebbf8d956c02a37a9f944f140d97c0f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 15 May 2016 12:49:07 -0700 Subject: [PATCH 22/61] disallow illegal use per #604 Signed-off-by: Nikolaj Bjorner --- src/muz/fp/dl_cmds.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/muz/fp/dl_cmds.cpp b/src/muz/fp/dl_cmds.cpp index 2a6ff04d4cd..874d1453820 100644 --- a/src/muz/fp/dl_cmds.cpp +++ b/src/muz/fp/dl_cmds.cpp @@ -219,6 +219,13 @@ class dl_query_cmd : public parametric_cmd { virtual void set_next_arg(cmd_context & ctx, func_decl* t) { m_target = t; + if (t->get_family_id() != null_family_id) { + throw cmd_exception("Invalid query argument, expected uinterpreted function name, but argument is interpreted"); + } + datalog::context& dlctx = m_dl_ctx->dlctx(); + if (!dlctx.get_predicates().contains(t)) { + throw cmd_exception("Invalid query argument, expected a predicate registered as a relation"); + } } virtual void prepare(cmd_context & ctx) { From e5ca6762516845e7c1a9a9f0548ec34f4a2d84a9 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 15 May 2016 12:59:42 -0700 Subject: [PATCH 23/61] initialize manager to avoid unrelated error message, issue #604 Signed-off-by: Nikolaj Bjorner --- src/muz/base/dl_context.cpp | 5 ++--- src/muz/fp/dl_cmds.cpp | 3 +++ 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/muz/base/dl_context.cpp b/src/muz/base/dl_context.cpp index 74c909c02cf..a90d420cb7b 100644 --- a/src/muz/base/dl_context.cpp +++ b/src/muz/base/dl_context.cpp @@ -188,9 +188,8 @@ namespace datalog { if (m_trail.get_num_scopes() == 0) { throw default_exception("there are no backtracking points to pop to"); } - if(m_engine.get()){ - if(get_engine() != DUALITY_ENGINE) - throw default_exception("operation is not supported by engine"); + if (m_engine.get() && get_engine() != DUALITY_ENGINE) { + throw default_exception("pop operation is only supported by duality engine"); } m_trail.pop_scope(1); } diff --git a/src/muz/fp/dl_cmds.cpp b/src/muz/fp/dl_cmds.cpp index 874d1453820..e8e93dafc62 100644 --- a/src/muz/fp/dl_cmds.cpp +++ b/src/muz/fp/dl_cmds.cpp @@ -229,6 +229,7 @@ class dl_query_cmd : public parametric_cmd { } virtual void prepare(cmd_context & ctx) { + ctx.m(); // ensure manager is initialized. parametric_cmd::prepare(ctx); m_target = 0; } @@ -390,6 +391,7 @@ class dl_declare_rel_cmd : public cmd { virtual unsigned get_arity() const { return VAR_ARITY; } virtual void prepare(cmd_context & ctx) { + ctx.m(); // ensure manager is initialized. m_arg_idx = 0; m_query_arg_idx = 0; m_domain = 0; @@ -450,6 +452,7 @@ class dl_declare_var_cmd : public cmd { virtual unsigned get_arity() const { return 2; } virtual void prepare(cmd_context & ctx) { + ctx.m(); // ensure manager is initialized. m_arg_idx = 0; } virtual cmd_arg_kind next_arg_kind(cmd_context & ctx) const { From cd937c07f325999fb03cf5e68448c9ce031ea0fe Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 15 May 2016 13:29:38 -0700 Subject: [PATCH 24/61] return proper ast-option from get_const_interp function insetad of raising exceptions from inside the C API. Fixes discrepancy with documentation and behavior across extensions of the API. Issue #587 Signed-off-by: Nikolaj Bjorner --- src/api/api_model.cpp | 3 +-- src/api/c++/z3++.h | 3 +++ src/api/python/z3.py | 5 ++++- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/api/api_model.cpp b/src/api/api_model.cpp index 63092b2cf56..10ede0922e2 100644 --- a/src/api/api_model.cpp +++ b/src/api/api_model.cpp @@ -50,14 +50,13 @@ extern "C" { Z3_CATCH; } - Z3_ast Z3_API Z3_model_get_const_interp(Z3_context c, Z3_model m, Z3_func_decl a) { + Z3_ast_opt Z3_API Z3_model_get_const_interp(Z3_context c, Z3_model m, Z3_func_decl a) { Z3_TRY; LOG_Z3_model_get_const_interp(c, m, a); RESET_ERROR_CODE(); CHECK_NON_NULL(m, 0); expr * r = to_model_ref(m)->get_const_interp(to_func_decl(a)); if (!r) { - SET_ERROR_CODE(Z3_INVALID_ARG); RETURN_Z3(0); } mk_c(c)->save_ast_trail(r); diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index 6e85447708a..9fb6648198a 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -1582,6 +1582,9 @@ namespace z3 { return static_cast(i) < num_consts() ? get_const_decl(i) : get_func_decl(i - num_consts()); } + // returns interpretation of constant declaration c. + // If c is not assigned any value in the model it returns + // an expression with a null ast reference. expr get_const_interp(func_decl c) const { check_context(*this, c); Z3_ast r = Z3_model_get_const_interp(ctx(), m_model, c); diff --git a/src/api/python/z3.py b/src/api/python/z3.py index 848883ba391..2126cf0fef9 100644 --- a/src/api/python/z3.py +++ b/src/api/python/z3.py @@ -5516,7 +5516,10 @@ def get_interp(self, decl): decl = decl.decl() try: if decl.arity() == 0: - r = _to_expr_ref(Z3_model_get_const_interp(self.ctx.ref(), self.model, decl.ast), self.ctx) + _r = Z3_model_get_const_interp(self.ctx.ref(), self.model, decl.ast) + if _r.value is None: + return None + r = _to_expr_ref(_r, self.ctx) if is_as_array(r): return self.get_interp(get_as_array_func(r)) else: From a8fca8f77e7ce6dd0e142b21f9a44d80b29e9d67 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 15 May 2016 20:28:46 -0700 Subject: [PATCH 25/61] remove unused private fields Signed-off-by: Nikolaj Bjorner --- src/qe/nlqsat.cpp | 3 +-- src/qe/qsat.cpp | 2 -- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/src/qe/nlqsat.cpp b/src/qe/nlqsat.cpp index e05bed9a78a..fbff2e583c9 100644 --- a/src/qe/nlqsat.cpp +++ b/src/qe/nlqsat.cpp @@ -435,12 +435,11 @@ namespace qe { }; class div_rewriter_cfg : public default_rewriter_cfg { - nlqsat& s; ast_manager& m; arith_util a; vector
m_divs; public: - div_rewriter_cfg(nlqsat& s): s(s), m(s.m), a(s.m) {} + div_rewriter_cfg(nlqsat& s): m(s.m), a(s.m) {} ~div_rewriter_cfg() {} br_status reduce_app(func_decl* f, unsigned sz, expr* const* args, expr_ref& result, proof_ref& pr) { if (is_decl_of(f, a.get_family_id(), OP_DIV) && sz == 2 && !a.is_numeral(args[1]) && is_ground(args[0]) && is_ground(args[1])) { diff --git a/src/qe/qsat.cpp b/src/qe/qsat.cpp index e50821256c3..73f6a9d4ca1 100644 --- a/src/qe/qsat.cpp +++ b/src/qe/qsat.cpp @@ -503,13 +503,11 @@ namespace qe { } class kernel { - ast_manager& m; smt_params m_smtp; smt::kernel m_kernel; public: kernel(ast_manager& m): - m(m), m_kernel(m, m_smtp) { m_smtp.m_model = true; From 99f5269b788ee1d2235ded2940d209db55e1b8d8 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Mon, 16 May 2016 16:15:44 +0100 Subject: [PATCH 26/61] debug output fix --- src/util/mpf.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/util/mpf.cpp b/src/util/mpf.cpp index 14fb1c535b8..fecee79705c 100644 --- a/src/util/mpf.cpp +++ b/src/util/mpf.cpp @@ -1524,9 +1524,9 @@ std::string mpf_manager::to_string(mpf const & x) { } } - DEBUG_CODE( - res += " " + to_string_raw(x); - ); + //DEBUG_CODE( + // res += " " + to_string_raw(x); + //); return res; } From f1b63691d81e203f9edcb4adb0d0544aef47c3c8 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 16 May 2016 08:35:04 -0700 Subject: [PATCH 27/61] Fixing issue #605 rlimit responsiveness in mam Signed-off-by: Nikolaj Bjorner --- src/ast/datatype_decl_plugin.cpp | 2 +- src/muz/base/dl_context.cpp | 5 ++- src/qe/nlqsat.cpp | 3 +- src/qe/qsat.cpp | 2 -- src/smt/mam.cpp | 53 +++++++++++++++++++------------- 5 files changed, 36 insertions(+), 29 deletions(-) diff --git a/src/ast/datatype_decl_plugin.cpp b/src/ast/datatype_decl_plugin.cpp index d837ebb2243..eb15910bc81 100644 --- a/src/ast/datatype_decl_plugin.cpp +++ b/src/ast/datatype_decl_plugin.cpp @@ -462,7 +462,7 @@ func_decl * datatype_decl_plugin::mk_update_field( } range = domain[0]; func_decl_info info(m_family_id, k, num_parameters, parameters); - return m.mk_func_decl(symbol("update_field"), arity, domain, range, info); + return m.mk_func_decl(symbol("update-field"), arity, domain, range, info); } func_decl * datatype_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters, diff --git a/src/muz/base/dl_context.cpp b/src/muz/base/dl_context.cpp index 74c909c02cf..a90d420cb7b 100644 --- a/src/muz/base/dl_context.cpp +++ b/src/muz/base/dl_context.cpp @@ -188,9 +188,8 @@ namespace datalog { if (m_trail.get_num_scopes() == 0) { throw default_exception("there are no backtracking points to pop to"); } - if(m_engine.get()){ - if(get_engine() != DUALITY_ENGINE) - throw default_exception("operation is not supported by engine"); + if (m_engine.get() && get_engine() != DUALITY_ENGINE) { + throw default_exception("pop operation is only supported by duality engine"); } m_trail.pop_scope(1); } diff --git a/src/qe/nlqsat.cpp b/src/qe/nlqsat.cpp index e05bed9a78a..fbff2e583c9 100644 --- a/src/qe/nlqsat.cpp +++ b/src/qe/nlqsat.cpp @@ -435,12 +435,11 @@ namespace qe { }; class div_rewriter_cfg : public default_rewriter_cfg { - nlqsat& s; ast_manager& m; arith_util a; vector
m_divs; public: - div_rewriter_cfg(nlqsat& s): s(s), m(s.m), a(s.m) {} + div_rewriter_cfg(nlqsat& s): m(s.m), a(s.m) {} ~div_rewriter_cfg() {} br_status reduce_app(func_decl* f, unsigned sz, expr* const* args, expr_ref& result, proof_ref& pr) { if (is_decl_of(f, a.get_family_id(), OP_DIV) && sz == 2 && !a.is_numeral(args[1]) && is_ground(args[0]) && is_ground(args[1])) { diff --git a/src/qe/qsat.cpp b/src/qe/qsat.cpp index 74b1101fe1a..e09f87e5f42 100644 --- a/src/qe/qsat.cpp +++ b/src/qe/qsat.cpp @@ -503,13 +503,11 @@ namespace qe { } class kernel { - ast_manager& m; smt_params m_smtp; smt::kernel m_kernel; public: kernel(ast_manager& m): - m(m), m_kernel(m, m_smtp) { m_smtp.m_model = true; diff --git a/src/smt/mam.cpp b/src/smt/mam.cpp index 764176ea0b0..0d7f6a3a689 100644 --- a/src/smt/mam.cpp +++ b/src/smt/mam.cpp @@ -1856,6 +1856,7 @@ namespace smt { ptr_vector m_used_enodes; unsigned m_curr_used_enodes_size; ptr_vector m_pattern_instances; // collect the pattern instances... used for computing min_top_generation and max_top_generation + unsigned_vector m_min_top_generation, m_max_top_generation; pool m_pool; @@ -2034,28 +2035,26 @@ namespace smt { // init(t) must be invoked before execute_core void execute_core(code_tree * t, enode * n); - // Return the min generation of the enodes in m_pattern_instances. - unsigned get_min_top_generation() const { - SASSERT(!m_pattern_instances.empty()); - unsigned min = m_pattern_instances[0]->get_generation(); - for (unsigned i = 1; i < m_pattern_instances.size(); i++) { - unsigned curr = m_pattern_instances[i]->get_generation(); - if (min > curr) - min = curr; - } - return min; - } + // Return the min, max generation of the enodes in m_pattern_instances. - // Return the max generation of the enodes in m_pattern_instances. - unsigned get_max_top_generation() const { + void get_min_max_top_generation(unsigned& min, unsigned& max) { SASSERT(!m_pattern_instances.empty()); - unsigned max = m_pattern_instances[0]->get_generation(); - for (unsigned i = 1; i < m_pattern_instances.size(); i++) { + if (m_min_top_generation.empty()) { + min = max = m_pattern_instances[0]->get_generation(); + m_min_top_generation.push_back(min); + m_max_top_generation.push_back(max); + } + else { + min = m_min_top_generation.back(); + max = m_max_top_generation.back(); + } + for (unsigned i = m_min_top_generation.size(); i < m_pattern_instances.size(); ++i) { unsigned curr = m_pattern_instances[i]->get_generation(); - if (max < curr) - max = curr; + min = std::min(min, curr); + m_min_top_generation.push_back(min); + max = std::max(max, curr); + m_max_top_generation.push_back(max); } - return max; } }; @@ -2278,6 +2277,8 @@ namespace smt { TRACE("mam_execute_core", tout << "EXEC " << t->get_root_lbl()->get_name() << "\n";); SASSERT(m_context.is_relevant(n)); m_pattern_instances.reset(); + m_min_top_generation.reset(); + m_max_top_generation.reset(); m_pattern_instances.push_back(n); m_max_generation = n->get_generation(); @@ -2289,8 +2290,10 @@ namespace smt { m_pc = t->get_root(); m_registers[0] = n; m_top = 0; + main_loop: + TRACE("mam_int", display_pc_info(tout);); #ifdef _PROFILE_MAM const_cast(m_pc)->m_counter++; @@ -2497,8 +2500,11 @@ namespace smt { case YIELD1: m_bindings[0] = m_registers[static_cast(m_pc)->m_bindings[0]]; -#define ON_MATCH(NUM) \ +#define ON_MATCH(NUM) \ m_max_generation = std::max(m_max_generation, get_max_generation(NUM, m_bindings.begin())); \ + if (m_context.get_cancel_flag()) { \ + return; \ + } \ m_mam.on_match(static_cast(m_pc)->m_qa, \ static_cast(m_pc)->m_pat, \ NUM, \ @@ -2770,9 +2776,12 @@ namespace smt { if (m_app->get_num_args() == c->m_num_args && m_context.is_relevant(m_app)) { // update the pattern instance SASSERT(!m_pattern_instances.empty()); + if (m_pattern_instances.size() == m_max_top_generation.size()) { + m_max_top_generation.pop_back(); + m_min_top_generation.pop_back(); + } m_pattern_instances.pop_back(); m_pattern_instances.push_back(m_app); - // continue succeeded update_max_generation(m_app); TRACE("mam_int", tout << "continue next candidate:\n" << mk_ll_pp(m_app->get_owner(), m_ast_manager);); @@ -3932,7 +3941,9 @@ namespace smt { SASSERT(bindings[i]->get_generation() <= max_generation); } #endif - m_context.add_instance(qa, pat, num_bindings, bindings, max_generation, m_interpreter.get_min_top_generation(), m_interpreter.get_max_top_generation(), used_enodes); + unsigned min_gen, max_gen; + m_interpreter.get_min_max_top_generation(min_gen, max_gen); + m_context.add_instance(qa, pat, num_bindings, bindings, max_generation, min_gen, max_gen, used_enodes); } virtual bool is_shared(enode * n) const { From 6f5785338ae8843d5302d286a8b35af7420ea8b1 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 16 May 2016 08:59:58 -0700 Subject: [PATCH 28/61] add line/pos information for pattern warnings. Issue #607 Signed-off-by: Nikolaj Bjorner --- src/api/api_quant.cpp | 2 +- src/parsers/smt/smtparser.cpp | 4 ++-- src/parsers/smt2/smt2parser.cpp | 2 +- src/parsers/util/pattern_validation.cpp | 25 ++++++++++++++----------- src/parsers/util/pattern_validation.h | 6 +++--- 5 files changed, 21 insertions(+), 18 deletions(-) diff --git a/src/api/api_quant.cpp b/src/api/api_quant.cpp index 73215580e4b..ddcd90cca1f 100644 --- a/src/api/api_quant.cpp +++ b/src/api/api_quant.cpp @@ -72,7 +72,7 @@ extern "C" { expr * const* no_ps = reinterpret_cast(no_patterns); pattern_validator v(mk_c(c)->m()); for (unsigned i = 0; i < num_patterns; i++) { - if (!v(num_decls, ps[i])) { + if (!v(num_decls, ps[i], 0, 0)) { SET_ERROR_CODE(Z3_INVALID_PATTERN); return 0; } diff --git a/src/parsers/smt/smtparser.cpp b/src/parsers/smt/smtparser.cpp index d2619054198..f50e8b33962 100644 --- a/src/parsers/smt/smtparser.cpp +++ b/src/parsers/smt/smtparser.cpp @@ -1574,7 +1574,7 @@ class smtparser : public parser { } } expr * p = m_manager.mk_pattern(ts.size(), (app*const*)(ts.c_ptr())); - if (!p || (!ignore_user_patterns() && !m_pattern_validator(num_bindings, p))) { + if (!p || (!ignore_user_patterns() && !m_pattern_validator(num_bindings, p, children[0]->line(), children[0]->pos()))) { set_error("invalid pattern", children[0]); return false; } @@ -1583,7 +1583,7 @@ class smtparser : public parser { else if (children[0]->string() == symbol("ex_act") && ts.size() == 1) { app * sk_hack = m_manager.mk_app(m_sk_hack, 1, ts.c_ptr()); expr * p = m_manager.mk_pattern(1, &sk_hack); - if (!p || (!ignore_user_patterns() && !m_pattern_validator(num_bindings, p))) { + if (!p || (!ignore_user_patterns() && !m_pattern_validator(num_bindings, p, children[0]->line(), children[0]->pos()))) { set_error("invalid pattern", children[0]); return false; } diff --git a/src/parsers/smt2/smt2parser.cpp b/src/parsers/smt2/smt2parser.cpp index 2e98a4072eb..a995c5917bf 100644 --- a/src/parsers/smt2/smt2parser.cpp +++ b/src/parsers/smt2/smt2parser.cpp @@ -1605,7 +1605,7 @@ namespace smt2 { unsigned j = begin_pats; for (unsigned i = begin_pats; i < end_pats; i++) { expr * pat = pattern_stack().get(i); - if (!pat_validator()(num_decls, pat)) { + if (!pat_validator()(num_decls, pat, m_scanner.get_line(), m_scanner.get_pos())) { if (!ignore_bad_patterns()) throw parser_exception("invalid pattern"); continue; diff --git a/src/parsers/util/pattern_validation.cpp b/src/parsers/util/pattern_validation.cpp index 3d59c221304..0e90e81269b 100644 --- a/src/parsers/util/pattern_validation.cpp +++ b/src/parsers/util/pattern_validation.cpp @@ -31,16 +31,19 @@ struct pattern_validation_functor { bool m_found_a_var; family_id m_bfid; family_id m_lfid; + unsigned m_line, m_pos; pattern_validation_functor(uint_set & found_vars, unsigned num_bindings, unsigned num_new_bindings, - family_id bfid, family_id lfid): + family_id bfid, family_id lfid, unsigned line, unsigned pos): m_found_vars(found_vars), m_num_bindings(num_bindings), m_num_new_bindings(num_new_bindings), m_result(true), m_found_a_var(false), m_bfid(bfid), - m_lfid(lfid) { + m_lfid(lfid), + m_line(line), + m_pos(pos) { } bool is_forbidden(func_decl const * decl) { @@ -55,7 +58,7 @@ struct pattern_validation_functor { void operator()(app * n) { func_decl * decl = to_app(n)->get_decl(); if (is_forbidden(decl)) { - warning_msg("'%s' cannot be used in patterns.", decl->get_name().str().c_str()); + warning_msg("(%d,%d): '%s' cannot be used in patterns.", m_line, m_pos, decl->get_name().str().c_str()); m_result = false; } } @@ -63,7 +66,7 @@ struct pattern_validation_functor { void operator()(var * v) { unsigned idx = to_var(v)->get_idx(); if (idx >= m_num_bindings) { - warning_msg("free variables cannot be used in patterns."); + warning_msg("(%d,%d): free variables cannot be used in patterns.", m_line, m_pos); m_result = false; return; } @@ -76,30 +79,30 @@ struct pattern_validation_functor { void operator()(quantifier * q) { m_result = false; } }; -bool pattern_validator::process(uint_set & found_vars, unsigned num_bindings, unsigned num_new_bindings, expr * n) { +bool pattern_validator::process(uint_set & found_vars, unsigned num_bindings, unsigned num_new_bindings, expr * n, unsigned line, unsigned pos) { // I'm traversing the DAG as a tree, this is not a problem since pattern are supposed to be small ASTs. if (n->get_kind() == AST_VAR) { - warning_msg("invalid pattern: variable."); + warning_msg("(%d,%d): invalid pattern: variable.", line, pos); return false; } - pattern_validation_functor f(found_vars, num_bindings, num_new_bindings, m_bfid, m_lfid); + pattern_validation_functor f(found_vars, num_bindings, num_new_bindings, m_bfid, m_lfid, line, pos); for_each_expr(f, n); if (!f.m_result) return false; if (!f.m_found_a_var) { - warning_msg("pattern does not contain any variable."); + warning_msg("(%d,%d): pattern does not contain any variable.", line, pos); return false; } return true; } -bool pattern_validator::operator()(unsigned num_bindings, unsigned num_new_bindings, expr * n) { +bool pattern_validator::operator()(unsigned num_bindings, unsigned num_new_bindings, expr * n, unsigned line, unsigned pos) { uint_set found_vars; - if (!process(found_vars, num_bindings, num_new_bindings, n)) + if (!process(found_vars, num_bindings, num_new_bindings, n, line, pos)) return false; bool r = found_vars.num_elems() == num_new_bindings; if (!r) - warning_msg("pattern does not contain all quantified variables."); + warning_msg("(%d,%d): pattern does not contain all quantified variables.", line, pos); return r; } diff --git a/src/parsers/util/pattern_validation.h b/src/parsers/util/pattern_validation.h index 6c2ad73b701..939781936d8 100644 --- a/src/parsers/util/pattern_validation.h +++ b/src/parsers/util/pattern_validation.h @@ -27,7 +27,7 @@ class pattern_validator { family_id m_bfid; family_id m_lfid; - bool process(uint_set & found_vars, unsigned num_bindings, unsigned num_new_bindings, expr * n); + bool process(uint_set & found_vars, unsigned num_bindings, unsigned num_new_bindings, expr * n, unsigned line, unsigned pos); public: pattern_validator(ast_manager const & m): @@ -35,8 +35,8 @@ class pattern_validator { m_lfid(m.get_label_family_id()) { } - bool operator()(unsigned num_bindings, unsigned num_new_bindings, expr * n); - bool operator()(unsigned num_new_bindings, expr * n) { return operator()(UINT_MAX, num_new_bindings, n); } + bool operator()(unsigned num_bindings, unsigned num_new_bindings, expr * n, unsigned line, unsigned pos); + bool operator()(unsigned num_new_bindings, expr * n, unsigned line, unsigned pos) { return operator()(UINT_MAX, num_new_bindings, n, line, pos); } }; #endif /* PATTERN_VALIDATION_H_ */ From 5250c3b9edf8b4d6d05478ad86adcbb311cc48e6 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 16 May 2016 09:37:15 -0700 Subject: [PATCH 29/61] ensure reference ownership on frame elements to avoid crashes due to nnf. Issue #588 Signed-off-by: Nikolaj Bjorner --- src/ast/normal_forms/nnf.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/ast/normal_forms/nnf.cpp b/src/ast/normal_forms/nnf.cpp index 6b10e8c10ed..e15e26bf209 100644 --- a/src/ast/normal_forms/nnf.cpp +++ b/src/ast/normal_forms/nnf.cpp @@ -200,14 +200,14 @@ typedef default_exception nnf_exception; struct nnf::imp { struct frame { - expr * m_curr; + expr_ref m_curr; unsigned m_i:28; unsigned m_pol:1; // pos/neg polarity unsigned m_in_q:1; // true if m_curr is nested in a quantifier unsigned m_new_child:1; unsigned m_cache_result:1; unsigned m_spos; // top of the result stack, when the frame was created. - frame(expr * n, bool pol, bool in_q, bool cache_res, unsigned spos): + frame(expr_ref& n, bool pol, bool in_q, bool cache_res, unsigned spos): m_curr(n), m_i(0), m_pol(pol), @@ -225,7 +225,7 @@ struct nnf::imp { #define POS_Q_CIDX 3 // positive polarity and nested in a quantifier ast_manager & m_manager; - svector m_frame_stack; + vector m_frame_stack; expr_ref_vector m_result_stack; typedef act_cache cache; @@ -324,7 +324,8 @@ struct nnf::imp { } void push_frame(expr * t, bool pol, bool in_q, bool cache_res) { - m_frame_stack.push_back(frame(t, pol, in_q, cache_res, m_result_stack.size())); + expr_ref tr(t, m()); + m_frame_stack.push_back(frame(tr, pol, in_q, cache_res, m_result_stack.size())); } static unsigned get_cache_idx(bool pol, bool in_q) { From ec565ae7a0710837b53dd5fcf3841f727fbf7bb1 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 17 May 2016 01:00:42 -0700 Subject: [PATCH 30/61] fixes to #596 and #592: use exponential step increments on integer problems, align int.to.str with canonizer and disequality checker Signed-off-by: Nikolaj Bjorner --- src/opt/optsmt.cpp | 241 ++++++++++++++++++++++++++++++------ src/opt/optsmt.h | 9 ++ src/smt/theory_arith_aux.h | 2 +- src/smt/theory_seq.cpp | 77 ++++++++++-- src/smt/theory_seq.h | 1 + src/solver/solver_na2as.cpp | 14 ++- 6 files changed, 289 insertions(+), 55 deletions(-) diff --git a/src/opt/optsmt.cpp b/src/opt/optsmt.cpp index e92ab4f97ba..d2363b36e72 100644 --- a/src/opt/optsmt.cpp +++ b/src/opt/optsmt.cpp @@ -34,6 +34,7 @@ Module Name: #include "arith_decl_plugin.h" #include "theory_arith.h" #include "ast_pp.h" +#include "ast_util.h" #include "model_pp.h" #include "th_rewriter.h" #include "opt_params.hpp" @@ -93,6 +94,158 @@ namespace opt { return l_true; } + /* + Enumerate locally optimal assignments until fixedpoint. + */ + lbool optsmt::geometric_opt() { + lbool is_sat = l_true; + + expr_ref bound(m); + + vector lower(m_lower); + unsigned steps = 0; + unsigned step_incs = 0; + rational delta_per_step(1); + unsigned num_scopes = 0; + unsigned delta_index = 0; // index of objective to speed up. + + while (!m.canceled()) { + SASSERT(delta_per_step.is_int()); + SASSERT(delta_per_step.is_pos()); + is_sat = m_s->check_sat(0, 0); + if (is_sat == l_true) { + bound = update_lower(); + if (!get_max_delta(lower, delta_index)) { + delta_per_step = rational::one(); + } + else if (steps > step_incs) { + delta_per_step *= rational(2); + ++step_incs; + steps = 0; + } + else { + ++steps; + } + if (delta_per_step > rational::one()) { + m_s->push(); + ++num_scopes; + // only try to improve delta_index. + bound = m_s->mk_ge(delta_index, m_lower[delta_index] + inf_eps(delta_per_step)); + } + TRACE("opt", tout << delta_per_step << " " << bound << "\n";); + m_s->assert_expr(bound); + } + else if (is_sat == l_false && delta_per_step > rational::one()) { + steps = 0; + step_incs = 0; + delta_per_step = rational::one(); + SASSERT(num_scopes > 0); + --num_scopes; + m_s->pop(1); + } + else { + break; + } + } + m_s->pop(num_scopes); + + if (m.canceled() || is_sat == l_undef) { + return l_undef; + } + + // set the solution tight. + for (unsigned i = 0; i < m_lower.size(); ++i) { + m_upper[i] = m_lower[i]; + } + + return l_true; + } + + + lbool optsmt::geometric_lex(unsigned obj_index, bool is_maximize) { + arith_util arith(m); + bool is_int = arith.is_int(m_objs[obj_index].get()); + lbool is_sat = l_true; + expr_ref bound(m); + + for (unsigned i = 0; i < obj_index; ++i) { + commit_assignment(i); + } + + unsigned steps = 0; + unsigned step_incs = 0; + rational delta_per_step(1); + unsigned num_scopes = 0; + + while (!m.canceled()) { + SASSERT(delta_per_step.is_int()); + SASSERT(delta_per_step.is_pos()); + is_sat = m_s->check_sat(0, 0); + if (is_sat == l_true) { + m_s->maximize_objective(obj_index, bound); + m_s->get_model(m_model); + m_s->get_labels(m_labels); + inf_eps obj = m_s->saved_objective_value(obj_index); + update_lower_lex(obj_index, obj, is_maximize); + if (!is_int || !m_lower[obj_index].is_finite()) { + delta_per_step = rational(1); + } + else if (steps > step_incs) { + delta_per_step *= rational(2); + ++step_incs; + steps = 0; + } + else { + ++steps; + } + if (delta_per_step > rational::one()) { + m_s->push(); + ++num_scopes; + bound = m_s->mk_ge(obj_index, obj + inf_eps(delta_per_step)); + } + TRACE("opt", tout << delta_per_step << " " << bound << "\n";); + m_s->assert_expr(bound); + } + else if (is_sat == l_false && delta_per_step > rational::one()) { + steps = 0; + step_incs = 0; + delta_per_step = rational::one(); + SASSERT(num_scopes > 0); + --num_scopes; + m_s->pop(1); + } + else { + break; + } + } + m_s->pop(num_scopes); + + if (m.canceled() || is_sat == l_undef) { + return l_undef; + } + + // set the solution tight. + m_upper[obj_index] = m_lower[obj_index]; + for (unsigned i = obj_index+1; i < m_lower.size(); ++i) { + m_lower[i] = inf_eps(rational(-1), inf_rational(0)); + } + return l_true; + } + + bool optsmt::get_max_delta(vector const& lower, unsigned& idx) { + arith_util arith(m); + inf_eps max_delta; + for (unsigned i = 0; i < m_lower.size(); ++i) { + if (arith.is_int(m_objs[i].get())) { + inf_eps delta = m_lower[i] - lower[i]; + if (m_lower[i].is_finite() && delta > max_delta) { + max_delta = delta; + } + } + } + return max_delta.is_pos(); + } + /* Enumerate locally optimal assignments until fixedpoint. */ @@ -122,6 +275,7 @@ namespace opt { } lbool optsmt::symba_opt() { + smt::theory_opt& opt = m_s->get_optimizer(); if (typeid(smt::theory_inf_arith) != typeid(opt)) { @@ -138,7 +292,7 @@ namespace opt { } - fml = m.mk_or(ors.size(), ors.c_ptr()); + fml = mk_or(ors); tmp = m.mk_fresh_const("b", m.mk_bool_sort()); fml = m.mk_implies(tmp, fml); vars[0] = tmp; @@ -163,7 +317,7 @@ namespace opt { } } set_max(m_lower, m_s->get_objective_values(), disj); - fml = m.mk_or(ors.size(), ors.c_ptr()); + fml = mk_or(ors); tmp = m.mk_fresh_const("b", m.mk_bool_sort()); fml = m.mk_implies(tmp, fml); vars[0] = tmp; @@ -176,13 +330,30 @@ namespace opt { } } } - bound = m.mk_or(m_lower_fmls.size(), m_lower_fmls.c_ptr()); + bound = mk_or(m_lower_fmls); m_s->assert_expr(bound); if (m.canceled()) { return l_undef; } - return basic_opt(); + return geometric_opt(); + } + + void optsmt::update_lower_lex(unsigned idx, inf_eps const& v, bool is_maximize) { + if (v > m_lower[idx]) { + m_lower[idx] = v; + IF_VERBOSE(1, + if (is_maximize) + verbose_stream() << "(optsmt lower bound: " << v << ")\n"; + else + verbose_stream() << "(optsmt upper bound: " << (-v) << ")\n"; + ); + expr_ref tmp(m); + for (unsigned i = idx+1; i < m_vars.size(); ++i) { + m_s->maximize_objective(i, tmp); + m_lower[i] = m_s->saved_objective_value(i); + } + } } void optsmt::update_lower(unsigned idx, inf_eps const& v) { @@ -196,28 +367,22 @@ namespace opt { m_upper[idx] = v; } + std::ostream& operator<<(std::ostream& out, vector const& vs) { + for (unsigned i = 0; i < vs.size(); ++i) { + out << vs[i] << " "; + } + return out; + } + expr_ref optsmt::update_lower() { expr_ref_vector disj(m); m_s->get_model(m_model); m_s->get_labels(m_labels); m_s->maximize_objectives(disj); set_max(m_lower, m_s->get_objective_values(), disj); - TRACE("opt", - for (unsigned i = 0; i < m_lower.size(); ++i) { - tout << m_lower[i] << " "; - } - tout << "\n"; - model_pp(tout, *m_model); - ); - IF_VERBOSE(2, verbose_stream() << "(optsmt.lower "; - for (unsigned i = 0; i < m_lower.size(); ++i) { - verbose_stream() << m_lower[i] << " "; - } - verbose_stream() << ")\n";); - IF_VERBOSE(3, verbose_stream() << disj << "\n";); - IF_VERBOSE(3, model_pp(verbose_stream(), *m_model);); - - return expr_ref(m.mk_or(disj.size(), disj.c_ptr()), m); + TRACE("opt", model_pp(tout << m_lower << "\n", *m_model);); + IF_VERBOSE(2, verbose_stream() << "(optsmt.lower " << m_lower << ")\n";); + return mk_or(disj); } lbool optsmt::update_upper() { @@ -312,12 +477,21 @@ namespace opt { TRACE("opt", tout << "optsmt:lex\n";); solver::scoped_push _push(*m_s); SASSERT(obj_index < m_vars.size()); - return basic_lex(obj_index, is_maximize); + if (is_maximize && m_optsmt_engine == symbol("farkas")) { + return farkas_opt(); + } + else if (is_maximize && m_optsmt_engine == symbol("symba")) { + return symba_opt(); + } + else { + return geometric_lex(obj_index, is_maximize); + } } + // deprecated lbool optsmt::basic_lex(unsigned obj_index, bool is_maximize) { lbool is_sat = l_true; - expr_ref block(m), tmp(m); + expr_ref bound(m); for (unsigned i = 0; i < obj_index; ++i) { commit_assignment(i); @@ -326,25 +500,13 @@ namespace opt { is_sat = m_s->check_sat(0, 0); if (is_sat != l_true) break; - m_s->maximize_objective(obj_index, block); + m_s->maximize_objective(obj_index, bound); m_s->get_model(m_model); m_s->get_labels(m_labels); inf_eps obj = m_s->saved_objective_value(obj_index); - if (obj > m_lower[obj_index]) { - m_lower[obj_index] = obj; - IF_VERBOSE(1, - if (is_maximize) - verbose_stream() << "(optsmt lower bound: " << obj << ")\n"; - else - verbose_stream() << "(optsmt upper bound: " << (-obj) << ")\n"; - ); - for (unsigned i = obj_index+1; i < m_vars.size(); ++i) { - m_s->maximize_objective(i, tmp); - m_lower[i] = m_s->saved_objective_value(i); - } - } - TRACE("opt", tout << "strengthen bound: " << block << "\n";); - m_s->assert_expr(block); + update_lower_lex(obj_index, obj, is_maximize); + TRACE("opt", tout << "strengthen bound: " << bound << "\n";); + m_s->assert_expr(bound); // TBD: only works for simplex // blocking formula should be extracted based @@ -365,6 +527,7 @@ namespace opt { } + /** Takes solver with hard constraints added. Returns an optimal assignment to objective functions. @@ -383,7 +546,7 @@ namespace opt { is_sat = symba_opt(); } else { - is_sat = basic_opt(); + is_sat = geometric_opt(); } return is_sat; } diff --git a/src/opt/optsmt.h b/src/opt/optsmt.h index e01c586817e..f90bd1c8189 100644 --- a/src/opt/optsmt.h +++ b/src/opt/optsmt.h @@ -69,19 +69,28 @@ namespace opt { void reset(); private: + + bool get_max_delta(vector const& lower, unsigned& idx); lbool basic_opt(); + lbool geometric_opt(); + lbool symba_opt(); lbool basic_lex(unsigned idx, bool is_maximize); + lbool geometric_lex(unsigned idx, bool is_maximize); + lbool farkas_opt(); void set_max(vector& dst, vector const& src, expr_ref_vector& fmls); expr_ref update_lower(); + void update_lower_lex(unsigned idx, inf_eps const& r, bool is_maximize); + + lbool update_upper(); diff --git a/src/smt/theory_arith_aux.h b/src/smt/theory_arith_aux.h index 72004f8b020..b4f88724569 100644 --- a/src/smt/theory_arith_aux.h +++ b/src/smt/theory_arith_aux.h @@ -813,7 +813,7 @@ namespace smt { continue; if (proofs_enabled()) { new_bound.push_lit(l, ante.lit_coeffs()[i]); - } + } else { new_bound.push_lit(l, numeral::zero()); lits.insert(l.index()); diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index 239ba742021..72d8929b865 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -1820,16 +1820,23 @@ bool theory_seq::solve_ne(unsigned idx) { TRACE("seq", display_disequation(tout << "reduces to false: ", n);); return true; } - else if (!change) { - TRACE("seq", tout << "no change " << n.ls(i) << " " << n.rs(i) << "\n";); - if (updated) { - new_ls.push_back(n.ls(i)); - new_rs.push_back(n.rs(i)); - } - continue; - } else { + // eliminate ite expressions. + reduce_ite(lhs, new_lits, num_undef_lits, change); + reduce_ite(rhs, new_lits, num_undef_lits, change); + reduce_ite(ls, new_lits, num_undef_lits, change); + reduce_ite(rs, new_lits, num_undef_lits, change); + + if (!change) { + TRACE("seq", tout << "no change " << n.ls(i) << " " << n.rs(i) << "\n";); + if (updated) { + new_ls.push_back(n.ls(i)); + new_rs.push_back(n.rs(i)); + } + continue; + } + if (!updated) { for (unsigned j = 0; j < i; ++j) { new_ls.push_back(n.ls(j)); @@ -1933,6 +1940,33 @@ bool theory_seq::solve_ne(unsigned idx) { return updated; } +void theory_seq::reduce_ite(expr_ref_vector & ls, literal_vector& new_lits, unsigned& num_undef_lits, bool& change) { + expr* cond, *th, *el; + context& ctx = get_context(); + for (unsigned i = 0; i < ls.size(); ++i) { + expr* e = ls[i].get(); + if (m.is_ite(e, cond, th, el)) { + literal lit(mk_literal(cond)); + switch (ctx.get_assignment(lit)) { + case l_true: + change = true; + new_lits.push_back(lit); + ls[i] = th; + break; + case l_false: + change = true; + new_lits.push_back(~lit); + ls[i] = el; + break; + case l_undef: + ++num_undef_lits; + break; + } + } + } +} + + bool theory_seq::solve_nc(unsigned idx) { nc const& n = m_ncs[idx]; @@ -2212,7 +2246,6 @@ bool theory_seq::add_itos_axiom(expr* e) { if (get_value(n, val)) { if (!m_itos_axioms.contains(val)) { m_itos_axioms.insert(val); - app_ref e1(m_util.str.mk_string(symbol(val.to_string().c_str())), m); expr_ref n1(arith_util(m).mk_numeral(val, true), m); add_axiom(mk_eq(m_util.str.mk_itos(n1), e1, false)); @@ -2604,6 +2637,32 @@ expr_ref theory_seq::expand(expr* e0, dependency*& eqs) { else if (m_util.str.is_index(e, e1, e2, e3)) { result = m_util.str.mk_index(expand(e1, deps), expand(e2, deps), e3); } + else if (m_util.str.is_itos(e, e1)) { + rational val; + if (get_value(e1, val)) { + expr_ref num(m), res(m); + context& ctx = get_context(); + num = m_autil.mk_numeral(val, true); + if (!ctx.e_internalized(num)) { + ctx.internalize(num, false); + } + enode* n1 = ctx.get_enode(num); + enode* n2 = ctx.get_enode(e1); + res = m_util.str.mk_string(symbol(val.to_string().c_str())); + if (n1->get_root() == n2->get_root()) { + result = res; + deps = m_dm.mk_join(deps, m_dm.mk_leaf(assumption(n1, n2))); + } + else { + add_axiom(~mk_eq(num, e1, false), mk_eq(e, res, false)); + add_axiom(mk_eq(num, e1, false), ~mk_eq(e, res, false)); + result = e; + } + } + else { + result = e; + } + } else { result = e; } diff --git a/src/smt/theory_seq.h b/src/smt/theory_seq.h index 4107f3d059c..8c4de211160 100644 --- a/src/smt/theory_seq.h +++ b/src/smt/theory_seq.h @@ -410,6 +410,7 @@ namespace smt { bool solve_nqs(unsigned i); bool solve_ne(unsigned i); bool solve_nc(unsigned i); + void reduce_ite(expr_ref_vector& ls, literal_vector& new_lits, unsigned& num_undef_lits, bool& change); struct cell { cell* m_parent; diff --git a/src/solver/solver_na2as.cpp b/src/solver/solver_na2as.cpp index 704038ffd02..2ca6e187c10 100644 --- a/src/solver/solver_na2as.cpp +++ b/src/solver/solver_na2as.cpp @@ -71,12 +71,14 @@ void solver_na2as::push() { } void solver_na2as::pop(unsigned n) { - pop_core(n); - unsigned lvl = m_scopes.size(); - SASSERT(n <= lvl); - unsigned new_lvl = lvl - n; - restore_assumptions(m_scopes[new_lvl]); - m_scopes.shrink(new_lvl); + if (n > 0) { + pop_core(n); + unsigned lvl = m_scopes.size(); + SASSERT(n <= lvl); + unsigned new_lvl = lvl - n; + restore_assumptions(m_scopes[new_lvl]); + m_scopes.shrink(new_lvl); + } } void solver_na2as::restore_assumptions(unsigned old_sz) { From df81ab72f53a92ce07ab1d628d4d80a292680d00 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Tue, 17 May 2016 16:35:45 +0100 Subject: [PATCH 31/61] Bug and performance fixes for FP UFs. --- src/ast/rewriter/fpa_rewriter.cpp | 48 ++++++++++++-- src/ast/rewriter/fpa_rewriter.h | 3 + src/smt/theory_fpa.cpp | 39 ++++++++++- src/smt/theory_fpa.h | 1 + src/tactic/fpa/fpa2bv_model_converter.cpp | 79 ++++++++++++----------- 5 files changed, 125 insertions(+), 45 deletions(-) diff --git a/src/ast/rewriter/fpa_rewriter.cpp b/src/ast/rewriter/fpa_rewriter.cpp index 619d5ffbf19..6c199fcd8b9 100644 --- a/src/ast/rewriter/fpa_rewriter.cpp +++ b/src/ast/rewriter/fpa_rewriter.cpp @@ -100,18 +100,17 @@ br_status fpa_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * con SASSERT(num_args == 2); st = BR_FAILED; break; case OP_FPA_INTERNAL_RM: - SASSERT(num_args == 1); st = mk_rm(args[0], result); break; + SASSERT(num_args == 1); SASSERT(num_args == 1); st = mk_rm(args[0], result); break; case OP_FPA_INTERNAL_TO_UBV_UNSPECIFIED: case OP_FPA_INTERNAL_TO_SBV_UNSPECIFIED: case OP_FPA_INTERNAL_TO_REAL_UNSPECIFIED: case OP_FPA_INTERNAL_TO_IEEE_BV_UNSPECIFIED: st = BR_FAILED; - - case OP_FPA_INTERNAL_BVWRAP: - case OP_FPA_INTERNAL_BVUNWRAP: - st = BR_FAILED; break; + case OP_FPA_INTERNAL_BVWRAP: SASSERT(num_args == 1); st = mk_bvwrap(args[0], result); break; + case OP_FPA_INTERNAL_BVUNWRAP: SASSERT(num_args == 1); st = mk_bvunwrap(args[0], result); break; + default: NOT_IMPLEMENTED_YET(); } @@ -892,3 +891,42 @@ br_status fpa_rewriter::mk_to_real(expr * arg, expr_ref & result) { return BR_FAILED; } + + +br_status fpa_rewriter::mk_bvwrap(expr * arg, expr_ref & result) { + if (is_app_of(arg, m_util.get_family_id(), OP_FPA_FP)) { + bv_util bu(m()); + SASSERT(to_app(arg)->get_num_args() == 3); + sort_ref fpsrt(m()); + fpsrt = to_app(arg)->get_decl()->get_range(); + expr_ref a0(m()), a1(m()), a2(m()); + a0 = to_app(arg)->get_arg(0); + a1 = to_app(arg)->get_arg(1); + a2 = to_app(arg)->get_arg(2); + if (bu.is_extract(a0) && bu.is_extract(a1) && bu.is_extract(a2)) { + unsigned w0 = bu.get_extract_high(a0) - bu.get_extract_low(a0) + 1; + unsigned w1 = bu.get_extract_high(a1) - bu.get_extract_low(a1) + 1; + unsigned w2 = bu.get_extract_high(a2) - bu.get_extract_low(a2) + 1; + unsigned cw = w0 + w1 + w2; + if (cw == m_util.get_ebits(fpsrt) + m_util.get_sbits(fpsrt)) { + expr_ref aa0(m()), aa1(m()), aa2(m()); + aa0 = to_app(a0)->get_arg(0); + aa1 = to_app(a1)->get_arg(0); + aa2 = to_app(a2)->get_arg(0); + if (aa0 == aa1 && aa1 == aa2 && bu.get_bv_size(aa0) == cw) { + result = aa0; + return BR_DONE; + } + } + } + } + + return BR_FAILED; +} + +br_status fpa_rewriter::mk_bvunwrap(expr * arg, expr_ref & result) { + if (is_app_of(arg, m_util.get_family_id(), OP_FPA_INTERNAL_BVWRAP)) + result = to_app(arg)->get_arg(0); + + return BR_FAILED; +} diff --git a/src/ast/rewriter/fpa_rewriter.h b/src/ast/rewriter/fpa_rewriter.h index 3afc31a9f28..f42d7c7191c 100644 --- a/src/ast/rewriter/fpa_rewriter.h +++ b/src/ast/rewriter/fpa_rewriter.h @@ -89,6 +89,9 @@ class fpa_rewriter { br_status mk_to_ubv_unspecified(unsigned ebits, unsigned sbits, unsigned with, expr_ref & result); br_status mk_to_sbv_unspecified(unsigned ebits, unsigned sbits, unsigned with, expr_ref & result); br_status mk_to_real_unspecified(unsigned ebits, unsigned sbits, expr_ref & result); + + br_status mk_bvwrap(expr * arg, expr_ref & result); + br_status mk_bvunwrap(expr * arg, expr_ref & result); }; #endif diff --git a/src/smt/theory_fpa.cpp b/src/smt/theory_fpa.cpp index 543b1348e56..4911af5ecac 100644 --- a/src/smt/theory_fpa.cpp +++ b/src/smt/theory_fpa.cpp @@ -84,6 +84,28 @@ namespace smt { } } + void theory_fpa::fpa2bv_converter_wrapped::mk_uninterpreted_output(sort * rng, func_decl * fbv, expr_ref_buffer & new_args, expr_ref & result) { + if (m_util.is_float(rng)) { + unsigned ebits = m_util.get_ebits(rng); + unsigned sbits = m_util.get_sbits(rng); + unsigned bv_sz = ebits + sbits; + + app_ref na(m); + na = m.mk_app(fbv, new_args.size(), new_args.c_ptr()); + mk_fp(m_bv_util.mk_extract(bv_sz - 1, bv_sz - 1, na), + m_bv_util.mk_extract(bv_sz - 2, sbits - 1, na), + m_bv_util.mk_extract(sbits - 2, 0, na), + result); + } + else if (m_util.is_rm(rng)) { + app_ref na(m); + na = m.mk_app(fbv, new_args.size(), new_args.c_ptr()); + mk_rm(na, result); + } + else + result = m.mk_app(fbv, new_args.size(), new_args.c_ptr()); + } + void theory_fpa::fpa2bv_converter_wrapped::mk_uninterpreted_function(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { // TODO: This introduces temporary func_decls that should be filtered in the end. @@ -93,11 +115,13 @@ namespace smt { expr_ref_buffer new_args(m); for (unsigned i = 0; i < num; i++) { + TRACE("t_fpa", tout << "UF arg[" << i << "]: " << mk_ismt2_pp(args[i], m) << std::endl; ); if (is_float(args[i]) || is_rm(args[i])) { expr_ref ai(m), wrapped(m); - ai = args[i]; + ai = args[i]; wrapped = m_th.wrap(ai); new_args.push_back(wrapped); + TRACE("t_fpa", tout << "UF wrap ai: " << mk_ismt2_pp(ai, m) << " --> " << mk_ismt2_pp(wrapped, m) << std::endl; ); m_extra_assertions.push_back(m.mk_eq(m_th.unwrap(wrapped, m.get_sort(ai)), ai)); } else @@ -105,8 +129,10 @@ namespace smt { } func_decl * fd; - if (m_uf2bvuf.find(f, fd)) + if (m_uf2bvuf.find(f, fd)) { + TRACE("t_fpa", tout << "UF reused: " << mk_ismt2_pp(fd, m) << std::endl; ); mk_uninterpreted_output(f->get_range(), fd, new_args, result); + } else { sort_ref_buffer new_domain(m); @@ -372,6 +398,10 @@ namespace smt { res = m.mk_app(w, e); } + + TRACE("t_fpa", tout << "e: " << mk_ismt2_pp(e, m) << "\n"; + tout << "r: " << mk_ismt2_pp(res, m) << "\n";); + return res; } @@ -415,6 +445,9 @@ namespace smt { proof_ref pr(m); m_rw(e, e_conv); + TRACE("t_fpa_detail", tout << "term: " << mk_ismt2_pp(e, get_manager()) << "\n"; + tout << "converted term: " << mk_ismt2_pp(e_conv, get_manager()) << "\n";); + if (is_app(e_conv) && to_app(e_conv)->get_family_id() != get_family_id()) { if (!m_fpa_util.is_float(e_conv)) m_th_rw(e_conv, res); @@ -844,7 +877,7 @@ namespace smt { void theory_fpa::init_model(model_generator & mg) { TRACE("t_fpa", tout << "initializing model" << std::endl; display(tout);); m_factory = alloc(fpa_value_factory, get_manager(), get_family_id()); - mg.register_factory(m_factory); + mg.register_factory(m_factory); } model_value_proc * theory_fpa::mk_value(enode * n, model_generator & mg) { diff --git a/src/smt/theory_fpa.h b/src/smt/theory_fpa.h index d693e3ede20..38001b5a639 100644 --- a/src/smt/theory_fpa.h +++ b/src/smt/theory_fpa.h @@ -83,6 +83,7 @@ namespace smt { virtual ~fpa2bv_converter_wrapped() {} virtual void mk_const(func_decl * f, expr_ref & result); virtual void mk_rm_const(func_decl * f, expr_ref & result); + void mk_uninterpreted_output(sort * rng, func_decl * fbv, expr_ref_buffer & new_args, expr_ref & result); virtual void mk_uninterpreted_function(func_decl * f, unsigned num, expr * const * args, expr_ref & result); virtual expr_ref mk_min_unspecified(func_decl * f, expr * x, expr * y); diff --git a/src/tactic/fpa/fpa2bv_model_converter.cpp b/src/tactic/fpa/fpa2bv_model_converter.cpp index 627e33a7bb0..fe9fc2a0f28 100644 --- a/src/tactic/fpa/fpa2bv_model_converter.cpp +++ b/src/tactic/fpa/fpa2bv_model_converter.cpp @@ -322,50 +322,55 @@ void fpa2bv_model_converter::convert(model * bv_mdl, model * float_mdl) { sort * rng = f->get_range(); if (arity > 0) { - func_interp * flt_fi = alloc(func_interp, m, f->get_arity()); - - func_interp * bv_fi = bv_mdl->get_func_interp(it->m_value); - SASSERT(bv_fi->args_are_values()); - - 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 * dj = f->get_domain(j); - expr * aj = bv_args[j]; - if (fu.is_float(dj)) - new_args.push_back(convert_bv2fp(bv_mdl, dj, aj)); - else if (fu.is_rm(dj)) { - expr_ref fv(m); - fv = convert_bv2rm(aj); - new_args.push_back(fv); + func_interp * bv_fi = bv_mdl->get_func_interp(it->m_value); + + if (bv_fi != 0) { + func_interp * flt_fi = alloc(func_interp, m, f->get_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 * dj = f->get_domain(j); + expr * aj = bv_args[j]; + expr_ref saj(m); + bv_mdl->eval(aj, saj, true); + + if (fu.is_float(dj)) + new_args.push_back(convert_bv2fp(bv_mdl, dj, saj)); + else if (fu.is_rm(dj)) { + expr_ref fv(m); + fv = convert_bv2rm(saj); + new_args.push_back(fv); + } + else + new_args.push_back(saj); } - else - new_args.push_back(aj); + + expr_ref ret(m); + ret = bv_fe->get_result(); + bv_mdl->eval(ret, ret); + if (fu.is_float(rng)) + ret = convert_bv2fp(bv_mdl, rng, ret); + else if (fu.is_rm(rng)) + ret = convert_bv2rm(ret); + + flt_fi->insert_new_entry(new_args.c_ptr(), ret); } - expr_ref ret(m); - ret = bv_fe->get_result(); + expr_ref els(m); + els = bv_fi->get_else(); if (fu.is_float(rng)) - ret = convert_bv2fp(bv_mdl, rng, ret); + els = convert_bv2fp(bv_mdl, rng, els); else if (fu.is_rm(rng)) - ret = convert_bv2rm(ret); - - flt_fi->insert_new_entry(new_args.c_ptr(), ret); - } - - expr_ref els(m); - els = bv_fi->get_else(); - if (fu.is_float(rng)) - els = convert_bv2fp(bv_mdl, rng, els); - else if (fu.is_rm(rng)) - els = convert_bv2rm(els); + els = convert_bv2rm(els); - flt_fi->set_else(els); + flt_fi->set_else(els); - float_mdl->register_decl(f, flt_fi); + float_mdl->register_decl(f, flt_fi); + } } else { func_decl * bvf = it->m_value; From 96e157e201308d7beba556f62b145edc9263d0a7 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 17 May 2016 13:54:22 -0700 Subject: [PATCH 32/61] fix warnings for unused variables Signed-off-by: Nikolaj Bjorner --- src/ackermannization/lackr.cpp | 5 +- src/ast/ast.cpp | 1 + src/ast/rewriter/bv_trailing.cpp | 10 +- src/ast/simplifier/simplifier.cpp | 1 + src/duality/duality_rpfp.cpp | 3 +- src/math/euclid/euclidean_solver.cpp | 4 +- src/math/polynomial/upolynomial.cpp | 7 +- .../polynomial/upolynomial_factorization.cpp | 6 +- src/math/simplex/simplex_def.h | 1 + src/math/simplex/sparse_matrix_def.h | 13 +-- src/muz/pdr/pdr_farkas_learner.cpp | 1 + src/muz/rel/dl_external_relation.cpp | 3 +- src/muz/rel/dl_finite_product_relation.cpp | 9 +- src/muz/rel/udoc_relation.cpp | 3 +- src/muz/transforms/dl_mk_bit_blast.cpp | 3 +- .../dl_mk_quantifier_abstraction.cpp | 3 +- src/nlsat/nlsat_explain.cpp | 3 +- src/nlsat/nlsat_interval_set.cpp | 16 ++-- src/nlsat/nlsat_solver.cpp | 35 +++---- src/opt/hitting_sets.cpp | 3 +- src/parsers/smt2/smt2parser.cpp | 3 + src/qe/qe.cpp | 3 +- src/qe/qe_arith_plugin.cpp | 21 ++-- src/qe/qe_sat_tactic.cpp | 3 +- src/sat/sat_integrity_checker.cpp | 8 +- src/sat/sat_sls.cpp | 95 ++++++++++--------- src/sat/sat_solver.cpp | 8 +- src/smt/smt_conflict_resolution.cpp | 5 +- src/smt/smt_context.cpp | 10 +- src/smt/theory_arith_aux.h | 2 +- src/smt/theory_array.cpp | 3 +- src/smt/theory_bv.cpp | 9 +- src/smt/theory_datatype.cpp | 3 +- src/smt/theory_diff_logic_def.h | 33 ++++--- src/smt/theory_fpa.cpp | 19 ++-- src/smt/theory_wmaxsat.cpp | 2 +- src/util/mpf.cpp | 4 +- src/util/mpff.cpp | 1 + 38 files changed, 179 insertions(+), 183 deletions(-) diff --git a/src/ackermannization/lackr.cpp b/src/ackermannization/lackr.cpp index b1a58c01bf9..461d2080fda 100644 --- a/src/ackermannization/lackr.cpp +++ b/src/ackermannization/lackr.cpp @@ -134,7 +134,6 @@ void lackr::eager_enc() { const fun2terms_map::iterator e = m_fun2terms.end(); for (fun2terms_map::iterator i = m_fun2terms.begin(); i != e; ++i) { checkpoint(); - func_decl* const fd = i->m_key; app_set * const ts = i->get_value(); const app_set::iterator r = ts->end(); for (app_set::iterator j = ts->begin(); j != r; ++j) { @@ -143,8 +142,8 @@ void lackr::eager_enc() { for (; k != r; ++k) { app * const t1 = *j; app * const t2 = *k; - SASSERT(t1->get_decl() == fd); - SASSERT(t2->get_decl() == fd); + SASSERT(t1->get_decl() == i->m_key); + SASSERT(t2->get_decl() == i->m_key); if (t1 == t2) continue; ackr(t1,t2); } diff --git a/src/ast/ast.cpp b/src/ast/ast.cpp index 0365a267ea2..fcf9365e33f 100644 --- a/src/ast/ast.cpp +++ b/src/ast/ast.cpp @@ -1495,6 +1495,7 @@ void ast_manager::copy_families_plugins(ast_manager const & from) { if (m_family_manager.has_family(fid)) tout << get_family_id(fid_name) << "\n";); if (!m_family_manager.has_family(fid)) { family_id new_fid = mk_family_id(fid_name); + (void)new_fid; TRACE("copy_families_plugins", tout << "new target fid created: " << new_fid << " fid_name: " << fid_name << "\n";); } TRACE("copy_families_plugins", tout << "target fid: " << get_family_id(fid_name) << "\n";); diff --git a/src/ast/rewriter/bv_trailing.cpp b/src/ast/rewriter/bv_trailing.cpp index 414854f3a76..cf50ab0e247 100644 --- a/src/ast/rewriter/bv_trailing.cpp +++ b/src/ast/rewriter/bv_trailing.cpp @@ -67,9 +67,10 @@ struct bv_trailing::imp { } expr_ref out1(m); expr_ref out2(m); - const unsigned rm1 = remove_trailing(e1, min, out1, TRAILING_DEPTH); - const unsigned rm2 = remove_trailing(e2, min, out2, TRAILING_DEPTH); - SASSERT(rm1 == min && rm2 == min); + DEBUG_CODE( + const unsigned rm1 = remove_trailing(e1, min, out1, TRAILING_DEPTH); + const unsigned rm2 = remove_trailing(e2, min, out2, TRAILING_DEPTH); + SASSERT(rm1 == min && rm2 == min);); const bool are_eq = m.are_equal(out1, out2); result = are_eq ? m.mk_true() : m.mk_eq(out1, out2); return are_eq ? BR_DONE : BR_REWRITE2; @@ -122,9 +123,8 @@ struct bv_trailing::imp { expr_ref tmp(m); for (unsigned i = 0; i < num; ++i) { expr * const curr = a->get_arg(i); - const unsigned crm = remove_trailing(curr, to_rm, tmp, depth - 1); + VERIFY(to_rm == remove_trailing(curr, to_rm, tmp, depth - 1)); new_args.push_back(tmp); - SASSERT(crm == to_rm); } result = m.mk_app(m_util.get_fid(), OP_BADD, new_args.size(), new_args.c_ptr()); return to_rm; diff --git a/src/ast/simplifier/simplifier.cpp b/src/ast/simplifier/simplifier.cpp index 895aa529bd6..63731c6794b 100644 --- a/src/ast/simplifier/simplifier.cpp +++ b/src/ast/simplifier/simplifier.cpp @@ -63,6 +63,7 @@ void simplifier::operator()(expr * s, expr_ref & r, proof_ref & p) { m_need_reset = true; reinitialize(); expr * s_orig = s; + (void)s_orig; expr * old_s; expr * result; proof * result_proof; diff --git a/src/duality/duality_rpfp.cpp b/src/duality/duality_rpfp.cpp index c47662ddf0b..c86ff9f62dd 100755 --- a/src/duality/duality_rpfp.cpp +++ b/src/duality/duality_rpfp.cpp @@ -2365,8 +2365,7 @@ namespace Duality { Term CanonIneqTerm(const Term &p){ Term term,bound; Term ps = p.simplify(); - bool ok = IsCanonIneq(ps,term,bound); - assert(ok); + VERIFY(IsCanonIneq(ps,term,bound)); return term - bound; } diff --git a/src/math/euclid/euclidean_solver.cpp b/src/math/euclid/euclidean_solver.cpp index af11d43044d..b33dbf3aab1 100644 --- a/src/math/euclid/euclidean_solver.cpp +++ b/src/math/euclid/euclidean_solver.cpp @@ -580,8 +580,8 @@ struct euclidean_solver::imp { void substitute_most_recent_solution(var x) { SASSERT(!m_solution.empty()); - equation & eq = *(m_solution.back()); - TRACE("euclidean_solver", tout << "applying solution for x" << x << "\n"; display(tout, eq); tout << "\n";); + TRACE("euclidean_solver", tout << "applying solution for x" << x << "\n"; + display(tout, *(m_solution.back())); tout << "\n";); occs & use_list = m_occs[x]; occs::iterator it = use_list.begin(); occs::iterator end = use_list.end(); diff --git a/src/math/polynomial/upolynomial.cpp b/src/math/polynomial/upolynomial.cpp index 78ce912f4f3..aa26ccf4ce8 100644 --- a/src/math/polynomial/upolynomial.cpp +++ b/src/math/polynomial/upolynomial.cpp @@ -2759,6 +2759,7 @@ namespace upolynomial { bool manager::refine_core(unsigned sz, numeral const * p, int sign_a, mpbq_manager & bqm, mpbq & a, mpbq & b) { SASSERT(sign_a == eval_sign_at(sz, p, a)); int sign_b = -sign_a; + (void)sign_b; SASSERT(sign_b == eval_sign_at(sz, p, b)); SASSERT(sign_a == -sign_b); SASSERT(sign_a != 0 && sign_b != 0); @@ -2810,9 +2811,8 @@ namespace upolynomial { bool manager::refine(unsigned sz, numeral const * p, mpbq_manager & bqm, mpbq & a, mpbq & b, unsigned prec_k) { int sign_a = eval_sign_at(sz, p, a); - int sign_b = -sign_a; - SASSERT(eval_sign_at(sz, p, b) == sign_b); - SASSERT(sign_a != 0 && sign_b != 0); + SASSERT(eval_sign_at(sz, p, b) == -sign_a); + SASSERT(sign_a != 0); return refine_core(sz, p, sign_a, bqm, a, b, prec_k); } @@ -2928,6 +2928,7 @@ namespace upolynomial { SASSERT(sign_a == eval_sign_at(sz, p, a)); } int sign_b = -sign_a; + (void) sign_b; SASSERT(sign_b == eval_sign_at(sz, p, b)); SASSERT(sign_a != 0 && sign_b != 0); if (has_zero_roots(sz, p)) { diff --git a/src/math/polynomial/upolynomial_factorization.cpp b/src/math/polynomial/upolynomial_factorization.cpp index b36658bba13..5a7aefa186d 100644 --- a/src/math/polynomial/upolynomial_factorization.cpp +++ b/src/math/polynomial/upolynomial_factorization.cpp @@ -371,9 +371,10 @@ void zp_square_free_factor(zp_manager & upm, numeral_vector const & f, zp_factor bool zp_factor(zp_manager & upm, numeral_vector const & f, zp_factors & factors) { - unsigned p = get_p_from_manager(upm.m()); - TRACE("polynomial::factorization", tout << "polynomial::factor("; upm.display(tout, f); tout << ") over Z_" << p << endl;); + TRACE("polynomial::factorization", + unsigned p = get_p_from_manager(upm.m()); + tout << "polynomial::factor("; upm.display(tout, f); tout << ") over Z_" << p << endl;); // get the sq-free parts (all of them will be monic) zp_factors sq_free_factors(upm); @@ -435,6 +436,7 @@ bool zp_factor_square_free_berlekamp(zp_manager & upm, numeral_vector const & f, // process the null space vectors (skip first one, it's [1, 0, ..., 0]) while generating the factors unsigned d = upm.degree(f); + (void)d; scoped_numeral_vector v_k(zpm); while (Q_I.next_null_space_vector(v_k)) { diff --git a/src/math/simplex/simplex_def.h b/src/math/simplex/simplex_def.h index 6ca4048ad87..cb86e2a8516 100644 --- a/src/math/simplex/simplex_def.h +++ b/src/math/simplex/simplex_def.h @@ -998,6 +998,7 @@ namespace simplex { template bool simplex::well_formed_row(row const& r) const { var_t s = m_row2base[r.id()]; + (void)s; SASSERT(m_vars[s].m_base2row == r.id()); SASSERT(m_vars[s].m_is_base); // SASSERT(m.is_neg(m_vars[s].m_base_coeff)); diff --git a/src/math/simplex/sparse_matrix_def.h b/src/math/simplex/sparse_matrix_def.h index 09a8a922503..78a4e830179 100644 --- a/src/math/simplex/sparse_matrix_def.h +++ b/src/math/simplex/sparse_matrix_def.h @@ -509,12 +509,13 @@ namespace simplex { dead.insert(i); continue; } - SASSERT(!vars.contains(e.m_var)); - SASSERT(!m.is_zero(e.m_coeff)); - SASSERT(e.m_var != dead_id); - col_entry const& c = m_columns[e.m_var].m_entries[e.m_col_idx]; - SASSERT((unsigned)c.m_row_id == row_id); - SASSERT((unsigned)c.m_row_idx == i); + DEBUG_CODE( + SASSERT(!vars.contains(e.m_var)); + SASSERT(!m.is_zero(e.m_coeff)); + SASSERT(e.m_var != dead_id); + col_entry const& c = m_columns[e.m_var].m_entries[e.m_col_idx]; + SASSERT((unsigned)c.m_row_id == row_id); + SASSERT((unsigned)c.m_row_idx == i);); vars.insert(e.m_var); } int idx = r.m_first_free_idx; diff --git a/src/muz/pdr/pdr_farkas_learner.cpp b/src/muz/pdr/pdr_farkas_learner.cpp index 0565cb23bd1..54d9ada89df 100644 --- a/src/muz/pdr/pdr_farkas_learner.cpp +++ b/src/muz/pdr/pdr_farkas_learner.cpp @@ -923,6 +923,7 @@ namespace pdr { if (p->get_decl_kind() == PR_ASSERTED && bs.contains(m.get_fact(p))) { expr* fact = m.get_fact(p); + (void)p0; TRACE("farkas_learner", tout << mk_ll_pp(p0,m) << "\n"; tout << "Add: " << mk_pp(p,m) << "\n";); diff --git a/src/muz/rel/dl_external_relation.cpp b/src/muz/rel/dl_external_relation.cpp index f3250947345..e9c24abd34d 100644 --- a/src/muz/rel/dl_external_relation.cpp +++ b/src/muz/rel/dl_external_relation.cpp @@ -338,9 +338,8 @@ namespace datalog { : m_plugin(p), m_condition(condition, p.get_ast_manager()), m_filter_fn(p.get_ast_manager()) { - ast_manager& m = p.get_ast_manager(); p.mk_filter_fn(relation_sort, condition, m_filter_fn); - SASSERT(m.is_bool(condition)); + SASSERT(p.get_ast_manager().is_bool(condition)); } virtual void operator()(relation_base & r) { diff --git a/src/muz/rel/dl_finite_product_relation.cpp b/src/muz/rel/dl_finite_product_relation.cpp index 86fef433b9c..879e2969981 100644 --- a/src/muz/rel/dl_finite_product_relation.cpp +++ b/src/muz/rel/dl_finite_product_relation.cpp @@ -1566,13 +1566,12 @@ namespace datalog { return; } - finite_product_relation_plugin & plugin = r.get_plugin(); - if(!m_neg_intersection_join) { - } scoped_rel intersection = get((*m_neg_intersection_join)(r, neg)); - SASSERT(&intersection->get_plugin()==&plugin); //the result of join is also finite product - SASSERT(r.get_signature()==intersection->get_signature()); + DEBUG_CODE( + finite_product_relation_plugin & plugin = r.get_plugin(); + SASSERT(&intersection->get_plugin()==&plugin); //the result of join is also finite product + SASSERT(r.get_signature()==intersection->get_signature());); table_base & r_table = r.get_table(); table_plugin & tplugin = r_table.get_plugin(); relation_manager & rmgr = r.get_manager(); diff --git a/src/muz/rel/udoc_relation.cpp b/src/muz/rel/udoc_relation.cpp index dda674131ee..22e70a3676e 100644 --- a/src/muz/rel/udoc_relation.cpp +++ b/src/muz/rel/udoc_relation.cpp @@ -404,7 +404,7 @@ namespace datalog { rename_fn(udoc_relation const& t, unsigned cycle_len, const unsigned * cycle) : convenient_relation_rename_fn(t.get_signature(), cycle_len, cycle) { udoc_plugin& p = t.get_plugin(); - ast_manager& m = p.get_ast_manager(); + relation_signature const& sig1 = t.get_signature(); relation_signature const& sig2 = get_result_signature(); unsigned_vector permutation0, column_info; @@ -429,6 +429,7 @@ namespace datalog { SASSERT(column == t.get_num_bits()); TRACE("doc", + ast_manager& m = p.get_ast_manager(); sig1.output(m, tout << "sig1: "); tout << "\n"; sig2.output(m, tout << "sig2: "); tout << "\n"; tout << "permute: "; diff --git a/src/muz/transforms/dl_mk_bit_blast.cpp b/src/muz/transforms/dl_mk_bit_blast.cpp index 6d1225641ab..98172f0413b 100644 --- a/src/muz/transforms/dl_mk_bit_blast.cpp +++ b/src/muz/transforms/dl_mk_bit_blast.cpp @@ -70,13 +70,12 @@ namespace datalog { func_interp* f = model->get_func_interp(p); if (!f) continue; expr_ref body(m); - unsigned arity_p = p->get_arity(); unsigned arity_q = q->get_arity(); TRACE("dl", model_v2_pp(tout, *model); tout << mk_pp(p, m) << "\n"; tout << mk_pp(q, m) << "\n";); - SASSERT(0 < arity_p); + SASSERT(0 < p->get_arity()); SASSERT(f); model->register_decl(p, f->copy()); func_interp* g = alloc(func_interp, m, arity_q); diff --git a/src/muz/transforms/dl_mk_quantifier_abstraction.cpp b/src/muz/transforms/dl_mk_quantifier_abstraction.cpp index 57948a2ff76..d3fe1004a7d 100644 --- a/src/muz/transforms/dl_mk_quantifier_abstraction.cpp +++ b/src/muz/transforms/dl_mk_quantifier_abstraction.cpp @@ -71,9 +71,8 @@ namespace datalog { svector const& is_bound = m_bound[i]; func_interp* f = old_model->get_func_interp(p); expr_ref body(m); - unsigned arity_p = p->get_arity(); unsigned arity_q = q->get_arity(); - SASSERT(0 < arity_p); + SASSERT(0 < p->get_arity()); func_interp* g = alloc(func_interp, m, arity_q); if (f) { diff --git a/src/nlsat/nlsat_explain.cpp b/src/nlsat/nlsat_explain.cpp index 23480eed4ab..92a80375eb5 100644 --- a/src/nlsat/nlsat_explain.cpp +++ b/src/nlsat/nlsat_explain.cpp @@ -1165,8 +1165,7 @@ namespace nlsat { if (max_var(new_lit) < max) { // The conflicting core may have redundant literals. // We should check whether new_lit is true in the current model, and discard it if that is the case - lbool val = m_solver.value(new_lit); - SASSERT(val != l_undef); + VERIFY(m_solver.value(new_lit) != l_undef); if (m_solver.value(new_lit) == l_false) add_literal(new_lit); new_lit = true_literal; diff --git a/src/nlsat/nlsat_interval_set.cpp b/src/nlsat/nlsat_interval_set.cpp index 68609cb3fef..44e1128d14d 100644 --- a/src/nlsat/nlsat_interval_set.cpp +++ b/src/nlsat/nlsat_interval_set.cpp @@ -102,14 +102,14 @@ namespace nlsat { // Check if the intervals are valid, ordered, and are disjoint. bool check_interval_set(anum_manager & am, unsigned sz, interval const * ints) { - for (unsigned i = 0; i < sz; i++) { - interval const & curr = ints[i]; - SASSERT(check_interval(am, curr)); - if (i < sz - 1) { - interval const & next = ints[i+1]; - SASSERT(check_no_overlap(am, curr, next)); - } - } + DEBUG_CODE( + for (unsigned i = 0; i < sz; i++) { + interval const & curr = ints[i]; + SASSERT(check_interval(am, curr)); + if (i < sz - 1) { + SASSERT(check_no_overlap(am, curr, ints[i+1])); + } + }); return true; } diff --git a/src/nlsat/nlsat_solver.cpp b/src/nlsat/nlsat_solver.cpp index ae3f1252b19..4f9854d8776 100644 --- a/src/nlsat/nlsat_solver.cpp +++ b/src/nlsat/nlsat_solver.cpp @@ -1728,27 +1728,28 @@ namespace nlsat { // ----------------------- bool check_watches() const { - for (var x = 0; x < num_vars(); x++) { - clause_vector const & cs = m_watches[x]; - unsigned sz = cs.size(); - for (unsigned i = 0; i < sz; i++) { - clause const & c = *(cs[i]); - SASSERT(max_var(c) == x); - } - } + DEBUG_CODE( + for (var x = 0; x < num_vars(); x++) { + clause_vector const & cs = m_watches[x]; + unsigned sz = cs.size(); + for (unsigned i = 0; i < sz; i++) { + SASSERT(max_var(*(cs[i])) == x); + } + }); return true; } bool check_bwatches() const { - for (bool_var b = 0; b < m_bwatches.size(); b++) { - clause_vector const & cs = m_bwatches[b]; - unsigned sz = cs.size(); - for (unsigned i = 0; i < sz; i++) { - clause const & c = *(cs[i]); - SASSERT(max_var(c) == null_var); - SASSERT(max_bvar(c) == b); - } - } + DEBUG_CODE( + for (bool_var b = 0; b < m_bwatches.size(); b++) { + clause_vector const & cs = m_bwatches[b]; + unsigned sz = cs.size(); + for (unsigned i = 0; i < sz; i++) { + clause const & c = *(cs[i]); + SASSERT(max_var(c) == null_var); + SASSERT(max_bvar(c) == b); + } + }); return true; } diff --git a/src/opt/hitting_sets.cpp b/src/opt/hitting_sets.cpp index 8bbad6683a9..678d7924e1d 100644 --- a/src/opt/hitting_sets.cpp +++ b/src/opt/hitting_sets.cpp @@ -762,6 +762,7 @@ namespace opt { } bool invariant() { + DEBUG_CODE( for (unsigned i = 0; i < m_fwatch.size(); ++i) { for (unsigned j = 0; j < m_fwatch[i].size(); ++j) { set const& S = *m_F[m_fwatch[i][j]]; @@ -773,7 +774,7 @@ namespace opt { set const& S = *m_T[m_twatch[i][j]]; SASSERT(S[0] == i || S[1] == i); } - } + }); return true; } diff --git a/src/parsers/smt2/smt2parser.cpp b/src/parsers/smt2/smt2parser.cpp index a995c5917bf..17a931cc3ae 100644 --- a/src/parsers/smt2/smt2parser.cpp +++ b/src/parsers/smt2/smt2parser.cpp @@ -473,6 +473,7 @@ namespace smt2 { void parse_sexpr() { unsigned stack_pos = sexpr_stack().size(); + (void)stack_pos; unsigned num_frames = 0; do { unsigned line = m_scanner.get_line(); @@ -631,6 +632,7 @@ namespace smt2 { void parse_psort() { unsigned stack_pos = psort_stack().size(); + (void)stack_pos; unsigned num_frames = 0; do { if (curr_is_identifier()) { @@ -693,6 +695,7 @@ namespace smt2 { void parse_sort(char const* context) { unsigned stack_pos = sort_stack().size(); + (void)stack_pos; unsigned num_frames = 0; do { if (curr_is_identifier()) { diff --git a/src/qe/qe.cpp b/src/qe/qe.cpp index 1df22e385f1..9742d205180 100644 --- a/src/qe/qe.cpp +++ b/src/qe/qe.cpp @@ -1899,8 +1899,7 @@ namespace qe { // The variable v is to be assigned a value in a range. // void constrain_assignment() { - expr* fml = m_current->fml(); - SASSERT(fml); + SASSERT(m_current->fml()); rational k; app* x; if (!find_min_weight(x, k)) { diff --git a/src/qe/qe_arith_plugin.cpp b/src/qe/qe_arith_plugin.cpp index 8bb3fa6e2da..38861df658a 100644 --- a/src/qe/qe_arith_plugin.cpp +++ b/src/qe/qe_arith_plugin.cpp @@ -1153,21 +1153,20 @@ namespace qe { bool get_bound(contains_app& contains_x, app* a) { - ast_manager& m = m_util.get_manager(); - app* x = contains_x.x(); - if (m_mark.is_marked(a) || + bool has_bound = + m_mark.is_marked(a) || get_le_bound(contains_x, a) || get_lt_bound(contains_x, a) || get_divides(contains_x, a) || - get_nested_divs(contains_x, a)) { - TRACE("qe_verbose", tout << "Bound for " << mk_pp(x, m) << " within " << mk_pp(a, m) << "\n";); + get_nested_divs(contains_x, a); + if (has_bound) { m_mark.mark(a, true); - return true; - } - else { - TRACE("qe", tout << "No bound for " << mk_pp(x, m) << " within " << mk_pp(a, m) << "\n";); - return false; } + TRACE("qe_verbose", + ast_manager& m = m_util.get_manager(); + app* x = contains_x.x(); + tout << has_bound << " bound for " << mk_pp(x, m) << " within " << mk_pp(a, m) << "\n";); + return has_bound; } unsigned lt_size() { return m_lt_terms.size(); } @@ -2323,7 +2322,6 @@ namespace qe { unsigned sz = bounds.size(is_strict, !is_lower); bool is_strict_real = !is_eq_ctx && m_util.is_real(x) && !is_strict_ctx; bool strict_resolve = is_strict || is_strict_ctx || is_strict_real; - app* atm = bounds.atoms(is_strict_ctx, is_lower)[index]; for (unsigned i = 0; i < sz; ++i) { app* e = bounds.atoms(is_strict, !is_lower)[i]; @@ -2341,6 +2339,7 @@ namespace qe { m_ctx.add_constraint(true, mk_not(e), tmp); TRACE("qe_verbose", + app* atm = bounds.atoms(is_strict_ctx, is_lower)[index]; tout << mk_pp(atm, m) << " "; tout << mk_pp(e, m) << " ==>\n"; tout << mk_pp(tmp, m) << "\n"; diff --git a/src/qe/qe_sat_tactic.cpp b/src/qe/qe_sat_tactic.cpp index 455c1d08ee9..c2912692cee 100644 --- a/src/qe/qe_sat_tactic.cpp +++ b/src/qe/qe_sat_tactic.cpp @@ -603,8 +603,7 @@ namespace qe { m_solver.assert_expr(m.mk_iff(proxies.back(), m_assignments[i].get())); TRACE("qe", tout << "assignment: " << mk_pp(m_assignments[i].get(), m) << "\n";); } - lbool is_sat = m_solver.check(proxies.size(), proxies.c_ptr()); - SASSERT(is_sat == l_false); + VERIFY(l_false == m_solver.check(proxies.size(), proxies.c_ptr())); unsigned core_size = m_solver.get_unsat_core_size(); for (unsigned i = 0; i < core_size; ++i) { core.push_back(proxy_map.find(m_solver.get_unsat_core_expr(i))); diff --git a/src/sat/sat_integrity_checker.cpp b/src/sat/sat_integrity_checker.cpp index d0052b8c220..ac2a51c4dd3 100644 --- a/src/sat/sat_integrity_checker.cpp +++ b/src/sat/sat_integrity_checker.cpp @@ -40,8 +40,7 @@ namespace sat { if (it->is_clause()) { if (it->get_clause_offset() == cls_off) { // the blocked literal must be in the clause. - literal l = it->get_blocked_literal(); - SASSERT(c.contains(l)); + SASSERT(c.contains(it->get_blocked_literal())); return true; } } @@ -154,10 +153,11 @@ namespace sat { } bool integrity_checker::check_watches() const { + DEBUG_CODE( vector::const_iterator it = s.m_watches.begin(); vector::const_iterator end = s.m_watches.end(); for (unsigned l_idx = 0; it != end; ++it, ++l_idx) { - literal l = ~to_literal(l_idx); + literal l = ~to_literal(l_idx); watch_list const & wlist = *it; CTRACE("sat_bug", s.was_eliminated(l.var()) && !wlist.empty(), tout << "l: " << l << "\n"; @@ -193,7 +193,7 @@ namespace sat { break; } } - } + }); return true; } diff --git a/src/sat/sat_sls.cpp b/src/sat/sat_sls.cpp index 76e222f026c..7efc0ce0b6a 100644 --- a/src/sat/sat_sls.cpp +++ b/src/sat/sat_sls.cpp @@ -269,35 +269,36 @@ namespace sat { } void sls::check_invariant() { - for (unsigned i = 0; i < m_clauses.size(); ++i) { - clause const& c = *m_clauses[i]; - bool is_sat = c.satisfied_by(m_model); - SASSERT(is_sat != m_false.contains(i)); - SASSERT(is_sat == (m_num_true[i] > 0)); - } + DEBUG_CODE( + for (unsigned i = 0; i < m_clauses.size(); ++i) { + clause const& c = *m_clauses[i]; + bool is_sat = c.satisfied_by(m_model); + SASSERT(is_sat != m_false.contains(i)); + SASSERT(is_sat == (m_num_true[i] > 0)); + }); } void sls::check_use_list() { - - for (unsigned i = 0; i < m_clauses.size(); ++i) { - clause const& c = *m_clauses[i]; - for (unsigned j = 0; j < c.size(); ++j) { - unsigned idx = c[j].index(); - SASSERT(m_use_list[idx].contains(i)); + DEBUG_CODE( + for (unsigned i = 0; i < m_clauses.size(); ++i) { + clause const& c = *m_clauses[i]; + for (unsigned j = 0; j < c.size(); ++j) { + unsigned idx = c[j].index(); + SASSERT(m_use_list[idx].contains(i)); + } } - } - for (unsigned i = 0; i < m_use_list.size(); ++i) { - literal lit = to_literal(i); - for (unsigned j = 0; j < m_use_list[i].size(); ++j) { - clause const& c = *m_clauses[m_use_list[i][j]]; - bool found = false; - for (unsigned k = 0; !found && k < c.size(); ++k) { - found = c[k] == lit; + for (unsigned i = 0; i < m_use_list.size(); ++i) { + literal lit = to_literal(i); + for (unsigned j = 0; j < m_use_list[i].size(); ++j) { + clause const& c = *m_clauses[m_use_list[i][j]]; + bool found = false; + for (unsigned k = 0; !found && k < c.size(); ++k) { + found = c[k] == lit; + } + SASSERT(found); } - SASSERT(found); - } - } + }); } void sls::display(std::ostream& out) const { @@ -556,8 +557,7 @@ namespace sat { void wsls::recompute_hscores(literal lit) { SASSERT(value_at(lit, m_model) == l_true); - bool_var v = lit.var(); - TRACE("sat", tout << v << " := " << m_hscore[v] << "\n";); + TRACE("sat", tout << lit.var() << " := " << m_hscore[lit.var()] << "\n";); unsigned_vector const& use1 = get_use(lit); unsigned sz = use1.size(); for (unsigned i = 0; i < sz; ++i) { @@ -647,28 +647,29 @@ namespace sat { // The hscore is the reward for flipping the truth value of variable v. // hscore(v) = Sum weight(c) for num_true(c) = 0 and v in c // - Sum weight(c) for num_true(c) = 1 and (v in c, M(v) or !v in c and !M(v)) - for (unsigned v = 0; v < s.num_vars(); ++v) { - int hs = compute_hscore(v); - CTRACE("sat", hs != m_hscore[v], display(tout << v << " - computed: " << hs << " - assigned: " << m_hscore[v] << "\n");); - SASSERT(m_hscore[v] == hs); - } - - // The score(v) is the reward on soft clauses for flipping v. - for (unsigned j = 0; j < m_soft.size(); ++j) { - unsigned v = m_soft[j].var(); - double ss = (l_true == value_at(m_soft[j], m_model))?(-m_weights[j]):m_weights[j]; - SASSERT(m_sscore[v] == ss); - } - - // m_H are values such that m_hscore > 0 and sscore = 0. - for (bool_var v = 0; v < m_hscore.size(); ++v) { - SASSERT((m_hscore[v] > 0 && !m_tabu[v] && m_sscore[v] == 0) == m_H.contains(v)); - } - - // m_S are values such that hscore = 0, sscore > 0 - for (bool_var v = 0; v < m_sscore.size(); ++v) { - SASSERT((m_hscore[v] == 0 && m_sscore[v] > 0 && !m_tabu[v]) == m_S.contains(v)); - } + DEBUG_CODE( + for (unsigned v = 0; v < s.num_vars(); ++v) { + int hs = compute_hscore(v); + CTRACE("sat", hs != m_hscore[v], display(tout << v << " - computed: " << hs << " - assigned: " << m_hscore[v] << "\n");); + SASSERT(m_hscore[v] == hs); + } + + // The score(v) is the reward on soft clauses for flipping v. + for (unsigned j = 0; j < m_soft.size(); ++j) { + unsigned v = m_soft[j].var(); + double ss = (l_true == value_at(m_soft[j], m_model))?(-m_weights[j]):m_weights[j]; + SASSERT(m_sscore[v] == ss); + } + + // m_H are values such that m_hscore > 0 and sscore = 0. + for (bool_var v = 0; v < m_hscore.size(); ++v) { + SASSERT((m_hscore[v] > 0 && !m_tabu[v] && m_sscore[v] == 0) == m_H.contains(v)); + } + + // m_S are values such that hscore = 0, sscore > 0 + for (bool_var v = 0; v < m_sscore.size(); ++v) { + SASSERT((m_hscore[v] == 0 && m_sscore[v] > 0 && !m_tabu[v]) == m_S.contains(v)); + }); } void wsls::display(std::ostream& out) const { diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index f636c726b20..78067238a24 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -80,8 +80,7 @@ namespace sat { SASSERT(!src.was_eliminated(v)); bool ext = src.m_external[v] != 0; bool dvar = src.m_decision[v] != 0; - bool_var new_v = mk_var(ext, dvar); - SASSERT(v == new_v); + VERIFY(v == mk_var(ext, dvar)); } } { @@ -407,9 +406,8 @@ namespace sat { unsigned num_lits = cls.size(); for (unsigned i = 1; i < num_lits; i++) { literal l = cls[i]; - lbool val = value(l); - CTRACE("sat", val != l_false, tout << l << ":=" << val;); - SASSERT(val == l_false); + CTRACE("sat", value(l) != l_false, tout << l << ":=" << value(l);); + SASSERT(value(l) == l_false); if (max_false_idx == UINT_MAX || lvl(l) > lvl(cls[max_false_idx])) max_false_idx = i; } diff --git a/src/smt/smt_conflict_resolution.cpp b/src/smt/smt_conflict_resolution.cpp index 86593b0f2ce..e3c2be12320 100644 --- a/src/smt/smt_conflict_resolution.cpp +++ b/src/smt/smt_conflict_resolution.cpp @@ -99,9 +99,10 @@ namespace smt { This method may update m_antecedents, m_todo_js and m_todo_eqs. */ void conflict_resolution::eq_justification2literals(enode * lhs, enode * rhs, eq_justification js) { - ast_manager& m = get_manager(); SASSERT(m_antecedents); - TRACE("conflict_detail", tout << mk_pp(lhs->get_owner(), m) << " = " << mk_pp(rhs->get_owner(), m); + TRACE("conflict_detail", + ast_manager& m = get_manager(); + tout << mk_pp(lhs->get_owner(), m) << " = " << mk_pp(rhs->get_owner(), m); switch (js.get_kind()) { case eq_justification::AXIOM: tout << " axiom\n"; break; case eq_justification::EQUATION: diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index 7d07f39971a..07f4440ff5c 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -2259,6 +2259,7 @@ namespace smt { } unsigned ilvl = 0; + (void)ilvl; for (unsigned j = 0; j < num; j++) { expr * atom = cls->get_atom(j); bool sign = cls->get_atom_sign(j); @@ -2855,8 +2856,7 @@ namespace smt { propagate(); if (was_consistent && inconsistent()) { // logical context became inconsistent during user PUSH - bool res = resolve_conflict(); // build the proof - SASSERT(!res); + VERIFY(!resolve_conflict()); // build the proof } push_scope(); m_base_scopes.push_back(base_scope()); @@ -3110,8 +3110,7 @@ namespace smt { else { TRACE("after_internalization", display(tout);); if (inconsistent()) { - bool res = resolve_conflict(); // build the proof - SASSERT(!res); + VERIFY(!resolve_conflict()); // build the proof r = l_false; } else { @@ -3197,8 +3196,7 @@ namespace smt { init_assumptions(num_assumptions, assumptions); TRACE("after_internalization", display(tout);); if (inconsistent()) { - bool res = resolve_conflict(); // build the proof - SASSERT(!res); + VERIFY(!resolve_conflict()); // build the proof mk_unsat_core(); r = l_false; } diff --git a/src/smt/theory_arith_aux.h b/src/smt/theory_arith_aux.h index b4f88724569..88676b4d957 100644 --- a/src/smt/theory_arith_aux.h +++ b/src/smt/theory_arith_aux.h @@ -1784,7 +1784,7 @@ namespace smt { template typename theory_arith::max_min_t theory_arith::max_min(theory_var v, bool max, bool maintain_integrality, bool& has_shared) { expr* e = get_enode(v)->get_owner(); - + (void)e; SASSERT(!maintain_integrality || valid_assignment()); SASSERT(satisfy_bounds()); SASSERT(!is_quasi_base(v)); diff --git a/src/smt/theory_array.cpp b/src/smt/theory_array.cpp index c60efe1b1f7..ef6b0e776b9 100644 --- a/src/smt/theory_array.cpp +++ b/src/smt/theory_array.cpp @@ -75,8 +75,7 @@ namespace smt { ast_manager& m = get_manager(); context& ctx = get_context(); theory_var r = theory_array_base::mk_var(n); - theory_var r2 = m_find.mk_var(); - SASSERT(r == r2); + VERIFY(r == m_find.mk_var()); SASSERT(r == static_cast(m_var_data.size())); m_var_data.push_back(alloc(var_data)); var_data * d = m_var_data[r]; diff --git a/src/smt/theory_bv.cpp b/src/smt/theory_bv.cpp index 3d6e341fae5..2945c8c9355 100644 --- a/src/smt/theory_bv.cpp +++ b/src/smt/theory_bv.cpp @@ -457,8 +457,7 @@ namespace smt { void theory_bv::fixed_var_eh(theory_var v) { numeral val; - bool r = get_fixed_value(v, val); - SASSERT(r); + VERIFY(get_fixed_value(v, val)); unsigned sz = get_bv_size(v); value_sort_pair key(val, sz); theory_var v2; @@ -554,9 +553,8 @@ namespace smt { void theory_bv::internalize_bv2int(app* n) { SASSERT(!get_context().e_internalized(n)); - ast_manager & m = get_manager(); context& ctx = get_context(); - TRACE("bv", tout << mk_bounded_pp(n, m) << "\n";); + TRACE("bv", tout << mk_bounded_pp(n, get_manager()) << "\n";); process_args(n); mk_enode(n); if (!ctx.relevancy()) { @@ -1142,9 +1140,8 @@ namespace smt { } void theory_bv::assign_eh(bool_var v, bool is_true) { - context & ctx = get_context(); atom * a = get_bv2a(v); - TRACE("bv", tout << "assert: v" << v << " #" << ctx.bool_var2expr(v)->get_id() << " is_true: " << is_true << "\n";); + TRACE("bv", tout << "assert: v" << v << " #" << get_context().bool_var2expr(v)->get_id() << " is_true: " << is_true << "\n";); if (a->is_bit()) { // The following optimization is not correct. // Boolean variables created for performing bit-blasting are reused. diff --git a/src/smt/theory_datatype.cpp b/src/smt/theory_datatype.cpp index 02b8f9514ff..e5c8b1313b5 100644 --- a/src/smt/theory_datatype.cpp +++ b/src/smt/theory_datatype.cpp @@ -198,8 +198,7 @@ namespace smt { theory_var theory_datatype::mk_var(enode * n) { theory_var r = theory::mk_var(n); - theory_var r2 = m_find.mk_var(); - SASSERT(r == r2); + VERIFY(r == m_find.mk_var()); SASSERT(r == static_cast(m_var_data.size())); m_var_data.push_back(alloc(var_data)); var_data * d = m_var_data[r]; diff --git a/src/smt/theory_diff_logic_def.h b/src/smt/theory_diff_logic_def.h index cca78e9c0e4..98f94c6d28a 100644 --- a/src/smt/theory_diff_logic_def.h +++ b/src/smt/theory_diff_logic_def.h @@ -273,8 +273,7 @@ bool theory_diff_logic::internalize_atom(app * n, bool gate_ctx) { template void theory_diff_logic::internalize_eq_eh(app * atom, bool_var v) { context & ctx = get_context(); - ast_manager& m = get_manager(); - TRACE("arith", tout << mk_pp(atom, m) << "\n";); + TRACE("arith", tout << mk_pp(atom, get_manager()) << "\n";); app * lhs = to_app(atom->get_arg(0)); app * rhs = to_app(atom->get_arg(1)); app * s; @@ -606,7 +605,6 @@ void theory_diff_logic::new_edge(dl_var src, dl_var dst, unsigned num_edges atom* a = 0; m_bool_var2atom.find(bv, a); SASSERT(a); - edge_id e_id = a->get_pos(); literal_vector lits; for (unsigned i = 0; i < num_edges; ++i) { @@ -616,7 +614,7 @@ void theory_diff_logic::new_edge(dl_var src, dl_var dst, unsigned num_edges TRACE("dl_activity", tout << mk_pp(le, get_manager()) << "\n"; - tout << "edge: " << e_id << "\n"; + tout << "edge: " << a->get_pos() << "\n"; ctx.display_literals_verbose(tout, lits.size(), lits.c_ptr()); tout << "\n"; ); @@ -927,18 +925,19 @@ void theory_diff_logic::display(std::ostream & out) const { template bool theory_diff_logic::is_consistent() const { - context& ctx = get_context(); - for (unsigned i = 0; i < m_atoms.size(); ++i) { - atom* a = m_atoms[i]; - bool_var bv = a->get_bool_var(); - lbool asgn = ctx.get_assignment(bv); - if (ctx.is_relevant(ctx.bool_var2expr(bv)) && asgn != l_undef) { - SASSERT((asgn == l_true) == a->is_true()); - int edge_id = a->get_asserted_edge(); - SASSERT(m_graph.is_enabled(edge_id)); - SASSERT(m_graph.is_feasible(edge_id)); - } - } + DEBUG_CODE( + context& ctx = get_context(); + for (unsigned i = 0; i < m_atoms.size(); ++i) { + atom* a = m_atoms[i]; + bool_var bv = a->get_bool_var(); + lbool asgn = ctx.get_assignment(bv); + if (ctx.is_relevant(ctx.bool_var2expr(bv)) && asgn != l_undef) { + SASSERT((asgn == l_true) == a->is_true()); + int edge_id = a->get_asserted_edge(); + SASSERT(m_graph.is_enabled(edge_id)); + SASSERT(m_graph.is_feasible(edge_id)); + } + }); return m_graph.is_feasible(); } @@ -1194,9 +1193,9 @@ theory_diff_logic::maximize(theory_var v, expr_ref& blocker, bool& has_shar ast_manager& m = get_manager(); update_simplex(S); - objective_term const& objective = m_objectives[v]; TRACE("arith", + objective_term const& objective = m_objectives[v]; for (unsigned i = 0; i < objective.size(); ++i) { tout << "Coefficient " << objective[i].second << " of theory_var " << objective[i].first << "\n"; diff --git a/src/smt/theory_fpa.cpp b/src/smt/theory_fpa.cpp index 543b1348e56..dfba7c17064 100644 --- a/src/smt/theory_fpa.cpp +++ b/src/smt/theory_fpa.cpp @@ -52,9 +52,8 @@ namespace smt { expr_ref bv(m); bv = m_th.wrap(m.mk_const(f)); unsigned bv_sz = m_th.m_bv_util.get_bv_size(bv); - unsigned ebits = m_th.m_fpa_util.get_ebits(s); unsigned sbits = m_th.m_fpa_util.get_sbits(s); - SASSERT(bv_sz == ebits + sbits); + SASSERT(bv_sz == m_th.m_fpa_util.get_ebits(s) + sbits); m_th.m_converter.mk_fp(m_bv_util.mk_extract(bv_sz - 1, bv_sz - 1, bv), m_bv_util.mk_extract(bv_sz - 2, sbits - 1, bv), m_bv_util.mk_extract(sbits - 2, 0, bv), @@ -231,10 +230,11 @@ namespace smt { } app * theory_fpa::fpa_value_proc::mk_value(model_generator & mg, ptr_vector & values) { - ast_manager & m = m_th.get_manager(); - TRACE("t_fpa_detail", for (unsigned i = 0; i < values.size(); i++) - tout << "value[" << i << "] = " << mk_ismt2_pp(values[i], m) << std::endl;); + 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;); mpf_manager & mpfm = m_fu.fm(); unsynch_mpz_manager & mpzm = mpfm.mpz_manager(); @@ -254,8 +254,7 @@ namespace smt { rational all_r(0); scoped_mpz all_z(mpzm); - bool r = m_bu.is_numeral(values[0], all_r, bv_sz); - SASSERT(r); + VERIFY(m_bu.is_numeral(values[0], all_r, bv_sz)); SASSERT(bv_sz == (m_ebits + m_sbits)); SASSERT(all_r.is_int()); mpzm.set(all_z, all_r.to_mpq().numerator()); @@ -316,8 +315,7 @@ namespace smt { unsigned bv_sz; rational val(0); - bool r = m_bu.is_numeral(values[0], val, bv_sz); - SASSERT(r); + VERIFY(m_bu.is_numeral(values[0], val, bv_sz)); SASSERT(bv_sz == 3); switch (val.get_uint64()) @@ -422,9 +420,8 @@ namespace smt { expr_ref bv(m); bv = wrap(e_conv); unsigned bv_sz = m_bv_util.get_bv_size(bv); - unsigned ebits = m_fpa_util.get_ebits(m.get_sort(e_conv)); unsigned sbits = m_fpa_util.get_sbits(m.get_sort(e_conv)); - SASSERT(bv_sz == ebits + sbits); + SASSERT(bv_sz == m_fpa_util.get_ebits(m.get_sort(e_conv)) + sbits); m_converter.mk_fp(m_bv_util.mk_extract(bv_sz - 1, bv_sz - 1, bv), m_bv_util.mk_extract(bv_sz - 2, sbits - 1, bv), m_bv_util.mk_extract(sbits - 2, 0, bv), diff --git a/src/smt/theory_wmaxsat.cpp b/src/smt/theory_wmaxsat.cpp index 9ed944d2c39..e52475d06e2 100644 --- a/src/smt/theory_wmaxsat.cpp +++ b/src/smt/theory_wmaxsat.cpp @@ -260,7 +260,6 @@ void theory_wmaxsat::block() { return; } ++m_stats.m_num_blocks; - ast_manager& m = get_manager(); context& ctx = get_context(); literal_vector lits; compare_cost compare_cost(*this); @@ -274,6 +273,7 @@ void theory_wmaxsat::block() { lits.push_back(~literal(m_var2bool[costs[i]])); } TRACE("opt", + ast_manager& m = get_manager(); tout << "block: "; for (unsigned i = 0; i < lits.size(); ++i) { expr_ref tmp(m); diff --git a/src/util/mpf.cpp b/src/util/mpf.cpp index e84298231f4..0fcff0da0ef 100644 --- a/src/util/mpf.cpp +++ b/src/util/mpf.cpp @@ -1092,6 +1092,7 @@ void mpf_manager::round_to_integral(mpf_rounding_mode rm, mpf const & x, mpf & o bool tie = m_mpz_manager.eq(rem, shiftm1_p); bool less_than_tie = m_mpz_manager.lt(rem, shiftm1_p); bool more_than_tie = m_mpz_manager.gt(rem, shiftm1_p); + (void)less_than_tie; TRACE("mpf_dbg", tout << "tie= " << tie << "; tie = " << more_than_tie << std::endl;); if (tie) { if ((rm == MPF_ROUND_NEAREST_TEVEN && m_mpz_manager.is_odd(div)) || @@ -1888,6 +1889,7 @@ void mpf_manager::round(mpf_rounding_mode rm, mpf & o) { const mpz & p_m1 = m_powers2(o.sbits+2); const mpz & p_m2 = m_powers2(o.sbits+3); + (void)p_m1; TRACE("mpf_dbg", tout << "p_m1 = " << m_mpz_manager.to_string(p_m1) << std::endl << "p_m2 = " << m_mpz_manager.to_string(p_m2) << std::endl;); @@ -2079,7 +2081,7 @@ void mpf_manager::round_sqrt(mpf_rounding_mode rm, mpf & o) { bool round = !m_mpz_manager.is_even(o.significand); m_mpz_manager.machine_div2k(o.significand, 1); bool last = !m_mpz_manager.is_even(o.significand); - + (void)last; bool inc = false; // Specialized rounding for sqrt, as there are no negative cases (or half-way cases?) diff --git a/src/util/mpff.cpp b/src/util/mpff.cpp index e5d3cf24c87..d26b3743c42 100644 --- a/src/util/mpff.cpp +++ b/src/util/mpff.cpp @@ -1395,6 +1395,7 @@ unsigned mpff_manager::prev_power_of_two(mpff const & a) { bool mpff_manager::check(mpff const & n) const { // n is zero or the most significand bit of the most significand word is 1. unsigned * s = sig(n); + (void)s; SASSERT(is_zero(n) || (s[m_precision - 1] & MIN_MSW) != 0); // if n is zero, then the sign must be 0 SASSERT(!is_zero(n) || n.m_sign == 0); From 40f8e16273a4fd8f11f1f64c342e00f33773f87c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 17 May 2016 14:00:30 -0700 Subject: [PATCH 33/61] removing warnings for unused variables, #579 Signed-off-by: Nikolaj Bjorner --- src/math/simplex/sparse_matrix_def.h | 9 +++++---- src/qe/qe.cpp | 5 +++-- src/smt/theory_fpa.cpp | 5 +++-- src/smt/theory_pb.cpp | 10 ++++------ 4 files changed, 15 insertions(+), 14 deletions(-) diff --git a/src/math/simplex/sparse_matrix_def.h b/src/math/simplex/sparse_matrix_def.h index 78a4e830179..b050e45e1bf 100644 --- a/src/math/simplex/sparse_matrix_def.h +++ b/src/math/simplex/sparse_matrix_def.h @@ -542,10 +542,11 @@ namespace simplex { continue; } SASSERT(!rows.contains(c.m_row_id)); - _row const& row = m_rows[c.m_row_id]; - _row_entry const& r = row.m_entries[c.m_row_idx]; - SASSERT(r.m_var == v); - SASSERT((unsigned)r.m_col_idx == i); + DEBUG_CODE( + _row const& row = m_rows[c.m_row_id]; + _row_entry const& r = row.m_entries[c.m_row_idx]; + SASSERT(r.m_var == v); + SASSERT((unsigned)r.m_col_idx == i);); rows.insert(c.m_row_id); } int idx = col.m_first_free_idx; diff --git a/src/qe/qe.cpp b/src/qe/qe.cpp index 9742d205180..721e389423a 100644 --- a/src/qe/qe.cpp +++ b/src/qe/qe.cpp @@ -861,11 +861,12 @@ namespace qe { void operator()(expr_ref& fml, atom_set& pos, atom_set& neg) { expr_ref orig(fml); - ast_manager& m = fml.get_manager(); m_nnf_core(fml); m_normalize_literals(fml); m_collect_atoms(fml, pos, neg); - TRACE("qe", tout << mk_ismt2_pp(orig, m) << "\n-->\n" << mk_ismt2_pp(fml, m) << "\n";); + TRACE("qe", + ast_manager& m = fml.get_manager(); + tout << mk_ismt2_pp(orig, m) << "\n-->\n" << mk_ismt2_pp(fml, m) << "\n";); } void reset() { diff --git a/src/smt/theory_fpa.cpp b/src/smt/theory_fpa.cpp index dfba7c17064..59bcf40e886 100644 --- a/src/smt/theory_fpa.cpp +++ b/src/smt/theory_fpa.cpp @@ -306,9 +306,10 @@ namespace smt { app * theory_fpa::fpa_rm_value_proc::mk_value(model_generator & mg, ptr_vector & values) { SASSERT(values.size() == 1); - ast_manager & m = m_th.get_manager(); - TRACE("t_fpa_detail", for (unsigned i = 0; i < values.size(); i++) + 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;); app * result = 0; diff --git a/src/smt/theory_pb.cpp b/src/smt/theory_pb.cpp index a1aebf3e1b8..273bffd9330 100644 --- a/src/smt/theory_pb.cpp +++ b/src/smt/theory_pb.cpp @@ -787,8 +787,7 @@ namespace smt { } for (unsigned i = 0; i < ineqs->size(); ++i) { - ineq* c = (*ineqs)[i]; - SASSERT(c->is_ge()); + SASSERT((*ineqs)[i]->is_ge()); if (assign_watch_ge(v, is_true, *ineqs, i)) { // i was removed from watch list. --i; @@ -1834,13 +1833,12 @@ namespace smt { void theory_pb::validate_assign(ineq const& c, literal_vector const& lits, literal l) const { uint_set nlits; - context& ctx = get_context(); for (unsigned i = 0; i < lits.size(); ++i) { - SASSERT(ctx.get_assignment(lits[i]) == l_true); + SASSERT(get_context().get_assignment(lits[i]) == l_true); nlits.insert((~lits[i]).index()); } - SASSERT(ctx.get_assignment(l) == l_undef); - SASSERT(ctx.get_assignment(c.lit()) == l_true); + SASSERT(get_context().get_assignment(l) == l_undef); + SASSERT(get_context().get_assignment(c.lit()) == l_true); nlits.insert(l.index()); numeral sum = numeral::zero(); for (unsigned i = 0; i < c.size(); ++i) { From 09b8c0e7fa4804b24bc776825b323ab970045ecd Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 17 May 2016 15:59:06 -0700 Subject: [PATCH 34/61] removing warnings for unused variables, #579 Signed-off-by: Nikolaj Bjorner --- src/ast/seq_decl_plugin.cpp | 5 ++--- src/cmd_context/cmd_context_to_goal.cpp | 3 +-- src/sat/sat_bceq.cpp | 9 +++++---- src/sat/sat_clause_set.cpp | 3 ++- src/smt/qi_queue.cpp | 9 +++------ src/smt/smt_model_finder.cpp | 26 ++++++++++++------------- src/smt/theory_seq.cpp | 6 ++---- 7 files changed, 27 insertions(+), 34 deletions(-) diff --git a/src/ast/seq_decl_plugin.cpp b/src/ast/seq_decl_plugin.cpp index 708da560293..21af0773a4a 100644 --- a/src/ast/seq_decl_plugin.cpp +++ b/src/ast/seq_decl_plugin.cpp @@ -277,13 +277,12 @@ bool seq_decl_plugin::is_sort_param(sort* s, unsigned& idx) { } bool seq_decl_plugin::match(ptr_vector& binding, sort* s, sort* sP) { - ast_manager& m = *m_manager; if (s == sP) return true; unsigned i; if (is_sort_param(sP, i)) { if (binding.size() <= i) binding.resize(i+1); if (binding[i] && (binding[i] != s)) return false; - TRACE("seq_verbose", tout << "setting binding @ " << i << " to " << mk_pp(s, m) << "\n";); + TRACE("seq_verbose", tout << "setting binding @ " << i << " to " << mk_pp(s, *m_manager) << "\n";); binding[i] = s; return true; } @@ -302,7 +301,7 @@ bool seq_decl_plugin::match(ptr_vector& binding, sort* s, sort* sP) { return true; } else { - TRACE("seq", tout << "Could not match " << mk_pp(s, m) << " and " << mk_pp(sP, m) << "\n";); + TRACE("seq", tout << "Could not match " << mk_pp(s, *m_manager) << " and " << mk_pp(sP, *m_manager) << "\n";); return false; } } diff --git a/src/cmd_context/cmd_context_to_goal.cpp b/src/cmd_context/cmd_context_to_goal.cpp index 26cb2766b1e..c0b4379aaa1 100644 --- a/src/cmd_context/cmd_context_to_goal.cpp +++ b/src/cmd_context/cmd_context_to_goal.cpp @@ -31,8 +31,7 @@ void assert_exprs_from(cmd_context const & ctx, goal & t) { ptr_vector::const_iterator it = ctx.begin_assertions(); ptr_vector::const_iterator end = ctx.end_assertions(); ptr_vector::const_iterator it2 = ctx.begin_assertion_names(); - ptr_vector::const_iterator end2 = ctx.end_assertion_names(); - SASSERT(end - it == end2 - it2); + SASSERT(end - it == ctx.end_assertion_names() - it2); for (; it != end; ++it, ++it2) { t.assert_expr(*it, proofs_enabled ? m.mk_asserted(*it) : 0, m.mk_leaf(*it2)); } diff --git a/src/sat/sat_bceq.cpp b/src/sat/sat_bceq.cpp index a194cdfd8d9..9ff286aaa91 100644 --- a/src/sat/sat_bceq.cpp +++ b/src/sat/sat_bceq.cpp @@ -345,10 +345,11 @@ namespace sat { } void bceq::verify_sweep() { - for (unsigned i = 0; i < m_L.size(); ++i) { - uint64 b = eval_clause(*m_L[i]); - SASSERT((~b) == 0); - } + DEBUG_CODE( + for (unsigned i = 0; i < m_L.size(); ++i) { + uint64 b = eval_clause(*m_L[i]); + SASSERT((~b) == 0); + }); } struct u64_hash { unsigned operator()(uint64 u) const { return (unsigned)u; } }; diff --git a/src/sat/sat_clause_set.cpp b/src/sat/sat_clause_set.cpp index 29c761130e6..1c424cce3b6 100644 --- a/src/sat/sat_clause_set.cpp +++ b/src/sat/sat_clause_set.cpp @@ -64,6 +64,7 @@ namespace sat { } bool clause_set::check_invariant() const { + DEBUG_CODE( { clause_vector::const_iterator it = m_set.begin(); clause_vector::const_iterator end = m_set.end(); @@ -83,7 +84,7 @@ namespace sat { SASSERT(pos < m_set.size()); SASSERT(m_set[pos]->id() == id); } - } + }); return true; } diff --git a/src/smt/qi_queue.cpp b/src/smt/qi_queue.cpp index 35dd19087eb..f9413be7262 100644 --- a/src/smt/qi_queue.cpp +++ b/src/smt/qi_queue.cpp @@ -367,8 +367,7 @@ namespace smt { unsigned sz = m_delayed_entries.size(); for (unsigned i = 0; i < sz; i++) { entry & e = m_delayed_entries[i]; - fingerprint * f = e.m_qb; - TRACE("qi_queue", tout << f << ", cost: " << e.m_cost << ", instantiated: " << e.m_instantiated << "\n";); + TRACE("qi_queue", tout << e.m_qb << ", cost: " << e.m_cost << ", instantiated: " << e.m_instantiated << "\n";); if (!e.m_instantiated && e.m_cost <= m_params.m_qi_lazy_threshold && (!init || e.m_cost < min_cost)) { init = true; min_cost = e.m_cost; @@ -379,11 +378,10 @@ namespace smt { for (unsigned i = 0; i < sz; i++) { entry & e = m_delayed_entries[i]; fingerprint * f = e.m_qb; - quantifier * qa = static_cast(f->get_data()); TRACE("qi_queue", tout << f << ", cost: " << e.m_cost << ", instantiated: " << e.m_instantiated << "\n";); if (!e.m_instantiated && e.m_cost <= min_cost) { TRACE("qi_queue", - tout << "lazy quantifier instantiation...\n" << mk_pp(qa, m_manager) << "\ncost: " << e.m_cost << "\n";); + tout << "lazy quantifier instantiation...\n" << mk_pp(static_cast(f->get_data()), m_manager) << "\ncost: " << e.m_cost << "\n";); result = false; m_instantiated_trail.push_back(i); m_stats.m_num_lazy_instances++; @@ -397,11 +395,10 @@ namespace smt { for (unsigned i = 0; i < m_delayed_entries.size(); i++) { entry & e = m_delayed_entries[i]; fingerprint * f = e.m_qb; - quantifier * qa = static_cast(f->get_data()); TRACE("qi_queue", tout << f << ", cost: " << e.m_cost << ", instantiated: " << e.m_instantiated << "\n";); if (!e.m_instantiated && e.m_cost <= m_params.m_qi_lazy_threshold) { TRACE("qi_queue", - tout << "lazy quantifier instantiation...\n" << mk_pp(qa, m_manager) << "\ncost: " << e.m_cost << "\n";); + tout << "lazy quantifier instantiation...\n" << mk_pp(static_cast(f->get_data()), m_manager) << "\ncost: " << e.m_cost << "\n";); result = false; m_instantiated_trail.push_back(i); m_stats.m_num_lazy_instances++; diff --git a/src/smt/smt_model_finder.cpp b/src/smt/smt_model_finder.cpp index 1f8f6dabe50..1f4f26b0646 100644 --- a/src/smt/smt_model_finder.cpp +++ b/src/smt/smt_model_finder.cpp @@ -2899,15 +2899,16 @@ namespace smt { } bool check_satisfied_residue_invariant() { - qsset::iterator it = m_satisfied.begin(); - qsset::iterator end = m_satisfied.end(); - for (; it != end; ++it) { - quantifier * q = *it; - SASSERT(!m_residue.contains(q)); - quantifier_info * qi = get_qinfo(q); - SASSERT(qi != 0); - SASSERT(qi->get_the_one() != 0); - } + DEBUG_CODE( + qsset::iterator it = m_satisfied.begin(); + qsset::iterator end = m_satisfied.end(); + for (; it != end; ++it) { + quantifier * q = *it; + SASSERT(!m_residue.contains(q)); + quantifier_info * qi = get_qinfo(q); + SASSERT(qi != 0); + SASSERT(qi->get_the_one() != 0); + }); return true; } @@ -3546,12 +3547,9 @@ namespace smt { bool asserted_something = false; quantifier * flat_q = get_flat_quantifier(q); unsigned num_decls = q->get_num_decls(); - unsigned flat_num_decls = flat_q->get_num_decls(); - unsigned num_sks = sks.size(); // Remark: sks were created for the flat version of q. - SASSERT(num_sks == flat_num_decls); - SASSERT(flat_num_decls >= num_decls); - SASSERT(num_sks >= num_decls); + SASSERT(flat_q->get_num_decls() == sks.size()); + SASSERT(sks.size() >= num_decls); for (unsigned i = 0; i < num_decls; i++) { expr * sk = sks.get(num_decls - i - 1); instantiation_set const * s = get_uvar_inst_set(q, i); diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index 72d8929b865..f2bd8be845b 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -3244,8 +3244,7 @@ void theory_seq::add_at_axiom(expr* e) { step(s, idx, re, i, j, t) -> nth(s, idx) == t & len(s) > idx */ void theory_seq::propagate_step(literal lit, expr* step) { - context& ctx = get_context(); - SASSERT(ctx.get_assignment(lit) == l_true); + SASSERT(get_context().get_assignment(lit) == l_true); expr* re, *acc, *s, *idx, *i, *j; VERIFY(is_step(step, s, idx, re, i, j, acc)); TRACE("seq", tout << mk_pp(step, m) << " -> " << mk_pp(acc, m) << "\n";); @@ -3265,9 +3264,8 @@ void theory_seq::propagate_step(literal lit, expr* step) { lit => s = (nth s 0) ++ (nth s 1) ++ ... ++ (nth s idx) ++ (tail s idx) */ void theory_seq::ensure_nth(literal lit, expr* s, expr* idx) { - context& ctx = get_context(); rational r; - SASSERT(ctx.get_assignment(lit) == l_true); + SASSERT(get_context().get_assignment(lit) == l_true); VERIFY(m_autil.is_numeral(idx, r) && r.is_unsigned()); unsigned _idx = r.get_unsigned(); expr_ref head(m), tail(m), conc(m), len1(m), len2(m); From cc3bfe8da22e53ba74dbec25f04c2fb32db10ea4 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 17 May 2016 16:02:08 -0700 Subject: [PATCH 35/61] removing warnings for unused variables, #579 Signed-off-by: Nikolaj Bjorner --- src/smt/qi_queue.cpp | 10 ++++------ src/smt/smt_model_finder.cpp | 3 +-- src/smt/theory_seq.cpp | 3 +-- 3 files changed, 6 insertions(+), 10 deletions(-) diff --git a/src/smt/qi_queue.cpp b/src/smt/qi_queue.cpp index f9413be7262..711cdc33600 100644 --- a/src/smt/qi_queue.cpp +++ b/src/smt/qi_queue.cpp @@ -377,11 +377,10 @@ namespace smt { bool result = true; for (unsigned i = 0; i < sz; i++) { entry & e = m_delayed_entries[i]; - fingerprint * f = e.m_qb; - TRACE("qi_queue", tout << f << ", cost: " << e.m_cost << ", instantiated: " << e.m_instantiated << "\n";); + TRACE("qi_queue", tout << e.m_qb << ", cost: " << e.m_cost << ", instantiated: " << e.m_instantiated << "\n";); if (!e.m_instantiated && e.m_cost <= min_cost) { TRACE("qi_queue", - tout << "lazy quantifier instantiation...\n" << mk_pp(static_cast(f->get_data()), m_manager) << "\ncost: " << e.m_cost << "\n";); + tout << "lazy quantifier instantiation...\n" << mk_pp(static_cast(e.m_qb->get_data()), m_manager) << "\ncost: " << e.m_cost << "\n";); result = false; m_instantiated_trail.push_back(i); m_stats.m_num_lazy_instances++; @@ -394,11 +393,10 @@ namespace smt { bool result = true; for (unsigned i = 0; i < m_delayed_entries.size(); i++) { entry & e = m_delayed_entries[i]; - fingerprint * f = e.m_qb; - TRACE("qi_queue", tout << f << ", cost: " << e.m_cost << ", instantiated: " << e.m_instantiated << "\n";); + TRACE("qi_queue", tout << e.m_qb << ", cost: " << e.m_cost << ", instantiated: " << e.m_instantiated << "\n";); if (!e.m_instantiated && e.m_cost <= m_params.m_qi_lazy_threshold) { TRACE("qi_queue", - tout << "lazy quantifier instantiation...\n" << mk_pp(static_cast(f->get_data()), m_manager) << "\ncost: " << e.m_cost << "\n";); + tout << "lazy quantifier instantiation...\n" << mk_pp(static_cast(e.m_qb->get_data()), m_manager) << "\ncost: " << e.m_cost << "\n";); result = false; m_instantiated_trail.push_back(i); m_stats.m_num_lazy_instances++; diff --git a/src/smt/smt_model_finder.cpp b/src/smt/smt_model_finder.cpp index 1f4f26b0646..5dc0dd8ecaf 100644 --- a/src/smt/smt_model_finder.cpp +++ b/src/smt/smt_model_finder.cpp @@ -3545,10 +3545,9 @@ namespace smt { // // Since we only care about q (and its bindings), it only makes sense to restrict the variables of q. bool asserted_something = false; - quantifier * flat_q = get_flat_quantifier(q); unsigned num_decls = q->get_num_decls(); // Remark: sks were created for the flat version of q. - SASSERT(flat_q->get_num_decls() == sks.size()); + SASSERT(get_flat_quantifier(q)->get_num_decls() == sks.size()); SASSERT(sks.size() >= num_decls); for (unsigned i = 0; i < num_decls; i++) { expr * sk = sks.get(num_decls - i - 1); diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index f2bd8be845b..97189ce4ca7 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -3741,7 +3741,6 @@ expr_ref theory_seq::mk_step(expr* s, expr* idx, expr* re, unsigned i, unsigned rej(s, idx, re, i) -> len(s) > idx if i is final */ void theory_seq::propagate_acc_rej_length(literal lit, expr* e) { - context& ctx = get_context(); expr *s, * idx, *re; unsigned src; eautomaton* aut = 0; @@ -3752,7 +3751,7 @@ void theory_seq::propagate_acc_rej_length(literal lit, expr* e) { } if (m_util.str.is_length(idx)) return; SASSERT(m_autil.is_numeral(idx)); - SASSERT(ctx.get_assignment(lit) == l_true); + SASSERT(get_context().get_assignment(lit) == l_true); bool is_final = aut->is_final_state(src); if (is_final == is_acc) { propagate_lit(0, 1, &lit, mk_literal(m_autil.mk_ge(m_util.str.mk_length(s), idx))); From 5e7db2e3e2bebb3507598af710aaf28177ce4375 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 18 May 2016 08:29:24 -0700 Subject: [PATCH 36/61] disable mk_array_eq as it breaks model evaluation/validation Signed-off-by: Nikolaj Bjorner --- src/math/grobner/grobner.cpp | 3 +++ src/model/model_evaluator.cpp | 3 +++ 2 files changed, 6 insertions(+) diff --git a/src/math/grobner/grobner.cpp b/src/math/grobner/grobner.cpp index 2bf4d5ba3ad..0c96dfde3cd 100644 --- a/src/math/grobner/grobner.cpp +++ b/src/math/grobner/grobner.cpp @@ -249,6 +249,7 @@ void grobner::update_order() { } bool grobner::var_lt::operator()(expr * v1, expr * v2) const { + if (v1 == v2) return false; int w1 = 0; int w2 = 0; m_var2weight.find(v1, w1); @@ -268,6 +269,8 @@ bool grobner::monomial_lt::operator()(monomial * m1, monomial * m2) const { for (; it1 != end1; ++it1, ++it2) { expr * v1 = *it1; expr * v2 = *it2; + if (v1 == v2) + continue; if (m_var_lt(v1, v2)) return true; if (v1 != v2) diff --git a/src/model/model_evaluator.cpp b/src/model/model_evaluator.cpp index a5b900ab7b6..c83da205032 100644 --- a/src/model/model_evaluator.cpp +++ b/src/model/model_evaluator.cpp @@ -259,6 +259,8 @@ struct evaluator_cfg : public default_rewriter_cfg { br_status mk_array_eq(expr* a, expr* b, expr_ref& result) { + return BR_FAILED; + // disabled until made more efficient if (a == b) { result = m().mk_true(); return BR_DONE; @@ -271,6 +273,7 @@ struct evaluator_cfg : public default_rewriter_cfg { conj.push_back(m().mk_eq(else1, else2)); args1.push_back(a); args2.push_back(b); + // TBD: this is too inefficient. for (unsigned i = 0; i < stores.size(); ++i) { args1.resize(1); args1.append(stores[i].size() - 1, stores[i].c_ptr()); args2.resize(1); args2.append(stores[i].size() - 1, stores[i].c_ptr()); From 85be486c1e102784fbbd28648e89a493784037bd Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 18 May 2016 09:58:34 -0700 Subject: [PATCH 37/61] add ite reduction to canonizer, remove it from ad-hoc routine Signed-off-by: Nikolaj Bjorner --- src/smt/theory_seq.cpp | 66 ++++++++++++++++-------------------------- src/smt/theory_seq.h | 1 - 2 files changed, 25 insertions(+), 42 deletions(-) diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index 97189ce4ca7..8a1ee29461d 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -1820,22 +1820,16 @@ bool theory_seq::solve_ne(unsigned idx) { TRACE("seq", display_disequation(tout << "reduces to false: ", n);); return true; } + else if (!change) { + TRACE("seq", tout << "no change " << n.ls(i) << " " << n.rs(i) << "\n";); + if (updated) { + new_ls.push_back(n.ls(i)); + new_rs.push_back(n.rs(i)); + } + continue; + } else { - // eliminate ite expressions. - reduce_ite(lhs, new_lits, num_undef_lits, change); - reduce_ite(rhs, new_lits, num_undef_lits, change); - reduce_ite(ls, new_lits, num_undef_lits, change); - reduce_ite(rs, new_lits, num_undef_lits, change); - - if (!change) { - TRACE("seq", tout << "no change " << n.ls(i) << " " << n.rs(i) << "\n";); - if (updated) { - new_ls.push_back(n.ls(i)); - new_rs.push_back(n.rs(i)); - } - continue; - } if (!updated) { for (unsigned j = 0; j < i; ++j) { @@ -1940,32 +1934,6 @@ bool theory_seq::solve_ne(unsigned idx) { return updated; } -void theory_seq::reduce_ite(expr_ref_vector & ls, literal_vector& new_lits, unsigned& num_undef_lits, bool& change) { - expr* cond, *th, *el; - context& ctx = get_context(); - for (unsigned i = 0; i < ls.size(); ++i) { - expr* e = ls[i].get(); - if (m.is_ite(e, cond, th, el)) { - literal lit(mk_literal(cond)); - switch (ctx.get_assignment(lit)) { - case l_true: - change = true; - new_lits.push_back(lit); - ls[i] = th; - break; - case l_false: - change = true; - new_lits.push_back(~lit); - ls[i] = el; - break; - case l_undef: - ++num_undef_lits; - break; - } - } - } -} - bool theory_seq::solve_nc(unsigned idx) { nc const& n = m_ncs[idx]; @@ -2613,6 +2581,7 @@ expr_ref theory_seq::expand(expr* e0, dependency*& eqs) { } expr* e = m_rep.find(e0, deps); expr* e1, *e2, *e3; + context& ctx = get_context(); if (m_util.str.is_concat(e, e1, e2)) { result = mk_concat(expand(e1, deps), expand(e2, deps)); } @@ -2637,11 +2606,26 @@ expr_ref theory_seq::expand(expr* e0, dependency*& eqs) { else if (m_util.str.is_index(e, e1, e2, e3)) { result = m_util.str.mk_index(expand(e1, deps), expand(e2, deps), e3); } + else if (m.is_ite(e, e1, e2, e3)) { + literal lit(mk_literal(e1)); + switch (ctx.get_assignment(lit)) { + case l_true: + deps = m_dm.mk_join(deps, m_dm.mk_leaf(assumption(lit))); + result = expand(e2, deps); + break; + case l_false: + deps = m_dm.mk_join(deps, m_dm.mk_leaf(assumption(~lit))); + result = expand(e3, deps); + break; + case l_undef: + result = e; + break; + } + } else if (m_util.str.is_itos(e, e1)) { rational val; if (get_value(e1, val)) { expr_ref num(m), res(m); - context& ctx = get_context(); num = m_autil.mk_numeral(val, true); if (!ctx.e_internalized(num)) { ctx.internalize(num, false); diff --git a/src/smt/theory_seq.h b/src/smt/theory_seq.h index 8c4de211160..4107f3d059c 100644 --- a/src/smt/theory_seq.h +++ b/src/smt/theory_seq.h @@ -410,7 +410,6 @@ namespace smt { bool solve_nqs(unsigned i); bool solve_ne(unsigned i); bool solve_nc(unsigned i); - void reduce_ite(expr_ref_vector& ls, literal_vector& new_lits, unsigned& num_undef_lits, bool& change); struct cell { cell* m_parent; From 3a6e6df4f55128061fb826692a6dad2d42273244 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 18 May 2016 11:02:10 -0700 Subject: [PATCH 38/61] fix unused-but-set-variable warnings reported in #579 Signed-off-by: Nikolaj Bjorner --- src/interp/iz3translate.cpp | 1 + src/interp/iz3translate_direct.cpp | 1 + src/muz/fp/dl_cmds.cpp | 1 + src/muz/rel/karr_relation.cpp | 1 + src/sat/sat_clause.cpp | 1 + src/sat/sat_integrity_checker.cpp | 5 +++-- src/smt/diff_logic.h | 1 + src/smt/theory_arith_aux.h | 1 + src/smt/theory_fpa.cpp | 1 + src/tactic/arith/fm_tactic.cpp | 1 + src/util/mpn.cpp | 13 +++++++------ 11 files changed, 19 insertions(+), 8 deletions(-) diff --git a/src/interp/iz3translate.cpp b/src/interp/iz3translate.cpp index ebb5e00c8df..4f674198902 100755 --- a/src/interp/iz3translate.cpp +++ b/src/interp/iz3translate.cpp @@ -342,6 +342,7 @@ class iz3translation_full : public iz3translation { else cls1.push_back(cls2[j]); } + (void)found_pivot2; assert(found_pivot2); return; } diff --git a/src/interp/iz3translate_direct.cpp b/src/interp/iz3translate_direct.cpp index f20f16a082c..95d66f61788 100755 --- a/src/interp/iz3translate_direct.cpp +++ b/src/interp/iz3translate_direct.cpp @@ -362,6 +362,7 @@ class iz3translation_direct : public iz3translation { else cls1.push_back(cls2[j]); } + (void)found_pivot2; assert(found_pivot2); return; } diff --git a/src/muz/fp/dl_cmds.cpp b/src/muz/fp/dl_cmds.cpp index e8e93dafc62..049c34343c0 100644 --- a/src/muz/fp/dl_cmds.cpp +++ b/src/muz/fp/dl_cmds.cpp @@ -300,6 +300,7 @@ class dl_query_cmd : public parametric_cmd { break; case datalog::OK: + (void)query_exn; SASSERT(query_exn); break; diff --git a/src/muz/rel/karr_relation.cpp b/src/muz/rel/karr_relation.cpp index 3b9198dc640..0baa297bc31 100644 --- a/src/muz/rel/karr_relation.cpp +++ b/src/muz/rel/karr_relation.cpp @@ -173,6 +173,7 @@ namespace datalog { else { processed = false; } + (void)processed; TRACE("dl", tout << (processed?"+ ":"- ") << mk_pp(e, m) << "\n"; if (processed) matrix::display_ineq(tout, row, M.b.back(), M.eq.back()); ); diff --git a/src/sat/sat_clause.cpp b/src/sat/sat_clause.cpp index 2881c03aeb2..eabc4fdb1f7 100644 --- a/src/sat/sat_clause.cpp +++ b/src/sat/sat_clause.cpp @@ -52,6 +52,7 @@ namespace sat { bool clause::check_approx() const { var_approx_set curr = m_approx; + (void)curr; const_cast(this)->update_approx(); SASSERT(may_eq(curr, m_approx)); return true; diff --git a/src/sat/sat_integrity_checker.cpp b/src/sat/sat_integrity_checker.cpp index ac2a51c4dd3..c60fb86cb3c 100644 --- a/src/sat/sat_integrity_checker.cpp +++ b/src/sat/sat_integrity_checker.cpp @@ -159,7 +159,8 @@ namespace sat { for (unsigned l_idx = 0; it != end; ++it, ++l_idx) { literal l = ~to_literal(l_idx); watch_list const & wlist = *it; - CTRACE("sat_bug", s.was_eliminated(l.var()) && !wlist.empty(), + CTRACE("sat_bug", + s.was_eliminated(l.var()) && !wlist.empty(), tout << "l: " << l << "\n"; s.display_watches(tout); s.display(tout);); @@ -179,7 +180,7 @@ namespace sat { tout << "\n"; sat::display(tout, s.m_cls_allocator, s.get_wlist(~(it2->get_literal()))); tout << "\n";); - SASSERT(s.get_wlist(~(it2->get_literal())).contains(watched(l, it2->is_learned()))); + SASSERT(s.get_wlist(~(it2->get_literal())).contains(watched(l, it2->is_learned()))); break; case watched::TERNARY: SASSERT(!s.was_eliminated(it2->get_literal1().var())); diff --git a/src/smt/diff_logic.h b/src/smt/diff_logic.h index daaed13ac59..f55945ce47d 100644 --- a/src/smt/diff_logic.h +++ b/src/smt/diff_logic.h @@ -739,6 +739,7 @@ class dl_graph { if (idx2 < idx1) { std::swap(idx1,idx2); } + (void) max_idx; SASSERT(idx1 < idx2 && idx2 < edges.size()); SASSERT(max_idx < edges.size()); dst = get_source(edges[idx2]); diff --git a/src/smt/theory_arith_aux.h b/src/smt/theory_arith_aux.h index 88676b4d957..163452d47c4 100644 --- a/src/smt/theory_arith_aux.h +++ b/src/smt/theory_arith_aux.h @@ -1342,6 +1342,7 @@ namespace smt { tout << "v" << x_i << " "; tout << (has_shared?"shared":"not shared") << "\n";); + (void) empty_column; SASSERT(!safe_gain(min_gain, max_gain) || empty_column || (unbounded_gain(max_gain) == (x_i == null_theory_var))); diff --git a/src/smt/theory_fpa.cpp b/src/smt/theory_fpa.cpp index 59bcf40e886..eecf97069c5 100644 --- a/src/smt/theory_fpa.cpp +++ b/src/smt/theory_fpa.cpp @@ -276,6 +276,7 @@ namespace smt { SASSERT(r && bv_sz == m_ebits); r = m_bu.is_numeral(values[2], sig_r, bv_sz); SASSERT(r && bv_sz == m_sbits - 1); + (void)r; SASSERT(mpzm.is_one(sgn_r.to_mpq().denominator())); SASSERT(mpzm.is_one(exp_r.to_mpq().denominator())); diff --git a/src/tactic/arith/fm_tactic.cpp b/src/tactic/arith/fm_tactic.cpp index 698128e2676..eae3ab5e6e9 100644 --- a/src/tactic/arith/fm_tactic.cpp +++ b/src/tactic/arith/fm_tactic.cpp @@ -156,6 +156,7 @@ class fm_tactic : public tactic { r = c; } } + (void)found; SASSERT(found); return is_lower ? LOWER : UPPER; } diff --git a/src/util/mpn.cpp b/src/util/mpn.cpp index 0c1744a09ff..ea2a60627ee 100644 --- a/src/util/mpn.cpp +++ b/src/util/mpn.cpp @@ -280,7 +280,6 @@ bool mpn_manager::div_1(mpn_sbuffer & numer, mpn_digit const denom, for (size_t j = numer.size()-1; j > 0; j--) { temp = (((mpn_double_digit)numer[j]) << DIGIT_BITS) | ((mpn_double_digit)numer[j-1]); q_hat = temp / (mpn_double_digit) denom; - r_hat = temp % (mpn_double_digit) denom; if (q_hat >= BASE) { UNREACHABLE(); // is this reachable with normalized v? } @@ -294,11 +293,13 @@ bool mpn_manager::div_1(mpn_sbuffer & numer, mpn_digit const denom, quot[j-1]--; numer[j] = numer[j-1] + denom; } - TRACE("mpn_div1", tout << "j=" << j << " q_hat=" << q_hat << " r_hat=" << r_hat; - tout << " ms=" << ms; - tout << " new numer="; display_raw(tout, numer.c_ptr(), numer.size()); - tout << " borrow=" << borrow; - tout << std::endl; ); + TRACE("mpn_div1", + r_hat = temp % (mpn_double_digit) denom; + tout << "j=" << j << " q_hat=" << q_hat << " r_hat=" << r_hat; + tout << " ms=" << ms; + tout << " new numer="; display_raw(tout, numer.c_ptr(), numer.size()); + tout << " borrow=" << borrow; + tout << std::endl; ); } return true; // return rem != 0? From d2622da7479490b61172d34b4b04cb10a898b6b1 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 18 May 2016 11:03:31 -0700 Subject: [PATCH 39/61] fix unused-but-set-variable warnings reported in #579 Signed-off-by: Nikolaj Bjorner --- src/util/mpn.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/util/mpn.cpp b/src/util/mpn.cpp index ea2a60627ee..df69ce76d99 100644 --- a/src/util/mpn.cpp +++ b/src/util/mpn.cpp @@ -274,7 +274,7 @@ void mpn_manager::div_unnormalize(mpn_sbuffer & numer, mpn_sbuffer & denom, bool mpn_manager::div_1(mpn_sbuffer & numer, mpn_digit const denom, mpn_digit * quot) const { - mpn_double_digit q_hat, temp, r_hat, ms; + mpn_double_digit q_hat, temp, ms; mpn_digit borrow; for (size_t j = numer.size()-1; j > 0; j--) { @@ -294,7 +294,7 @@ bool mpn_manager::div_1(mpn_sbuffer & numer, mpn_digit const denom, numer[j] = numer[j-1] + denom; } TRACE("mpn_div1", - r_hat = temp % (mpn_double_digit) denom; + mpn_double_digit r_hat = temp % (mpn_double_digit) denom; tout << "j=" << j << " q_hat=" << q_hat << " r_hat=" << r_hat; tout << " ms=" << ms; tout << " new numer="; display_raw(tout, numer.c_ptr(), numer.size()); From 1aa3fdab8a0ba97ecebac2110a2b4e5fb08a6edc Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 19 May 2016 13:04:20 -0700 Subject: [PATCH 40/61] remove min/max, use qmax; disable cancellation during model evaluation Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/rewriter.cpp | 1 + src/ast/rewriter/rewriter.h | 2 + src/ast/rewriter/rewriter_def.h | 4 +- src/model/model_evaluator.cpp | 1 + src/opt/opt_cmds.cpp | 69 -------------- src/opt/opt_context.cpp | 15 +-- src/opt/opt_context.h | 1 - src/opt/opt_solver.cpp | 4 + src/qe/qe_arith.cpp | 6 +- src/qe/qsat.cpp | 138 +-------------------------- src/qe/qsat.h | 11 --- src/tactic/arith/lia2card_tactic.cpp | 1 + 12 files changed, 19 insertions(+), 234 deletions(-) diff --git a/src/ast/rewriter/rewriter.cpp b/src/ast/rewriter/rewriter.cpp index 2b5e7e006bd..c7b110dff68 100644 --- a/src/ast/rewriter/rewriter.cpp +++ b/src/ast/rewriter/rewriter.cpp @@ -173,6 +173,7 @@ void rewriter_core::elim_reflex_prs(unsigned spos) { rewriter_core::rewriter_core(ast_manager & m, bool proof_gen): m_manager(m), m_proof_gen(proof_gen), + m_cancel_check(true), m_result_stack(m), m_result_pr_stack(m), m_num_qvars(0) { diff --git a/src/ast/rewriter/rewriter.h b/src/ast/rewriter/rewriter.h index 44f436fa898..401d00d8997 100644 --- a/src/ast/rewriter/rewriter.h +++ b/src/ast/rewriter/rewriter.h @@ -48,6 +48,7 @@ class rewriter_core { }; ast_manager & m_manager; bool m_proof_gen; + bool m_cancel_check; typedef act_cache cache; ptr_vector m_cache_stack; cache * m_cache; // current cache. @@ -114,6 +115,7 @@ class rewriter_core { ast_manager & m() const { return m_manager; } void reset(); void cleanup(); + void set_cancel_check(bool f) { m_cancel_check = f; } #ifdef _TRACE void display_stack(std::ostream & out, unsigned pp_depth); #endif diff --git a/src/ast/rewriter/rewriter_def.h b/src/ast/rewriter/rewriter_def.h index 4d55632d3e7..eaf5713ee1d 100644 --- a/src/ast/rewriter/rewriter_def.h +++ b/src/ast/rewriter/rewriter_def.h @@ -595,7 +595,7 @@ void rewriter_tpl::set_inv_bindings(unsigned num_bindings, expr * const template template void rewriter_tpl::main_loop(expr * t, expr_ref & result, proof_ref & result_pr) { - if (m().canceled()) { + if (m_cancel_check && m().canceled()) { throw rewriter_exception(m().limit().get_cancel_msg()); } SASSERT(!ProofGen || result_stack().size() == result_pr_stack().size()); @@ -629,7 +629,7 @@ template void rewriter_tpl::resume_core(expr_ref & result, proof_ref & result_pr) { SASSERT(!frame_stack().empty()); while (!frame_stack().empty()) { - if (m().canceled()) { + if (m_cancel_check && m().canceled()) { throw rewriter_exception(m().limit().get_cancel_msg()); } SASSERT(!ProofGen || result_stack().size() == result_pr_stack().size()); diff --git a/src/model/model_evaluator.cpp b/src/model/model_evaluator.cpp index c83da205032..74f6a18c1a4 100644 --- a/src/model/model_evaluator.cpp +++ b/src/model/model_evaluator.cpp @@ -365,6 +365,7 @@ struct model_evaluator::imp : public rewriter_tpl { false, // no proofs for evaluator m_cfg), m_cfg(md.get_manager(), md, p) { + set_cancel_check(false); } }; diff --git a/src/opt/opt_cmds.cpp b/src/opt/opt_cmds.cpp index f8f78835cc1..8822f4e77ba 100644 --- a/src/opt/opt_cmds.cpp +++ b/src/opt/opt_cmds.cpp @@ -137,81 +137,12 @@ class min_maximize_cmd : public cmd { } }; -class alternate_min_max_cmd : public cmd { - app_ref_vector* m_vars; - svector m_is_max; - unsigned m_position; - - app_ref_vector& vars(cmd_context& ctx) { - if (!m_vars) { - m_vars = alloc(app_ref_vector, ctx.m()); - } - return *m_vars; - } -public: - alternate_min_max_cmd(): - cmd("min-max"), - m_vars(0), - m_position(0) - {} - - virtual void reset(cmd_context & ctx) { - dealloc(m_vars); - m_vars = 0; - m_is_max.reset(); - m_position = 0; - } - virtual char const * get_usage() const { return "(min | max | var)+ "; } - virtual char const * get_descr(cmd_context & ctx) const { return "check sat modulo alternating min-max objectives";} - virtual unsigned get_arity() const { return 2; } - virtual void prepare(cmd_context & ctx) {} - virtual cmd_arg_kind next_arg_kind(cmd_context & ctx) const { - switch (m_position) { - case 0: return CPK_SYMBOL_LIST; - case 1: return CPK_EXPR; - default: return CPK_SYMBOL; - } - } - - virtual void set_next_arg(cmd_context & ctx, unsigned num, symbol const * slist) { - bool is_max = false; - for (unsigned i = 0; i < num; ++i) { - if (slist[i] == symbol("max")) { - is_max = true; - } - else if (slist[i] == symbol("min")) { - is_max = false; - } - else { - m_is_max.push_back(is_max); - vars(ctx).push_back(ctx.m().mk_const(ctx.find_func_decl(slist[i]))); - } - } - ++m_position; - } - - virtual void set_next_arg(cmd_context & ctx, expr * t) { - if (!is_app(t)) { - throw cmd_exception("malformed objective term: it cannot be a quantifier or bound variable"); - } - ++m_position; - get_opt(ctx).min_max(to_app(t), vars(ctx), m_is_max); - reset(ctx); - } - - virtual void failure_cleanup(cmd_context & ctx) { - reset(ctx); - } - - virtual void execute(cmd_context & ctx) { } -}; void install_opt_cmds(cmd_context & ctx) { ctx.insert(alloc(assert_soft_cmd)); ctx.insert(alloc(min_maximize_cmd, true)); ctx.insert(alloc(min_maximize_cmd, false)); - ctx.insert(alloc(alternate_min_max_cmd)); } diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 0c19e7987c6..fccdf9b55bf 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -212,18 +212,6 @@ namespace opt { m_hard_constraints.append(s.m_hard); } - lbool context::min_max(app* t, app_ref_vector const& vars, svector const& is_max) { - clear_state(); - init_solver(); - import_scoped_state(); - normalize(); - internalize(); - qe::max_min_opt max_min(m, m_params); - max_min.add(m_hard_constraints); - return max_min.check(is_max, vars, t); - } - - lbool context::optimize() { if (m_pareto) { return execute_pareto(); @@ -236,12 +224,12 @@ namespace opt { import_scoped_state(); normalize(); internalize(); + update_solver(); #if 0 if (is_qsat_opt()) { return run_qsat_opt(); } #endif - update_solver(); solver& s = get_solver(); s.assert_expr(m_hard_constraints); display_benchmark(); @@ -1473,6 +1461,7 @@ namespace opt { value.neg(); } if (result != l_undef) { + m_optsmt.setup(*m_opt_solver.get()); m_optsmt.update_lower(obj.m_index, value); m_optsmt.update_upper(obj.m_index, value); } diff --git a/src/opt/opt_context.h b/src/opt/opt_context.h index b7dceb67448..3339dc37ac8 100644 --- a/src/opt/opt_context.h +++ b/src/opt/opt_context.h @@ -172,7 +172,6 @@ namespace opt { virtual ~context(); unsigned add_soft_constraint(expr* f, rational const& w, symbol const& id); unsigned add_objective(app* t, bool is_max); - lbool min_max(app* t, app_ref_vector const& vars, svector const& is_max); void add_hard_constraint(expr* f); diff --git a/src/opt/opt_solver.cpp b/src/opt/opt_solver.cpp index eff70e48e65..fccc7fa1c5d 100644 --- a/src/opt/opt_solver.cpp +++ b/src/opt/opt_solver.cpp @@ -344,6 +344,10 @@ namespace opt { } expr_ref opt_solver::mk_ge(unsigned var, inf_eps const& val) { + if (!val.is_finite()) + { + return expr_ref(val.is_pos() ? m.mk_false() : m.mk_true(), m); + } smt::theory_opt& opt = get_optimizer(); smt::theory_var v = m_objective_vars[var]; diff --git a/src/qe/qe_arith.cpp b/src/qe/qe_arith.cpp index 58a290c0b7f..48dacdbf4df 100644 --- a/src/qe/qe_arith.cpp +++ b/src/qe/qe_arith.cpp @@ -24,9 +24,9 @@ Revision History: #include "ast_util.h" #include "arith_decl_plugin.h" #include "ast_pp.h" +#include "model_v2_pp.h" #include "th_rewriter.h" #include "expr_functors.h" -#include "model_v2_pp.h" #include "expr_safe_replace.h" #include "model_based_opt.h" @@ -103,19 +103,19 @@ namespace qe { expr_ref t(m); opt::ineq_type ty = opt::t_le; expr* e1, *e2; + DEBUG_CODE(expr_ref val(m); VERIFY(model.eval(lit, val) && m.is_true(val));); + bool is_not = m.is_not(lit, lit); if (is_not) { mul.neg(); } SASSERT(!m.is_not(lit)); if (a.is_le(lit, e1, e2) || a.is_ge(lit, e2, e1)) { - if (is_not) mul.neg(); linearize(mbo, model, mul, e1, c, ts, tids); linearize(mbo, model, -mul, e2, c, ts, tids); ty = is_not ? opt::t_lt : opt::t_le; } else if (a.is_lt(lit, e1, e2) || a.is_gt(lit, e2, e1)) { - if (is_not) mul.neg(); linearize(mbo, model, mul, e1, c, ts, tids); linearize(mbo, model, -mul, e2, c, ts, tids); ty = is_not ? opt::t_le: opt::t_lt; diff --git a/src/qe/qsat.cpp b/src/qe/qsat.cpp index 73f6a9d4ca1..fe11de1997d 100644 --- a/src/qe/qsat.cpp +++ b/src/qe/qsat.cpp @@ -618,7 +618,7 @@ namespace qe { } kernel& get_kernel(unsigned j) { - if (m_kernel_ex || is_exists(j)) { + if (is_exists(j)) { return m_ex; } else { @@ -735,11 +735,7 @@ namespace qe { void display(std::ostream& out) const { out << "level: " << m_level << "\n"; for (unsigned i = 0; i < m_vars.size(); ++i) { - for (unsigned j = 0; j < m_vars[i].size(); ++j) { - expr* v = m_vars[i][j]; - out << mk_pp(v, m) << " "; - } - out << "\n"; + out << m_vars[i] << "\n"; } m_pred_abs.display(out); } @@ -1070,8 +1066,7 @@ namespace qe { m_level(0), m_mode(mode), m_avars(m), - m_free_vars(m), - m_kernel_ex(false) + m_free_vars(m) { reset(); } @@ -1238,90 +1233,6 @@ namespace qe { } - bool m_kernel_ex; - - lbool max_min(expr_ref_vector const& fmls, svector const& is_max, app_ref_vector const& vars, app* t) { - m_kernel_ex = true; - // Assume this is the only call to check. - expr_ref_vector defs(m); - app_ref_vector free_vars(m), vars1(m); - expr_ref fml = mk_and(fmls); - m_pred_abs.get_free_vars(fml, free_vars); - m_pred_abs.abstract_atoms(fml, defs); - fml = m_pred_abs.mk_abstract(fml); - get_kernel(0).k().assert_expr(mk_and(defs)); - get_kernel(0).k().assert_expr(fml); - obj_hashtable var_set; - for (unsigned i = 0; i < vars.size(); ++i) { - var_set.insert(vars[i]); - } - for (unsigned i = 0; i < free_vars.size(); ++i) { - app* v = free_vars[i].get(); - if (!var_set.contains(v)) { - vars1.push_back(v); - } - } - // - // Insert all variables in alternating list of max/min objectives. - // By convention, the outer-most level is max. - // - bool is_m = true; - for (unsigned i = 0; i < vars.size(); ++i) { - if (is_m != is_max[i]) { - m_vars.push_back(vars1); - vars1.reset(); - is_m = is_max[i]; - } - vars1.push_back(vars[i]); - } - m_vars.push_back(vars1); - - return max_min(); - } - - lbool max_min() { - while (true) { - ++m_stats.m_num_rounds; - check_cancel(); - expr_ref_vector asms(m_asms); - m_pred_abs.get_assumptions(m_model.get(), asms); - // - // TBD: add bound to asms. - // - smt::kernel& k = get_kernel(m_level).k(); - lbool res = k.check(asms); - switch (res) { - case l_true: - k.get_model(m_model); - SASSERT(validate_model(asms)); - TRACE("qe", k.display(tout); display(tout << "\n", *m_model.get()); display(tout, asms); ); - // - // TBD: compute new bound on objective. - // - push(); - break; - case l_false: - switch (m_level) { - case 0: return l_false; - case 1: - // TBD - break; - default: - if (m_model.get()) { - project(asms); - } - else { - pop(1); - } - break; - } - break; - case l_undef: - return res; - } - } - return l_undef; - } }; @@ -1331,49 +1242,6 @@ namespace qe { return qs.maximize(fmls, t, mdl, value); } - - struct max_min_opt::imp { - - expr_ref_vector m_fmls; - qsat m_qsat; - - imp(ast_manager& m, params_ref const& p): - m_fmls(m), - m_qsat(m, p, qsat_maximize) - {} - - void add(expr* e) { - m_fmls.push_back(e); - } - - lbool check(svector const& is_max, app_ref_vector const& vars, app* t) { - return m_qsat.max_min(m_fmls, is_max, vars, t); - } - - }; - - max_min_opt::max_min_opt(ast_manager& m, params_ref const& p) { - m_imp = alloc(imp, m, p); - } - - max_min_opt::~max_min_opt() { - dealloc(m_imp); - } - - void max_min_opt::add(expr* e) { - m_imp->add(e); - } - - void max_min_opt::add(expr_ref_vector const& fmls) { - for (unsigned i = 0; i < fmls.size(); ++i) { - add(fmls[i]); - } - } - - lbool max_min_opt::check(svector const& is_max, app_ref_vector const& vars, app* t) { - return m_imp->check(is_max, vars, t); - } - }; tactic * mk_qsat_tactic(ast_manager& m, params_ref const& p) { diff --git a/src/qe/qsat.h b/src/qe/qsat.h index 59cf6d8a081..456711c4f3b 100644 --- a/src/qe/qsat.h +++ b/src/qe/qsat.h @@ -114,17 +114,6 @@ namespace qe { void collect_statistics(statistics& st) const; }; - class max_min_opt { - struct imp; - imp* m_imp; - public: - max_min_opt(ast_manager& m, params_ref const& p = params_ref()); - ~max_min_opt(); - void add(expr* e); - void add(expr_ref_vector const& fmls); - lbool check(svector const& is_max, app_ref_vector const& vars, app* t); - }; - lbool maximize(expr_ref_vector const& fmls, app* t, opt::inf_eps& value, model_ref& mdl, params_ref const& p); } diff --git a/src/tactic/arith/lia2card_tactic.cpp b/src/tactic/arith/lia2card_tactic.cpp index f36a93e6d1b..7256d19c731 100644 --- a/src/tactic/arith/lia2card_tactic.cpp +++ b/src/tactic/arith/lia2card_tactic.cpp @@ -300,6 +300,7 @@ class lia2card_tactic : public tactic { bool get_sum(expr* x, rational const& mul, expr_ref_vector& conds, expr_ref_vector& args, vector& coeffs, rational& coeff) { expr *y, *z, *u; rational r, q; + if (!is_app(x)) return false; app* f = to_app(x); bool ok = true; if (a.is_add(x)) { From d12efb6097c07cbdb64487b99f376c995ec2ed49 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 19 May 2016 13:10:43 -0700 Subject: [PATCH 41/61] remove min/max, use qmax; disable cancellation during model evaluation Signed-off-by: Nikolaj Bjorner --- src/tactic/arith/lia2card_tactic.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tactic/arith/lia2card_tactic.cpp b/src/tactic/arith/lia2card_tactic.cpp index 7256d19c731..4c2e0deadc8 100644 --- a/src/tactic/arith/lia2card_tactic.cpp +++ b/src/tactic/arith/lia2card_tactic.cpp @@ -300,7 +300,7 @@ class lia2card_tactic : public tactic { bool get_sum(expr* x, rational const& mul, expr_ref_vector& conds, expr_ref_vector& args, vector& coeffs, rational& coeff) { expr *y, *z, *u; rational r, q; - if (!is_app(x)) return false; + if (!is_app(x)) return false; app* f = to_app(x); bool ok = true; if (a.is_add(x)) { From 80731ef364cd7f89e98b3fc452c9cc453880b87d Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Fri, 20 May 2016 19:40:45 +0100 Subject: [PATCH 42/61] Exposed OP_FPA_MIN/MAX_I to the API --- src/api/api_ast.cpp | 6 +++--- src/api/z3_api.h | 3 +++ 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/api/api_ast.cpp b/src/api/api_ast.cpp index 9aea9d6f474..1e421cb2e98 100644 --- a/src/api/api_ast.cpp +++ b/src/api/api_ast.cpp @@ -1183,10 +1183,10 @@ extern "C" { case OP_FPA_TO_SBV: return Z3_OP_FPA_TO_SBV; case OP_FPA_TO_REAL: return Z3_OP_FPA_TO_REAL; case OP_FPA_TO_IEEE_BV: return Z3_OP_FPA_TO_IEEE_BV; + case OP_FPA_INTERNAL_MIN_I: return Z3_OP_FPA_MIN_I; + case OP_FPA_INTERNAL_MAX_I: return Z3_OP_FPA_MAX_I; + case OP_FPA_INTERNAL_RM_BVWRAP: case OP_FPA_INTERNAL_BVWRAP: - case OP_FPA_INTERNAL_BVUNWRAP: - case OP_FPA_INTERNAL_MIN_I: - case OP_FPA_INTERNAL_MAX_I: case OP_FPA_INTERNAL_MIN_UNSPECIFIED: case OP_FPA_INTERNAL_MAX_UNSPECIFIED: case OP_FPA_INTERNAL_TO_UBV_UNSPECIFIED: diff --git a/src/api/z3_api.h b/src/api/z3_api.h index 9d89bc9572a..114490015f3 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -1214,6 +1214,9 @@ typedef enum { Z3_OP_FPA_TO_IEEE_BV, + Z3_OP_FPA_MIN_I, + Z3_OP_FPA_MAX_I, + Z3_OP_UNINTERPRETED } Z3_decl_kind; From 1cc8146ababfc9231856e97ecbe33d64d3c3f75e Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Fri, 20 May 2016 19:53:57 +0100 Subject: [PATCH 43/61] Bugfixes for FP UFs and arrays. --- src/ast/fpa/fpa2bv_converter.cpp | 244 ++++++++++++----- src/ast/fpa/fpa2bv_converter.h | 9 +- src/ast/fpa/fpa2bv_rewriter.cpp | 10 +- src/ast/fpa_decl_plugin.cpp | 24 +- src/ast/fpa_decl_plugin.h | 22 +- src/ast/rewriter/fpa_rewriter.cpp | 20 +- src/smt/theory_fpa.cpp | 319 +++++++--------------- src/smt/theory_fpa.h | 5 +- src/tactic/fpa/fpa2bv_model_converter.cpp | 254 +++++++++-------- src/tactic/fpa/fpa2bv_model_converter.h | 40 ++- 10 files changed, 494 insertions(+), 453 deletions(-) diff --git a/src/ast/fpa/fpa2bv_converter.cpp b/src/ast/fpa/fpa2bv_converter.cpp index e6b9dda07b5..d5849a1fd6c 100644 --- a/src/ast/fpa/fpa2bv_converter.cpp +++ b/src/ast/fpa/fpa2bv_converter.cpp @@ -77,8 +77,8 @@ void fpa2bv_converter::mk_eq(expr * a, expr * b, expr_ref & result) { m_simp.mk_or(both_are_nan, both_the_same, result); } else if (is_rm(a) && is_rm(b)) { - SASSERT(is_app_of(a, m_plugin->get_family_id(), OP_FPA_INTERNAL_RM)); - SASSERT(is_app_of(b, m_plugin->get_family_id(), OP_FPA_INTERNAL_RM)); + SASSERT(m_util.is_rm_bvwrap(b)); + SASSERT(m_util.is_rm_bvwrap(a)); TRACE("fpa2bv", tout << "mk_eq_rm a=" << mk_ismt2_pp(a, m) << std::endl; tout << "mk_eq_rm b=" << mk_ismt2_pp(b, m) << std::endl;); @@ -221,14 +221,14 @@ void fpa2bv_converter::mk_var(unsigned base_inx, sort * srt, expr_ref & result) mk_fp(sgn, e, s, result); } -void fpa2bv_converter::mk_uninterpreted_output(sort * rng, func_decl * fbv, expr_ref_buffer & new_args, expr_ref & result) { +void fpa2bv_converter::mk_function_output(sort * rng, func_decl * fbv, expr * const * new_args, expr_ref & result) { if (m_util.is_float(rng)) { unsigned ebits = m_util.get_ebits(rng); unsigned sbits = m_util.get_sbits(rng); unsigned bv_sz = ebits + sbits; app_ref na(m); - na = m.mk_app(fbv, new_args.size(), new_args.c_ptr()); + na = m.mk_app(fbv, fbv->get_arity(), new_args); mk_fp(m_bv_util.mk_extract(bv_sz - 1, bv_sz - 1, na), m_bv_util.mk_extract(bv_sz - 2, sbits - 1, na), m_bv_util.mk_extract(sbits - 2, 0, na), @@ -236,71 +236,171 @@ void fpa2bv_converter::mk_uninterpreted_output(sort * rng, func_decl * fbv, expr } else if (m_util.is_rm(rng)) { app_ref na(m); - na = m.mk_app(fbv, new_args.size(), new_args.c_ptr()); + na = m.mk_app(fbv, fbv->get_arity(), new_args); mk_rm(na, result); } else - result = m.mk_app(fbv, new_args.size(), new_args.c_ptr()); + result = m.mk_app(fbv, fbv->get_arity(), new_args); } -void fpa2bv_converter::mk_uninterpreted_function(func_decl * f, unsigned num, expr * const * args, expr_ref & result) -{ - TRACE("fpa2bv", tout << "UF: " << mk_ismt2_pp(f, m) << std::endl; ); - SASSERT(f->get_arity() == num); +sort_ref fpa2bv_converter::replace_float_sorts(sort * s) { + sort_ref ns(m); - expr_ref_buffer new_args(m); - - for (unsigned i = 0; i < num; i++) { - if (is_float(args[i])) { - expr * sgn, *exp, *sig; - split_fp(args[i], sgn, exp, sig); - expr * args[3] = { sgn, exp, sig }; - new_args.push_back(m_bv_util.mk_concat(3, args)); - } - else if (is_rm(args[i])) { - SASSERT(is_app_of(args[i], m_util.get_family_id(), OP_FPA_INTERNAL_RM)); - new_args.push_back(to_app(args[i])->get_arg(0)); + if (m_util.is_float(s)) + ns = m_bv_util.mk_sort(m_util.get_sbits(s) + m_util.get_ebits(s)); + else if (m_util.is_rm(s)) + ns = m_bv_util.mk_sort(3); + else + ns = s; + + if (ns->get_num_parameters() != 0) { + vector new_params; + unsigned num_params = ns->get_num_parameters(); + for (unsigned i = 0; i < num_params; i++) + { + parameter const & pi = ns->get_parameter(i); + if (pi.is_ast() && pi.get_ast()->get_kind() == AST_SORT) { + sort_ref nsrt(m); + nsrt = replace_float_sorts(to_sort(pi.get_ast())); + parameter np = parameter((ast*)nsrt); + new_params.push_back(np); + } + else + new_params.push_back(pi); } - else - new_args.push_back(args[i]); + + TRACE("fpa2bv", tout << "New sort params:"; + for (unsigned i = 0; i < new_params.size(); i++) + tout << " " << new_params[i]; + tout << std::endl;); + + ns = m.mk_sort(ns->get_family_id(), ns->get_decl_kind(), new_params.size(), new_params.c_ptr()); + } + + TRACE("fpa2bv", tout << "sorts replaced: " << mk_ismt2_pp(s, m) << " --> " << mk_ismt2_pp(ns, m) << std::endl; ); + return ns; +} + +func_decl_ref fpa2bv_converter::replace_function(func_decl * f) { + TRACE("fpa2bv", tout << "replacing: " << mk_ismt2_pp(f, m) << std::endl;); + func_decl_ref res(m); + + sort_ref_buffer new_domain(m); + for (unsigned i = 0; i < f->get_arity(); i++) { + sort * di = f->get_domain()[i]; + new_domain.push_back(replace_float_sorts(di)); } func_decl * fd; if (m_uf2bvuf.find(f, fd)) - mk_uninterpreted_output(f->get_range(), fd, new_args, result); + res = fd; else { - sort_ref_buffer new_domain(m); - - for (unsigned i = 0; i < f->get_arity(); i++) { - sort * di = f->get_domain()[i]; - if (is_float(di)) - new_domain.push_back(m_bv_util.mk_sort(m_util.get_sbits(di) + m_util.get_ebits(di))); - else if (is_rm(di)) - new_domain.push_back(m_bv_util.mk_sort(3)); - else - new_domain.push_back(di); - } + sort_ref new_range(m); + new_range = replace_float_sorts(f->get_range()); + + if (f->get_family_id() == null_family_id) { + res = m.mk_fresh_func_decl(f->get_name(), symbol("bv"), new_domain.size(), new_domain.c_ptr(), new_range); + TRACE("fpa2bv", tout << "New UF func_decl: " << std::endl << mk_ismt2_pp(res, m) << std::endl;); - sort * orig_rng = f->get_range(); - sort_ref rng(orig_rng, m); - if (m_util.is_float(orig_rng)) - rng = m_bv_util.mk_sort(m_util.get_ebits(orig_rng) + m_util.get_sbits(orig_rng)); - else if (m_util.is_rm(orig_rng)) - rng = m_bv_util.mk_sort(3); + m_uf2bvuf.insert(f, res); + m.inc_ref(f); + m.inc_ref(res); + } + else + { + TRACE("fpa2bv", tout << "New domain:"; + for (unsigned i = 0; i < new_domain.size(); i++) + tout << " " << mk_ismt2_pp(new_domain[i], m); + tout << std::endl;); + + res = m.mk_func_decl(f->get_family_id(), f->get_decl_kind(), + f->get_num_parameters(), f->get_parameters(), + new_domain.size(), new_domain.c_ptr(), new_range); + TRACE("fpa2bv", tout << "New IF func_decl: " << mk_ismt2_pp(res, m) << std::endl;); + } + } - func_decl_ref fbv(m); - fbv = m.mk_fresh_func_decl(new_domain.size(), new_domain.c_ptr(), rng); - TRACE("fpa2bv", tout << "New UF func_decl : " << mk_ismt2_pp(fbv, m) << std::endl;); + return res; +} - m_uf2bvuf.insert(f, fbv); - m.inc_ref(f); - m.inc_ref(fbv); +expr_ref fpa2bv_converter::replace_float_arg(expr * a) { + expr_ref na(m); - mk_uninterpreted_output(f->get_range(), fbv, new_args, result); + switch (a->get_kind()) { + case AST_APP: + if (m_util.is_float(a)) { + SASSERT(m_util.is_fp(a)); + expr * sgn, *exp, *sig; + split_fp(a, sgn, exp, sig); + expr * args[3] = { sgn, exp, sig }; + na = m_bv_util.mk_concat(3, args); + } + else if (is_rm(a)) { + SASSERT(m_util.is_rm_bvwrap(a)); + na = to_app(a)->get_arg(0); + } + else if (m.is_value(a)) + na = a; + else { + sort_ref ns(m); + app_ref ar(m); + ar = to_app(a); + func_decl * f = to_app(ar)->get_decl(); + func_decl_ref rf(m); + rf = replace_function(f); + na = m.mk_app(rf, ar->get_num_args(), ar->get_args()); + } + break; + case AST_VAR: + na = m.mk_var(to_var(a)->get_idx(), replace_float_sorts(m.get_sort(a))); + break; + case AST_QUANTIFIER: { + quantifier * q = to_quantifier(a); + sort * const * srts = q->get_decl_sorts(); + vector new_sorts; + for (unsigned i = 0; q->get_num_decls(); i++) { + sort_ref ns(m); + ns = replace_float_sorts(q->get_decl_sort(i)); + new_sorts.push_back(ns); + } + na = m.mk_quantifier(q->is_forall(), + q->get_num_decls(), new_sorts.c_ptr(), + q->get_decl_names(), q->get_expr(), + q->get_weight(), q->get_qid(), q->get_skid(), + q->get_num_patterns(), q->get_patterns(), + q->get_num_no_patterns(), q->get_no_patterns()); + break; + } + case AST_SORT: + case AST_FUNC_DECL: + default: + UNREACHABLE(); } - TRACE("fpa2bv", tout << "UF result: " << mk_ismt2_pp(result, m) << std::endl; ); + TRACE("fpa2bv", tout << "arg replaced: " << mk_ismt2_pp(a, m) << " --> " << mk_ismt2_pp(na, m) << std::endl; ); + return na; +} + +void fpa2bv_converter::mk_function(func_decl * f, unsigned num, expr * const * args, expr_ref & result) +{ + TRACE("fpa2bv", tout << "UF: " << mk_ismt2_pp(f, m) << std::endl; ); + SASSERT(f->get_arity() == num); + expr_ref_buffer new_args(m); + + for (unsigned i = 0; i < num; i++) + new_args.push_back(replace_float_arg(args[i])); + + TRACE("fpa2bv", tout << "UF bv-args:"; + for (unsigned i = 0; i < num; i++) + tout << " " << mk_ismt2_pp(new_args[i], m); + tout << std::endl; ); + + func_decl_ref rf(m); + rf = replace_function(f); + mk_function_output(f->get_range(), rf, new_args.c_ptr(), result); + + TRACE("fpa2bv", tout << "UF result: " << mk_ismt2_pp(result, m) << std::endl; ); SASSERT(is_well_sorted(m, result)); } @@ -548,7 +648,7 @@ void fpa2bv_converter::add_core(unsigned sbits, unsigned ebits, void fpa2bv_converter::mk_add(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { SASSERT(num == 3); - SASSERT(is_app_of(args[0], m_util.get_family_id(), OP_FPA_INTERNAL_RM)); + SASSERT(m_util.is_rm_bvwrap(args[0])); expr_ref rm(m), x(m), y(m); rm = to_app(args[0])->get_arg(0); @@ -718,7 +818,7 @@ void fpa2bv_converter::mk_neg(sort * srt, expr_ref & x, expr_ref & result) { void fpa2bv_converter::mk_mul(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { SASSERT(num == 3); - SASSERT(is_app_of(args[0], m_util.get_family_id(), OP_FPA_INTERNAL_RM)); + SASSERT(m_util.is_rm_bvwrap(args[0])); expr_ref rm(m), x(m), y(m); rm = to_app(args[0])->get_arg(0); @@ -868,7 +968,7 @@ void fpa2bv_converter::mk_mul(sort * s, expr_ref & rm, expr_ref & x, expr_ref & void fpa2bv_converter::mk_div(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { SASSERT(num == 3); - SASSERT(is_app_of(args[0], m_util.get_family_id(), OP_FPA_INTERNAL_RM)); + SASSERT(m_util.is_rm_bvwrap(args[0])); expr_ref rm(m), x(m), y(m); rm = to_app(args[0])->get_arg(0); x = args[1]; @@ -1308,7 +1408,7 @@ expr_ref fpa2bv_converter::mk_max_unspecified(func_decl * f, expr * x, expr * y) void fpa2bv_converter::mk_fma(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { SASSERT(num == 4); - SASSERT(is_app_of(args[0], m_util.get_family_id(), OP_FPA_INTERNAL_RM)); + SASSERT(m_util.is_rm_bvwrap(args[0])); // fusedma means (x * y) + z expr_ref rm(m), x(m), y(m), z(m); @@ -1626,7 +1726,7 @@ void fpa2bv_converter::mk_fma(func_decl * f, unsigned num, expr * const * args, void fpa2bv_converter::mk_sqrt(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { SASSERT(num == 2); - SASSERT(is_app_of(args[0], m_util.get_family_id(), OP_FPA_INTERNAL_RM)); + SASSERT(m_util.is_rm_bvwrap(args[0])); expr_ref rm(m), x(m); rm = to_app(args[0])->get_arg(0); @@ -1775,7 +1875,7 @@ void fpa2bv_converter::mk_sqrt(func_decl * f, unsigned num, expr * const * args, void fpa2bv_converter::mk_round_to_integral(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { SASSERT(num == 2); - SASSERT(is_app_of(args[0], m_util.get_family_id(), OP_FPA_INTERNAL_RM)); + SASSERT(m_util.is_rm_bvwrap(args[0])); expr_ref rm(m), x(m); rm = to_app(args[0])->get_arg(0); @@ -2236,7 +2336,7 @@ void fpa2bv_converter::mk_to_fp(func_decl * f, unsigned num, expr * const * args void fpa2bv_converter::mk_to_fp_float(func_decl * f, sort * s, expr * rm, expr * x, expr_ref & result) { - SASSERT(is_app_of(rm, m_util.get_family_id(), OP_FPA_INTERNAL_RM)); + SASSERT(m_util.is_rm_bvwrap(rm)); mk_to_fp_float(s, to_app(rm)->get_arg(0), x, result); } @@ -2407,7 +2507,7 @@ void fpa2bv_converter::mk_to_fp_real(func_decl * f, sort * s, expr * rm, expr * "x: " << mk_ismt2_pp(x, m) << std::endl;); SASSERT(m_util.is_float(s)); SASSERT(au().is_real(x) || au().is_int(x)); - SASSERT(is_app_of(rm, m_util.get_family_id(), OP_FPA_INTERNAL_RM)); + SASSERT(m_util.is_rm_bvwrap(rm)); expr * bv_rm = to_app(rm)->get_arg(0); unsigned ebits = m_util.get_ebits(s); @@ -2542,7 +2642,7 @@ void fpa2bv_converter::mk_to_fp_real_int(func_decl * f, unsigned num, expr * con unsigned ebits = m_util.get_ebits(f->get_range()); unsigned sbits = m_util.get_sbits(f->get_range()); - SASSERT(is_app_of(args[0], m_util.get_family_id(), OP_FPA_INTERNAL_RM)); + SASSERT(m_util.is_rm_bvwrap(args[0])); expr * bv_rm = to_app(args[0])->get_arg(0); rational e; @@ -2700,7 +2800,7 @@ void fpa2bv_converter::mk_to_fp_signed(func_decl * f, unsigned num, expr * const SASSERT(num == 2); SASSERT(m_util.is_float(f->get_range())); - SASSERT(is_app_of(args[0], m_util.get_family_id(), OP_FPA_INTERNAL_RM)); + SASSERT(m_util.is_rm_bvwrap(args[0])); SASSERT(m_bv_util.is_bv(args[1])); expr_ref rm(m), x(m); @@ -2842,7 +2942,7 @@ void fpa2bv_converter::mk_to_fp_unsigned(func_decl * f, unsigned num, expr * con SASSERT(num == 2); SASSERT(m_util.is_float(f->get_range())); - SASSERT(is_app_of(args[0], m_util.get_family_id(), OP_FPA_INTERNAL_RM)); + SASSERT(m_util.is_rm_bvwrap(args[0])); SASSERT(m_bv_util.is_bv(args[1])); expr_ref rm(m), x(m); @@ -2994,7 +3094,7 @@ void fpa2bv_converter::mk_to_bv(func_decl * f, unsigned num, expr * const * args tout << "arg" << i << " = " << mk_ismt2_pp(args[i], m) << std::endl;); SASSERT(num == 2); - SASSERT(is_app_of(args[0], m_util.get_family_id(), OP_FPA_INTERNAL_RM)); + SASSERT(m_util.is_rm_bvwrap(args[0])); SASSERT(m_util.is_float(args[1])); expr * rm = to_app(args[0])->get_arg(0); @@ -3246,7 +3346,7 @@ expr_ref fpa2bv_converter::mk_to_ieee_bv_unspecified(unsigned ebits, unsigned sb void fpa2bv_converter::mk_rm(expr * bv3, expr_ref & result) { SASSERT(m_bv_util.is_bv(bv3) && m_bv_util.get_bv_size(bv3) == 3); - result = m.mk_app(m_util.get_family_id(), OP_FPA_INTERNAL_RM, 0, 0, 1, &bv3, m_util.mk_rm_sort()); + result = m.mk_app(m_util.get_family_id(), OP_FPA_INTERNAL_RM_BVWRAP, 0, 0, 1, &bv3, m_util.mk_rm_sort()); } void fpa2bv_converter::mk_fp(expr * sign, expr * exponent, expr * significand, expr_ref & result) { @@ -3266,7 +3366,7 @@ void fpa2bv_converter::mk_fp(func_decl * f, unsigned num, expr * const * args, e } void fpa2bv_converter::split_fp(expr * e, expr * & sgn, expr * & exp, expr * & sig) const { - SASSERT(is_app_of(e, m_plugin->get_family_id(), OP_FPA_FP)); + SASSERT(m_util.is_fp(e)); SASSERT(to_app(e)->get_num_args() == 3); sgn = to_app(e)->get_arg(0); exp = to_app(e)->get_arg(1); @@ -3274,7 +3374,7 @@ void fpa2bv_converter::split_fp(expr * e, expr * & sgn, expr * & exp, expr * & s } void fpa2bv_converter::split_fp(expr * e, expr_ref & sgn, expr_ref & exp, expr_ref & sig) const { - SASSERT(is_app_of(e, m_plugin->get_family_id(), OP_FPA_FP)); + SASSERT(m_util.is_fp(e)); SASSERT(to_app(e)->get_num_args() == 3); expr *e_sgn, *e_sig, *e_exp; split_fp(e, e_sgn, e_exp, e_sig); @@ -3324,7 +3424,7 @@ void fpa2bv_converter::mk_is_ninf(expr * e, expr_ref & result) { } void fpa2bv_converter::mk_is_pos(expr * e, expr_ref & result) { - SASSERT(is_app_of(e, m_plugin->get_family_id(), OP_FPA_FP)); + SASSERT(m_util.is_fp(e)); SASSERT(to_app(e)->get_num_args() == 3); expr * a0 = to_app(e)->get_arg(0); expr_ref zero(m); @@ -3333,7 +3433,7 @@ void fpa2bv_converter::mk_is_pos(expr * e, expr_ref & result) { } void fpa2bv_converter::mk_is_neg(expr * e, expr_ref & result) { - SASSERT(is_app_of(e, m_plugin->get_family_id(), OP_FPA_FP)); + SASSERT(m_util.is_fp(e)); SASSERT(to_app(e)->get_num_args() == 3); expr * a0 = to_app(e)->get_arg(0); expr_ref one(m); @@ -3502,7 +3602,7 @@ void fpa2bv_converter::mk_unbias(expr * e, expr_ref & result) { } void fpa2bv_converter::unpack(expr * e, expr_ref & sgn, expr_ref & sig, expr_ref & exp, expr_ref & lz, bool normalize) { - SASSERT(is_app_of(e, m_plugin->get_family_id(), OP_FPA_FP)); + SASSERT(m_util.is_fp(e)); SASSERT(to_app(e)->get_num_args() == 3); sort * srt = to_app(e)->get_decl()->get_range(); @@ -3599,9 +3699,9 @@ void fpa2bv_converter::unpack(expr * e, expr_ref & sgn, expr_ref & sig, expr_ref TRACE("fpa2bv_unpack", tout << "UNPACK EXP = " << mk_ismt2_pp(exp, m) << std::endl; ); } -void fpa2bv_converter::mk_rounding_mode(func_decl * f, expr_ref & result) +void fpa2bv_converter::mk_rounding_mode(decl_kind k, expr_ref & result) { - switch(f->get_decl_kind()) + switch(k) { case OP_FPA_RM_NEAREST_TIES_TO_EVEN: result = m_bv_util.mk_numeral(BV_RM_TIES_TO_EVEN, 3); break; case OP_FPA_RM_NEAREST_TIES_TO_AWAY: result = m_bv_util.mk_numeral(BV_RM_TIES_TO_AWAY, 3); break; @@ -3618,9 +3718,9 @@ void fpa2bv_converter::dbg_decouple(const char * prefix, expr_ref & e) { #ifdef Z3DEBUG return; // CMW: This works only for quantifier-free formulas. - if (is_app_of(e, m_plugin->get_family_id(), OP_FPA_FP)) { + if (m_util.is_fp(e)) { expr_ref new_bv(m); - expr *e_sgn, *e_sig, *e_exp; + expr *e_sgn, *e_sig, *e_exp; split_fp(e, e_sgn, e_exp, e_sig); unsigned ebits = m_bv_util.get_bv_size(e_exp); unsigned sbits = m_bv_util.get_bv_size(e_sig) + 1; diff --git a/src/ast/fpa/fpa2bv_converter.h b/src/ast/fpa/fpa2bv_converter.h index 32c3124dba1..879c1e080e1 100644 --- a/src/ast/fpa/fpa2bv_converter.h +++ b/src/ast/fpa/fpa2bv_converter.h @@ -72,11 +72,11 @@ class fpa2bv_converter { void mk_ite(expr * c, expr * t, expr * f, expr_ref & result); void mk_distinct(func_decl * f, unsigned num, expr * const * args, expr_ref & result); - void mk_rounding_mode(func_decl * f, expr_ref & result); + void mk_rounding_mode(decl_kind k, expr_ref & result); void mk_numeral(func_decl * f, unsigned num, expr * const * args, expr_ref & result); virtual void mk_const(func_decl * f, expr_ref & result); virtual void mk_rm_const(func_decl * f, expr_ref & result); - virtual void mk_uninterpreted_function(func_decl * f, unsigned num, expr * const * args, expr_ref & result); + virtual void mk_function(func_decl * f, unsigned num, expr * const * args, expr_ref & result); void mk_var(unsigned base_inx, sort * srt, expr_ref & result); void mk_pinf(func_decl * f, expr_ref & result); @@ -186,7 +186,10 @@ class fpa2bv_converter { void mk_to_bv(func_decl * f, unsigned num, expr * const * args, bool is_signed, expr_ref & result); - void mk_uninterpreted_output(sort * rng, func_decl * fbv, expr_ref_buffer & new_args, expr_ref & result); + sort_ref replace_float_sorts(sort * s); + func_decl_ref replace_function(func_decl * f); + expr_ref replace_float_arg(expr * a); + void mk_function_output(sort * rng, func_decl * fbv, expr * const * new_args, expr_ref & result); private: void mk_nan(sort * s, expr_ref & result); diff --git a/src/ast/fpa/fpa2bv_rewriter.cpp b/src/ast/fpa/fpa2bv_rewriter.cpp index 27fc8ebc766..2eb85c87c6c 100644 --- a/src/ast/fpa/fpa2bv_rewriter.cpp +++ b/src/ast/fpa/fpa2bv_rewriter.cpp @@ -107,7 +107,7 @@ br_status fpa2bv_rewriter_cfg::reduce_app(func_decl * f, unsigned num, expr * co case OP_FPA_RM_NEAREST_TIES_TO_EVEN: case OP_FPA_RM_TOWARD_NEGATIVE: case OP_FPA_RM_TOWARD_POSITIVE: - case OP_FPA_RM_TOWARD_ZERO: m_conv.mk_rounding_mode(f, result); return BR_DONE; + case OP_FPA_RM_TOWARD_ZERO: m_conv.mk_rounding_mode(f->get_decl_kind(), result); return BR_DONE; case OP_FPA_NUM: m_conv.mk_numeral(f, num, args, result); return BR_DONE; case OP_FPA_PLUS_INF: m_conv.mk_pinf(f, result); return BR_DONE; case OP_FPA_MINUS_INF: m_conv.mk_ninf(f, result); return BR_DONE; @@ -152,9 +152,9 @@ br_status fpa2bv_rewriter_cfg::reduce_app(func_decl * f, unsigned num, expr * co case OP_FPA_INTERNAL_MIN_I: m_conv.mk_min_i(f, num, args, result); return BR_DONE; case OP_FPA_INTERNAL_MAX_I: m_conv.mk_max_i(f, num, args, result); return BR_DONE; - case OP_FPA_INTERNAL_RM: case OP_FPA_INTERNAL_BVWRAP: - case OP_FPA_INTERNAL_BVUNWRAP: + case OP_FPA_INTERNAL_RM_BVWRAP: + case OP_FPA_INTERNAL_TO_REAL_UNSPECIFIED: case OP_FPA_INTERNAL_TO_UBV_UNSPECIFIED: case OP_FPA_INTERNAL_TO_SBV_UNSPECIFIED: @@ -169,14 +169,14 @@ br_status fpa2bv_rewriter_cfg::reduce_app(func_decl * f, unsigned num, expr * co else { SASSERT(!m_conv.is_float_family(f)); bool is_float_uf = m_conv.is_float(f->get_range()) || m_conv.is_rm(f->get_range()); - + for (unsigned i = 0; i < f->get_arity(); i++) { sort * di = f->get_domain()[i]; is_float_uf |= m_conv.is_float(di) || m_conv.is_rm(di); } if (is_float_uf) { - m_conv.mk_uninterpreted_function(f, num, args, result); + m_conv.mk_function(f, num, args, result); return BR_DONE; } } diff --git a/src/ast/fpa_decl_plugin.cpp b/src/ast/fpa_decl_plugin.cpp index 511d36e671e..069e7ed1806 100644 --- a/src/ast/fpa_decl_plugin.cpp +++ b/src/ast/fpa_decl_plugin.cpp @@ -711,18 +711,6 @@ func_decl * fpa_decl_plugin::mk_internal_bv_wrap(decl_kind k, unsigned num_param } } -func_decl * fpa_decl_plugin::mk_internal_bv_unwrap(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 bv_unwrap"); - if (!is_sort_of(domain[0], m_bv_fid, BV_SORT)) - m_manager->raise_exception("sort mismatch, expected argument of bitvector sort"); - if (!is_float_sort(range) && !is_rm_sort(range)) - m_manager->raise_exception("sort mismatch, expected range of FloatingPoint or RoundingMode sort"); - - return m_manager->mk_func_decl(symbol("bv_unwrap"), 1, domain, range, func_decl_info(m_family_id, k, num_parameters, parameters)); -} - func_decl * fpa_decl_plugin::mk_internal_to_ubv_unspecified( decl_kind k, unsigned num_parameters, parameter const * parameters, unsigned arity, sort * const * domain, sort * range) { @@ -847,12 +835,10 @@ func_decl * fpa_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, case OP_FPA_TO_IEEE_BV: return mk_to_ieee_bv(k, num_parameters, parameters, arity, domain, range); - case OP_FPA_INTERNAL_RM: - return mk_internal_rm(k, num_parameters, parameters, arity, domain, range); case OP_FPA_INTERNAL_BVWRAP: - return mk_internal_bv_wrap(k, num_parameters, parameters, arity, domain, range); - case OP_FPA_INTERNAL_BVUNWRAP: - return mk_internal_bv_unwrap(k, num_parameters, parameters, arity, domain, range); + return mk_internal_bv_wrap(k, num_parameters, parameters, arity, domain, range); + case OP_FPA_INTERNAL_RM_BVWRAP: + return mk_internal_rm(k, num_parameters, parameters, arity, domain, range); case OP_FPA_INTERNAL_MIN_I: case OP_FPA_INTERNAL_MAX_I: @@ -1027,12 +1013,12 @@ sort * fpa_util::mk_float_sort(unsigned ebits, unsigned sbits) { return m().mk_sort(m_fid, FLOATING_POINT_SORT, 2, ps); } -unsigned fpa_util::get_ebits(sort * s) { +unsigned fpa_util::get_ebits(sort * s) const { SASSERT(is_float(s)); return static_cast(s->get_parameter(0).get_int()); } -unsigned fpa_util::get_sbits(sort * s) { +unsigned fpa_util::get_sbits(sort * s) const { SASSERT(is_float(s)); return static_cast(s->get_parameter(1).get_int()); } diff --git a/src/ast/fpa_decl_plugin.h b/src/ast/fpa_decl_plugin.h index a351b261035..8683bf5f198 100644 --- a/src/ast/fpa_decl_plugin.h +++ b/src/ast/fpa_decl_plugin.h @@ -87,9 +87,8 @@ enum fpa_op_kind { OP_FPA_TO_IEEE_BV, /* Internal use only */ - OP_FPA_INTERNAL_RM, // Internal conversion from (_ BitVec 3) to RoundingMode OP_FPA_INTERNAL_BVWRAP, - OP_FPA_INTERNAL_BVUNWRAP, + OP_FPA_INTERNAL_RM_BVWRAP, // Internal conversion from (_ BitVec 3) to RoundingMode OP_FPA_INTERNAL_MIN_I, OP_FPA_INTERNAL_MAX_I, @@ -256,12 +255,13 @@ class fpa_util { sort * mk_float_sort(unsigned ebits, unsigned sbits); sort * mk_rm_sort() { return m().mk_sort(m_fid, ROUNDING_MODE_SORT); } - bool is_float(sort * s) { return is_sort_of(s, m_fid, FLOATING_POINT_SORT); } - bool is_rm(sort * s) { return is_sort_of(s, m_fid, ROUNDING_MODE_SORT); } - bool is_float(expr * e) { return is_float(m_manager.get_sort(e)); } - bool is_rm(expr * e) { return is_rm(m_manager.get_sort(e)); } - unsigned get_ebits(sort * s); - unsigned get_sbits(sort * s); + bool is_float(sort * s) const { return is_sort_of(s, m_fid, FLOATING_POINT_SORT); } + 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); } + unsigned get_ebits(sort * s) const; + unsigned get_sbits(sort * s) const; app * mk_round_nearest_ties_to_even() { return m().mk_const(m_fid, OP_FPA_RM_NEAREST_TIES_TO_EVEN); } app * mk_round_nearest_ties_to_away() { return m().mk_const(m_fid, OP_FPA_RM_NEAREST_TIES_TO_AWAY); } @@ -367,8 +367,10 @@ class fpa_util { app * mk_internal_to_ieee_bv_unspecified(unsigned ebits, unsigned sbits); app * mk_internal_to_real_unspecified(unsigned ebits, unsigned sbits); - bool is_wrap(expr * e) const { return is_app_of(e, get_family_id(), OP_FPA_INTERNAL_BVWRAP); } - bool is_unwrap(expr * e) const { return is_app_of(e, get_family_id(), OP_FPA_INTERNAL_BVUNWRAP); } + 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_rm_bvwrap(expr * e) const { return is_app_of(e, get_family_id(), OP_FPA_INTERNAL_RM_BVWRAP); } + bool is_rm_bvwrap(func_decl * f) const { return f->get_family_id() == get_family_id() && f->get_decl_kind() == OP_FPA_INTERNAL_RM_BVWRAP; } }; #endif diff --git a/src/ast/rewriter/fpa_rewriter.cpp b/src/ast/rewriter/fpa_rewriter.cpp index 6c199fcd8b9..19b8c3909b8 100644 --- a/src/ast/rewriter/fpa_rewriter.cpp +++ b/src/ast/rewriter/fpa_rewriter.cpp @@ -98,9 +98,10 @@ 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_RM_BVWRAP:SASSERT(num_args == 1); st = mk_rm(args[0], result); break; - case OP_FPA_INTERNAL_RM: - SASSERT(num_args == 1); SASSERT(num_args == 1); st = mk_rm(args[0], result); break; case OP_FPA_INTERNAL_TO_UBV_UNSPECIFIED: case OP_FPA_INTERNAL_TO_SBV_UNSPECIFIED: case OP_FPA_INTERNAL_TO_REAL_UNSPECIFIED: @@ -108,8 +109,7 @@ br_status fpa_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * con st = BR_FAILED; break; - case OP_FPA_INTERNAL_BVWRAP: SASSERT(num_args == 1); st = mk_bvwrap(args[0], result); break; - case OP_FPA_INTERNAL_BVUNWRAP: SASSERT(num_args == 1); st = mk_bvunwrap(args[0], result); break; + default: NOT_IMPLEMENTED_YET(); @@ -924,9 +924,9 @@ br_status fpa_rewriter::mk_bvwrap(expr * arg, expr_ref & result) { return BR_FAILED; } -br_status fpa_rewriter::mk_bvunwrap(expr * arg, expr_ref & result) { - if (is_app_of(arg, m_util.get_family_id(), OP_FPA_INTERNAL_BVWRAP)) - result = to_app(arg)->get_arg(0); - - return BR_FAILED; -} +//br_status fpa_rewriter::mk_bvunwrap(expr * arg, expr_ref & result) { +// if (is_app_of(arg, m_util.get_family_id(), OP_FPA_INTERNAL_BVWRAP)) +// result = to_app(arg)->get_arg(0); +// +// return BR_FAILED; +//} diff --git a/src/smt/theory_fpa.cpp b/src/smt/theory_fpa.cpp index 802c2c5008c..ea8ba0f791b 100644 --- a/src/smt/theory_fpa.cpp +++ b/src/smt/theory_fpa.cpp @@ -83,89 +83,8 @@ namespace smt { } } - void theory_fpa::fpa2bv_converter_wrapped::mk_uninterpreted_output(sort * rng, func_decl * fbv, expr_ref_buffer & new_args, expr_ref & result) { - if (m_util.is_float(rng)) { - unsigned ebits = m_util.get_ebits(rng); - unsigned sbits = m_util.get_sbits(rng); - unsigned bv_sz = ebits + sbits; - - app_ref na(m); - na = m.mk_app(fbv, new_args.size(), new_args.c_ptr()); - mk_fp(m_bv_util.mk_extract(bv_sz - 1, bv_sz - 1, na), - m_bv_util.mk_extract(bv_sz - 2, sbits - 1, na), - m_bv_util.mk_extract(sbits - 2, 0, na), - result); - } - else if (m_util.is_rm(rng)) { - app_ref na(m); - na = m.mk_app(fbv, new_args.size(), new_args.c_ptr()); - mk_rm(na, result); - } - else - result = m.mk_app(fbv, new_args.size(), new_args.c_ptr()); - } - - void theory_fpa::fpa2bv_converter_wrapped::mk_uninterpreted_function(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { - // TODO: This introduces temporary func_decls that should be filtered in the end. - - TRACE("t_fpa", tout << "UF: " << mk_ismt2_pp(f, m) << std::endl; ); - SASSERT(f->get_arity() == num); - - expr_ref_buffer new_args(m); - - for (unsigned i = 0; i < num; i++) { - TRACE("t_fpa", tout << "UF arg[" << i << "]: " << mk_ismt2_pp(args[i], m) << std::endl; ); - if (is_float(args[i]) || is_rm(args[i])) { - expr_ref ai(m), wrapped(m); - ai = args[i]; - wrapped = m_th.wrap(ai); - new_args.push_back(wrapped); - TRACE("t_fpa", tout << "UF wrap ai: " << mk_ismt2_pp(ai, m) << " --> " << mk_ismt2_pp(wrapped, m) << std::endl; ); - m_extra_assertions.push_back(m.mk_eq(m_th.unwrap(wrapped, m.get_sort(ai)), ai)); - } - else - new_args.push_back(args[i]); - } - - func_decl * fd; - if (m_uf2bvuf.find(f, fd)) { - TRACE("t_fpa", tout << "UF reused: " << mk_ismt2_pp(fd, m) << std::endl; ); - mk_uninterpreted_output(f->get_range(), fd, new_args, result); - } - else { - sort_ref_buffer new_domain(m); - - for (unsigned i = 0; i < f->get_arity(); i++) { - sort * di = f->get_domain()[i]; - if (is_float(di)) - new_domain.push_back(m_bv_util.mk_sort(m_util.get_sbits(di) + m_util.get_ebits(di))); - else if (is_rm(di)) - new_domain.push_back(m_bv_util.mk_sort(3)); - else - new_domain.push_back(di); - } - - sort * frng = f->get_range(); - sort_ref rng(frng, m); - if (m_util.is_float(frng)) - rng = m_bv_util.mk_sort(m_util.get_ebits(frng) + m_util.get_sbits(frng)); - else if (m_util.is_rm(frng)) - rng = m_bv_util.mk_sort(3); - - func_decl_ref fbv(m); - fbv = m.mk_fresh_func_decl(new_domain.size(), new_domain.c_ptr(), rng); - TRACE("t_fpa", tout << "New UF func_decl : " << mk_ismt2_pp(fbv, m) << std::endl;); - - m_uf2bvuf.insert(f, fbv); - m.inc_ref(f); - m.inc_ref(fbv); - - mk_uninterpreted_output(frng, fbv, new_args, result); - } - - expr_ref fapp(m); - fapp = m.mk_app(f, num, args); - m_extra_assertions.push_back(m.mk_eq(fapp, result)); + void theory_fpa::fpa2bv_converter_wrapped::mk_function(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { + return fpa2bv_converter::mk_function(f, num, args, result); TRACE("t_fpa", tout << "UF result: " << mk_ismt2_pp(result, m) << std::endl; ); } @@ -239,12 +158,10 @@ namespace smt { ast_manager & m = get_manager(); dec_ref_map_values(m, m_conversions); dec_ref_map_values(m, m_wraps); - dec_ref_map_values(m, m_unwraps); } else { SASSERT(m_conversions.empty()); SASSERT(m_wraps.empty()); - SASSERT(m_unwraps.empty()); } m_is_initialized = false; @@ -256,7 +173,6 @@ namespace smt { } app * theory_fpa::fpa_value_proc::mk_value(model_generator & mg, ptr_vector & values) { - TRACE("t_fpa_detail", ast_manager & m = m_th.get_manager(); for (unsigned i = 0; i < values.size(); i++) @@ -321,11 +237,11 @@ namespace smt { mpfm.set(f, m_ebits, m_sbits, mpzm.is_one(sgn_z), mpzm.get_int64(exp_u), sig_z); result = m_fu.mk_value(f); - TRACE("t_fpa", tout << "fpa_value_proc::mk_value [" << + TRACE("t_fpa", tout << "result: [" << mpzm.to_string(sgn_z) << "," << mpzm.to_string(exp_z) << "," << mpzm.to_string(sig_z) << "] --> " << - mk_ismt2_pp(result, m_th.get_manager()) << "\n";); + mk_ismt2_pp(result, m_th.get_manager()) << std::endl;); return result; } @@ -355,20 +271,18 @@ namespace smt { default: result = m_fu.mk_round_toward_zero(); } - TRACE("t_fpa", tout << "fpa_rm_value_proc::mk_value result: " << - mk_ismt2_pp(result, m_th.get_manager()) << "\n";); + TRACE("t_fpa", tout << "result: " << mk_ismt2_pp(result, m_th.get_manager()) << std::endl;); return result; } app_ref theory_fpa::wrap(expr * e) { - SASSERT(!m_fpa_util.is_wrap(e)); + SASSERT(m_fpa_util.is_float(e) || m_fpa_util.is_rm(e)); + SASSERT(!m_fpa_util.is_bvwrap(e)); ast_manager & m = get_manager(); app_ref res(m); - if (is_app(e) && - to_app(e)->get_family_id() == get_family_id() && - to_app(e)->get_decl_kind() == OP_FPA_FP) { + 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) }; res = m_bv_util.mk_concat(3, cargs); m_th_rw((expr_ref&)res); @@ -398,35 +312,42 @@ namespace smt { res = m.mk_app(w, e); } - TRACE("t_fpa", tout << "e: " << mk_ismt2_pp(e, m) << "\n"; - tout << "r: " << mk_ismt2_pp(res, m) << "\n";); - - return res; } app_ref theory_fpa::unwrap(expr * e, sort * s) { - SASSERT(!m_fpa_util.is_unwrap(e)); + 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(); sort * bv_srt = m.get_sort(e); + app_ref res(m); - func_decl *u; + unsigned bv_sz = m_bv_util.get_bv_size(e); - if (!m_unwraps.find(bv_srt, u)) { - SASSERT(!m_unwraps.contains(bv_srt)); - u = m.mk_func_decl(get_family_id(), OP_FPA_INTERNAL_BVUNWRAP, 0, 0, 1, &bv_srt, s); - m_unwraps.insert(bv_srt, u); - m.inc_ref(u); + if (m_fpa_util.is_rm(s)) { + SASSERT(bv_sz == 3); + res = m.mk_ite(m.mk_eq(e, m_bv_util.mk_numeral(BV_RM_TIES_TO_AWAY, 3)), m_fpa_util.mk_round_nearest_ties_to_away(), + m.mk_ite(m.mk_eq(e, m_bv_util.mk_numeral(BV_RM_TIES_TO_EVEN, 3)), m_fpa_util.mk_round_nearest_ties_to_even(), + m.mk_ite(m.mk_eq(e, m_bv_util.mk_numeral(BV_RM_TO_NEGATIVE, 3)), m_fpa_util.mk_round_toward_negative(), + m.mk_ite(m.mk_eq(e, m_bv_util.mk_numeral(BV_RM_TO_POSITIVE, 3)), m_fpa_util.mk_round_toward_positive(), + m_fpa_util.mk_round_toward_zero())))); } - - app_ref res(m); - res = m.mk_app(u, e); + else { + SASSERT(m_fpa_util.is_float(s)); + unsigned sbits = m_fpa_util.get_sbits(s); + SASSERT(bv_sz == m_fpa_util.get_ebits(s) + sbits); + res = m_fpa_util.mk_fp(m_bv_util.mk_extract(bv_sz - 1, bv_sz - 1, e), + m_bv_util.mk_extract(bv_sz - 2, sbits - 1, e), + m_bv_util.mk_extract(sbits - 2, 0, e)); + } + return res; } expr_ref theory_fpa::convert_atom(expr * e) { ast_manager & m = get_manager(); - TRACE("t_fpa_detail", tout << "converting atom: " << mk_ismt2_pp(e, get_manager()) << "\n";); + TRACE("t_fpa_detail", tout << "converting atom: " << mk_ismt2_pp(e, get_manager()) << std::endl;); expr_ref res(m); proof_ref pr(m); m_rw(e, res); @@ -444,33 +365,24 @@ namespace smt { proof_ref pr(m); m_rw(e, e_conv); - TRACE("t_fpa_detail", tout << "term: " << mk_ismt2_pp(e, get_manager()) << "\n"; - tout << "converted term: " << mk_ismt2_pp(e_conv, get_manager()) << "\n";); + 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 (is_app(e_conv) && to_app(e_conv)->get_family_id() != get_family_id()) { - if (!m_fpa_util.is_float(e_conv)) + UNREACHABLE(); + if (!m_fpa_util.is_float(e_conv) && !m_fpa_util.is_rm(e_conv)) m_th_rw(e_conv, res); - else { - expr_ref bv(m); - bv = wrap(e_conv); - unsigned bv_sz = m_bv_util.get_bv_size(bv); - unsigned sbits = m_fpa_util.get_sbits(m.get_sort(e_conv)); - SASSERT(bv_sz == m_fpa_util.get_ebits(m.get_sort(e_conv)) + sbits); - m_converter.mk_fp(m_bv_util.mk_extract(bv_sz - 1, bv_sz - 1, bv), - m_bv_util.mk_extract(bv_sz - 2, sbits - 1, bv), - m_bv_util.mk_extract(sbits - 2, 0, bv), - res); - } + else + res = unwrap(wrap(e_conv), m.get_sort(e)); } - else if (m_fpa_util.is_rm(e)) { - SASSERT(is_app_of(e_conv, get_family_id(), OP_FPA_INTERNAL_RM)); + else if (m_fpa_util.is_rm(e)) { + SASSERT(m_fpa_util.is_rm_bvwrap(e_conv)); expr_ref bv_rm(m); - bv_rm = to_app(e_conv)->get_arg(0); - m_th_rw(bv_rm); + m_th_rw(to_app(e_conv)->get_arg(0), bv_rm); m_converter.mk_rm(bv_rm, res); } else if (m_fpa_util.is_float(e)) { - SASSERT(is_app_of(e_conv, get_family_id(), OP_FPA_FP)); + SASSERT(m_fpa_util.is_fp(e_conv)); expr_ref sgn(m), sig(m), exp(m); m_converter.split_fp(e_conv, sgn, exp, sig); m_th_rw(sgn); @@ -486,6 +398,7 @@ namespace smt { } expr_ref theory_fpa::convert_conversion_term(expr * e) { + SASSERT(to_app(e)->get_family_id() == get_family_id()); /* This is for the conversion functions fp.to_* */ ast_manager & m = get_manager(); expr_ref res(m); @@ -498,28 +411,6 @@ namespace smt { return res; } - expr_ref theory_fpa::convert_unwrap(expr * e) { - SASSERT(m_fpa_util.is_unwrap(e)); - ast_manager & m = get_manager(); - sort * srt = m.get_sort(e); - expr_ref res(m); - if (m_fpa_util.is_rm(srt)) { - m_converter.mk_rm(to_app(e)->get_arg(0), res); - } - else { - SASSERT(m_fpa_util.is_float(srt)); - unsigned sbits = m_fpa_util.get_sbits(srt); - expr_ref bv(m); - bv = to_app(e)->get_arg(0); - unsigned bv_sz = m_bv_util.get_bv_size(bv); - m_converter.mk_fp(m_bv_util.mk_extract(bv_sz - 1, bv_sz - 1, bv), - m_bv_util.mk_extract(bv_sz - 2, sbits - 1, bv), - m_bv_util.mk_extract(sbits - 2, 0, bv), - res); - } - return res; - } - expr_ref theory_fpa::convert(expr * e) { ast_manager & m = get_manager(); @@ -534,8 +425,8 @@ namespace smt { mk_ismt2_pp(res, m) << std::endl;); } else { - if (m_fpa_util.is_unwrap(e)) - res = convert_unwrap(e); + if (m_fpa_util.is_fp(e)) + res = e; else if (m.is_bool(e)) res = convert_atom(e); else if (m_fpa_util.is_float(e) || m_fpa_util.is_rm(e)) @@ -577,7 +468,7 @@ namespace smt { m_th_rw(res); - CTRACE("t_fpa", !m.is_true(res), tout << "side condition: " << mk_ismt2_pp(res, m) << "\n";); + CTRACE("t_fpa", !m.is_true(res), tout << "side condition: " << mk_ismt2_pp(res, m) << std::endl;); return res; } @@ -589,18 +480,17 @@ namespace smt { literal lit(ctx.get_literal(e)); ctx.mark_as_relevant(lit); ctx.mk_th_axiom(get_id(), 1, &lit); - TRACE("t_fpa_detail", tout << "done asserting " << mk_ismt2_pp(e, get_manager()) << "\n";); } void theory_fpa::attach_new_th_var(enode * n) { context & ctx = get_context(); theory_var v = mk_var(n); ctx.attach_th_var(n, this, v); - TRACE("t_fpa_detail", tout << "new theory var: " << mk_ismt2_pp(n->get_owner(), get_manager()) << " := " << v << "\n";); + TRACE("t_fpa", tout << "new theory var: " << mk_ismt2_pp(n->get_owner(), get_manager()) << " := " << v << "\n";); } bool theory_fpa::internalize_atom(app * atom, bool gate_ctx) { - TRACE("t_fpa", tout << "internalizing atom: " << mk_ismt2_pp(atom, get_manager()) << "\n";); + TRACE("t_fpa_internalize", tout << "internalizing atom: " << mk_ismt2_pp(atom, get_manager()) << std::endl;); SASSERT(atom->get_family_id() == get_family_id()); ast_manager & m = get_manager(); @@ -625,11 +515,12 @@ namespace smt { } bool theory_fpa::internalize_term(app * term) { + 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(); - TRACE("t_fpa", tout << "internalizing term: " << mk_ismt2_pp(term, get_manager()) << "\n";); - SASSERT(term->get_family_id() == get_family_id()); - SASSERT(!ctx.e_internalized(term)); unsigned num_args = term->get_num_args(); for (unsigned i = 0; i < num_args; i++) @@ -638,29 +529,29 @@ namespace smt { enode * e = (ctx.e_internalized(term)) ? ctx.get_enode(term) : ctx.mk_enode(term, false, false, true); - if (is_attached_to_var(e)) - return false; - - attach_new_th_var(e); - - // The conversion operators fp.to_* appear in non-FP constraints. - // The corresponding constraints will not be translated and added - // via convert(...) and assert_cnstr(...) in initialize_atom(...). - // Therefore, we translate and assert them here. - fpa_op_kind k = (fpa_op_kind)term->get_decl_kind(); - switch (k) { - case OP_FPA_TO_FP: - case OP_FPA_TO_UBV: - case OP_FPA_TO_SBV: - case OP_FPA_TO_REAL: - case OP_FPA_TO_IEEE_BV: { - expr_ref conv(m); - conv = convert(term); - assert_cnstr(m.mk_eq(term, conv)); - assert_cnstr(mk_side_conditions()); - break; - } - default: /* ignore */; + if (!is_attached_to_var(e)) { + attach_new_th_var(e); + + // The conversion operators fp.to_* appear in non-FP constraints. + // The corresponding constraints will not be translated and added + // via convert(...) and assert_cnstr(...) in initialize_atom(...). + // Therefore, we translate and assert them here. + fpa_op_kind k = (fpa_op_kind)term->get_decl_kind(); + switch (k) { + case OP_FPA_TO_FP: + case OP_FPA_TO_UBV: + case OP_FPA_TO_SBV: + case OP_FPA_TO_REAL: + case OP_FPA_TO_IEEE_BV: { + + expr_ref conv(m); + conv = convert(term); + assert_cnstr(m.mk_eq(term, conv)); + assert_cnstr(mk_side_conditions()); + break; + } + default: /* ignore */; + } } return true; @@ -669,33 +560,35 @@ namespace smt { void theory_fpa::apply_sort_cnstr(enode * n, sort * s) { TRACE("t_fpa", tout << "apply sort cnstr for: " << mk_ismt2_pp(n->get_owner(), get_manager()) << "\n";); SASSERT(s->get_family_id() == get_family_id()); + SASSERT(m_fpa_util.is_float(s) || m_fpa_util.is_rm(s)); + SASSERT(m_fpa_util.is_float(n->get_owner()) || m_fpa_util.is_rm(n->get_owner())); + SASSERT(n->get_owner()->get_decl()->get_range() == s); ast_manager & m = get_manager(); - context & ctx = get_context(); - - app_ref owner(m); - owner = n->get_owner(); - - SASSERT(owner->get_decl()->get_range() == s); - - if ((m_fpa_util.is_float(s) || m_fpa_util.is_rm(s)) && - !is_attached_to_var(n)) { + context & ctx = get_context(); + app_ref owner(n->get_owner(), m); + if (!is_attached_to_var(n)) { attach_new_th_var(n); if (m_fpa_util.is_rm(s)) { // For every RM term, we need to make sure that it's // associated bit-vector is within the valid range. - if (!m_fpa_util.is_unwrap(owner)) { + if (!m_fpa_util.is_rm_bvwrap(owner)) { expr_ref valid(m), limit(m); limit = m_bv_util.mk_numeral(4, 3); valid = m_bv_util.mk_ule(wrap(owner), limit); assert_cnstr(valid); } } - - if (!ctx.relevancy() && !m_fpa_util.is_unwrap(owner)) - assert_cnstr(m.mk_eq(unwrap(wrap(owner), s), owner)); + + if (!ctx.relevancy()) { + relevant_eh(owner); + /*expr_ref wu(m); + wu = m.mk_eq(unwrap(wrap(owner), s), owner); + TRACE("t_fpa", tout << "w/u eq: " << std::endl << mk_ismt2_pp(wu, get_manager()) << std::endl;); + assert_cnstr(wu);*/ + } } } @@ -704,9 +597,9 @@ namespace smt { enode * e_x = get_enode(x); enode * e_y = get_enode(y); - TRACE("t_fpa", tout << "new eq: " << x << " = " << y << std::endl;); - TRACE("t_fpa_detail", tout << mk_ismt2_pp(e_x->get_owner(), m) << " = " << - mk_ismt2_pp(e_y->get_owner(), m) << std::endl;); + TRACE("t_fpa", tout << "new eq: " << x << " = " << y << std::endl; + tout << mk_ismt2_pp(e_x->get_owner(), m) << std::endl << " = " << std::endl << + mk_ismt2_pp(e_y->get_owner(), m) << std::endl;); fpa_util & fu = m_fpa_util; @@ -714,7 +607,7 @@ namespace smt { xe = e_x->get_owner(); ye = e_y->get_owner(); - if (m_fpa_util.is_wrap(xe) || m_fpa_util.is_wrap(ye)) + if (m_fpa_util.is_bvwrap(xe) || m_fpa_util.is_bvwrap(ye)) return; expr_ref xc(m), yc(m); @@ -744,9 +637,9 @@ namespace smt { enode * e_x = get_enode(x); enode * e_y = get_enode(y); - TRACE("t_fpa", tout << "new diseq: " << x << " != " << y << std::endl;); - TRACE("t_fpa_detail", tout << mk_ismt2_pp(get_enode(x)->get_owner(), m) << " != " << - mk_ismt2_pp(get_enode(y)->get_owner(), m) << std::endl;); + TRACE("t_fpa", tout << "new diseq: " << x << " != " << y << std::endl; + tout << mk_ismt2_pp(e_x->get_owner(), m) << std::endl << " != " << std::endl << + mk_ismt2_pp(e_y->get_owner(), m) << std::endl;); fpa_util & fu = m_fpa_util; @@ -754,7 +647,7 @@ namespace smt { xe = e_x->get_owner(); ye = e_y->get_owner(); - if (m_fpa_util.is_wrap(xe) || m_fpa_util.is_wrap(ye)) + if (m_fpa_util.is_bvwrap(xe) || m_fpa_util.is_bvwrap(ye)) return; expr_ref xc(m), yc(m); @@ -817,7 +710,7 @@ namespace smt { mpf_manager & mpfm = m_fpa_util.fm(); if (m_fpa_util.is_float(n) || m_fpa_util.is_rm(n)) { - if (!m_fpa_util.is_unwrap(n)) { + if (!m_fpa_util.is_fp(n)) { expr_ref wrapped(m), c(m); wrapped = wrap(n); mpf_rounding_mode rm; @@ -838,8 +731,10 @@ namespace smt { assert_cnstr(c); } else { - c = m.mk_eq(unwrap(wrapped, m.get_sort(n)), n); - assert_cnstr(c); + expr_ref wu(m); + wu = m.mk_eq(unwrap(wrapped, m.get_sort(n)), n); + TRACE("t_fpa", tout << "w/u eq: " << std::endl << mk_ismt2_pp(wu, get_manager()) << std::endl;); + assert_cnstr(wu); } } } @@ -862,7 +757,6 @@ namespace smt { ast_manager & m = get_manager(); dec_ref_map_values(m, m_conversions); dec_ref_map_values(m, m_wraps); - dec_ref_map_values(m, m_unwraps); theory::reset_eh(); } @@ -925,7 +819,7 @@ namespace smt { mk_ismt2_pp(a2, m) << " eq. cls. #" << get_enode(a2)->get_root()->get_owner()->get_id() << std::endl;); res = vp; } - else if (is_app_of(owner, get_family_id(), OP_FPA_INTERNAL_RM)) { + else if (is_app_of(owner, get_family_id(), OP_FPA_INTERNAL_RM_BVWRAP)) { SASSERT(to_app(owner)->get_num_args() == 1); app_ref a0(m); a0 = to_app(owner->get_arg(0)); @@ -1012,11 +906,10 @@ namespace smt { } bool theory_fpa::include_func_interp(func_decl * f) { - TRACE("t_fpa", tout << "f = " << mk_ismt2_pp(f, get_manager()) << std::endl;); - func_decl * wt; - - if (m_wraps.find(f->get_range(), wt) || m_unwraps.find(f->get_range(), wt)) - return wt == f; + TRACE("t_fpa", tout << "f = " << mk_ismt2_pp(f, get_manager()) << std::endl;); + + if (f->get_family_id() == get_family_id()) + return false; else if (m_converter.is_uf2bvuf(f) || m_converter.is_special(f)) return false; else diff --git a/src/smt/theory_fpa.h b/src/smt/theory_fpa.h index 38001b5a639..6c71b1d7db6 100644 --- a/src/smt/theory_fpa.h +++ b/src/smt/theory_fpa.h @@ -82,9 +82,8 @@ namespace smt { m_th(*th) {} virtual ~fpa2bv_converter_wrapped() {} virtual void mk_const(func_decl * f, expr_ref & result); - virtual void mk_rm_const(func_decl * f, expr_ref & result); - void mk_uninterpreted_output(sort * rng, func_decl * fbv, expr_ref_buffer & new_args, expr_ref & result); - virtual void mk_uninterpreted_function(func_decl * f, unsigned num, expr * const * args, expr_ref & result); + virtual void mk_rm_const(func_decl * f, expr_ref & result); + virtual void mk_function(func_decl * f, unsigned num, expr * const * args, expr_ref & result); virtual expr_ref mk_min_unspecified(func_decl * f, expr * x, expr * y); virtual expr_ref mk_max_unspecified(func_decl * f, expr * x, expr * y); diff --git a/src/tactic/fpa/fpa2bv_model_converter.cpp b/src/tactic/fpa/fpa2bv_model_converter.cpp index fe9fc2a0f28..d8b82652590 100644 --- a/src/tactic/fpa/fpa2bv_model_converter.cpp +++ b/src/tactic/fpa/fpa2bv_model_converter.cpp @@ -17,6 +17,7 @@ Module Name: --*/ #include"ast_smt2_pp.h" +#include"fpa_rewriter.h" #include"fpa2bv_model_converter.h" void fpa2bv_model_converter::display(std::ostream & out) { @@ -101,17 +102,15 @@ model_converter * fpa2bv_model_converter::translate(ast_translation & translator return res; } -expr_ref fpa2bv_model_converter::convert_bv2fp(sort * s, expr * sgn, expr * exp, expr * sig) const { - fpa_util fu(m); - bv_util bu(m); - unsynch_mpz_manager & mpzm = fu.fm().mpz_manager(); - unsynch_mpq_manager & mpqm = fu.fm().mpq_manager(); +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(); expr_ref res(m); mpf fp_val; - unsigned ebits = fu.get_ebits(s); - unsigned sbits = fu.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; @@ -119,47 +118,44 @@ expr_ref fpa2bv_model_converter::convert_bv2fp(sort * s, expr * sgn, expr * exp, rational sgn_q(0), sig_q(0), exp_q(0); - if (sgn) bu.is_numeral(sgn, sgn_q, sgn_sz); - if (exp) bu.is_numeral(exp, exp_q, exp_sz); - if (sig) bu.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 - fu.fm().m_powers2.m1(ebits - 1); + 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()); - fu.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); - res = fu.mk_value(fp_val); + 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;); - fu.fm().del(fp_val); + m_fpa_util.fm().del(fp_val); return res; } -expr_ref fpa2bv_model_converter::convert_bv2fp(model * bv_mdl, sort * s, expr * bv) const { - fpa_util fu(m); - bv_util bu(m); +expr_ref fpa2bv_model_converter::convert_bv2fp(model * bv_mdl, sort * s, expr * bv) { + SASSERT(m_bv_util.is_bv(bv)); - SASSERT(bu.is_bv(bv)); - - unsigned ebits = fu.get_ebits(s); - unsigned sbits = fu.get_sbits(s); + 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 = bu.mk_extract(bv_sz - 1, bv_sz - 1, bv); - exp = bu.mk_extract(bv_sz - 2, sbits - 1, bv); - sig = bu.mk_extract(sbits - 2, 0, bv); + 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); @@ -169,33 +165,28 @@ expr_ref fpa2bv_model_converter::convert_bv2fp(model * bv_mdl, sort * s, expr * return convert_bv2fp(s, v_sgn, v_exp, v_sig); } -expr_ref fpa2bv_model_converter::convert_bv2rm(expr * eval_v) const { - fpa_util fu(m); - bv_util bu(m); +expr_ref fpa2bv_model_converter::convert_bv2rm(expr * bv_rm) { expr_ref res(m); rational bv_val(0); unsigned sz = 0; - if (bu.is_numeral(eval_v, bv_val, sz)) { + 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 = fu.mk_round_nearest_ties_to_away(); break; - case BV_RM_TIES_TO_EVEN: res = fu.mk_round_nearest_ties_to_even(); break; - case BV_RM_TO_NEGATIVE: res = fu.mk_round_toward_negative(); break; - case BV_RM_TO_POSITIVE: res = fu.mk_round_toward_positive(); break; + 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 = fu.mk_round_toward_zero(); + default: res = m_fpa_util.mk_round_toward_zero(); } } return res; } -expr_ref fpa2bv_model_converter::convert_bv2rm(model * bv_mdl, func_decl * var, expr * val) const { - fpa_util fu(m); - bv_util bu(m); +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)) @@ -204,10 +195,100 @@ expr_ref fpa2bv_model_converter::convert_bv2rm(model * bv_mdl, func_decl * var, return res; } -void fpa2bv_model_converter::convert(model * bv_mdl, model * float_mdl) { - fpa_util fu(m); - bv_util bu(m); +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)) { + SASSERT(m_bv_util.is_bv(e)); + result = convert_bv2fp(bv_mdl, s, e); + } + else if (m_fpa_util.is_rm(s)) { + SASSERT(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); + 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() << " --> " << @@ -233,8 +314,8 @@ void fpa2bv_model_converter::convert(model * bv_mdl, model * float_mdl) { it++) { func_decl * f = it->m_key; expr_ref pzero(m), nzero(m); - pzero = fu.mk_pzero(f->get_range()); - nzero = fu.mk_nzero(f->get_range()); + 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); @@ -244,8 +325,8 @@ void fpa2bv_model_converter::convert(model * bv_mdl, model * float_mdl) { rational pn_num, np_num; unsigned bv_sz; - bu.is_numeral(pn, pn_num, bv_sz); - bu.is_numeral(np, np_num, 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 }; @@ -263,7 +344,7 @@ void fpa2bv_model_converter::convert(model * bv_mdl, model * float_mdl) { { func_decl * var = it->m_key; app * val = to_app(it->m_value); - SASSERT(fu.is_float(var->get_range())); + 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); @@ -271,7 +352,7 @@ void fpa2bv_model_converter::convert(model * bv_mdl, model * float_mdl) { bv_mdl->eval(val->get_arg(1), exp, true); bv_mdl->eval(val->get_arg(2), sig, true); - SASSERT(val->is_app_of(fu.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); @@ -301,84 +382,33 @@ void fpa2bv_model_converter::convert(model * bv_mdl, model * float_mdl) { it++) { func_decl * var = it->m_key; - SASSERT(fu.is_rm(var->get_range())); + SASSERT(m_fpa_util.is_rm(var->get_range())); expr * val = it->m_value; - SASSERT(is_app_of(val, fu.get_family_id(), OP_FPA_INTERNAL_RM)); + SASSERT(m_fpa_util.is_rm_bvwrap(val)); expr * bvval = to_app(val)->get_arg(0); expr_ref fv(m); - fv = convert_bv2rm(bv_mdl, var, bvval); + 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++) { + it != m_uf2bvuf.end(); + it++) { seen.insert(it->m_value); - func_decl * f = it->m_key; - unsigned arity = f->get_arity(); - sort * rng = f->get_range(); - - if (arity > 0) { - func_interp * bv_fi = bv_mdl->get_func_interp(it->m_value); - - if (bv_fi != 0) { - func_interp * flt_fi = alloc(func_interp, m, f->get_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 * dj = f->get_domain(j); - expr * aj = bv_args[j]; - expr_ref saj(m); - bv_mdl->eval(aj, saj, true); - - if (fu.is_float(dj)) - new_args.push_back(convert_bv2fp(bv_mdl, dj, saj)); - else if (fu.is_rm(dj)) { - expr_ref fv(m); - fv = convert_bv2rm(saj); - new_args.push_back(fv); - } - else - new_args.push_back(saj); - } - - expr_ref ret(m); - ret = bv_fe->get_result(); - bv_mdl->eval(ret, ret); - if (fu.is_float(rng)) - ret = convert_bv2fp(bv_mdl, rng, ret); - else if (fu.is_rm(rng)) - ret = convert_bv2rm(ret); - - flt_fi->insert_new_entry(new_args.c_ptr(), ret); - } - - expr_ref els(m); - els = bv_fi->get_else(); - if (fu.is_float(rng)) - els = convert_bv2fp(bv_mdl, rng, els); - else if (fu.is_rm(rng)) - els = convert_bv2rm(els); - - flt_fi->set_else(els); - - float_mdl->register_decl(f, flt_fi); - } - } + func_decl * f = it->m_key; + if (f->get_arity() == 0) + { + 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 { - func_decl * bvf = it->m_value; - expr_ref c(m), e(m); - c = m.mk_const(bvf); - bv_mdl->eval(c, e, true); - float_mdl->register_decl(f, e); - TRACE("fpa2bv_mc", tout << "model value for " << mk_ismt2_pp(f, m) << " is " << mk_ismt2_pp(e, m) << std::endl;); + func_interp * fmv = convert_func_interp(f, it->m_value, bv_mdl); + if (fmv) float_mdl->register_decl(f, fmv); } } diff --git a/src/tactic/fpa/fpa2bv_model_converter.h b/src/tactic/fpa/fpa2bv_model_converter.h index 854543f24d3..f7c817e1ba1 100644 --- a/src/tactic/fpa/fpa2bv_model_converter.h +++ b/src/tactic/fpa/fpa2bv_model_converter.h @@ -19,10 +19,15 @@ Module Name: #ifndef FPA2BV_MODEL_CONVERTER_H_ #define FPA2BV_MODEL_CONVERTER_H_ +#include"th_rewriter.h" #include"fpa2bv_converter.h" #include"model_converter.h" class fpa2bv_model_converter : public model_converter { + fpa_util m_fpa_util; + bv_util m_bv_util; + th_rewriter m_th_rw; + ast_manager & m; obj_map m_const2bv; obj_map m_rm_const2bv; @@ -30,7 +35,11 @@ class fpa2bv_model_converter : public model_converter { obj_map > m_specials; public: - fpa2bv_model_converter(ast_manager & m, fpa2bv_converter const & conv) : m(m) { + 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++) @@ -95,13 +104,32 @@ class fpa2bv_model_converter : public model_converter { virtual model_converter * translate(ast_translation & translator); protected: - fpa2bv_model_converter(ast_manager & m) : m(m){ } + fpa2bv_model_converter(ast_manager & m) : + m(m), + m_fpa_util(m), + m_bv_util(m), + m_th_rw(m) {} void convert(model * bv_mdl, model * float_mdl); - expr_ref convert_bv2fp(sort * s, expr * sgn, expr * exp, expr * sig) const; - expr_ref convert_bv2fp(model * bv_mdl, sort * s, expr * bv) const; - expr_ref convert_bv2rm(expr * eval_v) const; - expr_ref convert_bv2rm(model * bv_mdl, func_decl * var, expr * val) const; + 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) : result(m) {} + }; + + array_model convert_array_func_interp(func_decl * f, func_decl * bv_f, model * bv_mdl); }; From 4ed2b8a0f9d900547cfed92844418e7541ed1595 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Fri, 20 May 2016 20:15:08 +0100 Subject: [PATCH 44/61] Bugfix for unspecified FP model values. --- src/tactic/fpa/fpa2bv_model_converter.cpp | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/tactic/fpa/fpa2bv_model_converter.cpp b/src/tactic/fpa/fpa2bv_model_converter.cpp index d8b82652590..41650eda65e 100644 --- a/src/tactic/fpa/fpa2bv_model_converter.cpp +++ b/src/tactic/fpa/fpa2bv_model_converter.cpp @@ -401,10 +401,19 @@ void fpa2bv_model_converter::convert(model * bv_mdl, model * float_mdl) { func_decl * f = it->m_key; if (f->get_arity() == 0) { - 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); + 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. + expr_ref val(m); + bv_mdl->eval(it->m_value, val); + float_mdl->register_decl(f, val); + } } else { func_interp * fmv = convert_func_interp(f, it->m_value, bv_mdl); From 2bbca192e342d85f6bd886622d14afc5610dcfcc Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Fri, 20 May 2016 20:16:45 +0100 Subject: [PATCH 45/61] member init order --- src/tactic/fpa/fpa2bv_model_converter.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/tactic/fpa/fpa2bv_model_converter.h b/src/tactic/fpa/fpa2bv_model_converter.h index f7c817e1ba1..ce38527c131 100644 --- a/src/tactic/fpa/fpa2bv_model_converter.h +++ b/src/tactic/fpa/fpa2bv_model_converter.h @@ -24,11 +24,11 @@ Module Name: #include"model_converter.h" class fpa2bv_model_converter : public model_converter { - fpa_util m_fpa_util; - bv_util m_bv_util; - th_rewriter m_th_rw; - - ast_manager & m; + 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; From 339cd6e537813ff2ea07293e099784ed680f1769 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 20 May 2016 13:45:50 -0700 Subject: [PATCH 46/61] mbo Signed-off-by: Nikolaj Bjorner --- src/math/simplex/model_based_opt.cpp | 130 ++++++++++++++++++++++++++- src/math/simplex/model_based_opt.h | 21 ++++- src/qe/qe_arith.cpp | 6 +- src/qe/qe_mbp.cpp | 92 +++++++++++++++++-- src/qe/qe_mbp.h | 1 + src/qe/qsat.cpp | 3 +- src/smt/theory_pb.cpp | 8 +- src/test/model_based_opt.cpp | 75 ++++++++++++++++ 8 files changed, 317 insertions(+), 19 deletions(-) diff --git a/src/math/simplex/model_based_opt.cpp b/src/math/simplex/model_based_opt.cpp index e5db201a86a..06ba38b4a69 100644 --- a/src/math/simplex/model_based_opt.cpp +++ b/src/math/simplex/model_based_opt.cpp @@ -34,8 +34,7 @@ std::ostream& operator<<(std::ostream& out, opt::ineq_type ie) { namespace opt { - model_based_opt::model_based_opt(): - m_objective_id(0) + model_based_opt::model_based_opt() { m_rows.push_back(row()); } @@ -448,5 +447,132 @@ namespace opt { set_row(m_objective_id, coeffs, c, t_le); } + void model_based_opt::get_live_rows(vector& rows) { + for (unsigned i = 0; i < m_rows.size(); ++i) { + if (m_rows[i].m_alive) { + rows.push_back(m_rows[i]); + } + } + } + + // + // pick glb and lub representative. + // The representative is picked such that it + // represents the fewest inequalities. + // The constraints that enforce a glb or lub are not forced. + // The constraints that separate the glb from ub or the lub from lb + // are not forced. + // In other words, suppose there are + // . N inequalities of the form t <= x + // . M inequalities of the form s >= x + // . t0 is glb among N under valuation. + // . s0 is lub among M under valuation. + // If N < M + // create the inequalities: + // t <= t0 for each t other than t0 (N-1 inequalities). + // t0 <= s for each s (M inequalities). + // If N >= M the construction is symmetric. + // + void model_based_opt::project(unsigned x) { + unsigned_vector& lub_rows = m_lub; + unsigned_vector& glb_rows = m_glb; + unsigned lub_index = UINT_MAX, glb_index = UINT_MAX; + bool lub_strict = false, glb_strict = false; + rational lub_val, glb_val; + rational const& x_val = m_var2value[x]; + unsigned_vector const& row_ids = m_var2row_ids[x]; + uint_set visited; + lub_rows.reset(); + glb_rows.reset(); + // select the lub and glb. + for (unsigned i = 0; i < row_ids.size(); ++i) { + unsigned row_id = row_ids[i]; + if (visited.contains(row_id)) { + continue; + } + visited.insert(row_id); + row& r = m_rows[row_id]; + if (!r.m_alive) { + continue; + } + rational a = get_coefficient(row_id, x); + if (a.is_zero()) { + continue; + } + if (r.m_type == t_eq) { + solve_for(row_id, x); + return; + } + if (a.is_pos()) { + rational lub_value = x_val - (r.m_value/a); + if (lub_rows.empty() || + lub_value < lub_val || + (lub_value == lub_val && r.m_type == t_lt && !lub_strict)) { + lub_val = lub_value; + lub_index = row_id; + lub_strict = r.m_type == t_lt; + } + lub_rows.push_back(row_id); + } + else { + SASSERT(a.is_neg()); + rational glb_value = x_val - (r.m_value/a); + if (glb_rows.empty() || + glb_value > glb_val || + (glb_value == glb_val && r.m_type == t_lt && !glb_strict)) { + glb_val = glb_value; + glb_index = row_id; + glb_strict = r.m_type == t_lt; + } + glb_rows.push_back(row_id); + } + } + unsigned row_index = (lub_rows.size() <= glb_rows.size())? lub_index : glb_index; + glb_rows.append(lub_rows); + if (row_index == UINT_MAX) { + for (unsigned i = 0; i < glb_rows.size(); ++i) { + unsigned row_id = glb_rows[i]; + SASSERT(m_rows[row_id].m_alive); + SASSERT(!get_coefficient(row_id, x).is_zero()); + m_rows[row_id].m_alive = false; + } + } + else { + rational coeff = get_coefficient(row_index, x); + for (unsigned i = 0; i < glb_rows.size(); ++i) { + unsigned row_id = glb_rows[i]; + if (row_id != row_index) { + resolve(row_index, coeff, row_id, x); + } + } + m_rows[row_index].m_alive = false; + } + } + + void model_based_opt::solve_for(unsigned row_id1, unsigned x) { + rational a = get_coefficient(row_id1, x); + row& r1 = m_rows[row_id1]; + SASSERT(!a.is_zero()); + SASSERT(r1.m_type == t_eq); + SASSERT(r1.m_alive); + unsigned_vector const& row_ids = m_var2row_ids[x]; + uint_set visited; + visited.insert(row_id1); + for (unsigned i = 0; i < row_ids.size(); ++i) { + unsigned row_id2 = row_ids[i]; + if (!visited.contains(row_id2)) { + visited.insert(row_id2); + resolve(row_id1, a, row_id2, x); + } + } + r1.m_alive = false; + } + + void model_based_opt::project(unsigned num_vars, unsigned const* vars) { + for (unsigned i = 0; i < num_vars; ++i) { + project(vars[i]); + } + } + } diff --git a/src/math/simplex/model_based_opt.h b/src/math/simplex/model_based_opt.h index b48a96edbb0..e4ba288c88d 100644 --- a/src/math/simplex/model_based_opt.h +++ b/src/math/simplex/model_based_opt.h @@ -48,7 +48,6 @@ namespace opt { } }; }; - private: struct row { row(): m_type(t_le), m_value(0), m_alive(false) {} vector m_vars; // variables with coefficients @@ -58,11 +57,14 @@ namespace opt { bool m_alive; // rows can be marked dead if they have been processed. }; + private: + vector m_rows; - unsigned m_objective_id; + static const unsigned m_objective_id = 0; vector m_var2row_ids; vector m_var2value; vector m_new_vars; + unsigned_vector m_lub, m_glb; bool invariant(); bool invariant(unsigned index, row const& r); @@ -81,6 +83,10 @@ namespace opt { void update_values(unsigned_vector const& bound_vars, unsigned_vector const& bound_trail); + void project(unsigned var); + + void solve_for(unsigned row_id, unsigned x); + public: model_based_opt(); @@ -106,6 +112,17 @@ namespace opt { // inf_eps maximize(); + + // + // Project set of variables from inequalities. + // + void project(unsigned num_vars, unsigned const* vars); + + // + // Extract current rows (after projection). + // + void get_live_rows(vector& rows); + void display(std::ostream& out) const; void display(std::ostream& out, row const& r) const; diff --git a/src/qe/qe_arith.cpp b/src/qe/qe_arith.cpp index 48dacdbf4df..bdfd4513387 100644 --- a/src/qe/qe_arith.cpp +++ b/src/qe/qe_arith.cpp @@ -29,6 +29,7 @@ Revision History: #include "expr_functors.h" #include "expr_safe_replace.h" #include "model_based_opt.h" +#include "model_evaluator.h" namespace qe { @@ -658,6 +659,9 @@ namespace qe { bool new_max = true; rational max_r, r; expr_ref val(m); + model_evaluator eval(mdl); + eval.set_model_completion(true); + bool is_int = a.is_int(m_var->x()); for (unsigned i = 0; i < num_ineqs(); ++i) { rational const& ac = m_ineq_coeffs[i]; @@ -669,7 +673,7 @@ namespace qe { // ac < 0: x + t/ac > 0 <=> x > max { - t/ac | ac < 0 } = max { t/|ac| | ac < 0 } // if (ac.is_pos() == do_pos) { - VERIFY(mdl.eval(ineq_term(i), val)); + eval(ineq_term(i), val); VERIFY(a.is_numeral(val, r)); r /= abs(ac); new_max = diff --git a/src/qe/qe_mbp.cpp b/src/qe/qe_mbp.cpp index 7d5f3800eb8..d7ec22eee03 100644 --- a/src/qe/qe_mbp.cpp +++ b/src/qe/qe_mbp.cpp @@ -28,10 +28,15 @@ Revision History: #include "th_rewriter.h" #include "model_v2_pp.h" #include "expr_functors.h" +#include "for_each_expr.h" using namespace qe; +struct noop_op_proc { + void operator()(expr*) {} +}; + /** \brief return two terms that are equal in the model. @@ -106,6 +111,7 @@ void project_plugin::push_back(expr_ref_vector& lits, expr* e) { class mbp::impl { ast_manager& m; + th_rewriter m_rw; ptr_vector m_plugins; expr_mark m_visited; @@ -130,7 +136,6 @@ class mbp::impl { is_var.mark(vars[i].get()); } expr_ref tmp(m), t(m), v(m); - th_rewriter rw(m); for (unsigned i = 0; i < lits.size(); ++i) { expr* e = lits[i].get(), *l, *r; if (m.is_eq(e, l, r) && reduce_eq(is_var, l, r, v, t)) { @@ -141,7 +146,7 @@ class mbp::impl { is_rem.mark(v); for (unsigned j = 0; j < lits.size(); ++j) { sub(lits[j].get(), tmp); - rw(tmp); + m_rw(tmp); lits[j] = tmp; } } @@ -177,6 +182,29 @@ class mbp::impl { } + void filter_variables(model& model, app_ref_vector& vars, expr_ref_vector& lits, expr_ref_vector& unused_lits) { + ast_manager& m = vars.get_manager(); + expr_mark lit_visited; + for_each_expr_proc fe; + for (unsigned i = 0; i < lits.size(); ++i) { + for_each_expr(fe, lit_visited, lits[i].get()); + } + unsigned j = 0; + for (unsigned i = 0; i < vars.size(); ++i) { + app* var = vars[i].get(); + if (lit_visited.is_marked(var)) { + if (i != j) { + vars[j] = vars[i].get(); + } + ++j; + } + } + if (vars.size() != j) { + vars.resize(j); + } + } + + void extract_bools(model& model, expr_ref_vector& fmls, expr* fml) { TRACE("qe", tout << "extract bools: " << mk_pp(fml, m) << "\n";); ptr_vector todo; @@ -210,6 +238,42 @@ class mbp::impl { } } + void project_bools(model& model, app_ref_vector& vars, expr_ref_vector& fmls) { + expr_safe_replace sub(m); + expr_ref val(m); + unsigned j = 0; + for (unsigned i = 0; i < vars.size(); ++i) { + app* var = vars[i].get(); + if (m.is_bool(var)) { + VERIFY(model.eval(var, val)); + sub.insert(var, val); + } + else { + if (j != i) { + vars[j] = vars[i].get(); + } + ++j; + } + } + if (j != vars.size()) { + vars.resize(j); + j = 0; + for (unsigned i = 0; i < fmls.size(); ++i) { + sub(fmls[i].get(), val); + m_rw(val); + if (!m.is_true(val)) { + if (j != i) { + fmls[j] = fmls[i].get(); + } + ++j; + } + } + if (j != fmls.size()) { + fmls.resize(j); + } + } + } + public: @@ -333,7 +397,7 @@ class mbp::impl { m_visited.reset(); } - impl(ast_manager& m):m(m) { + impl(ast_manager& m):m(m), m_rw(m) { add_plugin(alloc(arith_project_plugin, m)); add_plugin(alloc(datatype_project_plugin, m)); add_plugin(alloc(array_project_plugin, m)); @@ -359,14 +423,16 @@ class mbp::impl { void operator()(bool force_elim, app_ref_vector& vars, model& model, expr_ref_vector& fmls) { expr_ref val(m), tmp(m); app_ref var(m); - th_rewriter rw(m); + expr_ref_vector unused_fmls(m); bool progress = true; TRACE("qe", tout << vars << " " << fmls << "\n";); - while (progress && !vars.empty()) { - preprocess_solve(model, vars, fmls); + preprocess_solve(model, vars, fmls); + filter_variables(model, vars, fmls, unused_fmls); + project_bools(model, vars, fmls); + while (progress && !vars.empty() && !fmls.empty()) { app_ref_vector new_vars(m); progress = false; - while (!vars.empty()) { + while (!vars.empty() && !fmls.empty()) { var = vars.back(); vars.pop_back(); project_plugin* p = get_plugin(var); @@ -377,7 +443,7 @@ class mbp::impl { new_vars.push_back(var); } } - if (!progress && !new_vars.empty() && force_elim) { + if (!progress && !new_vars.empty() && !fmls.empty() && force_elim) { var = new_vars.back(); new_vars.pop_back(); expr_safe_replace sub(m); @@ -385,7 +451,7 @@ class mbp::impl { sub.insert(var, val); for (unsigned i = 0; i < fmls.size(); ++i) { sub(fmls[i].get(), tmp); - rw(tmp); + m_rw(tmp); if (m.is_true(tmp)) { project_plugin::erase(fmls, i); } @@ -396,9 +462,17 @@ class mbp::impl { progress = true; } vars.append(new_vars); + if (progress) { + preprocess_solve(model, vars, fmls); + } + } + if (fmls.empty()) { + vars.reset(); } + fmls.append(unused_fmls); TRACE("qe", tout << vars << " " << fmls << "\n";); } + }; mbp::mbp(ast_manager& m) { diff --git a/src/qe/qe_mbp.h b/src/qe/qe_mbp.h index 332659c0b13..7cf08682442 100644 --- a/src/qe/qe_mbp.h +++ b/src/qe/qe_mbp.h @@ -37,6 +37,7 @@ namespace qe { virtual bool operator()(model& model, app* var, app_ref_vector& vars, expr_ref_vector& lits) = 0; virtual bool solve(model& model, app_ref_vector& vars, expr_ref_vector& lits) = 0; virtual family_id get_family_id() = 0; + virtual bool operator()(model& model, app_ref_vector& vars, expr_ref_vector& lits) { return false; }; static expr_ref pick_equality(ast_manager& m, model& model, expr* t); static void partition_values(model& model, expr_ref_vector const& vals, expr_ref_vector& lits); diff --git a/src/qe/qsat.cpp b/src/qe/qsat.cpp index fe11de1997d..0ab3c86bb89 100644 --- a/src/qe/qsat.cpp +++ b/src/qe/qsat.cpp @@ -575,6 +575,7 @@ namespace qe { lbool check_sat() { while (true) { ++m_stats.m_num_rounds; + IF_VERBOSE(3, verbose_stream() << "(check-qsat level: " << m_level << " round: " << m_stats.m_num_rounds << ")\n";); check_cancel(); expr_ref_vector asms(m_asms); m_pred_abs.get_assumptions(m_model.get(), asms); @@ -1191,7 +1192,7 @@ namespace qe { lbool maximize(expr_ref_vector const& fmls, app* t, model_ref& mdl, opt::inf_eps& value) { expr_ref_vector defs(m); - expr_ref fml = negate_core(fmls); + expr_ref fml = mk_and(fmls); hoist(fml); m_objective = t; m_value = opt::inf_eps(); diff --git a/src/smt/theory_pb.cpp b/src/smt/theory_pb.cpp index 273bffd9330..a85f9aa8097 100644 --- a/src/smt/theory_pb.cpp +++ b/src/smt/theory_pb.cpp @@ -1063,7 +1063,7 @@ namespace smt { } #endif else { - IF_VERBOSE(3, display(verbose_stream() << "no propagation ", c, true);); + IF_VERBOSE(14, display(verbose_stream() << "no propagation ", c, true);); } } @@ -1637,7 +1637,7 @@ namespace smt { // same order as the assignment stack. // It is not a correctness bug but causes to miss lemmas. // - IF_VERBOSE(2, display_resolved_lemma(verbose_stream());); + IF_VERBOSE(12, display_resolved_lemma(verbose_stream());); TRACE("pb", display_resolved_lemma(tout);); return false; } @@ -1735,12 +1735,12 @@ namespace smt { // 3x + 3y + z + u >= 4 // ~x /\ ~y => z + u >= - IF_VERBOSE(4, display(verbose_stream() << "lemma1: ", m_lemma);); + IF_VERBOSE(14, display(verbose_stream() << "lemma1: ", m_lemma);); hoist_maximal_values(); lbool is_true = m_lemma.normalize(false); m_lemma.prune(false); - IF_VERBOSE(4, display(verbose_stream() << "lemma2: ", m_lemma);); + IF_VERBOSE(14, display(verbose_stream() << "lemma2: ", m_lemma);); //unsigned l_size = m_ineq_literals.size() + ((is_true==l_false)?0:m_lemma.size()); //if (s_min_l_size >= l_size) { // verbose_stream() << "(pb.conflict min size: " << l_size << ")\n"; diff --git a/src/test/model_based_opt.cpp b/src/test/model_based_opt.cpp index 8c414863841..b5b8e2953ae 100644 --- a/src/test/model_based_opt.cpp +++ b/src/test/model_based_opt.cpp @@ -216,6 +216,77 @@ static void test4() { std::cout << "u: " << mbo.get_value(u) << "\n"; } +static void test5() { + opt::model_based_opt mbo; + unsigned x = mbo.add_var(rational(2)); + unsigned y = mbo.add_var(rational(3)); + unsigned z = mbo.add_var(rational(4)); + unsigned u = mbo.add_var(rational(5)); + + add_ineq(mbo, x, 1, y, -1, 0, opt::t_le); + add_ineq(mbo, x, 1, z, -1, 0, opt::t_le); + add_ineq(mbo, y, 1, u, -1, 0, opt::t_le); + add_ineq(mbo, z, 1, u, -1, 1, opt::t_le); + + unsigned vars[2] = { y, z }; + mbo.project(1, vars); + mbo.display(std::cout); + + mbo.project(1, vars); + mbo.display(std::cout); + + mbo.project(1, vars+1); + mbo.display(std::cout); + + vector rows; + mbo.get_live_rows(rows); +} + + +static void test6() { + opt::model_based_opt mbo; + unsigned x0 = mbo.add_var(rational(1)); + unsigned x = mbo.add_var(rational(2)); + unsigned y = mbo.add_var(rational(3)); + unsigned z = mbo.add_var(rational(4)); + unsigned u = mbo.add_var(rational(5)); + unsigned v = mbo.add_var(rational(6)); + unsigned w = mbo.add_var(rational(6)); + + add_ineq(mbo, x0, 1, y, -1, 0, opt::t_le); + add_ineq(mbo, x, 1, y, -1, 0, opt::t_le); + add_ineq(mbo, y, 1, u, -1, 0, opt::t_le); + add_ineq(mbo, y, 1, z, -1, 1, opt::t_le); + add_ineq(mbo, y, 1, v, -1, 1, opt::t_le); + add_ineq(mbo, y, 1, w, -1, 1, opt::t_le); + + mbo.display(std::cout); + mbo.project(1, &y); + mbo.display(std::cout); +} + +static void test7() { + opt::model_based_opt mbo; + unsigned x0 = mbo.add_var(rational(2)); + unsigned x = mbo.add_var(rational(1)); + unsigned y = mbo.add_var(rational(3)); + unsigned z = mbo.add_var(rational(4)); + unsigned u = mbo.add_var(rational(5)); + unsigned v = mbo.add_var(rational(6)); + unsigned w = mbo.add_var(rational(6)); + + add_ineq(mbo, x0, 1, y, -1, 0, opt::t_le); + add_ineq(mbo, x, 1, y, -1, 0, opt::t_lt); + add_ineq(mbo, y, 1, u, -1, 0, opt::t_le); + add_ineq(mbo, y, 1, z, -1, 1, opt::t_le); + add_ineq(mbo, y, 1, v, -1, 1, opt::t_le); + add_ineq(mbo, y, 1, w, -1, 1, opt::t_lt); + + mbo.display(std::cout); + mbo.project(1, &y); + mbo.display(std::cout); +} + // test with mix of upper and lower bounds void tst_model_based_opt() { @@ -224,4 +295,8 @@ void tst_model_based_opt() { test2(); test3(); test4(); + test5(); + test6(); + test7(); + } From 9a10d2dceea1c264a8d283d7d0190d669f7481ae Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Sat, 21 May 2016 12:19:03 +0100 Subject: [PATCH 47/61] bugfix for fpa2bv model converter --- src/tactic/fpa/fpa2bv_model_converter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tactic/fpa/fpa2bv_model_converter.cpp b/src/tactic/fpa/fpa2bv_model_converter.cpp index 41650eda65e..37e9942e979 100644 --- a/src/tactic/fpa/fpa2bv_model_converter.cpp +++ b/src/tactic/fpa/fpa2bv_model_converter.cpp @@ -412,7 +412,7 @@ void fpa2bv_model_converter::convert(model * bv_mdl, model * float_mdl) { // Just keep. expr_ref val(m); bv_mdl->eval(it->m_value, val); - float_mdl->register_decl(f, val); + if (val) float_mdl->register_decl(f, val); } } else { From 8001b1f0c71a4498e32c012fe60e21f4036a206f Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Sat, 21 May 2016 17:43:17 +0100 Subject: [PATCH 48/61] typo --- src/ast/datatype_decl_plugin.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ast/datatype_decl_plugin.h b/src/ast/datatype_decl_plugin.h index 51d33c896b6..8ef6fb557bd 100644 --- a/src/ast/datatype_decl_plugin.h +++ b/src/ast/datatype_decl_plugin.h @@ -109,7 +109,7 @@ class datatype_decl_plugin : public decl_plugin { parameters[o] - (int) m - number of constructors parameters[o+1] - (int) k_1 - offset for constructor definition ... - parameters[o+m] - (int) k_m - offset ofr constructor definition + parameters[o+m] - (int) k_m - offset for constructor definition for each offset k_i at parameters[o+s] for some s in 0..m-1 parameters[k_i] - (symbol) name of the constructor From b6d90a64dab39e1b4f9ccf16a5462ee446940ef4 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Sat, 21 May 2016 18:07:37 +0100 Subject: [PATCH 49/61] fpa rewriter tidy up --- src/ast/rewriter/fpa_rewriter.cpp | 10 ---------- src/ast/rewriter/fpa_rewriter.h | 1 - 2 files changed, 11 deletions(-) diff --git a/src/ast/rewriter/fpa_rewriter.cpp b/src/ast/rewriter/fpa_rewriter.cpp index 19b8c3909b8..b4ae744d38d 100644 --- a/src/ast/rewriter/fpa_rewriter.cpp +++ b/src/ast/rewriter/fpa_rewriter.cpp @@ -109,8 +109,6 @@ br_status fpa_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * con st = BR_FAILED; break; - - default: NOT_IMPLEMENTED_YET(); } @@ -892,7 +890,6 @@ br_status fpa_rewriter::mk_to_real(expr * arg, expr_ref & result) { return BR_FAILED; } - br_status fpa_rewriter::mk_bvwrap(expr * arg, expr_ref & result) { if (is_app_of(arg, m_util.get_family_id(), OP_FPA_FP)) { bv_util bu(m()); @@ -923,10 +920,3 @@ br_status fpa_rewriter::mk_bvwrap(expr * arg, expr_ref & result) { return BR_FAILED; } - -//br_status fpa_rewriter::mk_bvunwrap(expr * arg, expr_ref & result) { -// if (is_app_of(arg, m_util.get_family_id(), OP_FPA_INTERNAL_BVWRAP)) -// result = to_app(arg)->get_arg(0); -// -// return BR_FAILED; -//} diff --git a/src/ast/rewriter/fpa_rewriter.h b/src/ast/rewriter/fpa_rewriter.h index f42d7c7191c..10f4ab4aa7d 100644 --- a/src/ast/rewriter/fpa_rewriter.h +++ b/src/ast/rewriter/fpa_rewriter.h @@ -91,7 +91,6 @@ class fpa_rewriter { br_status mk_to_real_unspecified(unsigned ebits, unsigned sbits, expr_ref & result); br_status mk_bvwrap(expr * arg, expr_ref & result); - br_status mk_bvunwrap(expr * arg, expr_ref & result); }; #endif From fe3f8466b67e4a4a868c87920a4019dc6aba6baf Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Sat, 21 May 2016 18:08:48 +0100 Subject: [PATCH 50/61] Partial support for fpa2bv translation in complex types. --- src/ast/fpa/fpa2bv_converter.cpp | 191 +++++++++++++++++----- src/ast/fpa/fpa2bv_converter.h | 11 +- src/ast/fpa/fpa2bv_rewriter.cpp | 40 ++--- src/ast/fpa_decl_plugin.cpp | 63 ++++++- src/ast/fpa_decl_plugin.h | 4 +- src/tactic/fpa/fpa2bv_model_converter.cpp | 17 ++ src/tactic/fpa/fpa2bv_model_converter.h | 10 ++ 7 files changed, 266 insertions(+), 70 deletions(-) diff --git a/src/ast/fpa/fpa2bv_converter.cpp b/src/ast/fpa/fpa2bv_converter.cpp index d5849a1fd6c..c103f677326 100644 --- a/src/ast/fpa/fpa2bv_converter.cpp +++ b/src/ast/fpa/fpa2bv_converter.cpp @@ -33,6 +33,9 @@ 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()), m_mpz_manager(m_mpf_manager.mpz_manager()), m_hi_fp_unspecified(true), @@ -46,11 +49,10 @@ fpa2bv_converter::~fpa2bv_converter() { void fpa2bv_converter::mk_eq(expr * a, expr * b, expr_ref & result) { if (is_float(a) && is_float(b)) { - SASSERT(is_app_of(a, m_plugin->get_family_id(), OP_FPA_FP)); - SASSERT(is_app_of(b, m_plugin->get_family_id(), OP_FPA_FP)); + SASSERT(m_util.is_fp(a) && m_util.is_fp(b)); TRACE("fpa2bv", tout << "mk_eq a=" << mk_ismt2_pp(a, m) << std::endl; - tout << "mk_eq b=" << mk_ismt2_pp(b, m) << std::endl;); + tout << "mk_eq b=" << mk_ismt2_pp(b, m) << std::endl;); expr_ref eq_sgn(m), eq_exp(m), eq_sig(m); m_simp.mk_eq(to_app(a)->get_arg(0), to_app(b)->get_arg(0), eq_sgn); @@ -77,11 +79,10 @@ void fpa2bv_converter::mk_eq(expr * a, expr * b, expr_ref & result) { m_simp.mk_or(both_are_nan, both_the_same, result); } else if (is_rm(a) && is_rm(b)) { - SASSERT(m_util.is_rm_bvwrap(b)); - SASSERT(m_util.is_rm_bvwrap(a)); + SASSERT(m_util.is_rm_bvwrap(b) && m_util.is_rm_bvwrap(a)); TRACE("fpa2bv", tout << "mk_eq_rm a=" << mk_ismt2_pp(a, m) << std::endl; - tout << "mk_eq_rm b=" << mk_ismt2_pp(b, m) << std::endl;); + tout << "mk_eq_rm b=" << mk_ismt2_pp(b, m) << std::endl;); m_simp.mk_eq(to_app(a)->get_arg(0), to_app(b)->get_arg(0), result); } @@ -90,8 +91,7 @@ void fpa2bv_converter::mk_eq(expr * a, expr * b, expr_ref & result) { } void fpa2bv_converter::mk_ite(expr * c, expr * t, expr * f, expr_ref & result) { - SASSERT(is_app_of(t, m_plugin->get_family_id(), OP_FPA_FP)); - SASSERT(is_app_of(f, m_plugin->get_family_id(), OP_FPA_FP)); + SASSERT(m_util.is_fp(t) && m_util.is_fp(f)); expr *t_sgn, *t_sig, *t_exp; expr *f_sgn, *f_sig, *f_exp; @@ -244,46 +244,119 @@ void fpa2bv_converter::mk_function_output(sort * rng, func_decl * fbv, expr * co } sort_ref fpa2bv_converter::replace_float_sorts(sort * s) { - sort_ref ns(m); + sort_ref ns(m); - if (m_util.is_float(s)) - ns = m_bv_util.mk_sort(m_util.get_sbits(s) + m_util.get_ebits(s)); - else if (m_util.is_rm(s)) - ns = m_bv_util.mk_sort(3); - else - ns = s; + sort * found_sort; + if (m_subst_sorts.find(s, found_sort)) { + ns = found_sort; + } + else { + if (m_util.is_float(s)) + ns = m_bv_util.mk_sort(m_util.get_sbits(s) + m_util.get_ebits(s)); + else if (m_util.is_rm(s)) + ns = m_bv_util.mk_sort(3); + else if (m_array_util.is_array(s)) { + SASSERT(s->get_num_parameters() > 0); + vector new_params; + unsigned num_params = s->get_num_parameters(); + for (unsigned i = 0; i < num_params; i++) + { + parameter const & pi = s->get_parameter(i); + if (pi.is_ast() && is_sort(pi.get_ast())) { + sort_ref nsrt(m); + nsrt = replace_float_sorts(to_sort(pi.get_ast())); + parameter np((ast*)nsrt); + new_params.push_back(np); + } + else + new_params.push_back(pi); + } + ns = m.mk_sort(s->get_family_id(), s->get_decl_kind(), new_params.size(), new_params.c_ptr()); + } + else if (m_dt_util.is_datatype(s)) { + TRACE("fpa2bv", tout << "datatype:"; m_dt_util.display_datatype(s, tout); ); + bool is_recursive = m_dt_util.is_recursive(s); + SASSERT(!is_recursive); + ptr_vector const * cs = m_dt_util.get_datatype_constructors(s); + ptr_vector new_css; + bool has_news = false; + for (unsigned i = 0; i < cs->size(); i++) { + func_decl * cf = cs->get(i); + func_decl * rf = m_dt_util.get_constructor_recognizer(cf); + ptr_vector new_rf; + ptr_vector const * cas = m_dt_util.get_constructor_accessors(cf); + ptr_vector new_cas; + for (unsigned j = 0; j < cas->size(); j++) { + func_decl * ca = cas->get(j); + sort * s1 = ca->get_range(); + sort_ref s1r(m); + s1r = replace_float_sorts(s1); + + symbol name(ca->get_name()); + if (s1r != s1) { + std::stringstream ss; + ss << name << "!fpa2bv"; + name = symbol(ss.str().c_str()); + has_news = true; + } + + accessor_decl * ad = mk_accessor_decl(name, type_ref(s1r)); + new_cas.push_back(ad); + } + + constructor_decl * cd = 0; + symbol name(cf->get_name()); + symbol rf_name(rf->get_name()); + + if (has_news) { + std::stringstream ss; + ss << name << "!fpa2bv"; + name = symbol(ss.str().c_str()); + std::stringstream ss2; + ss2 << rf_name << "!fpa2bv"; + rf_name = symbol(ss2.str().c_str()); + } + + cd = mk_constructor_decl(name, rf_name, new_cas.size(), new_cas.c_ptr()); + new_css.push_back(cd); + } - if (ns->get_num_parameters() != 0) { - vector new_params; - unsigned num_params = ns->get_num_parameters(); - for (unsigned i = 0; i < num_params; i++) - { - parameter const & pi = ns->get_parameter(i); - if (pi.is_ast() && pi.get_ast()->get_kind() == AST_SORT) { - sort_ref nsrt(m); - nsrt = replace_float_sorts(to_sort(pi.get_ast())); - parameter np = parameter((ast*)nsrt); - new_params.push_back(np); + if (has_news) { + std::stringstream ss; + ss << s->get_name() << "!fpa2bv"; + symbol name(ss.str().c_str()); + datatype_decl * dtd = mk_datatype_decl(name, new_css.size(), new_css.c_ptr()); + datatype_decl_plugin * dtp = static_cast(m.get_plugin(m.mk_family_id("datatype"))); + sort_ref_vector sorts(m); + bool is_ok = dtp->mk_datatypes(1, &dtd, sorts); + SASSERT(is_ok); + ns = sorts.get(0); + TRACE("fpa2bv", tout << "new datatype:"; m_dt_util.display_datatype(ns, tout); ); } else - new_params.push_back(pi); + ns = s; } + else if (m_seq_util.is_seq(s)) { + NOT_IMPLEMENTED_YET(); + } + else + ns = s; - TRACE("fpa2bv", tout << "New sort params:"; - for (unsigned i = 0; i < new_params.size(); i++) - tout << " " << new_params[i]; - tout << std::endl;); - - ns = m.mk_sort(ns->get_family_id(), ns->get_decl_kind(), new_params.size(), new_params.c_ptr()); + if (ns != s) { + m_subst_sorts.insert(s, ns); + m.inc_ref(s); + m.inc_ref(ns); + } } + SASSERT(ns != 0); TRACE("fpa2bv", tout << "sorts replaced: " << mk_ismt2_pp(s, m) << " --> " << mk_ismt2_pp(ns, m) << std::endl; ); return ns; } func_decl_ref fpa2bv_converter::replace_function(func_decl * f) { TRACE("fpa2bv", tout << "replacing: " << mk_ismt2_pp(f, m) << std::endl;); - func_decl_ref res(m); + func_decl_ref res(m); sort_ref_buffer new_domain(m); for (unsigned i = 0; i < f->get_arity(); i++) { @@ -308,18 +381,44 @@ func_decl_ref fpa2bv_converter::replace_function(func_decl * f) { } else { - TRACE("fpa2bv", tout << "New domain:"; - for (unsigned i = 0; i < new_domain.size(); i++) - tout << " " << mk_ismt2_pp(new_domain[i], m); - tout << std::endl;); + TRACE("fpa2bv", tout << "Old domain:" << std::endl; + for (unsigned i = 0; i < f->get_arity(); i++) { + if (m_dt_util.is_datatype(f->get_domain(i))) + m_dt_util.display_datatype(f->get_domain(i), tout); + else + tout << mk_ismt2_pp(f->get_domain(i), m); + tout << std::endl; + }); + + TRACE("fpa2bv", tout << "New domain:" << std::endl; + for (unsigned i = 0; i < new_domain.size(); i++) { + if (m_dt_util.is_datatype(new_domain[i])) + m_dt_util.display_datatype(new_domain[i], tout); + else + tout << mk_ismt2_pp(new_domain[i], m); + tout << std::endl; + }); + + vector new_params; + for (unsigned i = 0; i < f->get_num_parameters(); i++) { + parameter const & pi = f->get_parameter(i); + if (pi.is_ast() && is_sort(pi.get_ast())) { + sort_ref ns(m); + ns = replace_float_sorts(to_sort(pi.get_ast())); + parameter np((ast*)ns); + new_params.push_back(np); + } + else + new_params.push_back(pi); + } res = m.mk_func_decl(f->get_family_id(), f->get_decl_kind(), - f->get_num_parameters(), f->get_parameters(), + new_params.size(), new_params.c_ptr(), new_domain.size(), new_domain.c_ptr(), new_range); - TRACE("fpa2bv", tout << "New IF func_decl: " << mk_ismt2_pp(res, m) << std::endl;); + TRACE("fpa2bv", tout << "IF func_decl: " << mk_ismt2_pp(res, m) << std::endl;); } } - + return res; } @@ -391,7 +490,8 @@ void fpa2bv_converter::mk_function(func_decl * f, unsigned num, expr * const * a for (unsigned i = 0; i < num; i++) new_args.push_back(replace_float_arg(args[i])); - TRACE("fpa2bv", tout << "UF bv-args:"; + + CTRACE("fpa2bv", num > 0, tout << "UF bv-args:"; for (unsigned i = 0; i < num; i++) tout << " " << mk_ismt2_pp(new_args[i], m); tout << std::endl; ); @@ -400,7 +500,11 @@ void fpa2bv_converter::mk_function(func_decl * f, unsigned num, expr * const * a rf = replace_function(f); mk_function_output(f->get_range(), rf, new_args.c_ptr(), result); - TRACE("fpa2bv", tout << "UF result: " << mk_ismt2_pp(result, m) << std::endl; ); + TRACE("fpa2bv", tout << "UF result: " << mk_ismt2_pp(result, m) << std::endl; + tout << "old: " << mk_ismt2_pp(f->get_range(), m) << std::endl; + tout << "new: " << mk_ismt2_pp(m.get_sort(result), m) << std::endl; + tout << "equal: " << (f->get_range() == m.get_sort(result)) << std::endl;); + SASSERT(is_well_sorted(m, result)); } @@ -4118,6 +4222,7 @@ void fpa2bv_converter::reset(void) { dec_ref_map_key_values(m, m_const2bv); dec_ref_map_key_values(m, m_rm_const2bv); dec_ref_map_key_values(m, m_uf2bvuf); + dec_ref_map_key_values(m, m_subst_sorts); for (obj_map >::iterator it = m_specials.begin(); it != m_specials.end(); it++) { diff --git a/src/ast/fpa/fpa2bv_converter.h b/src/ast/fpa/fpa2bv_converter.h index 879c1e080e1..17648917fca 100644 --- a/src/ast/fpa/fpa2bv_converter.h +++ b/src/ast/fpa/fpa2bv_converter.h @@ -24,6 +24,11 @@ Module Name: #include"ref_util.h" #include"fpa_decl_plugin.h" #include"bv_decl_plugin.h" +#include"array_decl_plugin.h" +#include"datatype_decl_plugin.h" +#include"dl_decl_plugin.h" +#include"pb_decl_plugin.h" +#include"seq_decl_plugin.h" #include"basic_simplifier_plugin.h" class fpa2bv_converter { @@ -33,6 +38,9 @@ class fpa2bv_converter { 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; unsynch_mpz_manager & m_mpz_manager; fpa_decl_plugin * m_plugin; @@ -41,6 +49,7 @@ class fpa2bv_converter { obj_map m_const2bv; obj_map m_rm_const2bv; obj_map m_uf2bvuf; + obj_map m_subst_sorts; obj_map > m_specials; @@ -145,7 +154,7 @@ class fpa2bv_converter { expr_ref_vector m_extra_assertions; bool is_special(func_decl * f) { return m_specials.contains(f); } - bool is_uf2bvuf(func_decl * f) { return m_uf2bvuf.contains(f); } + bool is_uf2bvuf(func_decl * f) { return m_uf2bvuf.contains(f); } protected: void mk_one(func_decl *f, expr_ref & sign, expr_ref & result); diff --git a/src/ast/fpa/fpa2bv_rewriter.cpp b/src/ast/fpa/fpa2bv_rewriter.cpp index 2eb85c87c6c..2a66da8d713 100644 --- a/src/ast/fpa/fpa2bv_rewriter.cpp +++ b/src/ast/fpa/fpa2bv_rewriter.cpp @@ -71,7 +71,7 @@ br_status fpa2bv_rewriter_cfg::reduce_app(func_decl * f, unsigned num, expr * co if (m().is_eq(f)) { SASSERT(num == 2); TRACE("fpa2bv_rw", tout << "(= " << mk_ismt2_pp(args[0], m()) << " " << - mk_ismt2_pp(args[1], m()) << ")" << std::endl;); + mk_ismt2_pp(args[1], m()) << ")" << std::endl;); SASSERT(m().get_sort(args[0]) == m().get_sort(args[1])); sort * ds = f->get_domain()[0]; if (m_conv.is_float(ds)) { @@ -83,7 +83,7 @@ br_status fpa2bv_rewriter_cfg::reduce_app(func_decl * f, unsigned num, expr * co return BR_DONE; } return BR_FAILED; - } + } else if (m().is_ite(f)) { SASSERT(num == 3); if (m_conv.is_float(args[1])) { @@ -100,7 +100,7 @@ br_status fpa2bv_rewriter_cfg::reduce_app(func_decl * f, unsigned num, expr * co } return BR_FAILED; } - + if (m_conv.is_float_family(f)) { switch (f->get_decl_kind()) { case OP_FPA_RM_NEAREST_TIES_TO_AWAY: @@ -166,16 +166,9 @@ br_status fpa2bv_rewriter_cfg::reduce_app(func_decl * f, unsigned num, expr * co NOT_IMPLEMENTED_YET(); } } - else { - SASSERT(!m_conv.is_float_family(f)); - bool is_float_uf = m_conv.is_float(f->get_range()) || m_conv.is_rm(f->get_range()); - - for (unsigned i = 0; i < f->get_arity(); i++) { - sort * di = f->get_domain()[i]; - is_float_uf |= m_conv.is_float(di) || m_conv.is_rm(di); - } - - if (is_float_uf) { + else if (f->get_arity() > 0 && !m_conv.is_float_family(f)) { + expr_ref q(m().mk_app(f, num, args), m()); + if (m_conv.fu().contains_floats(q)) { m_conv.mk_function(f, num, args, result); return BR_DONE; } @@ -249,17 +242,16 @@ bool fpa2bv_rewriter_cfg::reduce_var(var * t, expr_ref & result, proof_ref & res expr_ref new_exp(m()); sort * s = t->get_sort(); - if (m_conv.is_float(s)) - { - expr_ref new_var(m()); - unsigned ebits = m_conv.fu().get_ebits(s); - unsigned sbits = m_conv.fu().get_sbits(s); - new_var = m().mk_var(t->get_idx(), m_conv.bu().mk_sort(sbits+ebits)); - m_conv.mk_fp(m_conv.bu().mk_extract(sbits+ebits-1, sbits+ebits-1, new_var), - m_conv.bu().mk_extract(ebits - 1, 0, new_var), - m_conv.bu().mk_extract(sbits+ebits-2, ebits, new_var), - new_exp); - } + if (m_conv.is_float(s)) { + expr_ref new_var(m()); + unsigned ebits = m_conv.fu().get_ebits(s); + unsigned sbits = m_conv.fu().get_sbits(s); + new_var = m().mk_var(t->get_idx(), m_conv.bu().mk_sort(sbits+ebits)); + m_conv.mk_fp(m_conv.bu().mk_extract(sbits+ebits-1, sbits+ebits-1, new_var), + m_conv.bu().mk_extract(ebits - 1, 0, new_var), + m_conv.bu().mk_extract(sbits+ebits-2, ebits, new_var), + new_exp); + } else new_exp = m().mk_var(t->get_idx(), s); diff --git a/src/ast/fpa_decl_plugin.cpp b/src/ast/fpa_decl_plugin.cpp index 069e7ed1806..22043e7a425 100644 --- a/src/ast/fpa_decl_plugin.cpp +++ b/src/ast/fpa_decl_plugin.cpp @@ -691,7 +691,7 @@ func_decl * fpa_decl_plugin::mk_internal_rm(decl_kind k, unsigned num_parameters } func_decl * fpa_decl_plugin::mk_internal_bv_wrap(decl_kind k, unsigned num_parameters, parameter const * parameters, - unsigned arity, sort * const * domain, sort * range) { + unsigned arity, sort * const * domain, sort * range) { if (arity != 1) m_manager->raise_exception("invalid number of arguments to bv_wrap"); if (!is_float_sort(domain[0]) && !is_rm_sort(domain[0])) @@ -1076,3 +1076,64 @@ app * fpa_util::mk_internal_to_real_unspecified(unsigned ebits, unsigned sbits) sort * range = m_a_util.mk_real(); return m().mk_app(get_family_id(), OP_FPA_INTERNAL_TO_REAL_UNSPECIFIED, 2, ps, 0, 0, range); } + +bool fpa_util::contains_floats(ast * a) { + switch (a->get_kind()) { + case AST_APP: { + app * aa = to_app(a); + if (contains_floats(aa->get_decl())) + return true; + else + for (unsigned i = 0; i < aa->get_num_args(); i++) + if (contains_floats(aa->get_arg(i))) + return true; + break; + } + case AST_VAR: + return contains_floats(to_var(a)->get_sort()); + break; + case AST_QUANTIFIER: { + quantifier * q = to_quantifier(a); + for (unsigned i = 0; i < q->get_num_children(); i++) + if (contains_floats(q->get_child(i))) + return true; + for (unsigned i = 0; i < q->get_num_decls(); i++) + if (contains_floats(q->get_decl_sort(i))) + return true; + if (contains_floats(q->get_expr())) + return true; + break; + } + case AST_SORT: { + sort * s = to_sort(a); + if (is_float(s) || is_rm(s)) + return true; + else { + for (unsigned i = 0; i < s->get_num_parameters(); i++) { + parameter const & pi = s->get_parameter(i); + if (pi.is_ast() && contains_floats(pi.get_ast())) + return true; + } + } + break; + } + case AST_FUNC_DECL: { + func_decl * f = to_func_decl(a); + for (unsigned i = 0; i < f->get_arity(); i++) + if (contains_floats(f->get_domain(i))) + return true; + if (contains_floats(f->get_range())) + return true; + for (unsigned i = 0; i < f->get_num_parameters(); i++) { + parameter const & pi = f->get_parameter(i); + if (pi.is_ast() && contains_floats(pi.get_ast())) + return true; + } + break; + } + default: + UNREACHABLE(); + } + + return false; +} diff --git a/src/ast/fpa_decl_plugin.h b/src/ast/fpa_decl_plugin.h index 8683bf5f198..725e7371ab3 100644 --- a/src/ast/fpa_decl_plugin.h +++ b/src/ast/fpa_decl_plugin.h @@ -370,7 +370,9 @@ class fpa_util { 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_rm_bvwrap(expr * e) const { return is_app_of(e, get_family_id(), OP_FPA_INTERNAL_RM_BVWRAP); } - bool is_rm_bvwrap(func_decl * f) const { return f->get_family_id() == get_family_id() && f->get_decl_kind() == OP_FPA_INTERNAL_RM_BVWRAP; } + bool is_rm_bvwrap(func_decl * f) const { return f->get_family_id() == get_family_id() && f->get_decl_kind() == OP_FPA_INTERNAL_RM_BVWRAP; } + + bool contains_floats(ast * a); }; #endif diff --git a/src/tactic/fpa/fpa2bv_model_converter.cpp b/src/tactic/fpa/fpa2bv_model_converter.cpp index 37e9942e979..db8b1391347 100644 --- a/src/tactic/fpa/fpa2bv_model_converter.cpp +++ b/src/tactic/fpa/fpa2bv_model_converter.cpp @@ -46,6 +46,12 @@ void fpa2bv_model_converter::display(std::ostream & out) { unsigned indent = n.size() + 4; out << mk_ismt2_pp(it->m_value, m, indent) << ")"; } + for (obj_map::iterator it = m_subst_sorts.begin(); + it != m_subst_sorts.end(); + it++) { + out << "\n " << mk_ismt2_pp(it->m_key, m) << " -> "; + out << mk_ismt2_pp(it->m_value, m); + } for (obj_map >::iterator it = m_specials.begin(); it != m_specials.end(); it++) { @@ -55,6 +61,7 @@ void fpa2bv_model_converter::display(std::ostream & out) { out << mk_ismt2_pp(it->m_value.first, m, indent) << "; " << mk_ismt2_pp(it->m_value.second, m, indent) << ")"; } + out << ")"; } model_converter * fpa2bv_model_converter::translate(ast_translation & translator) { @@ -88,6 +95,15 @@ model_converter * fpa2bv_model_converter::translate(ast_translation & translator translator.to().inc_ref(k); translator.to().inc_ref(v); } + for (obj_map::iterator it = m_subst_sorts.begin(); + it != m_subst_sorts.end(); + it++) { + sort * k = translator(it->m_key); + sort * v = translator(it->m_value); + res->m_subst_sorts.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++) { @@ -410,6 +426,7 @@ void fpa2bv_model_converter::convert(model * bv_mdl, model * float_mdl) { } 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); diff --git a/src/tactic/fpa/fpa2bv_model_converter.h b/src/tactic/fpa/fpa2bv_model_converter.h index ce38527c131..bb7c780670d 100644 --- a/src/tactic/fpa/fpa2bv_model_converter.h +++ b/src/tactic/fpa/fpa2bv_model_converter.h @@ -32,6 +32,7 @@ class fpa2bv_model_converter : public model_converter { obj_map m_const2bv; obj_map m_rm_const2bv; obj_map m_uf2bvuf; + obj_map m_subst_sorts; obj_map > m_specials; public: @@ -64,6 +65,14 @@ class fpa2bv_model_converter : public model_converter { m.inc_ref(it->m_key); m.inc_ref(it->m_value); } + for (obj_map::iterator it = conv.m_subst_sorts.begin(); + it != conv.m_subst_sorts.end(); + it++) + { + m_subst_sorts.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_specials.begin(); it != conv.m_specials.end(); it++) { @@ -78,6 +87,7 @@ class fpa2bv_model_converter : public 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); + dec_ref_map_key_values(m, m_subst_sorts); for (obj_map >::iterator it = m_specials.begin(); it != m_specials.end(); it++) { From 8db17311aeecd721778db5352bddba665842dea9 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Sun, 22 May 2016 13:13:32 +0100 Subject: [PATCH 51/61] fpa2bv build fixes --- src/ast/fpa/fpa2bv_converter.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/ast/fpa/fpa2bv_converter.cpp b/src/ast/fpa/fpa2bv_converter.cpp index c103f677326..96480890d9f 100644 --- a/src/ast/fpa/fpa2bv_converter.cpp +++ b/src/ast/fpa/fpa2bv_converter.cpp @@ -300,7 +300,7 @@ sort_ref fpa2bv_converter::replace_float_sorts(sort * s) { has_news = true; } - accessor_decl * ad = mk_accessor_decl(name, type_ref(s1r)); + accessor_decl * ad = mk_accessor_decl(name, type_ref(s1r.get())); new_cas.push_back(ad); } @@ -455,7 +455,6 @@ expr_ref fpa2bv_converter::replace_float_arg(expr * a) { break; case AST_QUANTIFIER: { quantifier * q = to_quantifier(a); - sort * const * srts = q->get_decl_sorts(); vector new_sorts; for (unsigned i = 0; q->get_num_decls(); i++) { sort_ref ns(m); From d4bc8ebb70bea0fc561c2582296d7dd62a72b275 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Sun, 22 May 2016 18:16:57 +0100 Subject: [PATCH 52/61] FP to BV translation of UFs refactored. --- src/ast/fpa/fpa2bv_converter.cpp | 410 ++++------------------ src/ast/fpa/fpa2bv_converter.h | 11 +- src/ast/fpa/fpa2bv_rewriter.cpp | 23 +- src/ast/fpa_decl_plugin.h | 13 +- src/smt/theory_fpa.cpp | 31 +- src/tactic/fpa/fpa2bv_model_converter.cpp | 35 +- src/tactic/fpa/fpa2bv_model_converter.h | 15 +- 7 files changed, 136 insertions(+), 402 deletions(-) diff --git a/src/ast/fpa/fpa2bv_converter.cpp b/src/ast/fpa/fpa2bv_converter.cpp index 96480890d9f..cda3bd27e16 100644 --- a/src/ast/fpa/fpa2bv_converter.cpp +++ b/src/ast/fpa/fpa2bv_converter.cpp @@ -103,7 +103,7 @@ void fpa2bv_converter::mk_ite(expr * c, expr * t, expr * f, expr_ref & result) { m_simp.mk_ite(c, t_sig, f_sig, s); m_simp.mk_ite(c, t_exp, f_exp, e); - mk_fp(sgn, e, s, result); + result = m_util.mk_fp(sgn, e, s); } void fpa2bv_converter::mk_distinct(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { @@ -152,7 +152,7 @@ void fpa2bv_converter::mk_numeral(func_decl * f, unsigned num, expr * const * ar mk_bias(e, biased_exp); - mk_fp(bv_sgn, biased_exp, bv_sig, 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;); @@ -199,7 +199,7 @@ void fpa2bv_converter::mk_const(func_decl * f, expr_ref & result) { SASSERT(m_bv_util.get_bv_size(e) == ebits); #endif - mk_fp(sgn, e, s, result); + result = m_util.mk_fp(sgn, e, s); m_const2bv.insert(f, result); m.inc_ref(f); @@ -218,7 +218,7 @@ void fpa2bv_converter::mk_var(unsigned base_inx, sort * srt, expr_ref & result) s = m.mk_var(base_inx+1, m_bv_util.mk_sort(sbits-1)); e = m.mk_var(base_inx+2, m_bv_util.mk_sort(ebits)); - mk_fp(sgn, e, s, result); + result = m_util.mk_fp(sgn, e, s); } void fpa2bv_converter::mk_function_output(sort * rng, func_decl * fbv, expr * const * new_args, expr_ref & result) { @@ -229,281 +229,70 @@ void fpa2bv_converter::mk_function_output(sort * rng, func_decl * fbv, expr * co app_ref na(m); na = m.mk_app(fbv, fbv->get_arity(), new_args); - mk_fp(m_bv_util.mk_extract(bv_sz - 1, bv_sz - 1, na), - m_bv_util.mk_extract(bv_sz - 2, sbits - 1, na), - m_bv_util.mk_extract(sbits - 2, 0, na), - result); + result = m_util.mk_fp(m_bv_util.mk_extract(bv_sz - 1, bv_sz - 1, na), + m_bv_util.mk_extract(bv_sz - 2, sbits - 1, na), + m_bv_util.mk_extract(sbits - 2, 0, na)); } else if (m_util.is_rm(rng)) { app_ref na(m); na = m.mk_app(fbv, fbv->get_arity(), new_args); - mk_rm(na, result); + result = m_util.mk_rm(na); } else result = m.mk_app(fbv, fbv->get_arity(), new_args); } -sort_ref fpa2bv_converter::replace_float_sorts(sort * s) { - sort_ref ns(m); - - sort * found_sort; - if (m_subst_sorts.find(s, found_sort)) { - ns = found_sort; - } - else { - if (m_util.is_float(s)) - ns = m_bv_util.mk_sort(m_util.get_sbits(s) + m_util.get_ebits(s)); - else if (m_util.is_rm(s)) - ns = m_bv_util.mk_sort(3); - else if (m_array_util.is_array(s)) { - SASSERT(s->get_num_parameters() > 0); - vector new_params; - unsigned num_params = s->get_num_parameters(); - for (unsigned i = 0; i < num_params; i++) - { - parameter const & pi = s->get_parameter(i); - if (pi.is_ast() && is_sort(pi.get_ast())) { - sort_ref nsrt(m); - nsrt = replace_float_sorts(to_sort(pi.get_ast())); - parameter np((ast*)nsrt); - new_params.push_back(np); - } - else - new_params.push_back(pi); - } - ns = m.mk_sort(s->get_family_id(), s->get_decl_kind(), new_params.size(), new_params.c_ptr()); - } - else if (m_dt_util.is_datatype(s)) { - TRACE("fpa2bv", tout << "datatype:"; m_dt_util.display_datatype(s, tout); ); - bool is_recursive = m_dt_util.is_recursive(s); - SASSERT(!is_recursive); - ptr_vector const * cs = m_dt_util.get_datatype_constructors(s); - ptr_vector new_css; - bool has_news = false; - for (unsigned i = 0; i < cs->size(); i++) { - func_decl * cf = cs->get(i); - func_decl * rf = m_dt_util.get_constructor_recognizer(cf); - ptr_vector new_rf; - ptr_vector const * cas = m_dt_util.get_constructor_accessors(cf); - ptr_vector new_cas; - for (unsigned j = 0; j < cas->size(); j++) { - func_decl * ca = cas->get(j); - sort * s1 = ca->get_range(); - sort_ref s1r(m); - s1r = replace_float_sorts(s1); - - symbol name(ca->get_name()); - if (s1r != s1) { - std::stringstream ss; - ss << name << "!fpa2bv"; - name = symbol(ss.str().c_str()); - has_news = true; - } - - accessor_decl * ad = mk_accessor_decl(name, type_ref(s1r.get())); - new_cas.push_back(ad); - } - - constructor_decl * cd = 0; - symbol name(cf->get_name()); - symbol rf_name(rf->get_name()); - - if (has_news) { - std::stringstream ss; - ss << name << "!fpa2bv"; - name = symbol(ss.str().c_str()); - std::stringstream ss2; - ss2 << rf_name << "!fpa2bv"; - rf_name = symbol(ss2.str().c_str()); - } - - cd = mk_constructor_decl(name, rf_name, new_cas.size(), new_cas.c_ptr()); - new_css.push_back(cd); - } - - if (has_news) { - std::stringstream ss; - ss << s->get_name() << "!fpa2bv"; - symbol name(ss.str().c_str()); - datatype_decl * dtd = mk_datatype_decl(name, new_css.size(), new_css.c_ptr()); - datatype_decl_plugin * dtp = static_cast(m.get_plugin(m.mk_family_id("datatype"))); - sort_ref_vector sorts(m); - bool is_ok = dtp->mk_datatypes(1, &dtd, sorts); - SASSERT(is_ok); - ns = sorts.get(0); - TRACE("fpa2bv", tout << "new datatype:"; m_dt_util.display_datatype(ns, tout); ); - } - else - ns = s; - } - else if (m_seq_util.is_seq(s)) { - NOT_IMPLEMENTED_YET(); - } - else - ns = s; - - if (ns != s) { - m_subst_sorts.insert(s, ns); - m.inc_ref(s); - m.inc_ref(ns); - } - } - - SASSERT(ns != 0); - TRACE("fpa2bv", tout << "sorts replaced: " << mk_ismt2_pp(s, m) << " --> " << mk_ismt2_pp(ns, m) << std::endl; ); - return ns; -} - -func_decl_ref fpa2bv_converter::replace_function(func_decl * f) { - TRACE("fpa2bv", tout << "replacing: " << mk_ismt2_pp(f, m) << std::endl;); - func_decl_ref res(m); - - sort_ref_buffer new_domain(m); - for (unsigned i = 0; i < f->get_arity(); i++) { - sort * di = f->get_domain()[i]; - new_domain.push_back(replace_float_sorts(di)); - } - - func_decl * fd; - if (m_uf2bvuf.find(f, fd)) - res = fd; - else { - sort_ref new_range(m); - new_range = replace_float_sorts(f->get_range()); - - if (f->get_family_id() == null_family_id) { - res = m.mk_fresh_func_decl(f->get_name(), symbol("bv"), new_domain.size(), new_domain.c_ptr(), new_range); - TRACE("fpa2bv", tout << "New UF func_decl: " << std::endl << mk_ismt2_pp(res, m) << std::endl;); - - m_uf2bvuf.insert(f, res); - m.inc_ref(f); - m.inc_ref(res); - } - else - { - TRACE("fpa2bv", tout << "Old domain:" << std::endl; - for (unsigned i = 0; i < f->get_arity(); i++) { - if (m_dt_util.is_datatype(f->get_domain(i))) - m_dt_util.display_datatype(f->get_domain(i), tout); - else - tout << mk_ismt2_pp(f->get_domain(i), m); - tout << std::endl; - }); - - TRACE("fpa2bv", tout << "New domain:" << std::endl; - for (unsigned i = 0; i < new_domain.size(); i++) { - if (m_dt_util.is_datatype(new_domain[i])) - m_dt_util.display_datatype(new_domain[i], tout); - else - tout << mk_ismt2_pp(new_domain[i], m); - tout << std::endl; - }); - - vector new_params; - for (unsigned i = 0; i < f->get_num_parameters(); i++) { - parameter const & pi = f->get_parameter(i); - if (pi.is_ast() && is_sort(pi.get_ast())) { - sort_ref ns(m); - ns = replace_float_sorts(to_sort(pi.get_ast())); - parameter np((ast*)ns); - new_params.push_back(np); - } - else - new_params.push_back(pi); - } - - res = m.mk_func_decl(f->get_family_id(), f->get_decl_kind(), - new_params.size(), new_params.c_ptr(), - new_domain.size(), new_domain.c_ptr(), new_range); - TRACE("fpa2bv", tout << "IF func_decl: " << mk_ismt2_pp(res, m) << std::endl;); - } +func_decl * fpa2bv_converter::get_bv_uf(func_decl * f, sort * bv_rng, unsigned arity) { + func_decl * res; + if (!m_uf2bvuf.find(f, res)) { + res = m.mk_fresh_func_decl(f->get_name(), symbol("bv"), arity, f->get_domain(), bv_rng); + m_uf2bvuf.insert(f, res); + m.inc_ref(f); + m.inc_ref(res); + TRACE("fpa2bv", tout << "New UF func_decl: " << std::endl << mk_ismt2_pp(res, m) << std::endl;); } - return res; } - -expr_ref fpa2bv_converter::replace_float_arg(expr * a) { - expr_ref na(m); - - switch (a->get_kind()) { - case AST_APP: - if (m_util.is_float(a)) { - SASSERT(m_util.is_fp(a)); - expr * sgn, *exp, *sig; - split_fp(a, sgn, exp, sig); - expr * args[3] = { sgn, exp, sig }; - na = m_bv_util.mk_concat(3, args); - } - else if (is_rm(a)) { - SASSERT(m_util.is_rm_bvwrap(a)); - na = to_app(a)->get_arg(0); - } - else if (m.is_value(a)) - na = a; - else { - sort_ref ns(m); - app_ref ar(m); - ar = to_app(a); - func_decl * f = to_app(ar)->get_decl(); - func_decl_ref rf(m); - rf = replace_function(f); - na = m.mk_app(rf, ar->get_num_args(), ar->get_args()); - } - break; - case AST_VAR: - na = m.mk_var(to_var(a)->get_idx(), replace_float_sorts(m.get_sort(a))); - break; - case AST_QUANTIFIER: { - quantifier * q = to_quantifier(a); - vector new_sorts; - for (unsigned i = 0; q->get_num_decls(); i++) { - sort_ref ns(m); - ns = replace_float_sorts(q->get_decl_sort(i)); - new_sorts.push_back(ns); - } - na = m.mk_quantifier(q->is_forall(), - q->get_num_decls(), new_sorts.c_ptr(), - q->get_decl_names(), q->get_expr(), - q->get_weight(), q->get_qid(), q->get_skid(), - q->get_num_patterns(), q->get_patterns(), - q->get_num_no_patterns(), q->get_no_patterns()); - break; - } - case AST_SORT: - case AST_FUNC_DECL: - default: - UNREACHABLE(); - } - - TRACE("fpa2bv", tout << "arg replaced: " << mk_ismt2_pp(a, m) << " --> " << mk_ismt2_pp(na, m) << std::endl; ); - return na; -} - void fpa2bv_converter::mk_function(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { TRACE("fpa2bv", tout << "UF: " << mk_ismt2_pp(f, m) << std::endl; ); - SASSERT(f->get_arity() == num); - - expr_ref_buffer new_args(m); - - for (unsigned i = 0; i < num; i++) - new_args.push_back(replace_float_arg(args[i])); - - CTRACE("fpa2bv", num > 0, tout << "UF bv-args:"; - for (unsigned i = 0; i < num; i++) - tout << " " << mk_ismt2_pp(new_args[i], m); - tout << std::endl; ); - - func_decl_ref rf(m); - rf = replace_function(f); - mk_function_output(f->get_range(), rf, new_args.c_ptr(), result); - - TRACE("fpa2bv", tout << "UF result: " << mk_ismt2_pp(result, m) << std::endl; - tout << "old: " << mk_ismt2_pp(f->get_range(), m) << std::endl; - tout << "new: " << mk_ismt2_pp(m.get_sort(result), m) << std::endl; - tout << "equal: " << (f->get_range() == m.get_sort(result)) << std::endl;); + expr_ref fapp(m), feq(m); + sort_ref rng(m); + app_ref bv_app(m), flt_app(m); + rng = f->get_range(); + fapp = m.mk_app(f, num, args); + if (m_util.is_float(rng)) { + sort_ref bv_rng(m); + expr_ref new_eq(m); + unsigned ebits = m_util.get_ebits(rng); + unsigned sbits = m_util.get_sbits(rng); + unsigned bv_sz = ebits+sbits; + bv_rng = m_bv_util.mk_sort(bv_sz); + func_decl * bv_f = get_bv_uf(f, bv_rng, num); + bv_app = m.mk_app(bv_f, num, args); + flt_app = m_util.mk_fp(m_bv_util.mk_extract(bv_sz-1, bv_sz-1, bv_app), + m_bv_util.mk_extract(sbits+ebits-2, sbits-1, bv_app), + m_bv_util.mk_extract(sbits-2, 0, bv_app)); + new_eq = m.mk_eq(fapp, flt_app); + m_extra_assertions.push_back(new_eq); + result = flt_app; + } + else if (m_util.is_rm(rng)) { + sort_ref bv_rng(m); + expr_ref new_eq(m); + bv_rng = m_bv_util.mk_sort(3); + func_decl * bv_f = get_bv_uf(f, bv_rng, num); + bv_app = m.mk_app(bv_f, num, args); + flt_app = m_util.mk_rm(bv_app); + new_eq = m.mk_eq(fapp, flt_app); + m_extra_assertions.push_back(new_eq); + result = flt_app; + } + else + result = fapp; + TRACE("fpa2bv", tout << "UF result: " << mk_ismt2_pp(result, m) << std::endl; ); SASSERT(is_well_sorted(m, result)); } @@ -526,7 +315,7 @@ void fpa2bv_converter::mk_rm_const(func_decl * f, expr_ref & result) { #endif , m_bv_util.mk_sort(3)); - mk_rm(bv3, result); + result = m_util.mk_rm(bv3); m_rm_const2bv.insert(f, result); m.inc_ref(f); m.inc_ref(result); @@ -547,10 +336,7 @@ void fpa2bv_converter::mk_pinf(sort * s, expr_ref & result) { unsigned ebits = m_util.get_ebits(s); expr_ref top_exp(m); mk_top_exp(ebits, top_exp); - mk_fp(m_bv_util.mk_numeral(0, 1), - top_exp, - m_bv_util.mk_numeral(0, sbits-1), - result); + result = m_util.mk_fp(m_bv_util.mk_numeral(0, 1), top_exp, m_bv_util.mk_numeral(0, sbits-1)); } void fpa2bv_converter::mk_ninf(func_decl * f, expr_ref & result) { @@ -563,10 +349,7 @@ void fpa2bv_converter::mk_ninf(sort * s, expr_ref & result) { unsigned ebits = m_util.get_ebits(s); expr_ref top_exp(m); mk_top_exp(ebits, top_exp); - mk_fp(m_bv_util.mk_numeral(1, 1), - top_exp, - m_bv_util.mk_numeral(0, sbits-1), - result); + result = m_util.mk_fp(m_bv_util.mk_numeral(1, 1), top_exp, m_bv_util.mk_numeral(0, sbits-1)); } void fpa2bv_converter::mk_nan(func_decl * f, expr_ref & result) { @@ -579,10 +362,7 @@ void fpa2bv_converter::mk_nan(sort * s, expr_ref & result) { unsigned ebits = m_util.get_ebits(s); expr_ref top_exp(m); mk_top_exp(ebits, top_exp); - mk_fp(m_bv_util.mk_numeral(0, 1), - top_exp, - m_bv_util.mk_numeral(1, sbits - 1), - result); + result = m_util.mk_fp(m_bv_util.mk_numeral(0, 1), top_exp, m_bv_util.mk_numeral(1, sbits - 1)); } void fpa2bv_converter::mk_nzero(func_decl * f, expr_ref & result) { @@ -595,10 +375,7 @@ void fpa2bv_converter::mk_nzero(sort * s, expr_ref & result) { unsigned ebits = m_util.get_ebits(s); expr_ref bot_exp(m); mk_bot_exp(ebits, bot_exp); - mk_fp(m_bv_util.mk_numeral(1, 1), - bot_exp, - m_bv_util.mk_numeral(0, sbits - 1), - result); + result = m_util.mk_fp(m_bv_util.mk_numeral(1, 1), bot_exp, m_bv_util.mk_numeral(0, sbits - 1)); } void fpa2bv_converter::mk_pzero(func_decl * f, expr_ref & result) { @@ -611,10 +388,7 @@ void fpa2bv_converter::mk_pzero(sort * s, expr_ref & result) { unsigned ebits = m_util.get_ebits(s); expr_ref bot_exp(m); mk_bot_exp(ebits, bot_exp); - mk_fp(m_bv_util.mk_numeral(0, 1), - bot_exp, - m_bv_util.mk_numeral(0, sbits-1), - result); + result = m_util.mk_fp(m_bv_util.mk_numeral(0, 1), bot_exp, m_bv_util.mk_numeral(0, sbits-1)); } void fpa2bv_converter::mk_zero(sort * s, expr_ref & sgn, expr_ref & result) { @@ -633,10 +407,7 @@ void fpa2bv_converter::mk_one(sort * s, expr_ref & sign, expr_ref & result) { SASSERT(is_float(s)); unsigned sbits = m_util.get_sbits(s); unsigned ebits = m_util.get_ebits(s); - mk_fp(sign, - m_bv_util.mk_numeral(fu().fm().m_powers2.m1(ebits-1), ebits), - m_bv_util.mk_numeral(0, sbits-1), - result); + result = m_util.mk_fp(sign, m_bv_util.mk_numeral(fu().fm().m_powers2.m1(ebits-1), ebits), m_bv_util.mk_numeral(0, sbits-1)); } void fpa2bv_converter::add_core(unsigned sbits, unsigned ebits, @@ -916,7 +687,7 @@ void fpa2bv_converter::mk_neg(sort * srt, expr_ref & x, expr_ref & result) { nsgn = m_bv_util.mk_bv_not(sgn); expr_ref r_sgn(m); m_simp.mk_ite(c, sgn, nsgn, r_sgn); - mk_fp(r_sgn, e, sig, result); + result = m_util.mk_fp(r_sgn, e, sig); } void fpa2bv_converter::mk_mul(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { @@ -1333,7 +1104,7 @@ void fpa2bv_converter::mk_abs(func_decl * f, unsigned num, expr * const * args, SASSERT(num == 1); expr * sgn, * s, * e; split_fp(args[0], sgn, e, s); - mk_fp(m_bv_util.mk_numeral(0, 1), e, s, result); + result = m_util.mk_fp(m_bv_util.mk_numeral(0, 1), e, s); } void fpa2bv_converter::mk_min(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { @@ -1404,14 +1175,8 @@ expr_ref fpa2bv_converter::mk_min_unspecified(func_decl * f, expr * x, expr * y) } expr_ref pn(m), np(m); - mk_fp(decls.first, - m_bv_util.mk_numeral(0, ebits), - m_bv_util.mk_numeral(0, sbits - 1), - pn); - mk_fp(decls.second, - m_bv_util.mk_numeral(0, ebits), - m_bv_util.mk_numeral(0, sbits - 1), - np); + pn = m_util.mk_fp(decls.first, m_bv_util.mk_numeral(0, ebits), m_bv_util.mk_numeral(0, sbits - 1)); + np = m_util.mk_fp(decls.second, m_bv_util.mk_numeral(0, ebits), m_bv_util.mk_numeral(0, sbits - 1)); expr_ref x_is_pzero(m), x_is_nzero(m), xyzero(m); mk_is_pzero(x, x_is_pzero); @@ -1491,14 +1256,8 @@ expr_ref fpa2bv_converter::mk_max_unspecified(func_decl * f, expr * x, expr * y) } expr_ref pn(m), np(m); - mk_fp(decls.first, - m_bv_util.mk_numeral(0, ebits), - m_bv_util.mk_numeral(0, sbits - 1), - pn); - mk_fp(decls.second, - m_bv_util.mk_numeral(0, ebits), - m_bv_util.mk_numeral(0, sbits - 1), - np); + pn = m_util.mk_fp(decls.first, m_bv_util.mk_numeral(0, ebits), m_bv_util.mk_numeral(0, sbits - 1)); + np = m_util.mk_fp(decls.second, m_bv_util.mk_numeral(0, ebits), m_bv_util.mk_numeral(0, sbits - 1)); expr_ref x_is_pzero(m), x_is_nzero(m), xyzero(m); mk_is_pzero(x, x_is_pzero); @@ -2389,10 +2148,9 @@ void fpa2bv_converter::mk_to_fp(func_decl * f, unsigned num, expr * const * args int sz = m_bv_util.get_bv_size(bv); SASSERT((unsigned)sz == to_sbits + to_ebits); - mk_fp(m_bv_util.mk_extract(sz - 1, sz - 1, bv), - m_bv_util.mk_extract(sz - 2, sz - to_ebits - 1, bv), - m_bv_util.mk_extract(sz - to_ebits - 2, 0, bv), - result); + result = m_util.mk_fp(m_bv_util.mk_extract(sz - 1, sz - 1, bv), + m_bv_util.mk_extract(sz - 2, sz - to_ebits - 1, bv), + m_bv_util.mk_extract(sz - to_ebits - 2, 0, bv)); } else if (num == 2 && m_util.is_rm(args[0]) && @@ -2421,7 +2179,7 @@ void fpa2bv_converter::mk_to_fp(func_decl * f, unsigned num, expr * const * args SASSERT(m_bv_util.get_bv_size(args[0]) == 1); SASSERT(m_util.get_ebits(f->get_range()) == m_bv_util.get_bv_size(args[1])); SASSERT(m_util.get_sbits(f->get_range()) == m_bv_util.get_bv_size(args[2])+1); - mk_fp(args[0], args[1], args[2], result); + result = m_util.mk_fp(args[0], args[1], args[2]); } else if (num == 3 && m_util.is_rm(args[0]) && @@ -2648,7 +2406,7 @@ void fpa2bv_converter::mk_to_fp_real(func_decl * f, sort * s, expr * rm, expr * unbiased_exp = m_bv_util.mk_numeral(m_util.fm().exp(v), ebits); mk_bias(unbiased_exp, exp); - mk_fp(sgn, exp, sig, result); + result = m_util.mk_fp(sgn, exp, sig); } } else if (m_util.au().is_numeral(x)) { @@ -2681,32 +2439,32 @@ void fpa2bv_converter::mk_to_fp_real(func_decl * f, sort * s, expr * rm, expr * sig = m_bv_util.mk_numeral(m_util.fm().sig(v_nta), sbits - 1); unbiased_exp = m_bv_util.mk_numeral(m_util.fm().exp(v_nta), ebits); mk_bias(unbiased_exp, exp); - mk_fp(sgn, exp, sig, v1); + v1 = m_util.mk_fp(sgn, exp, sig); sgn = m_bv_util.mk_numeral((m_util.fm().sgn(v_nte)) ? 1 : 0, 1); sig = m_bv_util.mk_numeral(m_util.fm().sig(v_nte), sbits - 1); unbiased_exp = m_bv_util.mk_numeral(m_util.fm().exp(v_nte), ebits); mk_bias(unbiased_exp, exp); - mk_fp(sgn, exp, sig, v2); + v2 = m_util.mk_fp(sgn, exp, sig); sgn = m_bv_util.mk_numeral((m_util.fm().sgn(v_tp)) ? 1 : 0, 1); sig = m_bv_util.mk_numeral(m_util.fm().sig(v_tp), sbits - 1); unbiased_exp = m_bv_util.mk_numeral(m_util.fm().exp(v_tp), ebits); mk_bias(unbiased_exp, exp); - mk_fp(sgn, exp, sig, v3); + v3 = m_util.mk_fp(sgn, exp, sig); sgn = m_bv_util.mk_numeral((m_util.fm().sgn(v_tn)) ? 1 : 0, 1); sig = m_bv_util.mk_numeral(m_util.fm().sig(v_tn), sbits - 1); unbiased_exp = m_bv_util.mk_numeral(m_util.fm().exp(v_tn), ebits); mk_bias(unbiased_exp, exp); - mk_fp(sgn, exp, sig, v4); + v4 = m_util.mk_fp(sgn, exp, sig); sgn = m_bv_util.mk_numeral((m_util.fm().sgn(v_tp)) ? 1 : 0, 1); sig = m_bv_util.mk_numeral(m_util.fm().sig(v_tp), sbits - 1); unbiased_exp = m_bv_util.mk_numeral(m_util.fm().exp(v_tp), ebits); mk_bias(unbiased_exp, exp); - mk_fp(sgn, exp, sig, result); + result = m_util.mk_fp(sgn, exp, sig); mk_ite(rm_tn, v4, result, result); mk_ite(rm_tp, v3, result, result); mk_ite(rm_nte, v2, result, result); @@ -3447,27 +3205,14 @@ expr_ref fpa2bv_converter::mk_to_ieee_bv_unspecified(unsigned ebits, unsigned sb return result; } -void fpa2bv_converter::mk_rm(expr * bv3, expr_ref & result) { - SASSERT(m_bv_util.is_bv(bv3) && m_bv_util.get_bv_size(bv3) == 3); - result = m.mk_app(m_util.get_family_id(), OP_FPA_INTERNAL_RM_BVWRAP, 0, 0, 1, &bv3, m_util.mk_rm_sort()); -} - -void fpa2bv_converter::mk_fp(expr * sign, expr * exponent, expr * significand, expr_ref & result) { - SASSERT(m_bv_util.is_bv(sign) && m_bv_util.get_bv_size(sign) == 1); - SASSERT(m_bv_util.is_bv(significand)); - SASSERT(m_bv_util.is_bv(exponent)); - result = m.mk_app(m_util.get_family_id(), OP_FPA_FP, sign, exponent, significand); -} - 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); SASSERT(m_util.get_sbits(f->get_range()) == m_bv_util.get_bv_size(args[2]) + 1); SASSERT(m_util.get_ebits(f->get_range()) == m_bv_util.get_bv_size(args[1])); - mk_fp(args[0], args[1], args[2], result); + result = m_util.mk_fp(args[0], args[1], args[2]); TRACE("fpa2bv_mk_fp", tout << "mk_fp result = " << mk_ismt2_pp(result, m) << std::endl;); } - void fpa2bv_converter::split_fp(expr * e, expr * & sgn, expr * & exp, expr * & sig) const { SASSERT(m_util.is_fp(e)); SASSERT(to_app(e)->get_num_args() == 3); @@ -3814,7 +3559,7 @@ void fpa2bv_converter::mk_rounding_mode(decl_kind k, expr_ref & result) default: UNREACHABLE(); } - mk_rm(result, result); + result = m_util.mk_rm(result); } void fpa2bv_converter::dbg_decouple(const char * prefix, expr_ref & e) { @@ -4212,7 +3957,7 @@ void fpa2bv_converter::round(sort * s, expr_ref & rm, expr_ref & sgn, expr_ref & SASSERT(m_bv_util.get_bv_size(res_exp) == ebits); SASSERT(is_well_sorted(m, res_exp)); - mk_fp(res_sgn, res_exp, res_sig, result); + result = m_util.mk_fp(res_sgn, res_exp, res_sig); TRACE("fpa2bv_round", tout << "ROUND = " << mk_ismt2_pp(result, m) << std::endl; ); } @@ -4221,7 +3966,6 @@ void fpa2bv_converter::reset(void) { dec_ref_map_key_values(m, m_const2bv); dec_ref_map_key_values(m, m_rm_const2bv); dec_ref_map_key_values(m, m_uf2bvuf); - dec_ref_map_key_values(m, m_subst_sorts); for (obj_map >::iterator it = m_specials.begin(); it != m_specials.end(); it++) { diff --git a/src/ast/fpa/fpa2bv_converter.h b/src/ast/fpa/fpa2bv_converter.h index 17648917fca..19c5b33520a 100644 --- a/src/ast/fpa/fpa2bv_converter.h +++ b/src/ast/fpa/fpa2bv_converter.h @@ -48,8 +48,7 @@ class fpa2bv_converter { obj_map m_const2bv; obj_map m_rm_const2bv; - obj_map m_uf2bvuf; - obj_map m_subst_sorts; + obj_map m_uf2bvuf; obj_map > m_specials; @@ -68,12 +67,9 @@ class fpa2bv_converter { 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_rm(expr * bv3, expr_ref & result); - - void mk_fp(expr * sign, expr * exponent, expr * significand, expr_ref & result); + 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; @@ -199,6 +195,7 @@ class fpa2bv_converter { func_decl_ref replace_function(func_decl * f); expr_ref replace_float_arg(expr * a); void mk_function_output(sort * rng, func_decl * fbv, expr * const * new_args, expr_ref & result); + func_decl * get_bv_uf(func_decl * f, sort * bv_rng, unsigned arity); private: void mk_nan(sort * s, expr_ref & result); diff --git a/src/ast/fpa/fpa2bv_rewriter.cpp b/src/ast/fpa/fpa2bv_rewriter.cpp index 2a66da8d713..7680025e073 100644 --- a/src/ast/fpa/fpa2bv_rewriter.cpp +++ b/src/ast/fpa/fpa2bv_rewriter.cpp @@ -56,7 +56,10 @@ bool fpa2bv_rewriter_cfg::max_steps_exceeded(unsigned num_steps) const { br_status fpa2bv_rewriter_cfg::reduce_app(func_decl * f, unsigned num, expr * const * args, expr_ref & result, proof_ref & result_pr) { - TRACE("fpa2bv_rw", tout << "APP: " << f->get_name() << std::endl; ); + TRACE("fpa2bv_rw", tout << "func: " << f->get_name() << std::endl; + tout << "args: " << std::endl; + for (unsigned i = 0; i < num; i++) + tout << mk_ismt2_pp(args[i], m()) << std::endl;); if (num == 0 && f->get_family_id() == null_family_id && m_conv.is_float(f->get_range())) { m_conv.mk_const(f, result); @@ -166,12 +169,11 @@ br_status fpa2bv_rewriter_cfg::reduce_app(func_decl * f, unsigned num, expr * co NOT_IMPLEMENTED_YET(); } } - else if (f->get_arity() > 0 && !m_conv.is_float_family(f)) { - expr_ref q(m().mk_app(f, num, args), m()); - if (m_conv.fu().contains_floats(q)) { - m_conv.mk_function(f, num, args, result); - return BR_DONE; - } + else + { + SASSERT(!m_conv.is_float_family(f)); + m_conv.mk_function(f, num, args, result); + return BR_DONE; } return BR_FAILED; @@ -247,10 +249,9 @@ bool fpa2bv_rewriter_cfg::reduce_var(var * t, expr_ref & result, proof_ref & res unsigned ebits = m_conv.fu().get_ebits(s); unsigned sbits = m_conv.fu().get_sbits(s); new_var = m().mk_var(t->get_idx(), m_conv.bu().mk_sort(sbits+ebits)); - m_conv.mk_fp(m_conv.bu().mk_extract(sbits+ebits-1, sbits+ebits-1, new_var), - m_conv.bu().mk_extract(ebits - 1, 0, new_var), - m_conv.bu().mk_extract(sbits+ebits-2, ebits, new_var), - new_exp); + new_exp = m_conv.fu().mk_fp(m_conv.bu().mk_extract(sbits+ebits-1, sbits+ebits-1, new_var), + m_conv.bu().mk_extract(ebits - 1, 0, new_var), + m_conv.bu().mk_extract(sbits+ebits-2, ebits, new_var)); } else new_exp = m().mk_var(t->get_idx(), s); diff --git a/src/ast/fpa_decl_plugin.h b/src/ast/fpa_decl_plugin.h index 725e7371ab3..33667e3f7d4 100644 --- a/src/ast/fpa_decl_plugin.h +++ b/src/ast/fpa_decl_plugin.h @@ -294,7 +294,18 @@ class fpa_util { 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) { return m().mk_app(m_fid, OP_FPA_FP, sgn, exp, 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); + } + + app * mk_rm(expr * bv3) { + SASSERT(m_bv_util.is_bv(bv3) && m_bv_util.get_bv_size(bv3) == 3); + return m().mk_app(m_fid, OP_FPA_INTERNAL_RM_BVWRAP, 0, 0, 1, &bv3, mk_rm_sort()); + } + 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/smt/theory_fpa.cpp b/src/smt/theory_fpa.cpp index 0268d2353f8..c6c302dedb9 100644 --- a/src/smt/theory_fpa.cpp +++ b/src/smt/theory_fpa.cpp @@ -54,10 +54,9 @@ namespace smt { unsigned bv_sz = m_th.m_bv_util.get_bv_size(bv); unsigned sbits = m_th.m_fpa_util.get_sbits(s); SASSERT(bv_sz == m_th.m_fpa_util.get_ebits(s) + sbits); - m_th.m_converter.mk_fp(m_bv_util.mk_extract(bv_sz - 1, bv_sz - 1, bv), - m_bv_util.mk_extract(bv_sz - 2, sbits - 1, bv), - m_bv_util.mk_extract(sbits - 2, 0, bv), - result); + result = m_util.mk_fp(m_bv_util.mk_extract(bv_sz - 1, bv_sz - 1, bv), + m_bv_util.mk_extract(bv_sz - 2, sbits - 1, bv), + m_bv_util.mk_extract(sbits - 2, 0, bv)); SASSERT(m_th.m_fpa_util.is_float(result)); m_const2bv.insert(f, result); m.inc_ref(f); @@ -76,7 +75,7 @@ namespace smt { SASSERT(is_rm(f->get_range())); expr_ref bv(m); bv = m_th.wrap(m.mk_const(f)); - mk_rm(bv, result); + result = m_util.mk_rm(bv); m_rm_const2bv.insert(f, result); m.inc_ref(f); m.inc_ref(result); @@ -84,8 +83,8 @@ namespace smt { } void theory_fpa::fpa2bv_converter_wrapped::mk_function(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { - return fpa2bv_converter::mk_function(f, num, args, result); - TRACE("t_fpa", tout << "UF result: " << mk_ismt2_pp(result, m) << std::endl; ); + // Note: this introduces new UFs that should be filtered afterwards. + return fpa2bv_converter::mk_function(f, num, args, result); } expr_ref theory_fpa::fpa2bv_converter_wrapped::mk_min_unspecified(func_decl * f, expr * x, expr * y) { @@ -100,10 +99,9 @@ namespace smt { expr_ref a(m), wrapped(m); a = m.mk_app(w, x, y); wrapped = m_th.wrap(a); - m_th.m_converter.mk_fp(m_bv_util.mk_extract(bv_sz - 1, bv_sz - 1, wrapped), - m_bv_util.mk_extract(bv_sz - 2, sbits - 1, wrapped), - m_bv_util.mk_extract(sbits - 2, 0, wrapped), - res); + res = m_util.mk_fp(m_bv_util.mk_extract(bv_sz - 1, bv_sz - 1, wrapped), + m_bv_util.mk_extract(bv_sz - 2, sbits - 1, wrapped), + m_bv_util.mk_extract(sbits - 2, 0, wrapped)); expr_ref sc(m); m_th.m_converter.mk_is_zero(res, sc); @@ -123,10 +121,9 @@ namespace smt { expr_ref a(m), wrapped(m); a = m.mk_app(w, x, y); wrapped = m_th.wrap(a); - m_th.m_converter.mk_fp(m_bv_util.mk_extract(bv_sz - 1, bv_sz - 1, wrapped), - m_bv_util.mk_extract(bv_sz - 2, sbits - 1, wrapped), - m_bv_util.mk_extract(sbits - 2, 0, wrapped), - res); + res = m_util.mk_fp(m_bv_util.mk_extract(bv_sz - 1, bv_sz - 1, wrapped), + m_bv_util.mk_extract(bv_sz - 2, sbits - 1, wrapped), + m_bv_util.mk_extract(sbits - 2, 0, wrapped)); expr_ref sc(m); m_th.m_converter.mk_is_zero(res, sc); @@ -380,7 +377,7 @@ namespace smt { SASSERT(m_fpa_util.is_rm_bvwrap(e_conv)); expr_ref bv_rm(m); m_th_rw(to_app(e_conv)->get_arg(0), bv_rm); - m_converter.mk_rm(bv_rm, res); + res = m_fpa_util.mk_rm(bv_rm); } else if (m_fpa_util.is_float(e)) { SASSERT(m_fpa_util.is_fp(e_conv)); @@ -389,7 +386,7 @@ namespace smt { m_th_rw(sgn); m_th_rw(exp); m_th_rw(sig); - m_converter.mk_fp(sgn, exp, sig, res); + res = m_fpa_util.mk_fp(sgn, exp, sig); } else UNREACHABLE(); diff --git a/src/tactic/fpa/fpa2bv_model_converter.cpp b/src/tactic/fpa/fpa2bv_model_converter.cpp index db8b1391347..64423f22492 100644 --- a/src/tactic/fpa/fpa2bv_model_converter.cpp +++ b/src/tactic/fpa/fpa2bv_model_converter.cpp @@ -46,12 +46,6 @@ void fpa2bv_model_converter::display(std::ostream & out) { unsigned indent = n.size() + 4; out << mk_ismt2_pp(it->m_value, m, indent) << ")"; } - for (obj_map::iterator it = m_subst_sorts.begin(); - it != m_subst_sorts.end(); - it++) { - out << "\n " << mk_ismt2_pp(it->m_key, m) << " -> "; - out << mk_ismt2_pp(it->m_value, m); - } for (obj_map >::iterator it = m_specials.begin(); it != m_specials.end(); it++) { @@ -95,15 +89,6 @@ model_converter * fpa2bv_model_converter::translate(ast_translation & translator translator.to().inc_ref(k); translator.to().inc_ref(v); } - for (obj_map::iterator it = m_subst_sorts.begin(); - it != m_subst_sorts.end(); - it++) { - sort * k = translator(it->m_key); - sort * v = translator(it->m_value); - res->m_subst_sorts.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++) { @@ -213,16 +198,25 @@ expr_ref fpa2bv_model_converter::convert_bv2rm(model * bv_mdl, expr * val) { 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)) { - SASSERT(m_bv_util.is_bv(e)); - result = convert_bv2fp(bv_mdl, s, e); + 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)) { - SASSERT(m_bv_util.get_bv_size(e) == 3); - result = convert_bv2rm(bv_mdl, e); + 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); @@ -245,6 +239,7 @@ fpa2bv_model_converter::array_model fpa2bv_model_converter::convert_array_func_i 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++) diff --git a/src/tactic/fpa/fpa2bv_model_converter.h b/src/tactic/fpa/fpa2bv_model_converter.h index bb7c780670d..0e92841de37 100644 --- a/src/tactic/fpa/fpa2bv_model_converter.h +++ b/src/tactic/fpa/fpa2bv_model_converter.h @@ -32,7 +32,6 @@ class fpa2bv_model_converter : public model_converter { obj_map m_const2bv; obj_map m_rm_const2bv; obj_map m_uf2bvuf; - obj_map m_subst_sorts; obj_map > m_specials; public: @@ -65,14 +64,6 @@ class fpa2bv_model_converter : public model_converter { m.inc_ref(it->m_key); m.inc_ref(it->m_value); } - for (obj_map::iterator it = conv.m_subst_sorts.begin(); - it != conv.m_subst_sorts.end(); - it++) - { - m_subst_sorts.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_specials.begin(); it != conv.m_specials.end(); it++) { @@ -87,7 +78,6 @@ class fpa2bv_model_converter : public 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); - dec_ref_map_key_values(m, m_subst_sorts); for (obj_map >::iterator it = m_specials.begin(); it != m_specials.end(); it++) { @@ -128,15 +118,14 @@ class fpa2bv_model_converter : public model_converter { 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) : result(m) {} + 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); From 218e47f34b35aeba01ef5983efc8b177ef96c9bb Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Sun, 22 May 2016 18:21:28 +0100 Subject: [PATCH 53/61] Removed unused variable --- src/smt/theory_fpa.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/smt/theory_fpa.cpp b/src/smt/theory_fpa.cpp index c6c302dedb9..dca364686c5 100644 --- a/src/smt/theory_fpa.cpp +++ b/src/smt/theory_fpa.cpp @@ -317,8 +317,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(); - sort * bv_srt = m.get_sort(e); + ast_manager & m = get_manager(); app_ref res(m); unsigned bv_sz = m_bv_util.get_bv_size(e); From c725fe7698445e9b3fe16939dc4a475952fd75e5 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 22 May 2016 17:03:29 -0700 Subject: [PATCH 54/61] tune lra optimization Signed-off-by: Nikolaj Bjorner --- src/opt/opt_context.cpp | 21 ++++- src/opt/opt_context.h | 3 +- src/qe/qe_arith.cpp | 193 +++++++++++++++++++++++++++++++++------- src/qe/qe_arith.h | 2 + src/qe/qe_mbp.cpp | 24 +++-- src/qe/qe_mbp.h | 4 +- src/qe/qsat.cpp | 57 +++++++++--- src/qe/qsat.h | 10 +++ 8 files changed, 259 insertions(+), 55 deletions(-) diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index fccdf9b55bf..0b71fff1c9d 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -1300,6 +1300,9 @@ namespace opt { } get_memory_statistics(stats); get_rlimit_statistics(m.limit(), stats); + if (m_qmax) { + m_qmax->collect_statistics(stats); + } } void context::collect_param_descrs(param_descrs & r) { @@ -1440,6 +1443,9 @@ namespace opt { m_objectives[0].m_type != O_MINIMIZE) { return false; } + if (!m_arith.is_real(m_objectives[0].m_term)) { + return false; + } for (unsigned i = 0; i < m_hard_constraints.size(); ++i) { if (has_quantifiers(m_hard_constraints[i].get())) { return true; @@ -1456,12 +1462,21 @@ namespace opt { term = m_arith.mk_uminus(term); } inf_eps value; - lbool result = qe::maximize(m_hard_constraints, term, value, m_model, m_params); + m_qmax = alloc(qe::qmax, m, m_params); + lbool result = (*m_qmax)(m_hard_constraints, term, value, m_model); if (result != l_undef && obj.m_type == O_MINIMIZE) { value.neg(); } - if (result != l_undef) { - m_optsmt.setup(*m_opt_solver.get()); + m_optsmt.setup(*m_opt_solver.get()); + if (result == l_undef) { + if (obj.m_type == O_MINIMIZE) { + m_optsmt.update_upper(obj.m_index, value); + } + else { + m_optsmt.update_lower(obj.m_index, value); + } + } + else { m_optsmt.update_lower(obj.m_index, value); m_optsmt.update_upper(obj.m_index, value); } diff --git a/src/opt/opt_context.h b/src/opt/opt_context.h index 3339dc37ac8..07fe5326832 100644 --- a/src/opt/opt_context.h +++ b/src/opt/opt_context.h @@ -28,7 +28,7 @@ Module Name: #include "arith_decl_plugin.h" #include "bv_decl_plugin.h" #include "cmd_context.h" - +#include "qsat.h" namespace opt { @@ -145,6 +145,7 @@ namespace opt { ref m_solver; ref m_sat_solver; scoped_ptr m_pareto; + scoped_ptr m_qmax; sref_vector m_box_models; unsigned m_box_index; params_ref m_params; diff --git a/src/qe/qe_arith.cpp b/src/qe/qe_arith.cpp index bdfd4513387..38d46fefef0 100644 --- a/src/qe/qe_arith.cpp +++ b/src/qe/qe_arith.cpp @@ -64,6 +64,7 @@ namespace qe { expr_ref_vector m_div_terms; vector m_div_divisors, m_div_coeffs; expr_ref_vector m_new_lits; + expr_ref_vector m_trail; rational m_delta, m_u; scoped_ptr m_var; unsigned m_num_pos, m_num_neg; @@ -98,7 +99,7 @@ namespace qe { // It uses the current model to choose values for conditionals and it primes mbo with the current // interpretation of sub-expressions that are treated as variables for mbo. // - void linearize(opt::model_based_opt& mbo, model& model, expr* lit, obj_map& tids) { + bool linearize(opt::model_based_opt& mbo, model& model, expr* lit, expr_ref_vector& fmls, obj_map& tids) { obj_map ts; rational c(0), mul(1); expr_ref t(m); @@ -111,33 +112,45 @@ namespace qe { mul.neg(); } SASSERT(!m.is_not(lit)); - if (a.is_le(lit, e1, e2) || a.is_ge(lit, e2, e1)) { - linearize(mbo, model, mul, e1, c, ts, tids); - linearize(mbo, model, -mul, e2, c, ts, tids); + if ((a.is_le(lit, e1, e2) || a.is_ge(lit, e2, e1)) && a.is_real(e1)) { + linearize(mbo, model, mul, e1, c, fmls, ts, tids); + linearize(mbo, model, -mul, e2, c, fmls, ts, tids); ty = is_not ? opt::t_lt : opt::t_le; } - else if (a.is_lt(lit, e1, e2) || a.is_gt(lit, e2, e1)) { - linearize(mbo, model, mul, e1, c, ts, tids); - linearize(mbo, model, -mul, e2, c, ts, tids); + else if ((a.is_lt(lit, e1, e2) || a.is_gt(lit, e2, e1)) && a.is_real(e1)) { + linearize(mbo, model, mul, e1, c, fmls, ts, tids); + linearize(mbo, model, -mul, e2, c, fmls, ts, tids); ty = is_not ? opt::t_le: opt::t_lt; } - else if (m.is_eq(lit, e1, e2) && !is_not && is_arith(e1)) { - linearize(mbo, model, mul, e1, c, ts, tids); - linearize(mbo, model, -mul, e2, c, ts, tids); + else if (m.is_eq(lit, e1, e2) && !is_not && a.is_real(e1)) { + linearize(mbo, model, mul, e1, c, fmls, ts, tids); + linearize(mbo, model, -mul, e2, c, fmls, ts, tids); ty = opt::t_eq; } - else if (m.is_distinct(lit) && !is_not && is_arith(to_app(lit)->get_arg(0))) { - UNREACHABLE(); + else if (m.is_eq(lit, e1, e2) && is_not && a.is_real(e1)) { + expr_ref val1(m), val2(m); + rational r1, r2; + VERIFY(model.eval(e1, val1) && a.is_numeral(val1, r1)); + VERIFY(model.eval(e2, val2) && a.is_numeral(val2, r2)); + SASSERT(r1 != r2); + if (r2 < r1) { + std::swap(e1, e2); + } + ty = opt::t_lt; + linearize(mbo, model, mul, e1, c, fmls, ts, tids); + linearize(mbo, model, -mul, e2, c, fmls, ts, tids); + } + else if (m.is_distinct(lit) && !is_not && a.is_real(to_app(lit)->get_arg(0))) { + TRACE("qe", tout << "TBD: handle distinc\n";); + return false; } - else if (m.is_distinct(lit) && is_not && is_arith(to_app(lit)->get_arg(0))) { - UNREACHABLE(); + else if (m.is_distinct(lit) && is_not && a.is_real(to_app(lit)->get_arg(0))) { + TRACE("qe", tout << "TBD: handle negation of distinc\n";); + return false; } - else if (m.is_eq(lit, e1, e2) && is_not && is_arith(e1)) { - UNREACHABLE(); - } else { TRACE("qe", tout << "Skipping " << mk_pp(lit, m) << "\n";); - return; + return false; } #if 0 TBD for integers @@ -149,34 +162,35 @@ namespace qe { vars coeffs; extract_coefficients(mbo, model, ts, tids, coeffs); mbo.add_constraint(coeffs, c, ty); + return true; } // // convert linear arithmetic term into an inequality for mbo. // void linearize(opt::model_based_opt& mbo, model& model, rational const& mul, expr* t, rational& c, - obj_map& ts, obj_map& tids) { + expr_ref_vector& fmls, obj_map& ts, obj_map& tids) { expr* t1, *t2, *t3; rational mul1; expr_ref val(m); if (a.is_mul(t, t1, t2) && is_numeral(model, t1, mul1)) { - linearize(mbo, model, mul* mul1, t2, c, ts, tids); + linearize(mbo, model, mul* mul1, t2, c, fmls, ts, tids); } else if (a.is_mul(t, t1, t2) && is_numeral(model, t2, mul1)) { - linearize(mbo, model, mul* mul1, t1, c, ts, tids); + linearize(mbo, model, mul* mul1, t1, c, fmls, ts, tids); } else if (a.is_add(t)) { app* ap = to_app(t); for (unsigned i = 0; i < ap->get_num_args(); ++i) { - linearize(mbo, model, mul, ap->get_arg(i), c, ts, tids); + linearize(mbo, model, mul, ap->get_arg(i), c, fmls, ts, tids); } } else if (a.is_sub(t, t1, t2)) { - linearize(mbo, model, mul, t1, c, ts, tids); - linearize(mbo, model, -mul, t2, c, ts, tids); + linearize(mbo, model, mul, t1, c, fmls, ts, tids); + linearize(mbo, model, -mul, t2, c, fmls, ts, tids); } else if (a.is_uminus(t, t1)) { - linearize(mbo, model, -mul, t1, c, ts, tids); + linearize(mbo, model, -mul, t1, c, fmls, ts, tids); } else if (a.is_numeral(t, mul1)) { c += mul*mul1; @@ -186,13 +200,13 @@ namespace qe { SASSERT(m.is_true(val) || m.is_false(val)); TRACE("qe", tout << mk_pp(t1, m) << " := " << val << "\n";); if (m.is_true(val)) { - linearize(mbo, model, mul, t2, c, ts, tids); - linearize(mbo, model, t1, tids); + linearize(mbo, model, mul, t2, c, fmls, ts, tids); + fmls.push_back(t1); } else { expr_ref not_t1(mk_not(m, t1), m); - linearize(mbo, model, mul, t3, c, ts, tids); - linearize(mbo, model, not_t1, tids); + fmls.push_back(not_t1); + linearize(mbo, model, mul, t3, c, fmls, ts, tids); } } else { @@ -433,6 +447,7 @@ namespace qe { return a.is_int(e) || a.is_real(e); } + expr_ref add(expr_ref_vector const& ts) { switch (ts.size()) { case 0: @@ -952,7 +967,7 @@ namespace qe { } imp(ast_manager& m): - m(m), a(m), m_rw(m), m_ineq_terms(m), m_div_terms(m), m_new_lits(m) { + m(m), a(m), m_rw(m), m_ineq_terms(m), m_div_terms(m), m_new_lits(m), m_trail(m) { params_ref params; params.set_bool("gcd_rouding", true); m_rw.updt_params(params); @@ -979,11 +994,115 @@ namespace qe { } typedef opt::model_based_opt::var var; + typedef opt::model_based_opt::row row; typedef vector vars; - - opt::inf_eps maximize(expr_ref_vector const& fmls, model& mdl, app* t, expr_ref& bound) { + + void operator()(model& model, app_ref_vector& vars, expr_ref_vector& fmls) { + bool has_real = false; + for (unsigned i = 0; !has_real && i < vars.size(); ++i) { + has_real = a.is_real(vars[i].get()); + } + if (!has_real) { + return; + } + + opt::model_based_opt mbo; + obj_map tids; + m_trail.reset(); + unsigned j = 0; + for (unsigned i = 0; i < fmls.size(); ++i) { + if (!linearize(mbo, model, fmls[i].get(), fmls, tids)) { + if (i != j) { + fmls[j] = fmls[i].get(); + } + ++j; + } + } + fmls.resize(j); + + // fmls holds residue, + // mbo holds linear inequalities that are in scope + // collect variables in residue an in tids. + // filter variables that are absent from residue. + // project those. + // collect result of projection + // return those to fmls. + + expr_mark var_mark, fmls_mark; + for (unsigned i = 0; i < vars.size(); ++i) { + app* v = vars[i].get(); + var_mark.mark(v); + if (a.is_real(v) && !tids.contains(v)) { + tids.insert(v, tids.size()); + } + } + for (unsigned i = 0; i < fmls.size(); ++i) { + fmls_mark.mark(fmls[i].get()); + } + obj_map::iterator it = tids.begin(), end = tids.end(); + ptr_vector index2expr; + for (; it != end; ++it) { + expr* e = it->m_key; + if (!var_mark.is_marked(e)) { + mark_rec(fmls_mark, e); + } + index2expr.setx(it->m_value, e, 0); + } + j = 0; + unsigned_vector real_vars; + for (unsigned i = 0; i < vars.size(); ++i) { + app* v = vars[i].get(); + if (a.is_real(v) && !fmls_mark.is_marked(v)) { + real_vars.push_back(tids.find(v)); + } + else { + if (i != j) { + vars[j] = v; + } + ++j; + } + } + vars.resize(j); + mbo.project(real_vars.size(), real_vars.c_ptr()); + vector rows; + mbo.get_live_rows(rows); + + for (unsigned i = 0; i < rows.size(); ++i) { + expr_ref_vector ts(m); + expr_ref t(m), s(m); + row const& r = rows[i]; + for (j = 0; j < r.m_vars.size(); ++j) { + var const& v = r.m_vars[j]; + t = index2expr[v.m_id]; + if (!v.m_coeff.is_one()) { + t = a.mk_mul(t, a.mk_numeral(v.m_coeff, v.m_coeff.is_int())); + } + ts.push_back(t); + } + if (ts.empty()) { + continue; + } + s = a.mk_numeral(-r.m_coeff, r.m_coeff.is_int()); + if (ts.size() == 1) { + t = ts[0].get(); + } + else { + t = a.mk_add(ts.size(), ts.c_ptr()); + } + switch (r.m_type) { + case opt::t_lt: t = a.mk_lt(t, s); break; + case opt::t_le: t = a.mk_le(t, s); break; + case opt::t_eq: t = a.mk_eq(t, s); break; + } + fmls.push_back(t); + } + } + + opt::inf_eps maximize(expr_ref_vector const& fmls0, model& mdl, app* t, expr_ref& bound) { + m_trail.reset(); SASSERT(a.is_real(t)); + expr_ref_vector fmls(fmls0); opt::model_based_opt mbo; opt::inf_eps value; obj_map ts; @@ -992,13 +1111,14 @@ namespace qe { // extract objective function. vars coeffs; rational c(0), mul(1); - linearize(mbo, mdl, mul, t, c, ts, tids); + linearize(mbo, mdl, mul, t, c, fmls, ts, tids); extract_coefficients(mbo, mdl, ts, tids, coeffs); mbo.set_objective(coeffs, c); // extract linear constraints + for (unsigned i = 0; i < fmls.size(); ++i) { - linearize(mbo, mdl, fmls[i], tids); + linearize(mbo, mdl, fmls[i].get(), fmls, tids); } // find optimal value @@ -1052,6 +1172,7 @@ namespace qe { return; } tids.insert(it->m_key, id); + m_trail.push_back(it->m_key); } coeffs.push_back(var(id, it->m_value)); } @@ -1071,6 +1192,10 @@ namespace qe { return (*m_imp)(model, var, vars, lits); } + void arith_project_plugin::operator()(model& model, app_ref_vector& vars, expr_ref_vector& lits) { + (*m_imp)(model, vars, lits); + } + bool arith_project_plugin::solve(model& model, app_ref_vector& vars, expr_ref_vector& lits) { return m_imp->solve(model, vars, lits); } diff --git a/src/qe/qe_arith.h b/src/qe/qe_arith.h index b89d16d0402..f71156b1e23 100644 --- a/src/qe/qe_arith.h +++ b/src/qe/qe_arith.h @@ -29,6 +29,8 @@ namespace qe { virtual bool operator()(model& model, app* var, app_ref_vector& vars, expr_ref_vector& lits); virtual bool solve(model& model, app_ref_vector& vars, expr_ref_vector& lits); virtual family_id get_family_id(); + virtual void operator()(model& model, app_ref_vector& vars, expr_ref_vector& lits); + opt::inf_eps maximize(expr_ref_vector const& fmls, model& mdl, app* t, expr_ref& bound); }; diff --git a/src/qe/qe_mbp.cpp b/src/qe/qe_mbp.cpp index d7ec22eee03..727832d700d 100644 --- a/src/qe/qe_mbp.cpp +++ b/src/qe/qe_mbp.cpp @@ -38,6 +38,17 @@ struct noop_op_proc { }; +void project_plugin::mark_rec(expr_mark& visited, expr* e) { + for_each_expr_proc fe; + for_each_expr(fe, visited, e); +} + +void project_plugin::mark_rec(expr_mark& visited, expr_ref_vector const& es) { + for (unsigned i = 0; i < es.size(); ++i) { + mark_rec(visited, es[i]); + } +} + /** \brief return two terms that are equal in the model. The distinct term t is false in model, so there @@ -185,10 +196,8 @@ class mbp::impl { void filter_variables(model& model, app_ref_vector& vars, expr_ref_vector& lits, expr_ref_vector& unused_lits) { ast_manager& m = vars.get_manager(); expr_mark lit_visited; - for_each_expr_proc fe; - for (unsigned i = 0; i < lits.size(); ++i) { - for_each_expr(fe, lit_visited, lits[i].get()); - } + project_plugin::mark_rec(lit_visited, lits); + unsigned j = 0; for (unsigned i = 0; i < vars.size(); ++i) { app* var = vars[i].get(); @@ -425,13 +434,18 @@ class mbp::impl { app_ref var(m); expr_ref_vector unused_fmls(m); bool progress = true; - TRACE("qe", tout << vars << " " << fmls << "\n";); preprocess_solve(model, vars, fmls); filter_variables(model, vars, fmls, unused_fmls); project_bools(model, vars, fmls); while (progress && !vars.empty() && !fmls.empty()) { app_ref_vector new_vars(m); progress = false; + for (unsigned i = 0; i < m_plugins.size(); ++i) { + project_plugin* p = m_plugins[i]; + if (p) { + (*p)(model, vars, fmls); + } + } while (!vars.empty() && !fmls.empty()) { var = vars.back(); vars.pop_back(); diff --git a/src/qe/qe_mbp.h b/src/qe/qe_mbp.h index 7cf08682442..6c28555b0e4 100644 --- a/src/qe/qe_mbp.h +++ b/src/qe/qe_mbp.h @@ -37,13 +37,15 @@ namespace qe { virtual bool operator()(model& model, app* var, app_ref_vector& vars, expr_ref_vector& lits) = 0; virtual bool solve(model& model, app_ref_vector& vars, expr_ref_vector& lits) = 0; virtual family_id get_family_id() = 0; - virtual bool operator()(model& model, app_ref_vector& vars, expr_ref_vector& lits) { return false; }; + virtual void operator()(model& model, app_ref_vector& vars, expr_ref_vector& lits) { }; static expr_ref pick_equality(ast_manager& m, model& model, expr* t); static void partition_values(model& model, expr_ref_vector const& vals, expr_ref_vector& lits); static void partition_args(model& model, app_ref_vector const& sels, expr_ref_vector& lits); static void erase(expr_ref_vector& lits, unsigned& i); static void push_back(expr_ref_vector& lits, expr* lit); + static void mark_rec(expr_mark& visited, expr* e); + static void mark_rec(expr_mark& visited, expr_ref_vector const& es); }; class mbp { diff --git a/src/qe/qsat.cpp b/src/qe/qsat.cpp index 0ab3c86bb89..a9ca9e99db1 100644 --- a/src/qe/qsat.cpp +++ b/src/qe/qsat.cpp @@ -33,6 +33,7 @@ Revision History: #include "label_rewriter.h" #include "expr_replacer.h" #include "th_rewriter.h" +#include "model_evaluator.h" namespace qe { @@ -154,12 +155,14 @@ namespace qe { if (level == 0) { return; } + model_evaluator eval(*mdl); + expr_ref val(m); for (unsigned j = 0; j < m_preds[level - 1].size(); ++j) { app* p = m_preds[level - 1][j].get(); TRACE("qe", tout << "process level: " << level - 1 << ": " << mk_pp(p, m) << "\n";); - VERIFY(mdl->eval(p, val)); + eval(p, val); if (m.is_false(val)) { m_asms.push_back(m.mk_not(p)); @@ -179,7 +182,7 @@ namespace qe { (lvl.m_fa == i && (lvl.m_ex == UINT_MAX || lvl.m_ex < level)) || (lvl.m_ex == i && (lvl.m_fa == UINT_MAX || lvl.m_fa < level)); if (use) { - VERIFY(mdl->eval(p, val)); + eval(p, val); if (m.is_false(val)) { asms.push_back(m.mk_not(p)); } @@ -566,6 +569,9 @@ namespace qe { qsat_mode m_mode; app_ref_vector m_avars; // variables to project app_ref_vector m_free_vars; + app* m_objective; + opt::inf_eps* m_value; + bool m_was_sat; /** @@ -1067,7 +1073,10 @@ namespace qe { m_level(0), m_mode(mode), m_avars(m), - m_free_vars(m) + m_free_vars(m), + m_objective(0), + m_value(0), + m_was_sat(false) { reset(); } @@ -1162,6 +1171,9 @@ namespace qe { void collect_statistics(statistics & st) const { st.copy(m_st); + m_fa.k().collect_statistics(st); + m_ex.k().collect_statistics(st); + m_pred_abs.collect_statistics(st); st.update("qsat num rounds", m_stats.m_num_rounds); m_pred_abs.collect_statistics(st); } @@ -1169,7 +1181,7 @@ namespace qe { void reset_statistics() { m_stats.reset(); m_fa.k().reset_statistics(); - m_ex.k().reset_statistics(); + m_ex.k().reset_statistics(); } void cleanup() { @@ -1186,16 +1198,12 @@ namespace qe { return alloc(qsat, m, m_params, m_mode); } - app* m_objective; - opt::inf_eps m_value; - bool m_was_sat; - lbool maximize(expr_ref_vector const& fmls, app* t, model_ref& mdl, opt::inf_eps& value) { expr_ref_vector defs(m); expr_ref fml = mk_and(fmls); hoist(fml); m_objective = t; - m_value = opt::inf_eps(); + m_value = &value; m_was_sat = false; m_pred_abs.abstract_atoms(fml, defs); fml = m_pred_abs.mk_abstract(fml); @@ -1219,17 +1227,20 @@ namespace qe { if (s == "ok") { s = m_fa.k().last_failure_as_string(); } + throw tactic_exception(s.c_str()); } - value = m_value; return l_true; } void maximize(expr_ref_vector const& core, model& mdl) { + SASSERT(m_value); + SASSERT(m_objective); TRACE("qe", tout << "maximize: " << core << "\n";); m_was_sat |= !core.empty(); expr_ref bound(m); - m_value = m_mbp.maximize(core, mdl, m_objective, bound); + *m_value = m_mbp.maximize(core, mdl, m_objective, bound); + IF_VERBOSE(0, verbose_stream() << "(maximize " << *m_value << " bound: " << bound << ")\n";); m_ex.assert_expr(bound); } @@ -1243,6 +1254,30 @@ namespace qe { return qs.maximize(fmls, t, mdl, value); } + + struct qmax::imp { + qsat m_qsat; + imp(ast_manager& m, params_ref const& p): + m_qsat(m, p, qsat_maximize) + {} + }; + + qmax::qmax(ast_manager& m, params_ref const& p) { + m_imp = alloc(imp, m, p); + } + + qmax::~qmax() { + dealloc(m_imp); + } + + lbool qmax::operator()(expr_ref_vector const& fmls, app* t, opt::inf_eps& value, model_ref& mdl) { + return m_imp->m_qsat.maximize(fmls, t, mdl, value); + } + + void qmax::collect_statistics(statistics& st) const { + m_imp->m_qsat.collect_statistics(st); + }; + }; tactic * mk_qsat_tactic(ast_manager& m, params_ref const& p) { diff --git a/src/qe/qsat.h b/src/qe/qsat.h index 456711c4f3b..66676da054b 100644 --- a/src/qe/qsat.h +++ b/src/qe/qsat.h @@ -114,6 +114,16 @@ namespace qe { void collect_statistics(statistics& st) const; }; + class qmax { + struct imp; + imp* m_imp; + public: + qmax(ast_manager& m, params_ref const& p = params_ref()); + ~qmax(); + lbool operator()(expr_ref_vector const& fmls, app* t, opt::inf_eps& value, model_ref& mdl); + void collect_statistics(statistics& st) const; + }; + lbool maximize(expr_ref_vector const& fmls, app* t, opt::inf_eps& value, model_ref& mdl, params_ref const& p); } From 184aebab59045cc4d75c825f169267f5212465d5 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Mon, 23 May 2016 15:08:27 +0100 Subject: [PATCH 55/61] variable naming --- src/ast/fpa/fpa2bv_converter.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/ast/fpa/fpa2bv_converter.cpp b/src/ast/fpa/fpa2bv_converter.cpp index cda3bd27e16..9713ee852ea 100644 --- a/src/ast/fpa/fpa2bv_converter.cpp +++ b/src/ast/fpa/fpa2bv_converter.cpp @@ -1178,10 +1178,10 @@ expr_ref fpa2bv_converter::mk_min_unspecified(func_decl * f, expr * x, expr * y) pn = m_util.mk_fp(decls.first, m_bv_util.mk_numeral(0, ebits), m_bv_util.mk_numeral(0, sbits - 1)); np = m_util.mk_fp(decls.second, m_bv_util.mk_numeral(0, ebits), m_bv_util.mk_numeral(0, sbits - 1)); - expr_ref x_is_pzero(m), x_is_nzero(m), xyzero(m); + expr_ref x_is_pzero(m), y_is_nzero(m), xyzero(m); mk_is_pzero(x, x_is_pzero); - mk_is_nzero(y, x_is_nzero); - m_simp.mk_and(x_is_pzero, x_is_nzero, xyzero); + mk_is_nzero(y, y_is_nzero); + m_simp.mk_and(x_is_pzero, y_is_nzero, xyzero); mk_ite(xyzero, pn, np, res); return res; @@ -1259,10 +1259,10 @@ expr_ref fpa2bv_converter::mk_max_unspecified(func_decl * f, expr * x, expr * y) pn = m_util.mk_fp(decls.first, m_bv_util.mk_numeral(0, ebits), m_bv_util.mk_numeral(0, sbits - 1)); np = m_util.mk_fp(decls.second, m_bv_util.mk_numeral(0, ebits), m_bv_util.mk_numeral(0, sbits - 1)); - expr_ref x_is_pzero(m), x_is_nzero(m), xyzero(m); + expr_ref x_is_pzero(m), y_is_nzero(m), xyzero(m); mk_is_pzero(x, x_is_pzero); - mk_is_nzero(y, x_is_nzero); - m_simp.mk_and(x_is_pzero, x_is_nzero, xyzero); + mk_is_nzero(y, y_is_nzero); + m_simp.mk_and(x_is_pzero, y_is_nzero, xyzero); mk_ite(xyzero, pn, np, res); return res; From bf3a5effbc25699dce7889238e5314472a919df9 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Mon, 23 May 2016 15:38:25 +0100 Subject: [PATCH 56/61] Fixed and refactored fp.min/fp.max for theory_fpa. Fixes #616 --- src/ast/fpa/fpa2bv_converter.cpp | 37 ++---------------- src/ast/fpa/fpa2bv_converter.h | 3 +- src/ast/fpa/fpa2bv_rewriter.cpp | 4 +- src/ast/fpa_decl_plugin.h | 20 +++++++++- src/smt/theory_fpa.cpp | 66 ++++++++++++-------------------- src/smt/theory_fpa.h | 4 +- 6 files changed, 51 insertions(+), 83 deletions(-) diff --git a/src/ast/fpa/fpa2bv_converter.cpp b/src/ast/fpa/fpa2bv_converter.cpp index 9713ee852ea..c6b3c05e50d 100644 --- a/src/ast/fpa/fpa2bv_converter.cpp +++ b/src/ast/fpa/fpa2bv_converter.cpp @@ -1156,13 +1156,13 @@ void fpa2bv_converter::mk_min_i(func_decl * f, unsigned num, expr * const * args SASSERT(is_well_sorted(m, result)); } -expr_ref fpa2bv_converter::mk_min_unspecified(func_decl * f, expr * x, expr * y) { +expr_ref fpa2bv_converter::mk_min_max_unspecified(func_decl * f, expr * x, expr * y) { unsigned ebits = m_util.get_ebits(f->get_range()); unsigned sbits = m_util.get_sbits(f->get_range()); expr_ref res(m); - // The only cases in which min is unspecified for is when the arguments are +0.0 and -0.0. - // There is no "hardware interpretation" for fp.min. + // The only cases in which min/max is unspecified for is when the arguments are +0.0 and -0.0. + // There is no "hardware interpretation" for fp.min/fp.max. std::pair decls(0, 0); if (!m_specials.find(f, decls)) { @@ -1237,37 +1237,6 @@ void fpa2bv_converter::mk_max_i(func_decl * f, unsigned num, expr * const * args SASSERT(is_well_sorted(m, result)); } -expr_ref fpa2bv_converter::mk_max_unspecified(func_decl * f, expr * x, expr * y) { - unsigned ebits = m_util.get_ebits(f->get_range()); - unsigned sbits = m_util.get_sbits(f->get_range()); - expr_ref res(m); - - // The only cases in which max is unspecified for is when the arguments are +0.0 and -0.0. - // There is no "hardware interpretation" for fp.max. - - std::pair decls(0, 0); - if (!m_specials.find(f, decls)) { - decls.first = m.mk_fresh_const(0, m_bv_util.mk_sort(1)); - decls.second = m.mk_fresh_const(0, m_bv_util.mk_sort(1)); - m_specials.insert(f, decls); - m.inc_ref(f); - m.inc_ref(decls.first); - m.inc_ref(decls.second); - } - - expr_ref pn(m), np(m); - pn = m_util.mk_fp(decls.first, m_bv_util.mk_numeral(0, ebits), m_bv_util.mk_numeral(0, sbits - 1)); - np = m_util.mk_fp(decls.second, m_bv_util.mk_numeral(0, ebits), m_bv_util.mk_numeral(0, sbits - 1)); - - expr_ref x_is_pzero(m), y_is_nzero(m), xyzero(m); - mk_is_pzero(x, x_is_pzero); - mk_is_nzero(y, y_is_nzero); - m_simp.mk_and(x_is_pzero, y_is_nzero, xyzero); - mk_ite(xyzero, pn, np, res); - - return res; -} - void fpa2bv_converter::mk_fma(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { SASSERT(num == 4); SASSERT(m_util.is_rm_bvwrap(args[0])); diff --git a/src/ast/fpa/fpa2bv_converter.h b/src/ast/fpa/fpa2bv_converter.h index 19c5b33520a..d056a364231 100644 --- a/src/ast/fpa/fpa2bv_converter.h +++ b/src/ast/fpa/fpa2bv_converter.h @@ -133,11 +133,10 @@ class fpa2bv_converter { void mk_min(func_decl * f, unsigned num, expr * const * args, expr_ref & result); void mk_min_i(func_decl * f, unsigned num, expr * const * args, expr_ref & result); - virtual expr_ref mk_min_unspecified(func_decl * f, expr * x, expr * y); + virtual expr_ref mk_min_max_unspecified(func_decl * f, expr * x, expr * y); 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); - virtual expr_ref mk_max_unspecified(func_decl * f, expr * x, expr * y); expr_ref mk_to_ubv_unspecified(unsigned ebits, unsigned sbits, unsigned width); expr_ref mk_to_sbv_unspecified(unsigned ebits, unsigned sbits, unsigned width); diff --git a/src/ast/fpa/fpa2bv_rewriter.cpp b/src/ast/fpa/fpa2bv_rewriter.cpp index 7680025e073..2e6314ea035 100644 --- a/src/ast/fpa/fpa2bv_rewriter.cpp +++ b/src/ast/fpa/fpa2bv_rewriter.cpp @@ -150,8 +150,8 @@ br_status fpa2bv_rewriter_cfg::reduce_app(func_decl * f, unsigned num, expr * co 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; - case OP_FPA_INTERNAL_MIN_UNSPECIFIED: result = m_conv.mk_min_unspecified(f, args[0], args[1]); return BR_DONE; - case OP_FPA_INTERNAL_MAX_UNSPECIFIED: result = m_conv.mk_max_unspecified(f, args[0], args[1]); return BR_DONE; + case OP_FPA_INTERNAL_MIN_UNSPECIFIED: + case OP_FPA_INTERNAL_MAX_UNSPECIFIED: result = m_conv.mk_min_max_unspecified(f, args[0], args[1]); return BR_DONE; case OP_FPA_INTERNAL_MIN_I: m_conv.mk_min_i(f, num, args, result); return BR_DONE; case OP_FPA_INTERNAL_MAX_I: m_conv.mk_max_i(f, num, args, result); return BR_DONE; diff --git a/src/ast/fpa_decl_plugin.h b/src/ast/fpa_decl_plugin.h index 33667e3f7d4..8ac343f3cf9 100644 --- a/src/ast/fpa_decl_plugin.h +++ b/src/ast/fpa_decl_plugin.h @@ -297,7 +297,7 @@ class fpa_util { 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)); + SASSERT(m_bv_util.is_bv(sig)); return m().mk_app(m_fid, OP_FPA_FP, sgn, exp, sig); } @@ -383,6 +383,24 @@ class fpa_util { bool is_rm_bvwrap(expr * e) const { return is_app_of(e, get_family_id(), OP_FPA_INTERNAL_RM_BVWRAP); } bool is_rm_bvwrap(func_decl * f) const { return f->get_family_id() == get_family_id() && f->get_decl_kind() == OP_FPA_INTERNAL_RM_BVWRAP; } + 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(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 contains_floats(ast * a); }; diff --git a/src/smt/theory_fpa.cpp b/src/smt/theory_fpa.cpp index dca364686c5..8574af30e79 100644 --- a/src/smt/theory_fpa.cpp +++ b/src/smt/theory_fpa.cpp @@ -87,48 +87,23 @@ namespace smt { return fpa2bv_converter::mk_function(f, num, args, result); } - expr_ref theory_fpa::fpa2bv_converter_wrapped::mk_min_unspecified(func_decl * f, expr * x, expr * y) { - // The only cases in which min is unspecified for is when the arguments are +0.0 and -0.0. + expr_ref theory_fpa::fpa2bv_converter_wrapped::mk_min_max_unspecified(func_decl * f, expr * x, expr * y) { unsigned ebits = m_util.get_ebits(f->get_range()); unsigned sbits = m_util.get_sbits(f->get_range()); unsigned bv_sz = ebits + sbits; - expr_ref res(m); - expr * args[] = { x, y }; - func_decl * w = m.mk_func_decl(m_th.get_family_id(), OP_FPA_INTERNAL_MIN_UNSPECIFIED, 0, 0, 2, args, f->get_range()); - expr_ref a(m), wrapped(m); - a = m.mk_app(w, x, y); + expr_ref a(m), wrapped(m), wu(m), wu_eq(m); + a = m.mk_app(f, x, y); wrapped = m_th.wrap(a); - res = m_util.mk_fp(m_bv_util.mk_extract(bv_sz - 1, bv_sz - 1, wrapped), - m_bv_util.mk_extract(bv_sz - 2, sbits - 1, wrapped), - m_bv_util.mk_extract(sbits - 2, 0, wrapped)); + wu = m_th.unwrap(wrapped, f->get_range()); + wu_eq = m.mk_eq(wu, a); + m_extra_assertions.push_back(wu_eq); expr_ref sc(m); - m_th.m_converter.mk_is_zero(res, sc); + m_th.m_converter.mk_is_zero(wu, sc); m_extra_assertions.push_back(sc); - return res; - } - - expr_ref theory_fpa::fpa2bv_converter_wrapped::mk_max_unspecified(func_decl * f, expr * x, expr * y) { - // The only cases in which max is unspecified for is when the arguments are +0.0 and -0.0. - unsigned ebits = m_util.get_ebits(f->get_range()); - unsigned sbits = m_util.get_sbits(f->get_range()); - unsigned bv_sz = ebits + sbits; - expr_ref res(m); - expr * args[] = { x, y }; - func_decl * w = m.mk_func_decl(m_th.get_family_id(), OP_FPA_INTERNAL_MAX_UNSPECIFIED, 0, 0, 2, args, f->get_range()); - expr_ref a(m), wrapped(m); - a = m.mk_app(w, x, y); - wrapped = m_th.wrap(a); - res = m_util.mk_fp(m_bv_util.mk_extract(bv_sz - 1, bv_sz - 1, wrapped), - m_bv_util.mk_extract(bv_sz - 2, sbits - 1, wrapped), - m_bv_util.mk_extract(sbits - 2, 0, wrapped)); - - expr_ref sc(m); - m_th.m_converter.mk_is_zero(res, sc); - m_extra_assertions.push_back(sc); - return res; + return wu; } theory_fpa::theory_fpa(ast_manager & m) : @@ -579,13 +554,8 @@ namespace smt { } } - if (!ctx.relevancy()) { + if (!ctx.relevancy()) relevant_eh(owner); - /*expr_ref wu(m); - wu = m.mk_eq(unwrap(wrap(owner), s), owner); - TRACE("t_fpa", tout << "w/u eq: " << std::endl << mk_ismt2_pp(wu, get_manager()) << std::endl;); - assert_cnstr(wu);*/ - } } } @@ -798,7 +768,7 @@ namespace smt { " (owner " << (!ctx.e_internalized(owner) ? "not" : "is") << " internalized)" << std::endl;); - if (is_app_of(owner, get_family_id(), OP_FPA_FP)) { + if (m_fpa_util.is_fp(owner)) { SASSERT(to_app(owner)->get_num_args() == 3); app_ref a0(m), a1(m), a2(m); a0 = to_app(owner->get_arg(0)); @@ -816,7 +786,7 @@ namespace smt { mk_ismt2_pp(a2, m) << " eq. cls. #" << get_enode(a2)->get_root()->get_owner()->get_id() << std::endl;); res = vp; } - else if (is_app_of(owner, get_family_id(), OP_FPA_INTERNAL_RM_BVWRAP)) { + else if (m_fpa_util.is_rm_bvwrap(owner)) { SASSERT(to_app(owner)->get_num_args() == 1); app_ref a0(m); a0 = to_app(owner->get_arg(0)); @@ -905,8 +875,20 @@ namespace smt { bool theory_fpa::include_func_interp(func_decl * f) { TRACE("t_fpa", tout << "f = " << mk_ismt2_pp(f, get_manager()) << std::endl;); - if (f->get_family_id() == get_family_id()) + if (f->get_family_id() == get_family_id()) { + bool include = + m_fpa_util.is_min_unspecified(f) || + m_fpa_util.is_max_unspecified(f) || + m_fpa_util.is_to_ubv_unspecified(f) || + m_fpa_util.is_to_sbv_unspecified(f) || + m_fpa_util.is_to_ieee_bv_unspecified(f) || + m_fpa_util.is_to_real_unspecified(f); + if (include && !m_is_added_to_model.contains(f)) { + m_is_added_to_model.insert(f); + return true; + } return false; + } else if (m_converter.is_uf2bvuf(f) || m_converter.is_special(f)) return false; else diff --git a/src/smt/theory_fpa.h b/src/smt/theory_fpa.h index 6c71b1d7db6..f1ed5219fb6 100644 --- a/src/smt/theory_fpa.h +++ b/src/smt/theory_fpa.h @@ -85,8 +85,7 @@ namespace smt { virtual void mk_rm_const(func_decl * f, expr_ref & result); virtual void mk_function(func_decl * f, unsigned num, expr * const * args, expr_ref & result); - virtual expr_ref mk_min_unspecified(func_decl * f, expr * x, expr * y); - virtual expr_ref mk_max_unspecified(func_decl * f, expr * x, expr * y); + virtual expr_ref mk_min_max_unspecified(func_decl * f, expr * x, expr * y); }; class fpa_value_proc : public model_value_proc { @@ -149,6 +148,7 @@ namespace smt { obj_map m_unwraps; obj_map m_conversions; bool m_is_initialized; + obj_hashtable m_is_added_to_model; virtual final_check_status final_check_eh(); virtual bool internalize_atom(app * atom, bool gate_ctx); From 8370bb898611cb0361f57515b2c3be677866aaee Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Mon, 23 May 2016 16:31:57 +0100 Subject: [PATCH 57/61] removed unused variable --- src/smt/theory_fpa.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/smt/theory_fpa.cpp b/src/smt/theory_fpa.cpp index 8574af30e79..b97b35e2487 100644 --- a/src/smt/theory_fpa.cpp +++ b/src/smt/theory_fpa.cpp @@ -90,7 +90,6 @@ namespace smt { expr_ref theory_fpa::fpa2bv_converter_wrapped::mk_min_max_unspecified(func_decl * f, expr * x, expr * y) { unsigned ebits = m_util.get_ebits(f->get_range()); unsigned sbits = m_util.get_sbits(f->get_range()); - unsigned bv_sz = ebits + sbits; expr_ref a(m), wrapped(m), wu(m), wu_eq(m); a = m.mk_app(f, x, y); From 617e941015a199dab67b02b6b768ada89201058b Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Mon, 23 May 2016 18:10:17 +0100 Subject: [PATCH 58/61] fp2bv refactoring --- src/api/api_ast.cpp | 2 +- src/ast/fpa/fpa2bv_converter.cpp | 34 +++++++++++----------- src/ast/fpa/fpa2bv_rewriter.cpp | 2 +- src/ast/fpa_decl_plugin.cpp | 6 ++-- src/ast/fpa_decl_plugin.h | 19 ++++++------ src/ast/rewriter/fpa_rewriter.cpp | 4 +-- src/ast/rewriter/fpa_rewriter.h | 2 +- src/smt/theory_fpa.cpp | 35 ++++++----------------- src/smt/theory_fpa.h | 3 +- src/tactic/fpa/fpa2bv_model_converter.cpp | 2 +- 10 files changed, 45 insertions(+), 64 deletions(-) diff --git a/src/api/api_ast.cpp b/src/api/api_ast.cpp index 1e421cb2e98..1f16b2d35ed 100644 --- a/src/api/api_ast.cpp +++ b/src/api/api_ast.cpp @@ -1185,7 +1185,7 @@ extern "C" { case OP_FPA_TO_IEEE_BV: return Z3_OP_FPA_TO_IEEE_BV; case OP_FPA_INTERNAL_MIN_I: return Z3_OP_FPA_MIN_I; case OP_FPA_INTERNAL_MAX_I: return Z3_OP_FPA_MAX_I; - case OP_FPA_INTERNAL_RM_BVWRAP: + case OP_FPA_INTERNAL_BV2RM: case OP_FPA_INTERNAL_BVWRAP: case OP_FPA_INTERNAL_MIN_UNSPECIFIED: case OP_FPA_INTERNAL_MAX_UNSPECIFIED: diff --git a/src/ast/fpa/fpa2bv_converter.cpp b/src/ast/fpa/fpa2bv_converter.cpp index c6b3c05e50d..bd07b5bdc5b 100644 --- a/src/ast/fpa/fpa2bv_converter.cpp +++ b/src/ast/fpa/fpa2bv_converter.cpp @@ -79,7 +79,7 @@ void fpa2bv_converter::mk_eq(expr * a, expr * b, expr_ref & result) { m_simp.mk_or(both_are_nan, both_the_same, result); } else if (is_rm(a) && is_rm(b)) { - SASSERT(m_util.is_rm_bvwrap(b) && m_util.is_rm_bvwrap(a)); + SASSERT(m_util.is_bv2rm(b) && m_util.is_bv2rm(a)); TRACE("fpa2bv", tout << "mk_eq_rm a=" << mk_ismt2_pp(a, m) << std::endl; tout << "mk_eq_rm b=" << mk_ismt2_pp(b, m) << std::endl;); @@ -236,7 +236,7 @@ void fpa2bv_converter::mk_function_output(sort * rng, func_decl * fbv, expr * co else if (m_util.is_rm(rng)) { app_ref na(m); na = m.mk_app(fbv, fbv->get_arity(), new_args); - result = m_util.mk_rm(na); + result = m_util.mk_bv2rm(na); } else result = m.mk_app(fbv, fbv->get_arity(), new_args); @@ -284,7 +284,7 @@ void fpa2bv_converter::mk_function(func_decl * f, unsigned num, expr * const * a bv_rng = m_bv_util.mk_sort(3); func_decl * bv_f = get_bv_uf(f, bv_rng, num); bv_app = m.mk_app(bv_f, num, args); - flt_app = m_util.mk_rm(bv_app); + flt_app = m_util.mk_bv2rm(bv_app); new_eq = m.mk_eq(fapp, flt_app); m_extra_assertions.push_back(new_eq); result = flt_app; @@ -315,7 +315,7 @@ void fpa2bv_converter::mk_rm_const(func_decl * f, expr_ref & result) { #endif , m_bv_util.mk_sort(3)); - result = m_util.mk_rm(bv3); + result = m_util.mk_bv2rm(bv3); m_rm_const2bv.insert(f, result); m.inc_ref(f); m.inc_ref(result); @@ -522,7 +522,7 @@ void fpa2bv_converter::add_core(unsigned sbits, unsigned ebits, void fpa2bv_converter::mk_add(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { SASSERT(num == 3); - SASSERT(m_util.is_rm_bvwrap(args[0])); + SASSERT(m_util.is_bv2rm(args[0])); expr_ref rm(m), x(m), y(m); rm = to_app(args[0])->get_arg(0); @@ -692,7 +692,7 @@ void fpa2bv_converter::mk_neg(sort * srt, expr_ref & x, expr_ref & result) { void fpa2bv_converter::mk_mul(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { SASSERT(num == 3); - SASSERT(m_util.is_rm_bvwrap(args[0])); + SASSERT(m_util.is_bv2rm(args[0])); expr_ref rm(m), x(m), y(m); rm = to_app(args[0])->get_arg(0); @@ -842,7 +842,7 @@ void fpa2bv_converter::mk_mul(sort * s, expr_ref & rm, expr_ref & x, expr_ref & void fpa2bv_converter::mk_div(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { SASSERT(num == 3); - SASSERT(m_util.is_rm_bvwrap(args[0])); + SASSERT(m_util.is_bv2rm(args[0])); expr_ref rm(m), x(m), y(m); rm = to_app(args[0])->get_arg(0); x = args[1]; @@ -1239,7 +1239,7 @@ void fpa2bv_converter::mk_max_i(func_decl * f, unsigned num, expr * const * args void fpa2bv_converter::mk_fma(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { SASSERT(num == 4); - SASSERT(m_util.is_rm_bvwrap(args[0])); + SASSERT(m_util.is_bv2rm(args[0])); // fusedma means (x * y) + z expr_ref rm(m), x(m), y(m), z(m); @@ -1557,7 +1557,7 @@ void fpa2bv_converter::mk_fma(func_decl * f, unsigned num, expr * const * args, void fpa2bv_converter::mk_sqrt(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { SASSERT(num == 2); - SASSERT(m_util.is_rm_bvwrap(args[0])); + SASSERT(m_util.is_bv2rm(args[0])); expr_ref rm(m), x(m); rm = to_app(args[0])->get_arg(0); @@ -1706,7 +1706,7 @@ void fpa2bv_converter::mk_sqrt(func_decl * f, unsigned num, expr * const * args, void fpa2bv_converter::mk_round_to_integral(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { SASSERT(num == 2); - SASSERT(m_util.is_rm_bvwrap(args[0])); + SASSERT(m_util.is_bv2rm(args[0])); expr_ref rm(m), x(m); rm = to_app(args[0])->get_arg(0); @@ -2166,7 +2166,7 @@ void fpa2bv_converter::mk_to_fp(func_decl * f, unsigned num, expr * const * args void fpa2bv_converter::mk_to_fp_float(func_decl * f, sort * s, expr * rm, expr * x, expr_ref & result) { - SASSERT(m_util.is_rm_bvwrap(rm)); + SASSERT(m_util.is_bv2rm(rm)); mk_to_fp_float(s, to_app(rm)->get_arg(0), x, result); } @@ -2337,7 +2337,7 @@ void fpa2bv_converter::mk_to_fp_real(func_decl * f, sort * s, expr * rm, expr * "x: " << mk_ismt2_pp(x, m) << std::endl;); SASSERT(m_util.is_float(s)); SASSERT(au().is_real(x) || au().is_int(x)); - SASSERT(m_util.is_rm_bvwrap(rm)); + SASSERT(m_util.is_bv2rm(rm)); expr * bv_rm = to_app(rm)->get_arg(0); unsigned ebits = m_util.get_ebits(s); @@ -2472,7 +2472,7 @@ void fpa2bv_converter::mk_to_fp_real_int(func_decl * f, unsigned num, expr * con unsigned ebits = m_util.get_ebits(f->get_range()); unsigned sbits = m_util.get_sbits(f->get_range()); - SASSERT(m_util.is_rm_bvwrap(args[0])); + SASSERT(m_util.is_bv2rm(args[0])); expr * bv_rm = to_app(args[0])->get_arg(0); rational e; @@ -2630,7 +2630,7 @@ void fpa2bv_converter::mk_to_fp_signed(func_decl * f, unsigned num, expr * const SASSERT(num == 2); SASSERT(m_util.is_float(f->get_range())); - SASSERT(m_util.is_rm_bvwrap(args[0])); + SASSERT(m_util.is_bv2rm(args[0])); SASSERT(m_bv_util.is_bv(args[1])); expr_ref rm(m), x(m); @@ -2772,7 +2772,7 @@ void fpa2bv_converter::mk_to_fp_unsigned(func_decl * f, unsigned num, expr * con SASSERT(num == 2); SASSERT(m_util.is_float(f->get_range())); - SASSERT(m_util.is_rm_bvwrap(args[0])); + SASSERT(m_util.is_bv2rm(args[0])); SASSERT(m_bv_util.is_bv(args[1])); expr_ref rm(m), x(m); @@ -2924,7 +2924,7 @@ void fpa2bv_converter::mk_to_bv(func_decl * f, unsigned num, expr * const * args tout << "arg" << i << " = " << mk_ismt2_pp(args[i], m) << std::endl;); SASSERT(num == 2); - SASSERT(m_util.is_rm_bvwrap(args[0])); + SASSERT(m_util.is_bv2rm(args[0])); SASSERT(m_util.is_float(args[1])); expr * rm = to_app(args[0])->get_arg(0); @@ -3528,7 +3528,7 @@ void fpa2bv_converter::mk_rounding_mode(decl_kind k, expr_ref & result) default: UNREACHABLE(); } - result = m_util.mk_rm(result); + result = m_util.mk_bv2rm(result); } void fpa2bv_converter::dbg_decouple(const char * prefix, expr_ref & e) { diff --git a/src/ast/fpa/fpa2bv_rewriter.cpp b/src/ast/fpa/fpa2bv_rewriter.cpp index 2e6314ea035..62281226e61 100644 --- a/src/ast/fpa/fpa2bv_rewriter.cpp +++ b/src/ast/fpa/fpa2bv_rewriter.cpp @@ -156,7 +156,7 @@ br_status fpa2bv_rewriter_cfg::reduce_app(func_decl * f, unsigned num, expr * co case OP_FPA_INTERNAL_MAX_I: m_conv.mk_max_i(f, num, args, result); return BR_DONE; case OP_FPA_INTERNAL_BVWRAP: - case OP_FPA_INTERNAL_RM_BVWRAP: + case OP_FPA_INTERNAL_BV2RM: case OP_FPA_INTERNAL_TO_REAL_UNSPECIFIED: case OP_FPA_INTERNAL_TO_UBV_UNSPECIFIED: diff --git a/src/ast/fpa_decl_plugin.cpp b/src/ast/fpa_decl_plugin.cpp index 22043e7a425..6c8b7ac6fcd 100644 --- a/src/ast/fpa_decl_plugin.cpp +++ b/src/ast/fpa_decl_plugin.cpp @@ -676,7 +676,7 @@ func_decl * fpa_decl_plugin::mk_to_ieee_bv(decl_kind k, unsigned num_parameters, return m_manager->mk_func_decl(name, 1, domain, bv_srt, func_decl_info(m_family_id, k)); } -func_decl * fpa_decl_plugin::mk_internal_rm(decl_kind k, unsigned num_parameters, parameter const * parameters, +func_decl * fpa_decl_plugin::mk_internal_bv2rm(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 internal_rm"); @@ -837,8 +837,8 @@ func_decl * fpa_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, case OP_FPA_INTERNAL_BVWRAP: return mk_internal_bv_wrap(k, num_parameters, parameters, arity, domain, range); - case OP_FPA_INTERNAL_RM_BVWRAP: - return mk_internal_rm(k, num_parameters, parameters, arity, domain, range); + case OP_FPA_INTERNAL_BV2RM: + return mk_internal_bv2rm(k, num_parameters, parameters, arity, domain, range); case OP_FPA_INTERNAL_MIN_I: case OP_FPA_INTERNAL_MAX_I: diff --git a/src/ast/fpa_decl_plugin.h b/src/ast/fpa_decl_plugin.h index 8ac343f3cf9..ee7325014f8 100644 --- a/src/ast/fpa_decl_plugin.h +++ b/src/ast/fpa_decl_plugin.h @@ -88,7 +88,7 @@ enum fpa_op_kind { /* Internal use only */ OP_FPA_INTERNAL_BVWRAP, - OP_FPA_INTERNAL_RM_BVWRAP, // Internal conversion from (_ BitVec 3) to RoundingMode + OP_FPA_INTERNAL_BV2RM, OP_FPA_INTERNAL_MIN_I, OP_FPA_INTERNAL_MAX_I, @@ -164,8 +164,8 @@ class fpa_decl_plugin : public decl_plugin { func_decl * mk_to_ieee_bv(decl_kind k, unsigned num_parameters, parameter const * parameters, unsigned arity, sort * const * domain, sort * range); - func_decl * mk_internal_rm(decl_kind k, unsigned num_parameters, parameter const * parameters, - unsigned arity, sort * const * domain, sort * range); + func_decl * mk_internal_bv2rm(decl_kind k, unsigned num_parameters, parameter const * parameters, + unsigned arity, sort * const * domain, sort * range); func_decl * mk_internal_bv_wrap(decl_kind k, unsigned num_parameters, parameter const * parameters, unsigned arity, sort * const * domain, sort * range); func_decl * mk_internal_bv_unwrap(decl_kind k, unsigned num_parameters, parameter const * parameters, @@ -301,11 +301,6 @@ class fpa_util { return m().mk_app(m_fid, OP_FPA_FP, sgn, exp, sig); } - app * mk_rm(expr * bv3) { - SASSERT(m_bv_util.is_bv(bv3) && m_bv_util.get_bv_size(bv3) == 3); - return m().mk_app(m_fid, OP_FPA_INTERNAL_RM_BVWRAP, 0, 0, 1, &bv3, mk_rm_sort()); - } - 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); @@ -373,6 +368,10 @@ class fpa_util { app * mk_to_ieee_bv(expr * arg1) { return m().mk_app(m_fid, OP_FPA_TO_IEEE_BV, arg1); } + app * mk_bv2rm(expr * bv3) { + SASSERT(m_bv_util.is_bv(bv3) && m_bv_util.get_bv_size(bv3) == 3); + return m().mk_app(m_fid, OP_FPA_INTERNAL_BV2RM, 0, 0, 1, &bv3, mk_rm_sort()); + } app * mk_internal_to_ubv_unspecified(unsigned ebits, unsigned sbits, unsigned width); app * mk_internal_to_sbv_unspecified(unsigned ebits, unsigned sbits, unsigned width); app * mk_internal_to_ieee_bv_unspecified(unsigned ebits, unsigned sbits); @@ -380,8 +379,8 @@ class fpa_util { 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_rm_bvwrap(expr * e) const { return is_app_of(e, get_family_id(), OP_FPA_INTERNAL_RM_BVWRAP); } - bool is_rm_bvwrap(func_decl * f) const { return f->get_family_id() == get_family_id() && f->get_decl_kind() == OP_FPA_INTERNAL_RM_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_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); } diff --git a/src/ast/rewriter/fpa_rewriter.cpp b/src/ast/rewriter/fpa_rewriter.cpp index b4ae744d38d..b8d9c232fc5 100644 --- a/src/ast/rewriter/fpa_rewriter.cpp +++ b/src/ast/rewriter/fpa_rewriter.cpp @@ -100,7 +100,7 @@ br_status fpa_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * con 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_RM_BVWRAP:SASSERT(num_args == 1); st = mk_rm(args[0], result); break; + case OP_FPA_INTERNAL_BV2RM: SASSERT(num_args == 1); st = mk_bv2rm(args[0], result); break; case OP_FPA_INTERNAL_TO_UBV_UNSPECIFIED: case OP_FPA_INTERNAL_TO_SBV_UNSPECIFIED: @@ -719,7 +719,7 @@ br_status fpa_rewriter::mk_eq_core(expr * arg1, expr * arg2, expr_ref & result) return BR_FAILED; } -br_status fpa_rewriter::mk_rm(expr * arg, expr_ref & result) { +br_status fpa_rewriter::mk_bv2rm(expr * arg, expr_ref & result) { bv_util bu(m()); rational bv_val; unsigned sz = 0; diff --git a/src/ast/rewriter/fpa_rewriter.h b/src/ast/rewriter/fpa_rewriter.h index 10f4ab4aa7d..0d9c6a380e7 100644 --- a/src/ast/rewriter/fpa_rewriter.h +++ b/src/ast/rewriter/fpa_rewriter.h @@ -78,7 +78,7 @@ class fpa_rewriter { br_status mk_to_fp(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result); br_status mk_to_fp_unsigned(func_decl * f, expr * arg1, expr * arg2, expr_ref & result); - br_status mk_rm(expr * arg, expr_ref & result); + br_status mk_bv2rm(expr * arg, expr_ref & result); br_status mk_fp(expr * sgn, expr * exp, expr * sig, expr_ref & result); br_status mk_to_fp_unsigned(expr * arg1, expr * arg2, expr_ref & result); br_status mk_to_ubv(func_decl * f, expr * arg1, expr * arg2, expr_ref & result); diff --git a/src/smt/theory_fpa.cpp b/src/smt/theory_fpa.cpp index b97b35e2487..23095f03ab4 100644 --- a/src/smt/theory_fpa.cpp +++ b/src/smt/theory_fpa.cpp @@ -75,7 +75,7 @@ namespace smt { SASSERT(is_rm(f->get_range())); expr_ref bv(m); bv = m_th.wrap(m.mk_const(f)); - result = m_util.mk_rm(bv); + result = m_util.mk_bv2rm(bv); m_rm_const2bv.insert(f, result); m.inc_ref(f); m.inc_ref(result); @@ -339,18 +339,11 @@ 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 (is_app(e_conv) && to_app(e_conv)->get_family_id() != get_family_id()) { - UNREACHABLE(); - if (!m_fpa_util.is_float(e_conv) && !m_fpa_util.is_rm(e_conv)) - m_th_rw(e_conv, res); - else - res = unwrap(wrap(e_conv), m.get_sort(e)); - } - else if (m_fpa_util.is_rm(e)) { - SASSERT(m_fpa_util.is_rm_bvwrap(e_conv)); + 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); - res = m_fpa_util.mk_rm(bv_rm); + res = m_fpa_util.mk_bv2rm(bv_rm); } else if (m_fpa_util.is_float(e)) { SASSERT(m_fpa_util.is_fp(e_conv)); @@ -363,20 +356,14 @@ namespace smt { } else UNREACHABLE(); - - SASSERT(res.get() != 0); + return res; } expr_ref theory_fpa::convert_conversion_term(expr * e) { SASSERT(to_app(e)->get_family_id() == get_family_id()); /* This is for the conversion functions fp.to_* */ - ast_manager & m = get_manager(); - expr_ref res(m); - proof_ref pr(m); - - SASSERT(m_arith_util.is_real(e) || m_bv_util.is_bv(e)); - + expr_ref res(get_manager()); m_rw(e, res); m_th_rw(res, res); return res; @@ -402,10 +389,8 @@ 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 if (m_arith_util.is_real(e) || m_bv_util.is_bv(e)) + else res = convert_conversion_term(e); - else - UNREACHABLE(); TRACE("t_fpa_detail", tout << "converted; caching:" << std::endl; tout << mk_ismt2_pp(e, m) << std::endl << " -> " << std::endl << @@ -514,7 +499,6 @@ namespace smt { case OP_FPA_TO_SBV: case OP_FPA_TO_REAL: case OP_FPA_TO_IEEE_BV: { - expr_ref conv(m); conv = convert(term); assert_cnstr(m.mk_eq(term, conv)); @@ -545,7 +529,7 @@ namespace smt { if (m_fpa_util.is_rm(s)) { // For every RM term, we need to make sure that it's // associated bit-vector is within the valid range. - if (!m_fpa_util.is_rm_bvwrap(owner)) { + if (!m_fpa_util.is_bv2rm(owner)) { expr_ref valid(m), limit(m); limit = m_bv_util.mk_numeral(4, 3); valid = m_bv_util.mk_ule(wrap(owner), limit); @@ -649,7 +633,6 @@ namespace smt { void theory_fpa::pop_scope_eh(unsigned num_scopes) { m_trail_stack.pop_scope(num_scopes); TRACE("t_fpa", tout << "pop " << num_scopes << "; now " << m_trail_stack.get_num_scopes() << "\n";); - // unsigned num_old_vars = get_old_num_vars(num_scopes); theory::pop_scope_eh(num_scopes); } @@ -785,7 +768,7 @@ namespace smt { mk_ismt2_pp(a2, m) << " eq. cls. #" << get_enode(a2)->get_root()->get_owner()->get_id() << std::endl;); res = vp; } - else if (m_fpa_util.is_rm_bvwrap(owner)) { + else if (m_fpa_util.is_bv2rm(owner)) { SASSERT(to_app(owner)->get_num_args() == 1); app_ref a0(m); a0 = to_app(owner->get_arg(0)); diff --git a/src/smt/theory_fpa.h b/src/smt/theory_fpa.h index f1ed5219fb6..0a3ed94c68d 100644 --- a/src/smt/theory_fpa.h +++ b/src/smt/theory_fpa.h @@ -144,8 +144,7 @@ namespace smt { fpa_util & m_fpa_util; bv_util & m_bv_util; arith_util & m_arith_util; - obj_map m_wraps; - obj_map m_unwraps; + obj_map m_wraps; obj_map m_conversions; bool m_is_initialized; obj_hashtable m_is_added_to_model; diff --git a/src/tactic/fpa/fpa2bv_model_converter.cpp b/src/tactic/fpa/fpa2bv_model_converter.cpp index 64423f22492..20d8bbbcc8f 100644 --- a/src/tactic/fpa/fpa2bv_model_converter.cpp +++ b/src/tactic/fpa/fpa2bv_model_converter.cpp @@ -395,7 +395,7 @@ void fpa2bv_model_converter::convert(model * bv_mdl, model * float_mdl) { 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_rm_bvwrap(val)); + 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); From c20b391cf78be4f29210ff7b08d3125a34113b3a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 23 May 2016 14:32:51 -0700 Subject: [PATCH 59/61] reduce warnings Signed-off-by: Nikolaj Bjorner --- src/qe/qe_mbp.cpp | 1 - src/smt/theory_array.cpp | 2 +- src/smt/theory_datatype.cpp | 2 +- src/smt/theory_fpa.cpp | 2 -- 4 files changed, 2 insertions(+), 5 deletions(-) diff --git a/src/qe/qe_mbp.cpp b/src/qe/qe_mbp.cpp index 727832d700d..2bacb3a4f1a 100644 --- a/src/qe/qe_mbp.cpp +++ b/src/qe/qe_mbp.cpp @@ -194,7 +194,6 @@ class mbp::impl { void filter_variables(model& model, app_ref_vector& vars, expr_ref_vector& lits, expr_ref_vector& unused_lits) { - ast_manager& m = vars.get_manager(); expr_mark lit_visited; project_plugin::mark_rec(lit_visited, lits); diff --git a/src/smt/theory_array.cpp b/src/smt/theory_array.cpp index ef6b0e776b9..5e0539787df 100644 --- a/src/smt/theory_array.cpp +++ b/src/smt/theory_array.cpp @@ -75,7 +75,7 @@ namespace smt { ast_manager& m = get_manager(); context& ctx = get_context(); theory_var r = theory_array_base::mk_var(n); - VERIFY(r == m_find.mk_var()); + VERIFY(r == static_cast(m_find.mk_var())); SASSERT(r == static_cast(m_var_data.size())); m_var_data.push_back(alloc(var_data)); var_data * d = m_var_data[r]; diff --git a/src/smt/theory_datatype.cpp b/src/smt/theory_datatype.cpp index e5c8b1313b5..8e140661bf9 100644 --- a/src/smt/theory_datatype.cpp +++ b/src/smt/theory_datatype.cpp @@ -198,7 +198,7 @@ namespace smt { theory_var theory_datatype::mk_var(enode * n) { theory_var r = theory::mk_var(n); - VERIFY(r == m_find.mk_var()); + VERIFY(r == static_cast(m_find.mk_var())); SASSERT(r == static_cast(m_var_data.size())); m_var_data.push_back(alloc(var_data)); var_data * d = m_var_data[r]; diff --git a/src/smt/theory_fpa.cpp b/src/smt/theory_fpa.cpp index b97b35e2487..552d2363189 100644 --- a/src/smt/theory_fpa.cpp +++ b/src/smt/theory_fpa.cpp @@ -88,8 +88,6 @@ namespace smt { } expr_ref theory_fpa::fpa2bv_converter_wrapped::mk_min_max_unspecified(func_decl * f, expr * x, expr * y) { - unsigned ebits = m_util.get_ebits(f->get_range()); - unsigned sbits = m_util.get_sbits(f->get_range()); expr_ref a(m), wrapped(m), wu(m), wu_eq(m); a = m.mk_app(f, x, y); From c4610e0423a2e5fa7ef3e058606ad1ca22827e3a Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Tue, 24 May 2016 14:37:43 +0100 Subject: [PATCH 60/61] renamed variable to avoid clashes --- src/muz/transforms/dl_mk_quantifier_abstraction.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/muz/transforms/dl_mk_quantifier_abstraction.cpp b/src/muz/transforms/dl_mk_quantifier_abstraction.cpp index d3fe1004a7d..caff79d2ee7 100644 --- a/src/muz/transforms/dl_mk_quantifier_abstraction.cpp +++ b/src/muz/transforms/dl_mk_quantifier_abstraction.cpp @@ -97,7 +97,7 @@ namespace datalog { TRACE("dl", tout << mk_pp(body, m) << "\n";); // 2. replace bound variables by constants. - expr_ref_vector consts(m), bound(m), free(m); + expr_ref_vector consts(m), bound(m), _free(m); svector names; ptr_vector bound_sorts; for (unsigned i = 0; i < sorts.size(); ++i) { @@ -110,7 +110,7 @@ namespace datalog { bound_sorts.push_back(s); } else { - free.push_back(consts.back()); + _free.push_back(consts.back()); } } rep(body); @@ -123,8 +123,8 @@ namespace datalog { TRACE("dl", tout << mk_pp(body, m) << "\n";); // 4. replace remaining constants by variables. - for (unsigned i = 0; i < free.size(); ++i) { - rep.insert(free[i].get(), m.mk_var(i, m.get_sort(free[i].get()))); + for (unsigned i = 0; i < _free.size(); ++i) { + rep.insert(_free[i].get(), m.mk_var(i, m.get_sort(_free[i].get()))); } rep(body); g->set_else(body); From c45ed7c34cc131eebea5ca3c5f96f64060a63b57 Mon Sep 17 00:00:00 2001 From: martin-neuhaeusser Date: Wed, 25 May 2016 09:59:36 +0200 Subject: [PATCH 61/61] Make C-layer of OCaml bindings C89 compatible. This patch ensures that the C code generated for the OCaml stubs complies with C89. It is needed to compile Z3 with OCaml support with Visual Studio versions older than VS2013. --- scripts/update_api.py | 86 +++++++++++++++++++++++++-------- src/api/ml/z3native_stubs.c.pre | 7 +-- 2 files changed, 69 insertions(+), 24 deletions(-) diff --git a/scripts/update_api.py b/scripts/update_api.py index a06f1fbb188..733d5b1fa29 100755 --- a/scripts/update_api.py +++ b/scripts/update_api.py @@ -1324,36 +1324,80 @@ def mk_z3native_stubs_c(ml_dir): # C interface if len(ap) > 0: ml_wrapper.write(' unsigned _i;\n') - # declare locals, preprocess arrays, strings, in/out arguments - have_context = False + # determine if the function has a context as parameter. + have_context = (len(params) > 0) and (param_type(params[0]) == CONTEXT) + + if have_context and name not in Unwrapped: + ml_wrapper.write(' Z3_error_code ec;\n') + + if result != VOID: + ts = type2str(result) + if ml_has_plus_type(ts): + pts = ml_plus_type(ts) + ml_wrapper.write(' %s z3rv_m;\n' % ts) + ml_wrapper.write(' %s z3rv;\n' % pts) + else: + ml_wrapper.write(' %s z3rv;\n' % ts) + + # declare all required local variables + # To comply with C89, we need to first declare the variables and initialize them + # only afterwards. i = 0 for param in params: if param_type(param) == CONTEXT and i == 0: - ml_wrapper.write(' Z3_context_plus ctx_p = *(Z3_context_plus*) Data_custom_val(a' + str(i) + ');\n') - ml_wrapper.write(' Z3_context _a0 = ctx_p->ctx;\n') - have_context = True + ml_wrapper.write(' Z3_context_plus ctx_p;\n') + ml_wrapper.write(' Z3_context _a0;\n') else: k = param_kind(param) if k == OUT_ARRAY: - ml_wrapper.write(' %s * _a%s = (%s*) malloc(sizeof(%s) * (_a%s));\n' % ( - type2str(param_type(param)), + ml_wrapper.write(' %s * _a%s;\n' % (type2str(param_type(param)), i)) + elif k == OUT_MANAGED_ARRAY: + ml_wrapper.write(' %s * _a%s;\n' % (type2str(param_type(param)), i)) + elif k == IN_ARRAY or k == INOUT_ARRAY: + t = param_type(param) + ts = type2str(t) + ml_wrapper.write(' %s * _a%s;\n' % (ts, i)) + elif k == IN: + t = param_type(param) + ml_wrapper.write(' %s _a%s;\n' % (type2str(t), i)) + elif k == OUT or k == INOUT: + t = param_type(param) + ml_wrapper.write(' %s _a%s;\n' % (type2str(t), i)) + ts = type2str(t) + if ml_has_plus_type(ts): + pts = ml_plus_type(ts) + ml_wrapper.write(' %s _a%dp;\n' % (pts, i)) + i = i + 1 + + + # End of variable declarations in outermost block: + # To comply with C89, no variable declarations may occur in the outermost block + # from that point onwards (breaks builds with at least VC 2012 and prior) + ml_wrapper.write('\n') + + # Declare locals, preprocess arrays, strings, in/out arguments + i = 0 + for param in params: + if param_type(param) == CONTEXT and i == 0: + ml_wrapper.write(' ctx_p = *(Z3_context_plus*) Data_custom_val(a' + str(i) + ');\n') + ml_wrapper.write(' _a0 = ctx_p->ctx;\n') + else: + k = param_kind(param) + if k == OUT_ARRAY: + ml_wrapper.write(' _a%s = (%s*) malloc(sizeof(%s) * (_a%s));\n' % ( i, type2str(param_type(param)), type2str(param_type(param)), param_array_capacity_pos(param))) elif k == OUT_MANAGED_ARRAY: - ml_wrapper.write(' %s * _a%s = 0;\n' % (type2str(param_type(param)), i)) + ml_wrapper.write(' _a%s = 0;\n' % i) elif k == IN_ARRAY or k == INOUT_ARRAY: t = param_type(param) ts = type2str(t) - ml_wrapper.write(' %s * _a%s = (%s*) malloc(sizeof(%s) * _a%s);\n' % (ts, i, ts, ts, param_array_capacity_pos(param))) + ml_wrapper.write(' _a%s = (%s*) malloc(sizeof(%s) * _a%s);\n' % (i, ts, ts, param_array_capacity_pos(param))) elif k == IN: t = param_type(param) - ml_wrapper.write(' %s _a%s = %s;\n' % (type2str(t), i, ml_unwrap(t, type2str(t), 'a' + str(i)))) - elif k == OUT: - ml_wrapper.write(' %s _a%s;\n' % (type2str(param_type(param)), i)) - elif k == INOUT: - ml_wrapper.write(' %s _a%s = a%s;\n' % (type2str(param_type(param)), i, i)) + ml_wrapper.write(' _a%s = %s;\n' % (i, ml_unwrap(t, type2str(t), 'a' + str(i)))) i = i + 1 i = 0 @@ -1375,9 +1419,9 @@ def mk_z3native_stubs_c(ml_dir): # C interface if result != VOID: ts = type2str(result) if ml_has_plus_type(ts): - ml_wrapper.write('%s z3rv_m = ' % ts) + ml_wrapper.write('z3rv_m = ') else: - ml_wrapper.write('%s z3rv = ' % ts) + ml_wrapper.write('z3rv = ') # invoke procedure ml_wrapper.write('%s(' % name) @@ -1397,8 +1441,8 @@ def mk_z3native_stubs_c(ml_dir): # C interface ml_wrapper.write(');\n') if have_context and name not in Unwrapped: - ml_wrapper.write(' int ec = Z3_get_error_code(ctx_p->ctx);\n') - ml_wrapper.write(' if (ec != 0) {\n') + ml_wrapper.write(' ec = Z3_get_error_code(ctx_p->ctx);\n') + ml_wrapper.write(' if (ec != Z3_OK) {\n') ml_wrapper.write(' const char * msg = Z3_get_error_msg(ctx_p->ctx, ec);\n') ml_wrapper.write(' caml_raise_with_string(*caml_named_value("Z3EXCEPTION"), msg);\n') ml_wrapper.write(' }\n') @@ -1408,9 +1452,9 @@ def mk_z3native_stubs_c(ml_dir): # C interface if ml_has_plus_type(ts): pts = ml_plus_type(ts) if name in NULLWrapped: - ml_wrapper.write(' %s z3rv = %s_mk(z3rv_m);\n' % (pts, pts)) + ml_wrapper.write(' z3rv = %s_mk(z3rv_m);\n' % pts) else: - ml_wrapper.write(' %s z3rv = %s_mk(ctx_p, (%s) z3rv_m);\n' % (pts, pts, ml_minus_type(ts))) + ml_wrapper.write(' z3rv = %s_mk(ctx_p, (%s) z3rv_m);\n' % (pts, ml_minus_type(ts))) # convert output params if len(op) > 0: @@ -1450,7 +1494,7 @@ def mk_z3native_stubs_c(ml_dir): # C interface elif is_out_param(p): if ml_has_plus_type(ts): pts = ml_plus_type(ts) - ml_wrapper.write(' %s _a%dp = %s_mk(ctx_p, (%s) _a%d);\n' % (pts, i, pts, ml_minus_type(ts), i)) + ml_wrapper.write(' _a%dp = %s_mk(ctx_p, (%s) _a%d);\n' % (i, pts, ml_minus_type(ts), i)) ml_wrapper.write(' %s\n' % ml_alloc_and_store(pt, '_a%d_val' % i, '_a%dp' % i)) else: ml_wrapper.write(' %s\n' % ml_alloc_and_store(pt, '_a%d_val' % i, '_a%d' % i)) diff --git a/src/api/ml/z3native_stubs.c.pre b/src/api/ml/z3native_stubs.c.pre index d6b2cdab422..5960d5095c0 100644 --- a/src/api/ml/z3native_stubs.c.pre +++ b/src/api/ml/z3native_stubs.c.pre @@ -227,6 +227,7 @@ void Z3_ast_finalize(value v) { int Z3_ast_compare(value v1, value v2) { Z3_ast_plus * a1 = (Z3_ast_plus*)Data_custom_val(v1); Z3_ast_plus * a2 = (Z3_ast_plus*)Data_custom_val(v2); + unsigned id1, id2; /* if the two ASTs belong to different contexts, we take their contexts' addresses to order them (arbitrarily, but fixed) */ @@ -242,8 +243,8 @@ int Z3_ast_compare(value v1, value v2) { return +1; /* Comparison according to AST ids. */ - unsigned id1 = Z3_get_ast_id(a1->cp->ctx, a1->p); - unsigned id2 = Z3_get_ast_id(a2->cp->ctx, a2->p); + id1 = Z3_get_ast_id(a1->cp->ctx, a1->p); + id2 = Z3_get_ast_id(a2->cp->ctx, a2->p); if (id1 == id2) return 0; else if (id1 < id2) @@ -255,7 +256,7 @@ int Z3_ast_compare(value v1, value v2) { int Z3_ast_compare_ext(value v1, value v2) { Z3_ast_plus * a1 = (Z3_ast_plus*)Data_custom_val(v1); unsigned id1; - int id2 = Val_int(v2); + unsigned id2 = (unsigned)Val_int(v2); if (a1->p == NULL && id2 == 0) return 0; if (a1->p == NULL)