From b3b5c6226b8425d0bbc2f863e01eb8299ad8d820 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Thu, 2 Jun 2016 17:12:24 +0100 Subject: [PATCH 001/536] MPF code simplification --- src/util/mpf.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/util/mpf.cpp b/src/util/mpf.cpp index 0fcff0da0..d77b8c33f 100644 --- a/src/util/mpf.cpp +++ b/src/util/mpf.cpp @@ -1304,7 +1304,7 @@ void mpf_manager::partial_remainder(mpf & x, mpf const & y, mpf_exp_t const & ex // 3. Compute Y*Q / Y*QQ*2^{D-N} - bool YQ_sgn = y.sign ^ Q_sgn; + bool YQ_sgn = x.sign; 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); @@ -1360,9 +1360,7 @@ void mpf_manager::partial_remainder(mpf & x, mpf const & y, mpf_exp_t const & 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 ^ neg; // 5. Rounding if (m_mpz_manager.is_zero(X_YQ_sig)) From 83ad5d65e4ad34fd9790d4c81fc4cd0a6d8a9362 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Thu, 2 Jun 2016 20:22:02 +0100 Subject: [PATCH 002/536] Replaced fp.rem conversion to bit-vectors with an SMT-compliant one. Fixes #561 --- src/ast/fpa/fpa2bv_converter.cpp | 201 +++++++++++++++++++++++++------ src/ast/fpa/fpa2bv_converter.h | 7 ++ 2 files changed, 168 insertions(+), 40 deletions(-) diff --git a/src/ast/fpa/fpa2bv_converter.cpp b/src/ast/fpa/fpa2bv_converter.cpp index 97d18bcf2..f32e82dd3 100644 --- a/src/ast/fpa/fpa2bv_converter.cpp +++ b/src/ast/fpa/fpa2bv_converter.cpp @@ -25,7 +25,6 @@ Notes: #include"fpa2bv_converter.h" #define BVULT(X,Y,R) { expr_ref bvult_eq(m), bvult_not(m); m_simp.mk_eq(X, Y, bvult_eq); m_simp.mk_not(bvult_eq, bvult_not); expr_ref t(m); t = m_bv_util.mk_ule(X,Y); m_simp.mk_and(t, bvult_not, R); } -#define BVSLT(X,Y,R) { expr_ref bvslt_eq(m), bvslt_not(m); m_simp.mk_eq(X, Y, bvslt_eq); m_simp.mk_not(bvslt_eq, bvslt_not); expr_ref t(m); t = m_bv_util.mk_sle(X,Y); m_simp.mk_and(t, bvslt_not, R); } fpa2bv_converter::fpa2bv_converter(ast_manager & m) : m(m), @@ -125,10 +124,12 @@ void fpa2bv_converter::mk_numeral(func_decl * f, unsigned num, expr * const * ar SASSERT(num == 0); SASSERT(f->get_num_parameters() == 1); SASSERT(f->get_parameter(0).is_external()); - unsigned p_id = f->get_parameter(0).get_ext_id(); mpf const & v = m_plugin->get_value(p_id); + mk_numeral(f->get_range(), v, result); +} +void fpa2bv_converter::mk_numeral(sort * s, mpf const & v, expr_ref & result) { unsigned sbits = v.get_sbits(); unsigned ebits = v.get_ebits(); @@ -137,12 +138,12 @@ void fpa2bv_converter::mk_numeral(func_decl * f, unsigned num, expr * const * ar mpf_exp_t const & exp = m_util.fm().exp(v); if (m_util.fm().is_nan(v)) - mk_nan(f, result); + mk_nan(s, result); else if (m_util.fm().is_inf(v)) { if (m_util.fm().sgn(v)) - mk_ninf(f, result); + mk_ninf(s, result); else - mk_pinf(f, result); + mk_pinf(s, result); } else { expr_ref bv_sgn(m), bv_sig(m), e(m), biased_exp(m); @@ -1012,15 +1013,17 @@ void fpa2bv_converter::mk_rem(sort * s, expr_ref & x, expr_ref & y, expr_ref & r mk_ninf(s, ninf); mk_pinf(s, pinf); - expr_ref x_is_nan(m), x_is_zero(m), x_is_pos(m), x_is_inf(m); - expr_ref y_is_nan(m), y_is_zero(m), y_is_pos(m), y_is_inf(m); + expr_ref x_is_nan(m), x_is_zero(m), x_is_pos(m), x_is_neg(m), x_is_inf(m); + expr_ref y_is_nan(m), y_is_zero(m), y_is_pos(m), y_is_neg(m), y_is_inf(m); mk_is_nan(x, x_is_nan); mk_is_zero(x, x_is_zero); mk_is_pos(x, x_is_pos); + mk_is_neg(x, x_is_neg); mk_is_inf(x, x_is_inf); mk_is_nan(y, y_is_nan); mk_is_zero(y, y_is_zero); mk_is_pos(y, y_is_pos); + mk_is_neg(y, y_is_neg); mk_is_inf(y, y_is_inf); dbg_decouple("fpa2bv_rem_x_is_nan", x_is_nan); @@ -1054,34 +1057,120 @@ void fpa2bv_converter::mk_rem(sort * s, expr_ref & x, expr_ref & y, expr_ref & r // (x is 0) -> x c5 = x_is_zero; v5 = pzero; - + // exp(x) < exp(y) -> x + unsigned ebits = m_util.get_ebits(s); + unsigned sbits = m_util.get_sbits(s); expr * x_sgn, *x_sig, *x_exp; expr * y_sgn, *y_sig, *y_exp; split_fp(x, x_sgn, x_exp, x_sig); split_fp(y, y_sgn, y_exp, y_sig); - BVSLT(x_exp, y_exp, c6); + expr_ref one_ebits(m), y_exp_m1(m), xe_lt_yem1(m), ye_neq_zero(m); + one_ebits = m_bv_util.mk_numeral(1, ebits); + y_exp_m1 = m_bv_util.mk_bv_sub(y_exp, one_ebits); + BVULT(x_exp, y_exp_m1, xe_lt_yem1); + ye_neq_zero = m.mk_not(m.mk_eq(y_exp, m_bv_util.mk_numeral(0, ebits))); + c6 = m.mk_and(ye_neq_zero, xe_lt_yem1); v6 = x; - // else the actual remainder, r = x - y * n - expr_ref rne(m), nr(m), n(m), yn(m), r(m); - rne = m_bv_util.mk_numeral(BV_RM_TIES_TO_EVEN, 3); - mk_div(s, rne, x, y, nr); - mk_round_to_integral(s, rne, nr, n); - mk_mul(s, rne, y, n, yn); - mk_sub(s, rne, x, yn, r); + expr_ref a_sgn(m), a_sig(m), a_exp(m), a_lz(m); + expr_ref b_sgn(m), b_sig(m), b_exp(m), b_lz(m); + unpack(x, a_sgn, a_sig, a_exp, a_lz, true); + unpack(y, b_sgn, b_sig, b_exp, b_lz, true); - expr_ref r_is_zero(m), x_sgn_ref(x_sgn, m), x_sgn_zero(m); - mk_is_zero(r, r_is_zero); - mk_zero(s, x_sgn_ref, x_sgn_zero); - mk_ite(r_is_zero, x_sgn_zero, r, v7); + dbg_decouple("fpa2bv_rem_a_sgn", a_sgn); + dbg_decouple("fpa2bv_rem_a_sig", a_sig); + dbg_decouple("fpa2bv_rem_a_exp", a_exp); + dbg_decouple("fpa2bv_rem_a_lz", a_lz); + dbg_decouple("fpa2bv_rem_b_sgn", b_sgn); + dbg_decouple("fpa2bv_rem_b_sig", b_sig); + dbg_decouple("fpa2bv_rem_b_exp", b_exp); + dbg_decouple("fpa2bv_rem_b_lz", b_lz); - dbg_decouple("fpa2bv_rem_nr", nr); - dbg_decouple("fpa2bv_rem_n", n); - dbg_decouple("fpa2bv_rem_yn", yn); - dbg_decouple("fpa2bv_rem_r", r); - dbg_decouple("fpa2bv_rem_v7", v7); + // else the actual remainder. + // max. exponent difference is (2^ebits) - 3 + const mpz & two_to_ebits = fu().fm().m_powers2(ebits); + mpz max_exp_diff; + m_mpz_manager.sub(two_to_ebits, 3, max_exp_diff); + SASSERT(m_mpz_manager.is_int64(max_exp_diff)); + SASSERT(m_mpz_manager.get_uint64(max_exp_diff) <= UINT_MAX); + uint64 max_exp_diff_ui64 = m_mpz_manager.get_uint64(max_exp_diff); + SASSERT(max_exp_diff_ui64 <= UINT32_MAX); + unsigned max_exp_diff_ui = (unsigned)max_exp_diff_ui64; + m_mpz_manager.del(max_exp_diff); + + expr_ref a_exp_ext(m), b_exp_ext(m); + a_exp_ext = m_bv_util.mk_sign_extend(2, a_exp); + b_exp_ext = m_bv_util.mk_sign_extend(2, b_exp); + + expr_ref a_lz_ext(m), b_lz_ext(m); + a_lz_ext = m_bv_util.mk_zero_extend(2, a_lz); + b_lz_ext = m_bv_util.mk_zero_extend(2, b_lz); + + expr_ref exp_diff(m), neg_exp_diff(m), exp_diff_is_neg(m); + exp_diff = m_bv_util.mk_bv_sub( + m_bv_util.mk_bv_sub(a_exp_ext, a_lz_ext), + m_bv_util.mk_bv_sub(b_exp_ext, b_lz_ext)); + neg_exp_diff = m_bv_util.mk_bv_neg(exp_diff); + exp_diff_is_neg = m_bv_util.mk_sle(exp_diff, m_bv_util.mk_numeral(0, ebits+2)); + dbg_decouple("fpa2bv_rem_exp_diff", exp_diff); + + // CMW: This creates _huge_ bit-vectors, which is potentially sub-optimal, + // but calculating this via rem = x - y * nearest(x/y) creates huge + // circuits, too. Lazy instantiation seems the way to go in the long run + // (using the lazy bit-blaster helps on simple instances). + expr_ref a_sig_ext(m), b_sig_ext(m), lshift(m), rshift(m), shifted(m), huge_rem(m); + a_sig_ext = m_bv_util.mk_concat(m_bv_util.mk_zero_extend(max_exp_diff_ui, a_sig), m_bv_util.mk_numeral(0, 3)); + b_sig_ext = m_bv_util.mk_concat(m_bv_util.mk_zero_extend(max_exp_diff_ui, b_sig), m_bv_util.mk_numeral(0, 3)); + lshift = m_bv_util.mk_zero_extend(max_exp_diff_ui + sbits - (ebits+2) + 3, exp_diff); + rshift = m_bv_util.mk_zero_extend(max_exp_diff_ui + sbits - (ebits+2) + 3, neg_exp_diff); + shifted = m.mk_ite(exp_diff_is_neg, m_bv_util.mk_bv_ashr(a_sig_ext, rshift), + m_bv_util.mk_bv_shl(a_sig_ext, lshift)); + huge_rem = m_bv_util.mk_bv_urem(shifted, b_sig_ext); + dbg_decouple("fpa2bv_rem_huge_rem", huge_rem); + + expr_ref rndd_sgn(m), rndd_exp(m), rndd_sig(m), rne_bv(m), rndd(m); + rndd_sgn = a_sgn; + rndd_exp = m_bv_util.mk_bv_sub(b_exp_ext, b_lz_ext); + rndd_sig = m_bv_util.mk_extract(sbits+3, 0, huge_rem); + rne_bv = m_bv_util.mk_numeral(BV_RM_TIES_TO_EVEN, 3); + round(s, rne_bv, rndd_sgn, rndd_sig, rndd_exp, rndd); + + expr_ref y_half(m), ny_half(m), zero_e(m), two_e(m); + expr_ref y_half_is_zero(m), y_half_is_nz(m); + expr_ref r_ge_y_half(m), r_gt_ny_half(m), r_le_y_half(m), r_lt_ny_half(m); + expr_ref r_ge_zero(m), r_le_zero(m); + expr_ref rounded_sub_y(m), rounded_add_y(m); + mpf zero, two; + m_mpf_manager.set(two, ebits, sbits, 2); + m_mpf_manager.set(zero, ebits, sbits, 0); + mk_numeral(s, two, two_e); + mk_numeral(s, zero, zero_e); + mk_div(s, rne_bv, y, two_e, y_half); + mk_neg(s, y_half, ny_half); + mk_is_zero(y_half, y_half_is_zero); + y_half_is_nz = m.mk_not(y_half_is_zero); + + mk_float_ge(s, rndd, y_half, r_ge_y_half); + mk_float_gt(s, rndd, ny_half, r_gt_ny_half); + mk_float_le(s, rndd, y_half, r_le_y_half); + mk_float_lt(s, rndd, ny_half, r_lt_ny_half); + + mk_sub(s, rne_bv, rndd, y, rounded_sub_y); + mk_add(s, rne_bv, rndd, y, rounded_add_y); + + expr_ref sub_cnd(m), add_cnd(m); + sub_cnd = m.mk_and(y_half_is_nz, + m.mk_or(m.mk_and(y_is_pos, r_ge_y_half), + m.mk_and(y_is_neg, r_le_y_half))); + add_cnd = m.mk_and(y_half_is_nz, + m.mk_or(m.mk_and(y_is_pos, r_lt_ny_half), + m.mk_and(y_is_neg, r_gt_ny_half))); + + mk_ite(add_cnd, rounded_add_y, rndd, v7); + mk_ite(sub_cnd, rounded_sub_y, v7, v7); + // And finally, we tie them together. mk_ite(c6, v6, v7, result); mk_ite(c5, v5, result, result); @@ -1102,9 +1191,15 @@ void fpa2bv_converter::mk_rem(sort * s, expr_ref & x, expr_ref & y, expr_ref & r void fpa2bv_converter::mk_abs(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { SASSERT(num == 1); - expr * sgn, * s, * e; - split_fp(args[0], sgn, e, s); - result = m_util.mk_fp(m_bv_util.mk_numeral(0, 1), e, s); + expr_ref x(m); + x = args[0]; + mk_abs(f->get_range(), x, result); +} + +void fpa2bv_converter::mk_abs(sort * s, expr_ref & x, expr_ref & result) { + expr * sgn, *sig, *exp; + split_fp(x, sgn, exp, sig); + result = m_util.mk_fp(m_bv_util.mk_numeral(0, 1), exp, sig); } void fpa2bv_converter::mk_min(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { @@ -1954,11 +2049,15 @@ void fpa2bv_converter::mk_round_to_integral(sort * s, expr_ref & rm, expr_ref & void fpa2bv_converter::mk_float_eq(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { SASSERT(num == 2); + expr_ref x(m), y(m); + x = args[0]; + y = args[1]; + mk_float_eq(f->get_range(), x, y, result); +} - expr * x = args[0], * y = args[1]; - +void fpa2bv_converter::mk_float_eq(sort * s, expr_ref & x, expr_ref & y, expr_ref & result) { TRACE("fpa2bv_float_eq", tout << "X = " << mk_ismt2_pp(x, m) << std::endl; - tout << "Y = " << mk_ismt2_pp(y, m) << std::endl;); + tout << "Y = " << mk_ismt2_pp(y, m) << std::endl;); expr_ref c1(m), c2(m), x_is_nan(m), y_is_nan(m), x_is_zero(m), y_is_zero(m); mk_is_nan(x, x_is_nan); @@ -1992,9 +2091,13 @@ void fpa2bv_converter::mk_float_eq(func_decl * f, unsigned num, expr * const * a void fpa2bv_converter::mk_float_lt(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { SASSERT(num == 2); + expr_ref x(m), y(m); + x = args[0]; + y = args[1]; + mk_float_lt(f->get_range(), x, y, result); +} - expr * x = args[0], * y = args[1]; - +void fpa2bv_converter::mk_float_lt(sort * s, expr_ref & x, expr_ref & y, expr_ref & result) { expr_ref c1(m), c2(m), x_is_nan(m), y_is_nan(m), x_is_zero(m), y_is_zero(m); mk_is_nan(x, x_is_nan); mk_is_nan(y, y_is_nan); @@ -2039,11 +2142,15 @@ void fpa2bv_converter::mk_float_lt(func_decl * f, unsigned num, expr * const * a void fpa2bv_converter::mk_float_gt(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { SASSERT(num == 2); + expr_ref x(m), y(m); + x = args[0]; + y = args[1]; + mk_float_gt(f->get_range(), x, y, result); +} - expr * x = args[0], * y = args[1]; - +void fpa2bv_converter::mk_float_gt(sort * s, expr_ref & x, expr_ref & y, expr_ref & result) { expr_ref t3(m); - mk_float_le(f, num, args, t3); + mk_float_le(s, x, y, t3); expr_ref nan_or(m), xy_zero(m), not_t3(m), r_else(m); expr_ref x_is_nan(m), y_is_nan(m), x_is_zero(m), y_is_zero(m); @@ -2060,17 +2167,31 @@ void fpa2bv_converter::mk_float_gt(func_decl * f, unsigned num, expr * const * a void fpa2bv_converter::mk_float_le(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { SASSERT(num == 2); + expr_ref x(m), y(m); + x = args[0]; + y = args[1]; + mk_float_le(f->get_range(), x, y, result); +} + +void fpa2bv_converter::mk_float_le(sort * s, expr_ref & x, expr_ref & y, expr_ref & result) { expr_ref a(m), b(m); - mk_float_lt(f, num, args, a); - mk_float_eq(f, num, args, b); + mk_float_lt(s, x, y, a); + mk_float_eq(s, x, y, b); m_simp.mk_or(a, b, result); } void fpa2bv_converter::mk_float_ge(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { SASSERT(num == 2); + expr_ref x(m), y(m); + x = args[0]; + y = args[1]; + mk_float_ge(f->get_range(), x, y, result); +} + +void fpa2bv_converter::mk_float_ge(sort * s, expr_ref & x, expr_ref & y, expr_ref & result) { expr_ref a(m), b(m); - mk_float_gt(f, num, args, a); - mk_float_eq(f, num, args, b); + mk_float_gt(s, x, y, a); + mk_float_eq(s, x, y, b); m_simp.mk_or(a, b, result); } diff --git a/src/ast/fpa/fpa2bv_converter.h b/src/ast/fpa/fpa2bv_converter.h index d056a3642..45030b301 100644 --- a/src/ast/fpa/fpa2bv_converter.h +++ b/src/ast/fpa/fpa2bv_converter.h @@ -79,6 +79,7 @@ public: void mk_rounding_mode(decl_kind k, expr_ref & result); void mk_numeral(func_decl * f, unsigned num, expr * const * args, expr_ref & result); + void mk_numeral(sort * s, mpf const & v, expr_ref & result); virtual void mk_const(func_decl * f, expr_ref & result); virtual void mk_rm_const(func_decl * f, expr_ref & result); virtual void mk_function(func_decl * f, unsigned num, expr * const * args, expr_ref & result); @@ -100,12 +101,18 @@ public: void mk_fma(func_decl * f, unsigned num, expr * const * args, expr_ref & result); void mk_sqrt(func_decl * f, unsigned num, expr * const * args, expr_ref & result); void mk_round_to_integral(func_decl * f, unsigned num, expr * const * args, expr_ref & result); + void mk_abs(sort * s, expr_ref & x, expr_ref & result); void mk_float_eq(func_decl * f, unsigned num, expr * const * args, expr_ref & result); void mk_float_lt(func_decl * f, unsigned num, expr * const * args, expr_ref & result); void mk_float_gt(func_decl * f, unsigned num, expr * const * args, expr_ref & result); void mk_float_le(func_decl * f, unsigned num, expr * const * args, expr_ref & result); void mk_float_ge(func_decl * f, unsigned num, expr * const * args, expr_ref & result); + void mk_float_eq(sort * s, expr_ref & x, expr_ref & y, expr_ref & result); + void mk_float_lt(sort * s, expr_ref & x, expr_ref & y, expr_ref & result); + void mk_float_gt(sort *, expr_ref & x, expr_ref & y, expr_ref & result); + void mk_float_le(sort * s, expr_ref & x, expr_ref & y, expr_ref & result); + void mk_float_ge(sort * s, expr_ref & x, expr_ref & y, expr_ref & result); void mk_is_zero(func_decl * f, unsigned num, expr * const * args, expr_ref & result); void mk_is_nzero(func_decl * f, unsigned num, expr * const * args, expr_ref & result); From eab5a84f626bac42ac825a1477437be56f35479e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 2 Jun 2016 20:57:52 -0700 Subject: [PATCH 003/536] fix issues with int.to.str and seq.len encodings Signed-off-by: Nikolaj Bjorner --- src/ast/ast.cpp | 2 + src/smt/theory_seq.cpp | 120 ++++++++++++++++++++++++----------------- 2 files changed, 73 insertions(+), 49 deletions(-) diff --git a/src/ast/ast.cpp b/src/ast/ast.cpp index 00a08df00..507f75482 100644 --- a/src/ast/ast.cpp +++ b/src/ast/ast.cpp @@ -2563,6 +2563,8 @@ proof * ast_manager::mk_modus_ponens(proof * p1, proof * p2) { CTRACE("mk_modus_ponens", to_app(get_fact(p2))->get_arg(0) != get_fact(p1), tout << mk_pp(get_fact(p1), *this) << "\n" << mk_pp(get_fact(p2), *this) << "\n";); SASSERT(to_app(get_fact(p2))->get_arg(0) == get_fact(p1)); + CTRACE("mk_modus_ponens", !is_ground(p2) && !has_quantifiers(p2), tout << "Non-ground: " << mk_pp(p2, *this) << "\n";); + CTRACE("mk_modus_ponens", !is_ground(p1) && !has_quantifiers(p1), tout << "Non-ground: " << mk_pp(p1, *this) << "\n";); if (is_reflexivity(p2)) return p1; expr * f = to_app(get_fact(p2))->get_arg(1); diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index 89f08d3df..9c670e751 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -2208,6 +2208,7 @@ bool theory_seq::check_int_string() { } bool theory_seq::add_itos_axiom(expr* e) { + context& ctx = get_context(); rational val; expr* n; VERIFY(m_util.str.is_itos(e, n)); @@ -2219,8 +2220,13 @@ bool theory_seq::add_itos_axiom(expr* e) { #if 1 // itos(n) = "25" <=> n = 25 - add_axiom(~mk_eq(n1, n , false), mk_eq(e, e1, false)); - add_axiom(mk_eq(n1, n, false), ~mk_eq(e, e1, false)); + literal eq1 = mk_eq(n1, n , false); + literal eq2 = mk_eq(e, e1, false); + add_axiom(~eq1, eq2); + add_axiom(~eq2, eq1); + ctx.force_phase(eq1); + ctx.force_phase(eq2); + #else // "25" = itos(25) // stoi(itos(n)) = n @@ -2912,54 +2918,61 @@ void theory_seq::add_itos_length_axiom(expr* len) { VERIFY(m_util.str.is_length(len, x)); VERIFY(m_util.str.is_itos(x, n)); - add_axiom(mk_literal(m_autil.mk_ge(len, m_autil.mk_int(1)))); - rational val; - if (get_value(n, val)) { - bool neg = val.is_neg(); - rational ten(10); - if (neg) val.neg(); - unsigned num_char = neg?2:1; - // 0 < x < 10 - // 10 < x < 100 - // 100 < x < 1000 - rational hi(10); - while (val > hi) { - ++num_char; - hi *= ten; + unsigned num_char1 = 1, num_char2 = 1; + rational len1, len2; + rational ten(10); + if (get_value(n, len1)) { + bool neg = len1.is_neg(); + if (neg) len1.neg(); + num_char1 = neg?2:1; + // 0 <= x < 10 + // 10 <= x < 100 + // 100 <= x < 1000 + rational upper(10); + while (len1 > upper) { + ++num_char1; + upper *= ten; } - rational lo(div(hi - rational(1), ten)); - - literal len_le(mk_literal(m_autil.mk_ge(len, m_autil.mk_int(num_char)))); - literal len_ge(mk_literal(m_autil.mk_le(len, m_autil.mk_int(num_char)))); - literal n_le_mlo(mk_literal(m_autil.mk_le(n, m_autil.mk_numeral(-lo, true)))); - literal n_ge_lo(mk_literal(m_autil.mk_ge(n, m_autil.mk_numeral(lo, true)))); - - // len >= num_char => n <= -lo or n >= lo - // len <= num_char => -hi < n < hi - - add_axiom(~len_ge, n_le_mlo, n_ge_lo); - if (neg) { - // n <= -lo => len >= num_char - // -hi < n <= 0 => len <= num_char - // n <= -hi or ~(n <= 0) or len <= num_char - - add_axiom(~n_le_mlo, len_ge); - literal n_le_mhi(mk_literal(m_autil.mk_le(n, m_autil.mk_numeral(-hi, true)))); - literal n_le_0(mk_literal(m_autil.mk_le(n, m_autil.mk_int(0)))); - add_axiom(n_le_mhi, ~n_le_0, len_le); - add_axiom(~len_le, ~n_le_mhi); - } - else { - // n >= lo => len >= num_char - // 0 <= n < hi => len <= num_char - add_axiom(~n_ge_lo, len_ge); - literal n_ge_hi(mk_literal(m_autil.mk_ge(n, m_autil.mk_numeral(hi, true)))); - literal n_ge_0(mk_literal(m_autil.mk_ge(n, m_autil.mk_int(0)))); - add_axiom(n_ge_hi, ~n_ge_0, len_le); - add_axiom(~len_le, ~n_ge_hi); - } + SASSERT(len1 <= upper); } + if (get_value(len, len2) && len2.is_unsigned()) { + num_char2 = len2.get_unsigned(); + } + unsigned num_char = std::max(num_char1, num_char2); + + literal len_le(mk_literal(m_autil.mk_le(len, m_autil.mk_int(num_char)))); + literal len_ge(mk_literal(m_autil.mk_ge(len, m_autil.mk_int(num_char)))); + + if (num_char == 1) { + add_axiom(len_ge); + literal n_ge_0(mk_literal(m_autil.mk_ge(n, m_autil.mk_int(0)))); + literal n_ge_10(mk_literal(m_autil.mk_ge(n, m_autil.mk_int(10)))); + add_axiom(~n_ge_0, n_ge_10, len_le); + add_axiom(~len_le, n_ge_0); + add_axiom(~len_le, ~n_ge_10); + return; + } + rational hi(1); + for (unsigned i = 2; i < num_char; ++i) { + hi *= ten; + } + // n <= -hi or n >= hi*10 <=> len >= num_chars + // -10*hi < n < 100*hi <=> len <= num_chars + literal n_le_hi = mk_literal(m_autil.mk_le(n, m_autil.mk_numeral(-hi, true))); + literal n_ge_10hi = mk_literal(m_autil.mk_ge(n, m_autil.mk_numeral(ten*hi, true))); + literal n_le_m10hi = mk_literal(m_autil.mk_le(n, m_autil.mk_numeral(-ten*hi, true))); + literal n_ge_100hi = mk_literal(m_autil.mk_ge(n, m_autil.mk_numeral(ten*ten*hi, true))); + + add_axiom(~n_le_hi, len_ge); + add_axiom(~n_ge_10hi, len_ge); + add_axiom(n_le_hi, n_ge_10hi, ~len_ge); + + add_axiom(n_le_m10hi, n_ge_100hi, len_le); + add_axiom(~n_le_m10hi, ~len_le); + add_axiom(~n_ge_100hi, ~len_le); + + add_axiom(mk_literal(m_autil.mk_ge(len, m_autil.mk_int(1)))); } @@ -3060,8 +3073,17 @@ bool theory_seq::get_value(expr* e, rational& val) const { context& ctx = get_context(); theory_mi_arith* tha = get_th_arith(ctx, m_autil.get_family_id(), e); expr_ref _val(m); - if (!tha || !tha->get_value(ctx.get_enode(e), _val)) return false; - return m_autil.is_numeral(_val, val) && val.is_int(); + if (!tha) return false; + enode* next = ctx.get_enode(e), *n; + do { + n = next; + if (tha->get_value(n, _val) && m_autil.is_numeral(_val, val) && val.is_int()) { + return true; + } + next = n->get_next(); + } + while (next != n); + return false; } bool theory_seq::lower_bound(expr* _e, rational& lo) const { From e9e926d4d67eb3729b72da850e7cbc2103237baa Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 2 Jun 2016 21:00:18 -0700 Subject: [PATCH 004/536] UINT32_MAX -> UINT_MAX Signed-off-by: Nikolaj Bjorner --- src/ast/fpa/fpa2bv_converter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ast/fpa/fpa2bv_converter.cpp b/src/ast/fpa/fpa2bv_converter.cpp index f32e82dd3..777840fc9 100644 --- a/src/ast/fpa/fpa2bv_converter.cpp +++ b/src/ast/fpa/fpa2bv_converter.cpp @@ -1096,7 +1096,7 @@ void fpa2bv_converter::mk_rem(sort * s, expr_ref & x, expr_ref & y, expr_ref & r SASSERT(m_mpz_manager.get_uint64(max_exp_diff) <= UINT_MAX); uint64 max_exp_diff_ui64 = m_mpz_manager.get_uint64(max_exp_diff); - SASSERT(max_exp_diff_ui64 <= UINT32_MAX); + SASSERT(max_exp_diff_ui64 <= UINT_MAX); unsigned max_exp_diff_ui = (unsigned)max_exp_diff_ui64; m_mpz_manager.del(max_exp_diff); From a94aff23e60fe985fc099d388918ad6f5fba25ff Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Fri, 3 Jun 2016 13:23:12 +0100 Subject: [PATCH 005/536] Added clearer FP conversion functions to the Python API. Implements #476 --- src/api/python/z3.py | 86 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) diff --git a/src/api/python/z3.py b/src/api/python/z3.py index 942201b0e..c9aa9beb5 100644 --- a/src/api/python/z3.py +++ b/src/api/python/z3.py @@ -8994,6 +8994,92 @@ def fpToFP(a1, a2=None, a3=None, ctx=None): else: raise Z3Exception("Unsupported combination of arguments for conversion to floating-point term.") +def fpBVToFP(v, sort, ctx=None): + """Create a Z3 floating-point conversion expression that represents the + conversion from a bit-vector term to a floating-point term. + + >>> x_bv = BitVecVal(0x3F800000, 32) + >>> x_fp = fpBVToFP(x_bv, Float32()) + >>> x_fp + fpToFP(1065353216) + >>> simplify(x_fp) + 1 + """ + _z3_assert(is_bv(v), "First argument must be a Z3 floating-point rounding mode expression.") + _z3_assert(is_fp_sort(sort), "Second argument must be a Z3 floating-point sort.") + ctx = _get_ctx(ctx) + return FPRef(Z3_mk_fpa_to_fp_bv(ctx.ref(), v.ast, sort.ast), ctx) + +def fpFPToFP(rm, v, sort, ctx=None): + """Create a Z3 floating-point conversion expression that represents the + conversion from a floating-point term to a floating-point term of different precision. + + >>> x_sgl = FPVal(1.0, Float32()) + >>> x_dbl = fpFPToFP(RNE(), x_sgl, Float64()) + >>> x_dbl + fpToFP(RNE(), 1) + >>> simplify(x_dbl) + 1 + >>> x_dbl.sort() + FPSort(11, 53) + """ + _z3_assert(is_fprm(rm), "First argument must be a Z3 floating-point rounding mode expression.") + _z3_assert(is_fp(v), "Second argument must be a Z3 floating-point expression.") + _z3_assert(is_fp_sort(sort), "Third argument must be a Z3 floating-point sort.") + ctx = _get_ctx(ctx) + return FPRef(Z3_mk_fpa_to_fp_float(ctx.ref(), rm.ast, v.ast, sort.ast), ctx) + +def fpRealToFP(rm, v, sort, ctx=None): + """Create a Z3 floating-point conversion expression that represents the + conversion from a real term to a floating-point term. + + >>> x_r = RealVal(1.5) + >>> x_fp = fpRealToFP(RNE(), x_r, Float32()) + >>> x_fp + fpToFP(RNE(), 3/2) + >>> simplify(x_fp) + 1.5 + """ + _z3_assert(is_fprm(rm), "First argument must be a Z3 floating-point rounding mode expression.") + _z3_assert(is_real(v), "Second argument must be a Z3 expression or real sort.") + _z3_assert(is_fp_sort(sort), "Third argument must be a Z3 floating-point sort.") + ctx = _get_ctx(ctx) + return FPRef(Z3_mk_fpa_to_fp_real(ctx.ref(), rm.ast, v.ast, sort.ast), ctx) + +def fpSignedToFP(rm, v, sort, ctx=None): + """Create a Z3 floating-point conversion expression that represents the + conversion from a signed bit-vector term (encoding an integer) to a floating-point term. + + >>> x_signed = BitVecVal(-5, BitVecSort(32)) + >>> x_fp = fpSignedToFP(RNE(), x_signed, Float32()) + >>> x_fp + fpToFP(RNE(), 4294967291) + >>> simplify(x_fp) + -1.25*(2**2) + """ + _z3_assert(is_fprm(rm), "First argument must be a Z3 floating-point rounding mode expression.") + _z3_assert(is_bv(v), "Second argument must be a Z3 expression or real sort.") + _z3_assert(is_fp_sort(sort), "Third argument must be a Z3 floating-point sort.") + ctx = _get_ctx(ctx) + return FPRef(Z3_mk_fpa_to_fp_signed(ctx.ref(), rm.ast, v.ast, sort.ast), ctx) + +def fpUnsignedToFP(rm, v, sort, ctx=None): + """Create a Z3 floating-point conversion expression that represents the + conversion from an unsigned bit-vector term (encoding an integer) to a floating-point term. + + >>> x_signed = BitVecVal(-5, BitVecSort(32)) + >>> x_fp = fpUnsignedToFP(RNE(), x_signed, Float32()) + >>> x_fp + fpToFPUnsigned(RNE(), 4294967291) + >>> simplify(x_fp) + 1*(2**32) + """ + _z3_assert(is_fprm(rm), "First argument must be a Z3 floating-point rounding mode expression.") + _z3_assert(is_bv(v), "Second argument must be a Z3 expression or real sort.") + _z3_assert(is_fp_sort(sort), "Third argument must be a Z3 floating-point sort.") + ctx = _get_ctx(ctx) + return FPRef(Z3_mk_fpa_to_fp_unsigned(ctx.ref(), rm.ast, v.ast, sort.ast), ctx) + def fpToFPUnsigned(rm, x, s, ctx=None): """Create a Z3 floating-point conversion expression, from unsigned bit-vector to floating-point expression.""" if __debug__: From 219b47822b8912c1d8846820635589cf12d25dbb Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 3 Jun 2016 10:13:16 -0700 Subject: [PATCH 006/536] avoid qsat when formulas are quantifier-free. Go directly to SMT Signed-off-by: Nikolaj Bjorner --- src/muz/pdr/pdr_context.cpp | 1 + src/muz/pdr/pdr_prop_solver.h | 3 +++ src/tactic/smtlogics/quant_tactics.cpp | 6 ++++-- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/muz/pdr/pdr_context.cpp b/src/muz/pdr/pdr_context.cpp index 1c25b015d..3a735165a 100644 --- a/src/muz/pdr/pdr_context.cpp +++ b/src/muz/pdr/pdr_context.cpp @@ -889,6 +889,7 @@ namespace pdr { void model_node::dequeue(model_node*& root) { TRACE("pdr", tout << this << " " << state() << "\n";); + root = 0; if (!m_next && !m_prev) return; SASSERT(m_next); SASSERT(m_prev); diff --git a/src/muz/pdr/pdr_prop_solver.h b/src/muz/pdr/pdr_prop_solver.h index ad7e1fd9a..58bd611a9 100644 --- a/src/muz/pdr/pdr_prop_solver.h +++ b/src/muz/pdr/pdr_prop_solver.h @@ -87,6 +87,9 @@ namespace pdr { void set_subset_based_core(bool f) { m_subset_based_core = f; } void set_consequences(expr_ref_vector* consequences) { m_consequences = consequences; } + + void set_background_assumptions(expr_ref_vector const& assumptions); + bool assumes_level() const { return m_assumes_level; } void add_level(); diff --git a/src/tactic/smtlogics/quant_tactics.cpp b/src/tactic/smtlogics/quant_tactics.cpp index 045b0ec87..bc3585d09 100644 --- a/src/tactic/smtlogics/quant_tactics.cpp +++ b/src/tactic/smtlogics/quant_tactics.cpp @@ -114,8 +114,10 @@ tactic * mk_lra_tactic(ast_manager & m, params_ref const & p) { #else tactic * st = and_then(mk_quant_preprocessor(m), mk_qe_lite_tactic(m, p), - or_else(mk_qsat_tactic(m, p), - and_then(mk_qe_tactic(m), mk_smt_tactic()))); + cond(mk_has_quantifier_probe(), + or_else(mk_qsat_tactic(m, p), + and_then(mk_qe_tactic(m), mk_smt_tactic())), + mk_smt_tactic())); #endif st->updt_params(p); return st; From b54ef3623b796586af7f2915077946409d1734e3 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Fri, 3 Jun 2016 20:26:05 +0100 Subject: [PATCH 007/536] added collect-statistics tactic --- src/tactic/core/collect_statistics_tactic.cpp | 173 ++++++++++++++++++ src/tactic/core/collect_statistics_tactic.h | 33 ++++ 2 files changed, 206 insertions(+) create mode 100644 src/tactic/core/collect_statistics_tactic.cpp create mode 100644 src/tactic/core/collect_statistics_tactic.h diff --git a/src/tactic/core/collect_statistics_tactic.cpp b/src/tactic/core/collect_statistics_tactic.cpp new file mode 100644 index 000000000..f50195673 --- /dev/null +++ b/src/tactic/core/collect_statistics_tactic.cpp @@ -0,0 +1,173 @@ +/*++ +Copyright (c) 2016 Microsoft Corporation + +Module Name: + + collect_statistics_tactic.cpp + +Abstract: + + A tactic for collection of various statistics. + +Author: + + Mikolas Janota (mikjan) 2016-06-03 + Christoph (cwinter) 2016-06-03 + +Notes: + +--*/ +#include +#include + +#include"ast.h" +#include"params.h" +#include"arith_decl_plugin.h" +#include"array_decl_plugin.h" +#include"bv_decl_plugin.h" +#include"datatype_decl_plugin.h" +#include"fpa_decl_plugin.h" +#include"tactical.h" +#include"stats.h" + +#include"collect_statistics_tactic.h" + +class collect_statistics_tactic : public tactic { + ast_manager & m; + params_ref m_params; + basic_decl_plugin m_basic_pi; + arith_decl_plugin m_arith_pi; + array_decl_plugin m_array_pi; + bv_decl_plugin m_bv_pi; + datatype_decl_plugin m_datatype_pi; + fpa_decl_plugin m_fpa_pi; + + typedef std::unordered_map stats_type; + stats_type m_stats; + +public: + collect_statistics_tactic(ast_manager & m, params_ref const & p) : + m(m), + m_params(p) { + } + + virtual ~collect_statistics_tactic() {} + + virtual tactic * translate(ast_manager & m_) { + return alloc(collect_statistics_tactic, m_, m_params); + } + + virtual void updt_params(params_ref const & p) { + m_params = p; + } + + virtual void collect_param_descrs(param_descrs & r) {} + + virtual void operator()(goal_ref const & g, goal_ref_buffer & result, + model_converter_ref & mc, proof_converter_ref & pc, + expr_dependency_ref & core) { + mc = 0; + tactic_report report("collect-statistics", *g); + + collect_proc cp(m, m_stats); + expr_mark visited; + const unsigned sz = g->size(); + for (unsigned i = 0; i < sz; i++) + for_each_expr(cp, visited, g->form(i)); + + std::cout << "(" << std::endl; + stats_type::iterator it = m_stats.begin(); + stats_type::iterator end = m_stats.end(); + for (; it != end; it++) + std::cout << " :" << it->first << " " << it->second << std::endl; + std::cout << ")" << std::endl; + + g->inc_depth(); + result.push_back(g.get()); + } + + virtual void cleanup() {} + + virtual void collect_statistics(statistics & st) const { + } + + virtual void reset_statistics() { reset(); } + virtual void reset() { cleanup(); } + +protected: + class collect_proc { + public: + ast_manager & m; + stats_type & m_stats; + obj_hashtable m_seen_sorts; + obj_hashtable m_seen_func_decls; + + collect_proc(ast_manager & m, stats_type & s) : m(m), m_stats(s) {} + + void operator()(var * v) { + m_stats["bound-variables"]++; + this->operator()(v->get_sort()); + } + + void operator()(quantifier * q) { + m_stats["quantifiers"]++; + SASSERT(is_app(q->get_expr())); + app * body = to_app(q->get_expr()); + this->operator()(body); + } + + void operator()(app * n) { + m_stats["function-applications"]++; + this->operator()(n->get_decl()); + } + + void operator()(sort * s) { + if (m.is_uninterp(s)) { + if (!m_seen_sorts.contains(s)) { + m_stats["uninterpreted-sorts"]++; + m_seen_sorts.insert(s); + } + m_stats["uninterpreted-sort-occurrences"]++; + } + else { + params_ref prms; + prms.set_bool("pp.single_line", true); + std::stringstream ss; + ss << mk_ismt2_pp(s, m, prms); + m_stats[ss.str().c_str()]++; + } + } + + void operator()(func_decl * f) { + for (unsigned i = 0; i < f->get_arity(); i++) + this->operator()(f->get_domain()[i]); + this->operator()(f->get_range()); + + if (f->get_family_id() == null_family_id) { + if (!m_seen_func_decls.contains(f)) { + if (f->get_arity() == 0) + m_stats["uninterpreted-constants"]++; + else + m_stats["uninterpreted-functions"]++; + m_seen_func_decls.insert(f); + } + + if (f->get_arity() > 0) + m_stats["uninterpreted-function-occurrences"]++; + } + else { + params_ref prms; + prms.set_bool("pp.single_line", true); + std::stringstream ss; + ss << mk_ismt2_pp(f, m, prms); + m_stats[ss.str().c_str()]++; + } + m_stats["function-applications"]++; + } + }; +}; + + +tactic * mk_collect_statistics_tactic(ast_manager & m, params_ref const & p) { + return clean(alloc(collect_statistics_tactic, m, p)); +} diff --git a/src/tactic/core/collect_statistics_tactic.h b/src/tactic/core/collect_statistics_tactic.h new file mode 100644 index 000000000..5734af3c7 --- /dev/null +++ b/src/tactic/core/collect_statistics_tactic.h @@ -0,0 +1,33 @@ +/*++ +Copyright (c) 2016 Microsoft Corporation + +Module Name: + + collect_statistics_tactic.h + +Abstract: + + A tactic for collection of various statistics. + +Author: + + Mikolas Janota (mikjan) 2016-06-03 + Christoph (cwinter) 2016-06-03 + +Notes: + +--*/ +#ifndef COLLECT_STATISTICS_H_ +#define COLLECT_STATISTICS_H_ + +#include"params.h" +class ast_manager; +class tactic; + +tactic * mk_collect_statistics_tactic(ast_manager & m, params_ref const & p = params_ref()); +/* + ADD_TACTIC("collect-statistics", "Collects various statistics.", "mk_collect_statistics_tactic(m, p)") +*/ + + +#endif From 626b9160bfb1e7032202b489ff9bb86a64b087e5 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Fri, 3 Jun 2016 20:45:42 +0100 Subject: [PATCH 008/536] collect-statistics additions --- src/tactic/core/collect_statistics_tactic.cpp | 20 ++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/src/tactic/core/collect_statistics_tactic.cpp b/src/tactic/core/collect_statistics_tactic.cpp index f50195673..99af8f773 100644 --- a/src/tactic/core/collect_statistics_tactic.cpp +++ b/src/tactic/core/collect_statistics_tactic.cpp @@ -133,8 +133,14 @@ protected: params_ref prms; prms.set_bool("pp.single_line", true); std::stringstream ss; - ss << mk_ismt2_pp(s, m, prms); - m_stats[ss.str().c_str()]++; + ss << "(declare-sort " << mk_ismt2_pp(s, m, prms) << ")"; + m_stats[ss.str()]++; + + if (s->get_info()->get_num_parameters() > 0) { + std::stringstream ssname; + ssname << "(declare-sort (_ " << s->get_name() << " *))"; + m_stats[ssname.str()]++; + } } } @@ -160,8 +166,16 @@ protected: prms.set_bool("pp.single_line", true); std::stringstream ss; ss << mk_ismt2_pp(f, m, prms); - m_stats[ss.str().c_str()]++; + m_stats[ss.str()]++; + + std::stringstream ssfname; + if (f->get_num_parameters() > 0) + ssfname << "(declare-fun (_ " << f->get_name() << " *) *)"; + else + ssfname << "(declare-fun " << f->get_name() << " *)"; + m_stats[ssfname.str()]++; } + m_stats["function-applications"]++; } }; From f2a869fb5807f01e007c8ac55a7076b72e6628db Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Sat, 4 Jun 2016 11:01:46 +0100 Subject: [PATCH 009/536] std::unordered_map -> std::map --- src/tactic/core/collect_statistics_tactic.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tactic/core/collect_statistics_tactic.cpp b/src/tactic/core/collect_statistics_tactic.cpp index 99af8f773..8e8879fef 100644 --- a/src/tactic/core/collect_statistics_tactic.cpp +++ b/src/tactic/core/collect_statistics_tactic.cpp @@ -18,7 +18,7 @@ Notes: --*/ #include -#include +#include #include"ast.h" #include"params.h" @@ -42,7 +42,7 @@ class collect_statistics_tactic : public tactic { datatype_decl_plugin m_datatype_pi; fpa_decl_plugin m_fpa_pi; - typedef std::unordered_map stats_type; + typedef std::map stats_type; stats_type m_stats; public: From e8d85f91d7246f62825e72e42eff9b2107efaa99 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 4 Jun 2016 20:08:13 -0700 Subject: [PATCH 010/536] disable filtering on negated tails. Issue #634 Signed-off-by: Nikolaj Bjorner --- src/muz/transforms/dl_mk_filter_rules.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/muz/transforms/dl_mk_filter_rules.cpp b/src/muz/transforms/dl_mk_filter_rules.cpp index d23da72fb..b112f4c99 100644 --- a/src/muz/transforms/dl_mk_filter_rules.cpp +++ b/src/muz/transforms/dl_mk_filter_rules.cpp @@ -111,7 +111,7 @@ namespace datalog { bool rule_modified = false; for (unsigned i = 0; i < sz; i++) { app * tail = r->get_tail(i); - if (is_candidate(tail)) { + if (is_candidate(tail) && !r->is_neg_tail(i)) { TRACE("mk_filter_rules", tout << "is_candidate: " << mk_pp(tail, m) << "\n";); var_idx_set non_local_vars = rm.collect_rule_vars_ex(r, tail); func_decl * filter_decl = mk_filter_decl(tail, non_local_vars); From 9df2a183d6972cb408e88a3d3d245d0a2cfe45ce Mon Sep 17 00:00:00 2001 From: Mikolas Janota Date: Mon, 6 Jun 2016 18:06:45 +0100 Subject: [PATCH 011/536] Adding translation to ackr_model_converter. --- src/ackermannization/ackr_info.h | 24 +++++++++++++++---- src/ackermannization/ackr_model_converter.cpp | 11 ++++++++- 2 files changed, 29 insertions(+), 6 deletions(-) diff --git a/src/ackermannization/ackr_info.h b/src/ackermannization/ackr_info.h index 703f1f3d5..76be45e2b 100644 --- a/src/ackermannization/ackr_info.h +++ b/src/ackermannization/ackr_info.h @@ -20,6 +20,7 @@ Revision History: #include"ast.h" #include"ref.h" #include"expr_replacer.h" +#include"ast_translation.h" /** \brief Information about how a formula is being converted into @@ -35,7 +36,6 @@ class ackr_info { public: ackr_info(ast_manager& m) : m_m(m) - , m_consts(m) , m_er(mk_default_expr_replacer(m)) , m_subst(m_m) , m_ref_count(0) @@ -43,16 +43,20 @@ class ackr_info { {} virtual ~ackr_info() { - m_consts.reset(); + for (t2ct::iterator i = m_t2c.begin(); i != m_t2c.end(); ++i) { + m_m.dec_ref(i->m_key); + m_m.dec_ref(i->m_value); + } } inline void set_abstr(app* term, app* c) { SASSERT(!m_sealed); - SASSERT(c); + SASSERT(c && term); m_t2c.insert(term,c); m_c2t.insert(c->get_decl(),term); m_subst.insert(term, c); - m_consts.push_back(c); + m_m.inc_ref(term); + m_m.inc_ref(c); } inline void abstract(expr * e, expr_ref& res) { @@ -77,6 +81,17 @@ class ackr_info { m_er->set_substitution(&m_subst); } + virtual ackr_info * translate(ast_translation & translator) { + ackr_info * const retv = alloc(ackr_info, translator.to()); + for (t2ct::iterator i = m_t2c.begin(); i != m_t2c.end(); ++i) { + app * const k = translator(i->m_key); + app * const v = translator(i->m_value); + retv->set_abstr(k, v); + } + if (m_sealed) retv->seal(); + return retv; + } + // // Reference counting // @@ -94,7 +109,6 @@ class ackr_info { t2ct m_t2c; // terms to constants c2tt m_c2t; // constants to terms (inversion of m_t2c) - expr_ref_vector m_consts; // the constants introduced during abstraction // replacer and substitution used to compute abstractions scoped_ptr m_er; diff --git a/src/ackermannization/ackr_model_converter.cpp b/src/ackermannization/ackr_model_converter.cpp index eb24ee927..ea4f858ad 100644 --- a/src/ackermannization/ackr_model_converter.cpp +++ b/src/ackermannization/ackr_model_converter.cpp @@ -53,7 +53,16 @@ public: //void display(std::ostream & out); - virtual model_converter * translate(ast_translation & translator) {NOT_IMPLEMENTED_YET();} + virtual model_converter * translate(ast_translation & translator) { + ackr_info_ref retv_info = info->translate(translator); + if (fixed_model) { + model_ref retv_mod_ref = abstr_model->translate(translator); + return alloc(ackr_model_converter, translator.to(), retv_info, retv_mod_ref); + } + else { + return alloc(ackr_model_converter, translator.to(), retv_info); + } + } protected: ast_manager& m; const ackr_info_ref info; From 9bfa73ee062370b35eb0dedc9611b6443f83939b Mon Sep 17 00:00:00 2001 From: Johannes Kanig Date: Wed, 8 Jun 2016 11:17:26 +0900 Subject: [PATCH 012/536] Take into account number of monomials for rlimit counting Should fix issue #611 --- src/math/grobner/grobner.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/math/grobner/grobner.cpp b/src/math/grobner/grobner.cpp index 0c96dfde3..baa16b405 100644 --- a/src/math/grobner/grobner.cpp +++ b/src/math/grobner/grobner.cpp @@ -446,6 +446,7 @@ void grobner::merge_monomials(ptr_vector & monomials) { SASSERT(&m_del_monomials != &monomials); ptr_vector& to_delete = m_del_monomials; to_delete.reset(); + m_manager.limit().inc(sz); for (unsigned i = 1; i < sz; ++i) { monomial * m1 = monomials[j]; monomial * m2 = monomials[i]; From a2eb8245900c84607c7e55ac501b75fb6d0407dd Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Wed, 8 Jun 2016 12:07:13 +0100 Subject: [PATCH 013/536] Added __nonzero__ and __bool__ functions to Python Z3 ASTs to enable use of Python lists (and similar). Thanks to Vlad Shcherbina for the recommendation (see http://stackoverflow.com/questions/37669576/converting-z3-cnf-formula-into-list-of-lists-representation-using-z3py/37679447?noredirect=1#comment62859886_37679447)! --- src/api/python/z3.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/api/python/z3.py b/src/api/python/z3.py index c9aa9beb5..ff6e91c4a 100644 --- a/src/api/python/z3.py +++ b/src/api/python/z3.py @@ -292,6 +292,19 @@ class AstRef(Z3PPObject): def __hash__(self): return self.hash() + def __nonzero__(self): + return self.__bool__() + + def __bool__(self): + if is_true(self): + return True + elif is_false(self): + return False + elif is_eq(self) and self.num_args() == 2: + return self.arg(0).eq(self.arg(1)) + else: + raise Z3Exception("Symbolic expressions cannot be cast to concrete Boolean values.") + def sexpr(self): """Return an string representing the AST node in s-expression notation. From 5253f3a12b36821a9c2a84bc604540689d80ddff Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 8 Jun 2016 13:56:01 -0700 Subject: [PATCH 014/536] internalize unsupported operations Signed-off-by: Nikolaj Bjorner --- src/muz/pdr/pdr_prop_solver.h | 3 --- src/smt/theory_arith_core.h | 28 ++++++++++++++++++---------- 2 files changed, 18 insertions(+), 13 deletions(-) diff --git a/src/muz/pdr/pdr_prop_solver.h b/src/muz/pdr/pdr_prop_solver.h index 58bd611a9..ad7e1fd9a 100644 --- a/src/muz/pdr/pdr_prop_solver.h +++ b/src/muz/pdr/pdr_prop_solver.h @@ -87,9 +87,6 @@ namespace pdr { void set_subset_based_core(bool f) { m_subset_based_core = f; } void set_consequences(expr_ref_vector* consequences) { m_consequences = consequences; } - - void set_background_assumptions(expr_ref_vector const& assumptions); - bool assumes_level() const { return m_assumes_level; } void add_level(); diff --git a/src/smt/theory_arith_core.h b/src/smt/theory_arith_core.h index 95c7fdfad..8dfe8498f 100644 --- a/src/smt/theory_arith_core.h +++ b/src/smt/theory_arith_core.h @@ -747,17 +747,25 @@ namespace smt { enode * e = mk_enode(n); return mk_var(e); } - else { - TRACE("arith_internalize_detail", tout << "before:\n" << mk_pp(n, get_manager()) << "\n";); - if (!ctx.e_internalized(n)) - ctx.internalize(n, false); - TRACE("arith_internalize_detail", tout << "after:\n" << mk_pp(n, get_manager()) << "\n";); - enode * e = ctx.get_enode(n); - if (!is_attached_to_var(e)) - return mk_var(e); - else - return e->get_th_var(get_id()); + if (m_util.get_family_id() == n->get_family_id()) { + found_unsupported_op(n); + if (ctx.e_internalized(n)) + return expr2var(n); + for (unsigned i = 0; i < n->get_num_args(); ++i) { + ctx.internalize(n->get_arg(i), false); + } + return mk_var(mk_enode(n)); } + + TRACE("arith_internalize_detail", tout << "before:\n" << mk_pp(n, get_manager()) << "\n";); + if (!ctx.e_internalized(n)) + ctx.internalize(n, false); + TRACE("arith_internalize_detail", tout << "after:\n" << mk_pp(n, get_manager()) << "\n";); + enode * e = ctx.get_enode(n); + if (!is_attached_to_var(e)) + return mk_var(e); + else + return e->get_th_var(get_id()); } /** From 879363157f008d8e635f7c4a66c12c241640e8b6 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Thu, 9 Jun 2016 12:09:53 +0100 Subject: [PATCH 015/536] Bugfix for fpa2bv_converter --- src/ast/fpa/fpa2bv_converter.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ast/fpa/fpa2bv_converter.cpp b/src/ast/fpa/fpa2bv_converter.cpp index 777840fc9..6e74f60b1 100644 --- a/src/ast/fpa/fpa2bv_converter.cpp +++ b/src/ast/fpa/fpa2bv_converter.cpp @@ -4107,5 +4107,6 @@ void fpa2bv_converter::reset(void) { m.dec_ref(it->m_value.first); m.dec_ref(it->m_value.second); } + m_specials.reset(); m_extra_assertions.reset(); } From bfeab9cc154dc93547d67aee36e6210f2fa6638c Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Thu, 9 Jun 2016 17:49:45 +0100 Subject: [PATCH 016/536] Added facilities for hiding UFs in smt::model_generator --- src/smt/smt_model_generator.cpp | 7 +++++-- src/smt/smt_model_generator.h | 3 +++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/smt/smt_model_generator.cpp b/src/smt/smt_model_generator.cpp index 21a310a42..b9c1ac453 100644 --- a/src/smt/smt_model_generator.cpp +++ b/src/smt/smt_model_generator.cpp @@ -20,6 +20,7 @@ Revision History: #include"smt_context.h" #include"smt_model_generator.h" #include"proto_model.h" +#include"ref_util.h" #include"for_each_expr.h" #include"ast_ll_pp.h" #include"ast_pp.h" @@ -36,6 +37,7 @@ namespace smt { } model_generator::~model_generator() { + dec_ref_collection_values(m_manager, m_hidden_ufs); } void model_generator::reset() { @@ -386,6 +388,7 @@ namespace smt { enode * n = *it3; if (is_uninterp_const(n->get_owner()) && m_context->is_relevant(n)) { func_decl * d = n->get_owner()->get_decl(); + if (m_hidden_ufs.contains(d)) continue; expr * val = get_value(n); m_model->register_decl(d, val); } @@ -404,9 +407,9 @@ namespace smt { */ bool model_generator::include_func_interp(func_decl * f) const { family_id fid = f->get_family_id(); - if (fid == null_family_id) return true; + if (fid == null_family_id) return !m_hidden_ufs.contains(f); if (fid == m_manager.get_basic_family_id()) return false; - theory * th = m_context->get_theory(fid); + theory * th = m_context->get_theory(fid); if (!th) return true; return th->include_func_interp(f); } diff --git a/src/smt/smt_model_generator.h b/src/smt/smt_model_generator.h index 6017176e5..07f508e69 100644 --- a/src/smt/smt_model_generator.h +++ b/src/smt/smt_model_generator.h @@ -182,6 +182,7 @@ namespace smt { obj_map m_root2value; ast_ref_vector m_asts; proto_model * m_model; + obj_hashtable m_hidden_ufs; void init_model(); void mk_bool_model(); @@ -220,6 +221,8 @@ namespace smt { obj_map const & get_root2value() const { return m_root2value; } app * get_value(enode * n) const; + + void hide(func_decl * f) { m_hidden_ufs.insert_if_not_there(f); m_manager.inc_ref(f); } }; }; From bd187e098988c57b5dc8e75480c42717ffeb3482 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Thu, 9 Jun 2016 17:51:31 +0100 Subject: [PATCH 017/536] Bugfix for fp.min/fp.max in fpa2bv converter; hide BV UFs from FP models. Fixes #642 --- src/ast/fpa/fpa2bv_converter.cpp | 10 +++--- src/ast/fpa/fpa2bv_converter.h | 22 ++++++++----- src/smt/theory_fpa.cpp | 42 ++++++++++--------------- src/smt/theory_fpa.h | 3 -- src/tactic/fpa/fpa2bv_model_converter.h | 4 +-- 5 files changed, 38 insertions(+), 43 deletions(-) diff --git a/src/ast/fpa/fpa2bv_converter.cpp b/src/ast/fpa/fpa2bv_converter.cpp index 6e74f60b1..d833e2381 100644 --- a/src/ast/fpa/fpa2bv_converter.cpp +++ b/src/ast/fpa/fpa2bv_converter.cpp @@ -1273,10 +1273,10 @@ expr_ref fpa2bv_converter::mk_min_max_unspecified(func_decl * f, expr * x, expr // There is no "hardware interpretation" for fp.min/fp.max. std::pair decls(0, 0); - if (!m_specials.find(f, decls)) { + if (!m_min_max_specials.find(f, decls)) { decls.first = m.mk_fresh_const(0, m_bv_util.mk_sort(1)); decls.second = m.mk_fresh_const(0, m_bv_util.mk_sort(1)); - m_specials.insert(f, decls); + m_min_max_specials.insert(f, decls); m.inc_ref(f); m.inc_ref(decls.first); m.inc_ref(decls.second); @@ -4100,13 +4100,13 @@ void fpa2bv_converter::reset(void) { dec_ref_map_key_values(m, m_const2bv); dec_ref_map_key_values(m, m_rm_const2bv); dec_ref_map_key_values(m, m_uf2bvuf); - for (obj_map >::iterator it = m_specials.begin(); - it != m_specials.end(); + for (obj_map >::iterator it = m_min_max_specials.begin(); + it != m_min_max_specials.end(); it++) { m.dec_ref(it->m_key); m.dec_ref(it->m_value.first); m.dec_ref(it->m_value.second); } - m_specials.reset(); + m_min_max_specials.reset(); m_extra_assertions.reset(); } diff --git a/src/ast/fpa/fpa2bv_converter.h b/src/ast/fpa/fpa2bv_converter.h index 45030b301..3f5e76c66 100644 --- a/src/ast/fpa/fpa2bv_converter.h +++ b/src/ast/fpa/fpa2bv_converter.h @@ -32,6 +32,11 @@ Notes: #include"basic_simplifier_plugin.h" class fpa2bv_converter { +public: + typedef obj_map > special_t; + typedef obj_map const2bv_t; + typedef obj_map uf2bvuf_t; + protected: ast_manager & m; basic_simplifier_plugin m_simp; @@ -46,11 +51,10 @@ protected: fpa_decl_plugin * m_plugin; bool m_hi_fp_unspecified; - obj_map m_const2bv; - obj_map m_rm_const2bv; - obj_map m_uf2bvuf; - - obj_map > m_specials; + const2bv_t m_const2bv; + const2bv_t m_rm_const2bv; + uf2bvuf_t m_uf2bvuf; + special_t m_min_max_specials; friend class fpa2bv_model_converter; @@ -154,9 +158,11 @@ public: void dbg_decouple(const char * prefix, expr_ref & e); expr_ref_vector m_extra_assertions; - - bool is_special(func_decl * f) { return m_specials.contains(f); } - bool is_uf2bvuf(func_decl * f) { return m_uf2bvuf.contains(f); } + + special_t const & get_min_max_specials() const { return m_min_max_specials; }; + const2bv_t const & get_const2bv() const { return m_const2bv; }; + const2bv_t const & get_rm_const2bv() const { return m_rm_const2bv; }; + uf2bvuf_t const & get_uf2bvuf() const { return m_uf2bvuf; }; protected: void mk_one(func_decl *f, expr_ref & sign, expr_ref & result); diff --git a/src/smt/theory_fpa.cpp b/src/smt/theory_fpa.cpp index 6038867aa..8e96c925d 100644 --- a/src/smt/theory_fpa.cpp +++ b/src/smt/theory_fpa.cpp @@ -83,27 +83,6 @@ namespace smt { } } - void theory_fpa::fpa2bv_converter_wrapped::mk_function(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { - // 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_max_unspecified(func_decl * f, expr * x, expr * y) { - expr_ref a(m), wrapped(m), wu(m), wu_eq(m); - a = m.mk_app(f, x, y); - wrapped = m_th.wrap(a); - wu = m_th.unwrap(wrapped, f->get_range()); - wu_eq = m.mk_eq(wu, a); - m_extra_assertions.push_back(wu_eq); - - unsigned bv_sz = m_bv_util.get_bv_size(wrapped); - expr_ref sc(m); - sc = m.mk_eq(m_bv_util.mk_extract(bv_sz-2, 0, wrapped), m_bv_util.mk_numeral(0, bv_sz-1)); - m_extra_assertions.push_back(sc); - - return wu; - } - theory_fpa::theory_fpa(ast_manager & m) : theory(m.mk_family_id("fpa")), m_converter(m, this), @@ -727,8 +706,23 @@ 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); + ast_manager & m = get_manager(); + m_factory = alloc(fpa_value_factory, m, get_family_id()); + mg.register_factory(m_factory); + + fpa2bv_converter::uf2bvuf_t const & uf2bvuf = m_converter.get_uf2bvuf(); + for (fpa2bv_converter::uf2bvuf_t::iterator it = uf2bvuf.begin(); + it != uf2bvuf.end(); + it++) { + mg.hide(it->m_value); + } + fpa2bv_converter::special_t const & specials = m_converter.get_min_max_specials(); + for (fpa2bv_converter::special_t::iterator it = specials.begin(); + it != specials.end(); + it++) { + mg.hide(it->m_value.first->get_decl()); + mg.hide(it->m_value.second->get_decl()); + } } model_value_proc * theory_fpa::mk_value(enode * n, model_generator & mg) { @@ -882,8 +876,6 @@ namespace smt { } return false; } - 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 32fcfcffc..2b327eb66 100644 --- a/src/smt/theory_fpa.h +++ b/src/smt/theory_fpa.h @@ -83,9 +83,6 @@ 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_function(func_decl * f, unsigned num, expr * const * args, expr_ref & result); - - virtual expr_ref mk_min_max_unspecified(func_decl * f, expr * x, expr * y); }; class fpa_value_proc : public model_value_proc { diff --git a/src/tactic/fpa/fpa2bv_model_converter.h b/src/tactic/fpa/fpa2bv_model_converter.h index 0e92841de..909a7cb78 100644 --- a/src/tactic/fpa/fpa2bv_model_converter.h +++ b/src/tactic/fpa/fpa2bv_model_converter.h @@ -64,8 +64,8 @@ public: 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(); + for (obj_map >::iterator it = conv.m_min_max_specials.begin(); + it != conv.m_min_max_specials.end(); it++) { m_specials.insert(it->m_key, it->m_value); m.inc_ref(it->m_key); From 19f98547f7d3155f4a8985a068f5171f9e16a090 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 9 Jun 2016 21:59:10 -0700 Subject: [PATCH 018/536] fix memory leak Issue #643 Signed-off-by: Nikolaj Bjorner --- src/smt/smt_model_generator.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/smt/smt_model_generator.h b/src/smt/smt_model_generator.h index 07f508e69..f360dbd7e 100644 --- a/src/smt/smt_model_generator.h +++ b/src/smt/smt_model_generator.h @@ -222,7 +222,12 @@ namespace smt { obj_map const & get_root2value() const { return m_root2value; } app * get_value(enode * n) const; - void hide(func_decl * f) { m_hidden_ufs.insert_if_not_there(f); m_manager.inc_ref(f); } + void hide(func_decl * f) { + if (!m_hidden_ufs.contains(f)) { + m_hidden_ufs.insert(f); + m_manager.inc_ref(f); + } + } }; }; From 22097efd4a494b50447d1886aae30d6f73464638 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20R=2E=20Neuh=C3=A4u=C3=9Fer?= Date: Tue, 7 Jun 2016 12:15:51 +0200 Subject: [PATCH 019/536] Extend build scripts to support MinGW64 cross-compilation on Windows. --- README.md | 10 ++++++++++ scripts/mk_util.py | 34 +++++++++++++++++++++++++++------- 2 files changed, 37 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 3985fad27..502b32147 100644 --- a/README.md +++ b/README.md @@ -56,6 +56,16 @@ CXX=clang++ CC=clang python scripts/mk_make.py Note that Clang < 3.7 does not support OpenMP. +You can also build Z3 for Windows using Cygwin and the Mingw-w64 cross-compiler. +To configure that case correctly, make sure to use Cygwin's own python and not +some Windows installation of Python. + +For a 64 bit build (from Cygwin64), configure Z3's sources with +```bash +CXX=x86_64-w64-mingw32-g++ CC=x86_64-w64-mingw32-gcc AR=x86_64-w64-mingw32-ar python scripts/mk_make.py +``` +A 32 bit build should work similarly (but is untested); the same is true for 32/64 bit builds from within Cygwin32. + By default, it will install z3 executable at ``PREFIX/bin``, libraries at ``PREFIX/lib``, and include files at ``PREFIX/include``, where ``PREFIX`` installation prefix if inferred by the ``mk_make.py`` script. It is usually diff --git a/scripts/mk_util.py b/scripts/mk_util.py index a73a0e59c..53f3e15c6 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -70,6 +70,7 @@ IS_OSX=False IS_FREEBSD=False IS_OPENBSD=False IS_CYGWIN=False +IS_CYGWIN_MINGW=False VERBOSE=True DEBUG_MODE=False SHOW_CPPS = True @@ -143,6 +144,9 @@ def is_osx(): def is_cygwin(): return IS_CYGWIN +def is_cygwin_mingw(): + return IS_CYGWIN_MINGW + def norm_path(p): # We use '/' on mk_project for convenience return os.path.join(*(p.split('/'))) @@ -219,7 +223,10 @@ def rmf(fname): def exec_compiler_cmd(cmd): r = exec_cmd(cmd) - rmf('a.out') + if is_windows() or is_cygwin_mingw(): + rmf('a.exe') + else: + rmf('a.out') return r def test_cxx_compiler(cc): @@ -597,6 +604,8 @@ elif os.name == 'posix': IS_OPENBSD=True elif os.uname()[0][:6] == 'CYGWIN': IS_CYGWIN=True + if ("mingw" in CC): + IS_CYGWIN_MINGW=True def display_help(exit_code): print("mk_make.py: Z3 Makefile generator\n") @@ -1821,7 +1830,7 @@ class MLComponent(Component): CP_CMD='copy' OCAML_FLAGS = '' - if DEBUG_MODE: + if DEBUG_MODE: OCAML_FLAGS += '-g' OCAMLCF = OCAMLC + ' ' + OCAML_FLAGS OCAMLOPTF = OCAMLOPT + ' ' + OCAML_FLAGS @@ -1875,12 +1884,15 @@ class MLComponent(Component): OCAMLMKLIB = 'ocamlmklib' - LIBZ3 = '-L. -lz3' - if is_cygwin(): - # Some ocamlmklib's don't like -g; observed on cygwin, but may be others as well. + + LIBZ3 = '-L. -lz3' + if is_cygwin() and not(is_cygwin_mingw()): LIBZ3 = 'libz3.dll' - elif DEBUG_MODE: + + if DEBUG_MODE and not(is_cygwin()): + # Some ocamlmklib's don't like -g; observed on cygwin, but may be others as well. OCAMLMKLIB += ' -g' + z3mls = os.path.join(self.sub_dir, 'z3ml') out.write('%s.cma: %s %s %s\n' % (z3mls, cmos, stubso, z3dllso)) out.write('\t%s -o %s -I %s %s %s %s\n' % (OCAMLMKLIB, z3mls, self.sub_dir, stubso, cmos, LIBZ3)) @@ -1943,7 +1955,7 @@ class MLComponent(Component): out.write(' %s' % ((os.path.join(self.sub_dir, 'z3ml.cmxa')))) out.write(' %s' % ((os.path.join(self.sub_dir, 'z3ml.cmxs')))) out.write(' %s' % ((os.path.join(self.sub_dir, 'dllz3ml')))) - if IS_WINDOWS: + if is_windows() or is_cygwin_mingw(): out.write('.dll') else: out.write('.so') # .so also on OSX! @@ -2382,6 +2394,12 @@ def mk_config(): CPPFLAGS = '%s -DNDEBUG -D_EXTERNAL_RELEASE' % CPPFLAGS if TRACE or DEBUG_MODE: CPPFLAGS = '%s -D_TRACE' % CPPFLAGS + if is_cygwin_mingw(): + # when cross-compiling with MinGW, we need to statically link its standard libraries + # and to make it create an import library. + SLIBEXTRAFLAGS = '%s -static-libgcc -static-libstdc++ -Wl,--out-implib,libz3.dll.a' % SLIBEXTRAFLAGS + LDFLAGS = '%s -static-libgcc -static-libstdc++' % LDFLAGS + config.write('PREFIX=%s\n' % PREFIX) config.write('CC=%s\n' % CC) config.write('CXX=%s\n' % CXX) @@ -2411,6 +2429,8 @@ def mk_config(): print('Host platform: %s' % sysname) print('C++ Compiler: %s' % CXX) print('C Compiler : %s' % CC) + if is_cygwin_mingw(): + print('MinGW32 cross: %s' % (is_cygwin_mingw())) print('Archive Tool: %s' % AR) print('Arithmetic: %s' % ARITH) print('OpenMP: %s' % HAS_OMP) From f069b1c0e980094048826183d88276c0db73961b Mon Sep 17 00:00:00 2001 From: martin-neuhaeusser Date: Wed, 25 May 2016 09:59:36 +0200 Subject: [PATCH 020/536] 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 a06f1fbb1..733d5b1fa 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 d6b2cdab4..5960d5095 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) From 9f5a117443122bfac118a73475f67bbb45adc4a4 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 10 Jun 2016 16:24:14 -0700 Subject: [PATCH 021/536] move mus to solver Signed-off-by: Nikolaj Bjorner --- contrib/cmake/src/opt/CMakeLists.txt | 1 - contrib/cmake/src/solver/CMakeLists.txt | 1 + src/opt/maxres.cpp | 2 +- src/opt/mus.h | 55 -------- src/opt/opt_context.cpp | 2 +- src/qe/qsat.cpp | 103 +++++++++------ src/solver/check_sat_result.h | 1 + src/{opt => solver}/mus.cpp | 160 +++++++++++++++++++++--- src/solver/mus.h | 54 ++++++++ src/solver/solver.h | 4 + 10 files changed, 273 insertions(+), 110 deletions(-) delete mode 100644 src/opt/mus.h rename src/{opt => solver}/mus.cpp (55%) create mode 100644 src/solver/mus.h diff --git a/contrib/cmake/src/opt/CMakeLists.txt b/contrib/cmake/src/opt/CMakeLists.txt index c50f8be52..e4166e3d4 100644 --- a/contrib/cmake/src/opt/CMakeLists.txt +++ b/contrib/cmake/src/opt/CMakeLists.txt @@ -8,7 +8,6 @@ z3_add_component(opt maxsls.cpp maxsmt.cpp mss.cpp - mus.cpp opt_cmds.cpp opt_context.cpp opt_pareto.cpp diff --git a/contrib/cmake/src/solver/CMakeLists.txt b/contrib/cmake/src/solver/CMakeLists.txt index 5e76c91ce..8142ca872 100644 --- a/contrib/cmake/src/solver/CMakeLists.txt +++ b/contrib/cmake/src/solver/CMakeLists.txt @@ -2,6 +2,7 @@ z3_add_component(solver SOURCES check_sat_result.cpp combined_solver.cpp + mus.cpp solver.cpp solver_na2as.cpp tactic2solver.cpp diff --git a/src/opt/maxres.cpp b/src/opt/maxres.cpp index 7c1fad80e..741bab4b5 100644 --- a/src/opt/maxres.cpp +++ b/src/opt/maxres.cpp @@ -119,7 +119,7 @@ public: maxsmt_solver_base(c, ws, soft), m_index(index), m_B(m), m_asms(m), m_defs(m), - m_mus(c.get_solver(), m), + m_mus(c.get_solver()), m_mss(c.get_solver(), m), m_trail(m), m_st(st), diff --git a/src/opt/mus.h b/src/opt/mus.h deleted file mode 100644 index 8ca7ab91d..000000000 --- a/src/opt/mus.h +++ /dev/null @@ -1,55 +0,0 @@ -/*++ -Copyright (c) 2014 Microsoft Corporation - -Module Name: - - mus.h - -Abstract: - - Basic MUS extraction - -Author: - - Nikolaj Bjorner (nbjorner) 2014-20-7 - -Notes: - ---*/ -#ifndef MUS_H_ -#define MUS_H_ - -namespace opt { - class mus { - struct imp; - imp * m_imp; - public: - mus(solver& s, ast_manager& m); - ~mus(); - /** - Add soft constraint. - - Assume that the solver context enforces that - cls is equivalent to a disjunction of args. - Assume also that cls is a literal. - */ - unsigned add_soft(expr* cls); - - lbool get_mus(unsigned_vector& mus); - - void reset(); - - /** - Instrument MUS extraction to also provide the minimal - penalty model, if any is found. - The minimal penalty model has the least weight for the - supplied soft constraints. - */ - void set_soft(unsigned sz, expr* const* soft, rational const* weights); - rational get_best_model(model_ref& mdl); - - }; - -}; - -#endif diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 0b71fff1c..5082fde37 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -225,7 +225,7 @@ namespace opt { normalize(); internalize(); update_solver(); -#if 0 +#if 1 if (is_qsat_opt()) { return run_qsat_opt(); } diff --git a/src/qe/qsat.cpp b/src/qe/qsat.cpp index a9ca9e99d..4c6efdcd4 100644 --- a/src/qe/qsat.cpp +++ b/src/qe/qsat.cpp @@ -34,7 +34,9 @@ Notes: #include "expr_replacer.h" #include "th_rewriter.h" #include "model_evaluator.h" - +#include "smt_solver.h" +#include "solver.h" +#include "mus.h" namespace qe { @@ -506,33 +508,58 @@ namespace qe { } class kernel { - smt_params m_smtp; - smt::kernel m_kernel; + ast_manager& m; + params_ref m_params; + ref m_solver; public: kernel(ast_manager& m): - m_kernel(m, m_smtp) + m(m), + m_solver(mk_smt_solver(m, m_params, symbol::null)) { - m_smtp.m_model = true; - m_smtp.m_relevancy_lvl = 0; - m_smtp.m_case_split_strategy = CS_ACTIVITY_WITH_CACHE; + m_params.set_bool("model", true); + m_params.set_uint("relevancy_lvl", 0); + m_params.set_uint("case_split_strategy", CS_ACTIVITY_WITH_CACHE); + m_solver->updt_params(m_params); } - smt::kernel& k() { return m_kernel; } - smt::kernel const& k() const { return m_kernel; } + solver& s() { return *m_solver; } + solver const& s() const { return *m_solver; } + + void reset() { + m_solver = mk_smt_solver(m, m_params, symbol::null); + } void assert_expr(expr* e) { - m_kernel.assert_expr(e); + m_solver->assert_expr(e); } + ptr_vector m_core; + void get_core(expr_ref_vector& core) { - unsigned sz = m_kernel.get_unsat_core_size(); core.reset(); - for (unsigned i = 0; i < sz; ++i) { - core.push_back(m_kernel.get_unsat_core_expr(i)); + m_core.reset(); + m_solver->get_unsat_core(m_core); + core.append(m_core.size(), m_core.c_ptr()); + +#if 0 + + mus mus(*m_solver); + for (unsigned i = 0; i < m_core.size(); ++i) { + VERIFY(i == mus.add_soft(m_core[i])); } + unsigned_vector mus2; + core.reset(); + if (mus.get_mus(mus2) != l_undef) { + for (unsigned i = 0; i < mus2.size(); ++i) { + core.push_back(m_core[mus2[i]]); + } + } + std::cout << m_core.size() << " => " << core.size() << "\n"; +#endif + TRACE("qe", tout << "core: " << core << "\n"; - m_kernel.display(tout); + m_solver->display(tout); tout << "\n"; ); } @@ -586,13 +613,13 @@ namespace qe { expr_ref_vector asms(m_asms); m_pred_abs.get_assumptions(m_model.get(), asms); TRACE("qe", tout << asms << "\n";); - smt::kernel& k = get_kernel(m_level).k(); - lbool res = k.check(asms); + solver& s = get_kernel(m_level).s(); + lbool res = s.check_sat(asms); switch (res) { case l_true: - k.get_model(m_model); + s.get_model(m_model); SASSERT(validate_model(asms)); - TRACE("qe", k.display(tout); display(tout << "\n", *m_model.get()); display(tout, asms); ); + TRACE("qe", s.display(tout); display(tout << "\n", *m_model.get()); display(tout, asms); ); push(); break; case l_false: @@ -655,8 +682,8 @@ namespace qe { void reset() { m_st.reset(); - m_fa.k().collect_statistics(m_st); - m_ex.k().collect_statistics(m_st); + m_fa.s().collect_statistics(m_st); + m_ex.s().collect_statistics(m_st); m_pred_abs.collect_statistics(m_st); m_level = 0; m_answer.reset(); @@ -664,8 +691,8 @@ namespace qe { m_pred_abs.reset(); m_vars.reset(); m_model = 0; - m_fa.k().reset(); - m_ex.k().reset(); + m_fa.reset(); + m_ex.reset(); m_free_vars.reset(); } @@ -964,10 +991,12 @@ namespace qe { bool validate_core(expr_ref_vector const& core) { TRACE("qe", tout << "Validate core\n";); - smt::kernel& k = get_kernel(m_level).k(); + solver& s = get_kernel(m_level).s(); expr_ref_vector fmls(m); fmls.append(core.size(), core.c_ptr()); - fmls.append(k.size(), k.get_formulas()); + for (unsigned i = 0; i < s.get_num_assertions(); ++i) { + fmls.push_back(s.get_assertion(i)); + } return check_fmls(fmls) || m.canceled(); } @@ -985,10 +1014,14 @@ namespace qe { bool validate_model(expr_ref_vector const& asms) { TRACE("qe", tout << "Validate model\n";); - smt::kernel& k = get_kernel(m_level).k(); + solver& s = get_kernel(m_level).s(); + expr_ref_vector fmls(m); + for (unsigned i = 0; i < s.get_num_assertions(); ++i) { + fmls.push_back(s.get_assertion(i)); + } return validate_model(*m_model, asms.size(), asms.c_ptr()) && - validate_model(*m_model, k.size(), k.get_formulas()); + validate_model(*m_model, fmls.size(), fmls.c_ptr()); } bool validate_model(model& mdl, unsigned sz, expr* const* fmls) { @@ -1161,9 +1194,9 @@ namespace qe { break; case l_undef: result.push_back(in.get()); - std::string s = m_ex.k().last_failure_as_string(); - if (s == "ok") { - s = m_fa.k().last_failure_as_string(); + std::string s = m_ex.s().reason_unknown(); + if (s == "ok" || s == "unknown") { + s = m_fa.s().reason_unknown(); } throw tactic_exception(s.c_str()); } @@ -1171,8 +1204,8 @@ 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_fa.s().collect_statistics(st); + m_ex.s().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); @@ -1180,8 +1213,8 @@ namespace qe { void reset_statistics() { m_stats.reset(); - m_fa.k().reset_statistics(); - m_ex.k().reset_statistics(); + m_fa.reset(); + m_ex.reset(); } void cleanup() { @@ -1223,9 +1256,9 @@ namespace qe { UNREACHABLE(); break; case l_undef: - std::string s = m_ex.k().last_failure_as_string(); + std::string s = m_ex.s().reason_unknown(); if (s == "ok") { - s = m_fa.k().last_failure_as_string(); + s = m_fa.s().reason_unknown(); } throw tactic_exception(s.c_str()); diff --git a/src/solver/check_sat_result.h b/src/solver/check_sat_result.h index e6586d492..b981b3119 100644 --- a/src/solver/check_sat_result.h +++ b/src/solver/check_sat_result.h @@ -54,6 +54,7 @@ public: virtual void set_reason_unknown(char const* msg) = 0; virtual void get_labels(svector & r) = 0; virtual ast_manager& get_manager() = 0; + }; /** diff --git a/src/opt/mus.cpp b/src/solver/mus.cpp similarity index 55% rename from src/opt/mus.cpp rename to src/solver/mus.cpp index aa8446256..ebdffca13 100644 --- a/src/opt/mus.cpp +++ b/src/solver/mus.cpp @@ -19,14 +19,11 @@ Notes: --*/ #include "solver.h" -#include "smt_literal.h" #include "mus.h" #include "ast_pp.h" #include "ast_util.h" +#include "uint_set.h" -using namespace opt; - -// struct mus::imp { solver& m_s; @@ -38,15 +35,14 @@ struct mus::imp { vector m_weights; rational m_weight; - imp(solver& s, ast_manager& m): - m_s(s), m(m), m_cls2expr(m), m_soft(m) + imp(solver& s): + m_s(s), m(s.get_manager()), m_cls2expr(m), m_soft(m) {} void reset() { m_cls2expr.reset(); m_expr2cls.reset(); - } - + } unsigned add_soft(expr* cls) { SASSERT(is_uninterp_const(cls) || @@ -55,7 +51,7 @@ struct mus::imp { m_expr2cls.insert(cls, idx); m_cls2expr.push_back(cls); TRACE("opt", tout << idx << ": " << mk_pp(cls, m) << "\n"; - display_vec(tout, m_cls2expr);); + display_vec(tout, m_cls2expr);); return idx; } @@ -70,11 +66,16 @@ struct mus::imp { mus.push_back(core.back()); return l_true; } + mus.reset(); + if (core.size() > 64) { + return qx(mus); + } + expr_ref_vector assumptions(m); ptr_vector core_exprs; while (!core.empty()) { - IF_VERBOSE(2, verbose_stream() << "(opt.mus reducing core: " << core.size() << " new core: " << mus.size() << ")\n";); + IF_VERBOSE(12, verbose_stream() << "(opt.mus reducing core: " << core.size() << " new core: " << mus.size() << ")\n";); unsigned cls_id = core.back(); TRACE("opt", display_vec(tout << "core: ", core); @@ -84,11 +85,12 @@ struct mus::imp { expr* cls = m_cls2expr[cls_id].get(); expr_ref not_cls(m); not_cls = mk_not(m, cls); - unsigned sz = assumptions.size(); - assumptions.push_back(not_cls); - add_core(core, assumptions); - lbool is_sat = m_s.check_sat(assumptions.size(), assumptions.c_ptr()); - assumptions.resize(sz); + lbool is_sat = l_undef; + { + scoped_append _sa(*this, assumptions, core); + assumptions.push_back(not_cls); + is_sat = m_s.check_sat(assumptions); + } switch (is_sat) { case l_undef: return is_sat; @@ -132,6 +134,30 @@ struct mus::imp { return l_true; } + class scoped_append { + expr_ref_vector& m_fmls; + unsigned m_size; + public: + scoped_append(imp& imp, expr_ref_vector& fmls1, unsigned_vector const& fmls2): + m_fmls(fmls1), + m_size(fmls1.size()) { + for (unsigned i = 0; i < fmls2.size(); ++i) { + fmls1.push_back(imp.m_cls2expr[fmls2[i]].get()); + } + } + scoped_append(imp& imp, expr_ref_vector& fmls1, uint_set const& fmls2): + m_fmls(fmls1), + m_size(fmls1.size()) { + uint_set::iterator it = fmls2.begin(), end = fmls2.end(); + for (; it != end; ++it) { + fmls1.push_back(imp.m_cls2expr[*it].get()); + } + } + ~scoped_append() { + m_fmls.shrink(m_size); + } + }; + void add_core(unsigned_vector const& core, expr_ref_vector& assumptions) { for (unsigned i = 0; i < core.size(); ++i) { assumptions.push_back(m_cls2expr[core[i]].get()); @@ -193,10 +219,110 @@ struct mus::imp { } + lbool qx(unsigned_vector& mus) { + uint_set core, support; + for (unsigned i = 0; i < m_cls2expr.size(); ++i) { + core.insert(i); + } + lbool is_sat = qx(core, support, false); + if (is_sat == l_true) { + uint_set::iterator it = core.begin(), end = core.end(); + mus.reset(); + for (; it != end; ++it) { + mus.push_back(*it); + } + } + return is_sat; + } + + lbool qx(uint_set& assignment, uint_set& support, bool has_support) { + lbool is_sat = l_true; +#if 0 + if (s.m_config.m_minimize_core_partial && s.m_stats.m_restart - m_restart > m_max_restarts) { + IF_VERBOSE(1, verbose_stream() << "(sat restart budget exceeded)\n";); + return l_true; + } +#endif + if (has_support) { + expr_ref_vector asms(m); + scoped_append _sa(*this, asms, support); + is_sat = m_s.check_sat(asms); + switch (is_sat) { + case l_false: { + uint_set core; + get_core(core); + support &= core; + assignment.reset(); + return l_true; + } + case l_undef: + return l_undef; + case l_true: + update_model(); + break; + default: + break; + } + } + if (assignment.num_elems() == 1) { + return l_true; + } + uint_set assign2; + split(assignment, assign2); + support |= assignment; + is_sat = qx(assign2, support, !assignment.empty()); + unsplit(support, assignment); + if (is_sat != l_true) return is_sat; + support |= assign2; + is_sat = qx(assignment, support, !assign2.empty()); + assignment |= assign2; + unsplit(support, assign2); + return is_sat; + } + + void get_core(uint_set& core) { + ptr_vector core_exprs; + m_s.get_unsat_core(core_exprs); + for (unsigned i = 0; i < core_exprs.size(); ++i) { + expr* cls = core_exprs[i]; + core.insert(m_expr2cls.find(cls)); + } + } + + void unsplit(uint_set& A, uint_set& B) { + uint_set A1, B1; + uint_set::iterator it = A.begin(), end = A.end(); + for (; it != end; ++it) { + if (B.contains(*it)) { + B1.insert(*it); + } + else { + A1.insert(*it); + } + } + A = A1; + B = B1; + } + + void split(uint_set& lits1, uint_set& lits2) { + unsigned half = lits1.num_elems()/2; + uint_set lits3; + uint_set::iterator it = lits1.begin(), end = lits1.end(); + for (unsigned i = 0; it != end; ++it, ++i) { + if (i < half) { + lits3.insert(*it); + } + else { + lits2.insert(*it); + } + } + lits1 = lits3; + } + }; -mus::mus(solver& s, ast_manager& m) { - m_imp = alloc(imp, s, m); +mus::mus(solver& s) { + m_imp = alloc(imp, s); } mus::~mus() { diff --git a/src/solver/mus.h b/src/solver/mus.h new file mode 100644 index 000000000..d66049030 --- /dev/null +++ b/src/solver/mus.h @@ -0,0 +1,54 @@ +/*++ +Copyright (c) 2014 Microsoft Corporation + +Module Name: + + mus.h + +Abstract: + + Basic MUS extraction + +Author: + + Nikolaj Bjorner (nbjorner) 2014-20-7 + +Notes: + +--*/ +#ifndef MUS_H_ +#define MUS_H_ + +class mus { + struct imp; + imp * m_imp; + public: + mus(solver& s); + ~mus(); + /** + Add soft constraint. + + Assume that the solver context enforces that + cls is equivalent to a disjunction of args. + Assume also that cls is a literal. + */ + unsigned add_soft(expr* cls); + + lbool get_mus(unsigned_vector& mus); + + void reset(); + + /** + Instrument MUS extraction to also provide the minimal + penalty model, if any is found. + The minimal penalty model has the least weight for the + supplied soft constraints. + */ + void set_soft(unsigned sz, expr* const* soft, rational const* weights); + + rational get_best_model(model_ref& mdl); + +}; + + +#endif diff --git a/src/solver/solver.h b/src/solver/solver.h index 5a1514795..0b2578968 100644 --- a/src/solver/solver.h +++ b/src/solver/solver.h @@ -108,6 +108,10 @@ public: */ virtual lbool check_sat(unsigned num_assumptions, expr * const * assumptions) = 0; + lbool check_sat(expr_ref_vector const& asms) { return check_sat(asms.size(), asms.c_ptr()); } + + lbool check_sat(app_ref_vector const& asms) { return check_sat(asms.size(), (expr* const*)asms.c_ptr()); } + /** \brief Set a progress callback procedure that is invoked by this solver during check_sat. From ea201a776d09b889c76b3822b3d08a944e8ea8d4 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 11 Jun 2016 10:39:27 -0700 Subject: [PATCH 022/536] enable qsat-opt Signed-off-by: Nikolaj Bjorner --- src/opt/opt_context.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 0b71fff1c..5082fde37 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -225,7 +225,7 @@ namespace opt { normalize(); internalize(); update_solver(); -#if 0 +#if 1 if (is_qsat_opt()) { return run_qsat_opt(); } From dfc80d3b697125a2d4b3694786ef9507245c52a6 Mon Sep 17 00:00:00 2001 From: George Karpenkov Date: Sun, 12 Jun 2016 14:14:11 +0200 Subject: [PATCH 023/536] Do not needlessly catch exceptions in Java bindings A lot of existing code in Java bindings catches exceptions just to silence them later. This is: a) Unnecessary: it is OK for a function to throw a RuntimeException without declaring it. b) Highly unidiomatic and not recommended by Java experts (see Effective Java and others) c) Confusing as has the potential to hide the existing bugs and have them resurface at the most inconvenient/unexpected moment. --- src/api/java/AST.java | 11 ++--------- src/api/java/ASTMap.java | 8 +------- src/api/java/ASTVector.java | 11 ++--------- src/api/java/ApplyResult.java | 11 ++--------- src/api/java/BitVecNum.java | 8 +------- src/api/java/FPNum.java | 8 +------- src/api/java/FiniteDomainNum.java | 8 +------- src/api/java/Fixedpoint.java | 8 +------- src/api/java/FuncDecl.java | 8 +------- src/api/java/Goal.java | 11 ++--------- src/api/java/IntNum.java | 11 ++--------- src/api/java/Model.java | 11 ++--------- src/api/java/ParamDescrs.java | 11 ++--------- src/api/java/Params.java | 8 +------- src/api/java/Pattern.java | 8 +------- src/api/java/RatNum.java | 11 ++--------- src/api/java/Solver.java | 10 ++-------- src/api/java/Sort.java | 12 +++--------- src/api/java/Statistics.java | 21 +++++---------------- 19 files changed, 34 insertions(+), 161 deletions(-) diff --git a/src/api/java/AST.java b/src/api/java/AST.java index e84dc8c81..f43aa85d2 100644 --- a/src/api/java/AST.java +++ b/src/api/java/AST.java @@ -175,15 +175,8 @@ public class AST extends Z3Object implements Comparable * A string representation of the AST. **/ @Override - public String toString() - { - try - { - return Native.astToString(getContext().nCtx(), getNativeObject()); - } catch (Z3Exception e) - { - return "Z3Exception: " + e.getMessage(); - } + public String toString() { + return Native.astToString(getContext().nCtx(), getNativeObject()); } /** diff --git a/src/api/java/ASTMap.java b/src/api/java/ASTMap.java index 7bc485bf5..a6201d8a0 100644 --- a/src/api/java/ASTMap.java +++ b/src/api/java/ASTMap.java @@ -104,13 +104,7 @@ class ASTMap extends Z3Object @Override public String toString() { - try - { - return Native.astMapToString(getContext().nCtx(), getNativeObject()); - } catch (Z3Exception e) - { - return "Z3Exception: " + e.getMessage(); - } + return Native.astMapToString(getContext().nCtx(), getNativeObject()); } ASTMap(Context ctx, long obj) diff --git a/src/api/java/ASTVector.java b/src/api/java/ASTVector.java index ab99e2aee..da1ab0f12 100644 --- a/src/api/java/ASTVector.java +++ b/src/api/java/ASTVector.java @@ -88,15 +88,8 @@ public class ASTVector extends Z3Object * Retrieves a string representation of the vector. **/ @Override - public String toString() - { - try - { - return Native.astVectorToString(getContext().nCtx(), getNativeObject()); - } catch (Z3Exception e) - { - return "Z3Exception: " + e.getMessage(); - } + public String toString() { + return Native.astVectorToString(getContext().nCtx(), getNativeObject()); } ASTVector(Context ctx, long obj) diff --git a/src/api/java/ApplyResult.java b/src/api/java/ApplyResult.java index 84c63e966..f598c9504 100644 --- a/src/api/java/ApplyResult.java +++ b/src/api/java/ApplyResult.java @@ -64,15 +64,8 @@ public class ApplyResult extends Z3Object * A string representation of the ApplyResult. **/ @Override - public String toString() - { - try - { - return Native.applyResultToString(getContext().nCtx(), getNativeObject()); - } catch (Z3Exception e) - { - return "Z3Exception: " + e.getMessage(); - } + public String toString() { + return Native.applyResultToString(getContext().nCtx(), getNativeObject()); } ApplyResult(Context ctx, long obj) diff --git a/src/api/java/BitVecNum.java b/src/api/java/BitVecNum.java index 5a62f8087..d6c176855 100644 --- a/src/api/java/BitVecNum.java +++ b/src/api/java/BitVecNum.java @@ -66,13 +66,7 @@ public class BitVecNum extends BitVecExpr @Override public String toString() { - try - { - return Native.getNumeralString(getContext().nCtx(), getNativeObject()); - } catch (Z3Exception e) - { - return "Z3Exception: " + e.getMessage(); - } + return Native.getNumeralString(getContext().nCtx(), getNativeObject()); } BitVecNum(Context ctx, long obj) diff --git a/src/api/java/FPNum.java b/src/api/java/FPNum.java index 69a44c559..9aeb41759 100644 --- a/src/api/java/FPNum.java +++ b/src/api/java/FPNum.java @@ -87,13 +87,7 @@ public class FPNum extends FPExpr */ public String toString() { - try - { - return Native.getNumeralString(getContext().nCtx(), getNativeObject()); - } catch (Z3Exception e) - { - return "Z3Exception: " + e.getMessage(); - } + return Native.getNumeralString(getContext().nCtx(), getNativeObject()); } } diff --git a/src/api/java/FiniteDomainNum.java b/src/api/java/FiniteDomainNum.java index e53ed22b2..68467e408 100644 --- a/src/api/java/FiniteDomainNum.java +++ b/src/api/java/FiniteDomainNum.java @@ -68,12 +68,6 @@ public class FiniteDomainNum extends FiniteDomainExpr @Override public String toString() { - try - { - return Native.getNumeralString(getContext().nCtx(), getNativeObject()); - } catch (Z3Exception e) - { - return "Z3Exception: " + e.getMessage(); - } + return Native.getNumeralString(getContext().nCtx(), getNativeObject()); } } diff --git a/src/api/java/Fixedpoint.java b/src/api/java/Fixedpoint.java index 14fb3a44a..2ff10a1f3 100644 --- a/src/api/java/Fixedpoint.java +++ b/src/api/java/Fixedpoint.java @@ -255,14 +255,8 @@ public class Fixedpoint extends Z3Object @Override public String toString() { - try - { - return Native.fixedpointToString(getContext().nCtx(), getNativeObject(), + return Native.fixedpointToString(getContext().nCtx(), getNativeObject(), 0, null); - } catch (Z3Exception e) - { - return "Z3Exception: " + e.getMessage(); - } } /** diff --git a/src/api/java/FuncDecl.java b/src/api/java/FuncDecl.java index 301978c44..273e853c0 100644 --- a/src/api/java/FuncDecl.java +++ b/src/api/java/FuncDecl.java @@ -47,13 +47,7 @@ public class FuncDecl extends AST @Override public String toString() { - try - { - return Native.funcDeclToString(getContext().nCtx(), getNativeObject()); - } catch (Z3Exception e) - { - return "Z3Exception: " + e.getMessage(); - } + return Native.funcDeclToString(getContext().nCtx(), getNativeObject()); } /** diff --git a/src/api/java/Goal.java b/src/api/java/Goal.java index 46b04f6bf..e60971179 100644 --- a/src/api/java/Goal.java +++ b/src/api/java/Goal.java @@ -211,15 +211,8 @@ public class Goal extends Z3Object * * @return A string representation of the Goal. **/ - public String toString() - { - try - { - return Native.goalToString(getContext().nCtx(), getNativeObject()); - } catch (Z3Exception e) - { - return "Z3Exception: " + e.getMessage(); - } + public String toString() { + return Native.goalToString(getContext().nCtx(), getNativeObject()); } /** diff --git a/src/api/java/IntNum.java b/src/api/java/IntNum.java index 71d878311..d3a5b456f 100644 --- a/src/api/java/IntNum.java +++ b/src/api/java/IntNum.java @@ -63,14 +63,7 @@ public class IntNum extends IntExpr /** * Returns a string representation of the numeral. **/ - public String toString() - { - try - { - return Native.getNumeralString(getContext().nCtx(), getNativeObject()); - } catch (Z3Exception e) - { - return "Z3Exception: " + e.getMessage(); - } + public String toString() { + return Native.getNumeralString(getContext().nCtx(), getNativeObject()); } } diff --git a/src/api/java/Model.java b/src/api/java/Model.java index 0695d7cf1..1bf77d246 100644 --- a/src/api/java/Model.java +++ b/src/api/java/Model.java @@ -283,15 +283,8 @@ public class Model extends Z3Object * @return A string representation of the model. **/ @Override - public String toString() - { - try - { - return Native.modelToString(getContext().nCtx(), getNativeObject()); - } catch (Z3Exception e) - { - return "Z3Exception: " + e.getMessage(); - } + public String toString() { + return Native.modelToString(getContext().nCtx(), getNativeObject()); } Model(Context ctx, long obj) diff --git a/src/api/java/ParamDescrs.java b/src/api/java/ParamDescrs.java index 8f8c6df0b..f265fb19e 100644 --- a/src/api/java/ParamDescrs.java +++ b/src/api/java/ParamDescrs.java @@ -82,15 +82,8 @@ public class ParamDescrs extends Z3Object * Retrieves a string representation of the ParamDescrs. **/ @Override - public String toString() - { - try - { - return Native.paramDescrsToString(getContext().nCtx(), getNativeObject()); - } catch (Z3Exception e) - { - return "Z3Exception: " + e.getMessage(); - } + public String toString() { + return Native.paramDescrsToString(getContext().nCtx(), getNativeObject()); } ParamDescrs(Context ctx, long obj) diff --git a/src/api/java/Params.java b/src/api/java/Params.java index 25d009b12..4be36c23d 100644 --- a/src/api/java/Params.java +++ b/src/api/java/Params.java @@ -115,13 +115,7 @@ public class Params extends Z3Object @Override public String toString() { - try - { - return Native.paramsToString(getContext().nCtx(), getNativeObject()); - } catch (Z3Exception e) - { - return "Z3Exception: " + e.getMessage(); - } + return Native.paramsToString(getContext().nCtx(), getNativeObject()); } Params(Context ctx) diff --git a/src/api/java/Pattern.java b/src/api/java/Pattern.java index eb12b6448..852ffcd0f 100644 --- a/src/api/java/Pattern.java +++ b/src/api/java/Pattern.java @@ -53,13 +53,7 @@ public class Pattern extends AST @Override public String toString() { - try - { - return Native.patternToString(getContext().nCtx(), getNativeObject()); - } catch (Z3Exception e) - { - return "Z3Exception: " + e.getMessage(); - } + return Native.patternToString(getContext().nCtx(), getNativeObject()); } Pattern(Context ctx, long obj) diff --git a/src/api/java/RatNum.java b/src/api/java/RatNum.java index f44823a2b..2bf1b28dd 100644 --- a/src/api/java/RatNum.java +++ b/src/api/java/RatNum.java @@ -75,15 +75,8 @@ public class RatNum extends RealExpr * Returns a string representation of the numeral. **/ @Override - public String toString() - { - try - { - return Native.getNumeralString(getContext().nCtx(), getNativeObject()); - } catch (Z3Exception e) - { - return "Z3Exception: " + e.getMessage(); - } + public String toString() { + return Native.getNumeralString(getContext().nCtx(), getNativeObject()); } RatNum(Context ctx, long obj) diff --git a/src/api/java/Solver.java b/src/api/java/Solver.java index ea76637c8..431811b8d 100644 --- a/src/api/java/Solver.java +++ b/src/api/java/Solver.java @@ -323,14 +323,8 @@ public class Solver extends Z3Object @Override public String toString() { - try - { - return Native - .solverToString(getContext().nCtx(), getNativeObject()); - } catch (Z3Exception e) - { - return "Z3Exception: " + e.getMessage(); - } + return Native + .solverToString(getContext().nCtx(), getNativeObject()); } Solver(Context ctx, long obj) diff --git a/src/api/java/Sort.java b/src/api/java/Sort.java index e30e0b8b3..30a43e7dd 100644 --- a/src/api/java/Sort.java +++ b/src/api/java/Sort.java @@ -82,15 +82,9 @@ public class Sort extends AST /** * A string representation of the sort. **/ - public String toString() - { - try - { - return Native.sortToString(getContext().nCtx(), getNativeObject()); - } catch (Z3Exception e) - { - return "Z3Exception: " + e.getMessage(); - } + @Override + public String toString() { + return Native.sortToString(getContext().nCtx(), getNativeObject()); } /** diff --git a/src/api/java/Statistics.java b/src/api/java/Statistics.java index 5af0cf863..1e842a892 100644 --- a/src/api/java/Statistics.java +++ b/src/api/java/Statistics.java @@ -84,15 +84,9 @@ public class Statistics extends Z3Object /** * The string representation of the Entry. **/ - public String toString() - { - try - { - return Key + ": " + getValueString(); - } catch (Z3Exception e) - { - return "Z3Exception: " + e.getMessage(); - } + @Override + public String toString() { + return Key + ": " + getValueString(); } private boolean m_is_int = false; @@ -118,15 +112,10 @@ public class Statistics extends Z3Object /** * A string representation of the statistical data. **/ + @Override public String toString() { - try - { - return Native.statsToString(getContext().nCtx(), getNativeObject()); - } catch (Z3Exception e) - { - return "Z3Exception: " + e.getMessage(); - } + return Native.statsToString(getContext().nCtx(), getNativeObject()); } /** From 495ef0f055f300089ec57f7aa71c2cc48d0fd402 Mon Sep 17 00:00:00 2001 From: George Karpenkov Date: Sun, 12 Jun 2016 14:18:13 +0200 Subject: [PATCH 024/536] Java bindings with no finalizers Replacing finalizers with PhantomReferences, required quite a lot of changes to the codebase. --- src/api/java/AST.java | 25 +-- src/api/java/ASTDecRefQueue.java | 25 +-- src/api/java/ASTMap.java | 11 +- src/api/java/ASTVector.java | 11 +- src/api/java/ApplyResult.java | 14 +- src/api/java/ApplyResultDecRefQueue.java | 25 +-- src/api/java/AstMapDecRefQueue.java | 25 +-- src/api/java/AstVectorDecRefQueue.java | 25 +-- src/api/java/BoolExpr.java | 10 +- src/api/java/Constructor.java | 44 ++--- src/api/java/ConstructorList.java | 25 +-- src/api/java/Context.java | 176 +++++++++---------- src/api/java/EnumSort.java | 12 +- src/api/java/Expr.java | 25 +-- src/api/java/FPNum.java | 6 +- src/api/java/Fixedpoint.java | 13 +- src/api/java/FixedpointDecRefQueue.java | 21 +-- src/api/java/FuncInterp.java | 86 +++------ src/api/java/FuncInterpDecRefQueue.java | 25 +-- src/api/java/FuncInterpEntryDecRefQueue.java | 25 +-- src/api/java/Goal.java | 25 +-- src/api/java/GoalDecRefQueue.java | 23 +-- src/api/java/IDecRefQueue.java | 59 ++++--- src/api/java/IDisposable.java | 25 --- src/api/java/InterpolationContext.java | 21 ++- src/api/java/ListSort.java | 15 +- src/api/java/Model.java | 14 +- src/api/java/ModelDecRefQueue.java | 25 +-- src/api/java/Optimize.java | 15 +- src/api/java/OptimizeDecRefQueue.java | 26 +-- src/api/java/ParamDescrs.java | 14 +- src/api/java/ParamDescrsDecRefQueue.java | 25 +-- src/api/java/Params.java | 14 +- src/api/java/ParamsDecRefQueue.java | 25 +-- src/api/java/Probe.java | 11 +- src/api/java/ProbeDecRefQueue.java | 22 +-- src/api/java/Quantifier.java | 73 ++++---- src/api/java/Solver.java | 20 +-- src/api/java/SolverDecRefQueue.java | 25 +-- src/api/java/Sort.java | 1 + src/api/java/Statistics.java | 14 +- src/api/java/StatisticsDecRefQueue.java | 25 +-- src/api/java/StringSymbol.java | 4 +- src/api/java/Symbol.java | 25 ++- src/api/java/Tactic.java | 11 +- src/api/java/TacticDecRefQueue.java | 25 +-- src/api/java/TupleSort.java | 8 +- src/api/java/Z3Object.java | 88 ++-------- 48 files changed, 368 insertions(+), 939 deletions(-) delete mode 100644 src/api/java/IDisposable.java diff --git a/src/api/java/AST.java b/src/api/java/AST.java index f43aa85d2..4b5b37d46 100644 --- a/src/api/java/AST.java +++ b/src/api/java/AST.java @@ -187,34 +187,15 @@ public class AST extends Z3Object implements Comparable return Native.astToString(getContext().nCtx(), getNativeObject()); } - AST(Context ctx) - { - super(ctx); - } - - AST(Context ctx, long obj) - { + AST(Context ctx, long obj) { super(ctx, obj); } @Override void incRef(long o) { - // Console.WriteLine("AST IncRef()"); - if (getContext() == null || o == 0) - return; - getContext().getASTDRQ().incAndClear(getContext(), o); - super.incRef(o); - } - - @Override - void decRef(long o) - { - // Console.WriteLine("AST DecRef()"); - if (getContext() == null || o == 0) - return; - getContext().getASTDRQ().add(o); - super.decRef(o); + Native.incRef(getContext().nCtx(), o); + getContext().getASTDRQ().storeReference(getContext(), this); } static AST create(Context ctx, long obj) diff --git a/src/api/java/ASTDecRefQueue.java b/src/api/java/ASTDecRefQueue.java index 32f6a5d0e..d462e16d5 100644 --- a/src/api/java/ASTDecRefQueue.java +++ b/src/api/java/ASTDecRefQueue.java @@ -17,7 +17,7 @@ Notes: package com.microsoft.z3; -class ASTDecRefQueue extends IDecRefQueue +class ASTDecRefQueue extends IDecRefQueue { public ASTDecRefQueue() { @@ -30,26 +30,7 @@ class ASTDecRefQueue extends IDecRefQueue } @Override - protected void incRef(Context ctx, long obj) - { - try - { - Native.incRef(ctx.nCtx(), obj); - } catch (Z3Exception e) - { - // OK. - } - } - - @Override - protected void decRef(Context ctx, long obj) - { - try - { - Native.decRef(ctx.nCtx(), obj); - } catch (Z3Exception e) - { - // OK. - } + protected void decRef(Context ctx, long obj) { + Native.decRef(ctx.nCtx(), obj); } }; diff --git a/src/api/java/ASTMap.java b/src/api/java/ASTMap.java index a6201d8a0..b4ae7102a 100644 --- a/src/api/java/ASTMap.java +++ b/src/api/java/ASTMap.java @@ -120,14 +120,7 @@ class ASTMap extends Z3Object @Override void incRef(long o) { - getContext().getASTMapDRQ().incAndClear(getContext(), o); - super.incRef(o); - } - - @Override - void decRef(long o) - { - getContext().getASTMapDRQ().add(o); - super.decRef(o); + Native.astMapIncRef(getContext().nCtx(), o); + getContext().getASTMapDRQ().storeReference(getContext(), this); } } diff --git a/src/api/java/ASTVector.java b/src/api/java/ASTVector.java index da1ab0f12..7c5ca1067 100644 --- a/src/api/java/ASTVector.java +++ b/src/api/java/ASTVector.java @@ -105,17 +105,10 @@ public class ASTVector extends Z3Object @Override void incRef(long o) { - getContext().getASTVectorDRQ().incAndClear(getContext(), o); - super.incRef(o); + Native.astVectorIncRef(getContext().nCtx(), o); + getContext().getASTVectorDRQ().storeReference(getContext(), this); } - @Override - void decRef(long o) - { - getContext().getASTVectorDRQ().add(o); - super.decRef(o); - } - /** * Translates the AST vector into an AST[] * */ diff --git a/src/api/java/ApplyResult.java b/src/api/java/ApplyResult.java index f598c9504..8b3c1daf6 100644 --- a/src/api/java/ApplyResult.java +++ b/src/api/java/ApplyResult.java @@ -74,16 +74,8 @@ public class ApplyResult extends Z3Object } @Override - void incRef(long o) - { - getContext().getApplyResultDRQ().incAndClear(getContext(), o); - super.incRef(o); - } - - @Override - void decRef(long o) - { - getContext().getApplyResultDRQ().add(o); - super.decRef(o); + void incRef(long o) { + Native.applyResultIncRef(getContext().nCtx(), o); + getContext().getApplyResultDRQ().storeReference(getContext(), this); } } diff --git a/src/api/java/ApplyResultDecRefQueue.java b/src/api/java/ApplyResultDecRefQueue.java index 63f315ecd..d28ff755e 100644 --- a/src/api/java/ApplyResultDecRefQueue.java +++ b/src/api/java/ApplyResultDecRefQueue.java @@ -17,7 +17,7 @@ Notes: package com.microsoft.z3; -class ApplyResultDecRefQueue extends IDecRefQueue +class ApplyResultDecRefQueue extends IDecRefQueue { public ApplyResultDecRefQueue() { @@ -30,26 +30,7 @@ class ApplyResultDecRefQueue extends IDecRefQueue } @Override - protected void incRef(Context ctx, long obj) - { - try - { - Native.applyResultIncRef(ctx.nCtx(), obj); - } catch (Z3Exception e) - { - // OK. - } - } - - @Override - protected void decRef(Context ctx, long obj) - { - try - { - Native.applyResultDecRef(ctx.nCtx(), obj); - } catch (Z3Exception e) - { - // OK. - } + protected void decRef(Context ctx, long obj) { + Native.applyResultDecRef(ctx.nCtx(), obj); } }; diff --git a/src/api/java/AstMapDecRefQueue.java b/src/api/java/AstMapDecRefQueue.java index 1598f75e7..234b7eec4 100644 --- a/src/api/java/AstMapDecRefQueue.java +++ b/src/api/java/AstMapDecRefQueue.java @@ -17,7 +17,7 @@ Notes: package com.microsoft.z3; -class ASTMapDecRefQueue extends IDecRefQueue +class ASTMapDecRefQueue extends IDecRefQueue { public ASTMapDecRefQueue() { @@ -30,26 +30,7 @@ class ASTMapDecRefQueue extends IDecRefQueue } @Override - protected void incRef(Context ctx, long obj) - { - try - { - Native.astMapIncRef(ctx.nCtx(), obj); - } catch (Z3Exception e) - { - // OK. - } - } - - @Override - protected void decRef(Context ctx, long obj) - { - try - { - Native.astMapDecRef(ctx.nCtx(), obj); - } catch (Z3Exception e) - { - // OK. - } + protected void decRef(Context ctx, long obj) { + Native.astMapDecRef(ctx.nCtx(), obj); } }; diff --git a/src/api/java/AstVectorDecRefQueue.java b/src/api/java/AstVectorDecRefQueue.java index a63d808d3..3a486ee06 100644 --- a/src/api/java/AstVectorDecRefQueue.java +++ b/src/api/java/AstVectorDecRefQueue.java @@ -17,7 +17,7 @@ Notes: package com.microsoft.z3; -class ASTVectorDecRefQueue extends IDecRefQueue +class ASTVectorDecRefQueue extends IDecRefQueue { public ASTVectorDecRefQueue() { @@ -30,26 +30,7 @@ class ASTVectorDecRefQueue extends IDecRefQueue } @Override - protected void incRef(Context ctx, long obj) - { - try - { - Native.astVectorIncRef(ctx.nCtx(), obj); - } catch (Z3Exception e) - { - // OK. - } - } - - @Override - protected void decRef(Context ctx, long obj) - { - try - { - Native.astVectorDecRef(ctx.nCtx(), obj); - } catch (Z3Exception e) - { - // OK. - } + protected void decRef(Context ctx, long obj) { + Native.astVectorDecRef(ctx.nCtx(), obj); } }; diff --git a/src/api/java/BoolExpr.java b/src/api/java/BoolExpr.java index 02eabd2b5..dc75b2e7c 100644 --- a/src/api/java/BoolExpr.java +++ b/src/api/java/BoolExpr.java @@ -20,15 +20,7 @@ package com.microsoft.z3; /** * Boolean expressions **/ -public class BoolExpr extends Expr -{ - /** - * Constructor for BoolExpr - **/ - protected BoolExpr(Context ctx) - { - super(ctx); - } +public class BoolExpr extends Expr { /** * Constructor for BoolExpr diff --git a/src/api/java/Constructor.java b/src/api/java/Constructor.java index a6c2856d4..28558b15a 100644 --- a/src/api/java/Constructor.java +++ b/src/api/java/Constructor.java @@ -20,8 +20,14 @@ package com.microsoft.z3; /** * Constructors are used for datatype sorts. **/ -public class Constructor extends Z3Object -{ +public class Constructor extends Z3Object { + private final int n; + + Constructor(Context ctx, int n, long nativeObj) { + super(ctx, nativeObj); + this.n = n; + } + /** * The number of fields of the constructor. * @throws Z3Exception @@ -78,29 +84,16 @@ public class Constructor extends Z3Object return t; } - /** - * Destructor. - * @throws Throwable - * @throws Z3Exception on error - **/ - protected void finalize() throws Throwable - { - try { - Native.delConstructor(getContext().nCtx(), getNativeObject()); - } finally { - super.finalize(); - } + @Override + void incRef(long o) { + + // Datatype constructors are not reference counted. + getContext().getConstructorDRQ().storeReference(getContext(), this); } - private int n = 0; - - Constructor(Context ctx, Symbol name, Symbol recognizer, - Symbol[] fieldNames, Sort[] sorts, int[] sortRefs) - - { - super(ctx); - - n = AST.arrayLength(fieldNames); + static Constructor of(Context ctx, Symbol name, Symbol recognizer, + Symbol[] fieldNames, Sort[] sorts, int[] sortRefs) { + int n = AST.arrayLength(fieldNames); if (n != AST.arrayLength(sorts)) throw new Z3Exception( @@ -112,9 +105,10 @@ public class Constructor extends Z3Object if (sortRefs == null) sortRefs = new int[n]; - setNativeObject(Native.mkConstructor(ctx.nCtx(), name.getNativeObject(), + long nativeObj = Native.mkConstructor(ctx.nCtx(), name.getNativeObject(), recognizer.getNativeObject(), n, Symbol.arrayToNative(fieldNames), - Sort.arrayToNative(sorts), sortRefs)); + Sort.arrayToNative(sorts), sortRefs); + return new Constructor(ctx, n, nativeObj); } } diff --git a/src/api/java/ConstructorList.java b/src/api/java/ConstructorList.java index fe3fae1ac..3f1835082 100644 --- a/src/api/java/ConstructorList.java +++ b/src/api/java/ConstructorList.java @@ -20,32 +20,21 @@ package com.microsoft.z3; /** * Lists of constructors **/ -public class ConstructorList extends Z3Object -{ - /** - * Destructor. - * @throws Throwable - * @throws Z3Exception on error - **/ - protected void finalize() throws Throwable - { - try { - Native.delConstructorList(getContext().nCtx(), getNativeObject()); - } finally { - super.finalize(); - } - } +public class ConstructorList extends Z3Object { ConstructorList(Context ctx, long obj) { super(ctx, obj); } + @Override + void incRef(long o) { + getContext().getConstructorListDRQ().storeReference(getContext(), this); + } + ConstructorList(Context ctx, Constructor[] constructors) { - super(ctx); - - setNativeObject(Native.mkConstructorList(getContext().nCtx(), + super(ctx, Native.mkConstructorList(ctx.nCtx(), constructors.length, Constructor.arrayToNative(constructors))); } diff --git a/src/api/java/Context.java b/src/api/java/Context.java index 9fa17fcd4..41fb027fe 100644 --- a/src/api/java/Context.java +++ b/src/api/java/Context.java @@ -17,34 +17,35 @@ Notes: package com.microsoft.z3; -import java.util.Map; -import java.util.concurrent.atomic.AtomicInteger; +import static com.microsoft.z3.Constructor.of; import com.microsoft.z3.enumerations.Z3_ast_print_mode; +import java.util.Map; + /** * The main interaction with Z3 happens via the Context. **/ -public class Context extends IDisposable -{ - /** - * Constructor. - **/ - public Context() - { - super(); - synchronized (creation_lock) { +public class Context implements AutoCloseable { + private final long m_ctx; + static final Object creation_lock = new Object(); + + public static Context mkContext() { + long m_ctx; + synchronized (creation_lock) { m_ctx = Native.mkContextRc(0); - initContext(); + // TODO: then adding settings will not be under the lock. } + return new Context(m_ctx); } + /** * Constructor. * Remarks: - * The following parameters can be set: + * The following parameters can be set: * - proof (Boolean) Enable proof generation - * - debug_ref_count (Boolean) Enable debug support for Z3_ast reference counting + * - debug_ref_count (Boolean) Enable debug support for Z3_ast reference counting * - trace (Boolean) Tracing support for VCC * - trace_file_name (String) Trace out file for VCC traces * - timeout (unsigned) default timeout (in milliseconds) used for solvers @@ -53,20 +54,32 @@ public class Context extends IDisposable * - model model generation for solvers, this parameter can be overwritten when creating a solver * - model_validate validate models produced by solvers * - unsat_core unsat-core generation for solvers, this parameter can be overwritten when creating a solver - * Note that in previous versions of Z3, this constructor was also used to set global and + * Note that in previous versions of Z3, this constructor was also used to set global and * module parameters. For this purpose we should now use {@code Global.setParameter} **/ - public Context(Map settings) + public static Context mkContext(Map settings) { - super(); - synchronized (creation_lock) { + long m_ctx; + synchronized (creation_lock) { long cfg = Native.mkConfig(); for (Map.Entry kv : settings.entrySet()) Native.setParamValue(cfg, kv.getKey(), kv.getValue()); m_ctx = Native.mkContextRc(cfg); Native.delConfig(cfg); - initContext(); } + return new Context(m_ctx); + } + + /** + * Constructor. + **/ + protected Context(long m_ctx) + { + this.m_ctx = m_ctx; + + // Code which used to be in "initContext". + setPrintMode(Z3_ast_print_mode.Z3_PRINT_SMTLIB2_COMPLIANT); + Native.setInternalErrorHandler(m_ctx); } /** @@ -242,7 +255,7 @@ public class Context extends IDisposable checkContextMatch(name); checkContextMatch(fieldNames); checkContextMatch(fieldSorts); - return new TupleSort(this, name, (int) fieldNames.length, fieldNames, + return new TupleSort(this, name, fieldNames.length, fieldNames, fieldSorts); } @@ -319,8 +332,7 @@ public class Context extends IDisposable Symbol[] fieldNames, Sort[] sorts, int[] sortRefs) { - - return new Constructor(this, name, recognizer, fieldNames, sorts, + return of(this, name, recognizer, fieldNames, sorts, sortRefs); } @@ -329,10 +341,8 @@ public class Context extends IDisposable **/ public Constructor mkConstructor(String name, String recognizer, String[] fieldNames, Sort[] sorts, int[] sortRefs) - { - - return new Constructor(this, mkSymbol(name), mkSymbol(recognizer), + return of(this, mkSymbol(name), mkSymbol(recognizer), mkSymbols(fieldNames), sorts, sortRefs); } @@ -525,7 +535,7 @@ public class Context extends IDisposable throw new Z3Exception("Cannot create a pattern from zero terms"); long[] termsNative = AST.arrayToNative(terms); - return new Pattern(this, Native.mkPattern(nCtx(), (int) terms.length, + return new Pattern(this, Native.mkPattern(nCtx(), terms.length, termsNative)); } @@ -688,7 +698,7 @@ public class Context extends IDisposable public BoolExpr mkDistinct(Expr... args) { checkContextMatch(args); - return new BoolExpr(this, Native.mkDistinct(nCtx(), (int) args.length, + return new BoolExpr(this, Native.mkDistinct(nCtx(), args.length, AST.arrayToNative(args))); } @@ -756,7 +766,7 @@ public class Context extends IDisposable public BoolExpr mkAnd(BoolExpr... t) { checkContextMatch(t); - return new BoolExpr(this, Native.mkAnd(nCtx(), (int) t.length, + return new BoolExpr(this, Native.mkAnd(nCtx(), t.length, AST.arrayToNative(t))); } @@ -766,7 +776,7 @@ public class Context extends IDisposable public BoolExpr mkOr(BoolExpr... t) { checkContextMatch(t); - return new BoolExpr(this, Native.mkOr(nCtx(), (int) t.length, + return new BoolExpr(this, Native.mkOr(nCtx(), t.length, AST.arrayToNative(t))); } @@ -777,7 +787,7 @@ public class Context extends IDisposable { checkContextMatch(t); return (ArithExpr) Expr.create(this, - Native.mkAdd(nCtx(), (int) t.length, AST.arrayToNative(t))); + Native.mkAdd(nCtx(), t.length, AST.arrayToNative(t))); } /** @@ -787,7 +797,7 @@ public class Context extends IDisposable { checkContextMatch(t); return (ArithExpr) Expr.create(this, - Native.mkMul(nCtx(), (int) t.length, AST.arrayToNative(t))); + Native.mkMul(nCtx(), t.length, AST.arrayToNative(t))); } /** @@ -797,7 +807,7 @@ public class Context extends IDisposable { checkContextMatch(t); return (ArithExpr) Expr.create(this, - Native.mkSub(nCtx(), (int) t.length, AST.arrayToNative(t))); + Native.mkSub(nCtx(), t.length, AST.arrayToNative(t))); } /** @@ -1814,7 +1824,7 @@ public class Context extends IDisposable { checkContextMatch(args); return (ArrayExpr)Expr.create(this, - Native.mkSetUnion(nCtx(), (int) args.length, + Native.mkSetUnion(nCtx(), args.length, AST.arrayToNative(args))); } @@ -1825,7 +1835,7 @@ public class Context extends IDisposable { checkContextMatch(args); return (ArrayExpr)Expr.create(this, - Native.mkSetIntersect(nCtx(), (int) args.length, + Native.mkSetIntersect(nCtx(), args.length, AST.arrayToNative(args))); } @@ -1912,7 +1922,7 @@ public class Context extends IDisposable public SeqExpr MkConcat(SeqExpr... t) { checkContextMatch(t); - return new SeqExpr(this, Native.mkSeqConcat(nCtx(), (int)t.length, AST.arrayToNative(t))); + return new SeqExpr(this, Native.mkSeqConcat(nCtx(), t.length, AST.arrayToNative(t))); } @@ -2040,7 +2050,7 @@ public class Context extends IDisposable public ReExpr MkConcat(ReExpr... t) { checkContextMatch(t); - return new ReExpr(this, Native.mkReConcat(nCtx(), (int)t.length, AST.arrayToNative(t))); + return new ReExpr(this, Native.mkReConcat(nCtx(), t.length, AST.arrayToNative(t))); } /** @@ -2049,7 +2059,7 @@ public class Context extends IDisposable public ReExpr MkUnion(ReExpr... t) { checkContextMatch(t); - return new ReExpr(this, Native.mkReUnion(nCtx(), (int)t.length, AST.arrayToNative(t))); + return new ReExpr(this, Native.mkReUnion(nCtx(), t.length, AST.arrayToNative(t))); } @@ -2258,7 +2268,7 @@ public class Context extends IDisposable Symbol quantifierID, Symbol skolemID) { - return new Quantifier(this, true, sorts, names, body, weight, patterns, + return Quantifier.of(this, true, sorts, names, body, weight, patterns, noPatterns, quantifierID, skolemID); } @@ -2271,7 +2281,7 @@ public class Context extends IDisposable Symbol skolemID) { - return new Quantifier(this, true, boundConstants, body, weight, + return Quantifier.of(this, true, boundConstants, body, weight, patterns, noPatterns, quantifierID, skolemID); } @@ -2284,7 +2294,7 @@ public class Context extends IDisposable Symbol quantifierID, Symbol skolemID) { - return new Quantifier(this, false, sorts, names, body, weight, + return Quantifier.of(this, false, sorts, names, body, weight, patterns, noPatterns, quantifierID, skolemID); } @@ -2297,7 +2307,7 @@ public class Context extends IDisposable Symbol skolemID) { - return new Quantifier(this, false, boundConstants, body, weight, + return Quantifier.of(this, false, boundConstants, body, weight, patterns, noPatterns, quantifierID, skolemID); } @@ -3814,7 +3824,7 @@ public class Context extends IDisposable * must be a native object obtained from Z3 (e.g., through * {@code UnwrapAST}) and that it must have a correct reference count. * @see Native#incRef - * @see unwrapAST + * @see #unwrapAST * @param nativeObject The native pointer to wrap. **/ public AST wrapAST(long nativeObject) @@ -3869,19 +3879,12 @@ public class Context extends IDisposable Native.updateParamValue(nCtx(), id, value); } - protected long m_ctx = 0; - protected static final Object creation_lock = new Object(); long nCtx() { return m_ctx; } - void initContext() - { - setPrintMode(Z3_ast_print_mode.Z3_PRINT_SMTLIB2_COMPLIANT); - Native.setInternalErrorHandler(nCtx()); - } void checkContextMatch(Z3Object other) { @@ -3925,110 +3928,103 @@ public class Context extends IDisposable private TacticDecRefQueue m_Tactic_DRQ = new TacticDecRefQueue(10); private FixedpointDecRefQueue m_Fixedpoint_DRQ = new FixedpointDecRefQueue(10); private OptimizeDecRefQueue m_Optimize_DRQ = new OptimizeDecRefQueue(10); + private ConstructorDecRefQueue m_Constructor_DRQ = new ConstructorDecRefQueue(10); + private ConstructorListDecRefQueue m_ConstructorList_DRQ = + new ConstructorListDecRefQueue(10); - public IDecRefQueue getASTDRQ() + public IDecRefQueue getConstructorDRQ() { + return m_Constructor_DRQ; + } + + public IDecRefQueue getConstructorListDRQ() { + return m_ConstructorList_DRQ; + } + + public IDecRefQueue getASTDRQ() { return m_AST_DRQ; } - public IDecRefQueue getASTMapDRQ() + public IDecRefQueue getASTMapDRQ() { return m_ASTMap_DRQ; } - public IDecRefQueue getASTVectorDRQ() + public IDecRefQueue getASTVectorDRQ() { return m_ASTVector_DRQ; } - public IDecRefQueue getApplyResultDRQ() + public IDecRefQueue getApplyResultDRQ() { return m_ApplyResult_DRQ; } - public IDecRefQueue getFuncEntryDRQ() + public IDecRefQueue getFuncEntryDRQ() { return m_FuncEntry_DRQ; } - public IDecRefQueue getFuncInterpDRQ() + public IDecRefQueue getFuncInterpDRQ() { return m_FuncInterp_DRQ; } - public IDecRefQueue getGoalDRQ() + public IDecRefQueue getGoalDRQ() { return m_Goal_DRQ; } - public IDecRefQueue getModelDRQ() + public IDecRefQueue getModelDRQ() { return m_Model_DRQ; } - public IDecRefQueue getParamsDRQ() + public IDecRefQueue getParamsDRQ() { return m_Params_DRQ; } - public IDecRefQueue getParamDescrsDRQ() + public IDecRefQueue getParamDescrsDRQ() { return m_ParamDescrs_DRQ; } - public IDecRefQueue getProbeDRQ() + public IDecRefQueue getProbeDRQ() { return m_Probe_DRQ; } - public IDecRefQueue getSolverDRQ() + public IDecRefQueue getSolverDRQ() { return m_Solver_DRQ; } - public IDecRefQueue getStatisticsDRQ() + public IDecRefQueue getStatisticsDRQ() { return m_Statistics_DRQ; } - public IDecRefQueue getTacticDRQ() + public IDecRefQueue getTacticDRQ() { return m_Tactic_DRQ; } - public IDecRefQueue getFixedpointDRQ() + public IDecRefQueue getFixedpointDRQ() { return m_Fixedpoint_DRQ; } - public IDecRefQueue getOptimizeDRQ() + public IDecRefQueue getOptimizeDRQ() { return m_Optimize_DRQ; } - protected AtomicInteger m_refCount = new AtomicInteger(0); - - /** - * Finalizer. - * @throws Throwable - **/ - protected void finalize() throws Throwable - { - try { - dispose(); - } - catch (Throwable t) { - throw t; - } - finally { - super.finalize(); - } - } - /** * Disposes of the context. **/ - public void dispose() + @Override + public void close() { m_AST_DRQ.clear(this); m_ASTMap_DRQ.clear(this); @@ -4052,15 +4048,7 @@ public class Context extends IDisposable m_stringSort = null; synchronized (creation_lock) { - if (m_refCount.get() == 0 && m_ctx != 0) { - try { - Native.delContext(m_ctx); - } catch (Z3Exception e) { - // OK? - System.out.println("Context deletion failed; memory leak possible."); - } - m_ctx = 0; - } + Native.delContext(m_ctx); } } } diff --git a/src/api/java/EnumSort.java b/src/api/java/EnumSort.java index bb60eef56..ce2f8d578 100644 --- a/src/api/java/EnumSort.java +++ b/src/api/java/EnumSort.java @@ -92,13 +92,9 @@ public class EnumSort extends Sort EnumSort(Context ctx, Symbol name, Symbol[] enumNames) { - super(ctx, 0); - - int n = enumNames.length; - long[] n_constdecls = new long[n]; - long[] n_testers = new long[n]; - setNativeObject(Native.mkEnumerationSort(ctx.nCtx(), - name.getNativeObject(), n, Symbol.arrayToNative(enumNames), - n_constdecls, n_testers)); + super(ctx, Native.mkEnumerationSort(ctx.nCtx(), + name.getNativeObject(), enumNames.length, + Symbol.arrayToNative(enumNames), + new long[enumNames.length], new long[enumNames.length])); } }; diff --git a/src/api/java/Expr.java b/src/api/java/Expr.java index b24d3ac62..ea3fd2147 100644 --- a/src/api/java/Expr.java +++ b/src/api/java/Expr.java @@ -120,13 +120,13 @@ public class Expr extends AST * @param args arguments * @throws Z3Exception on error **/ - public void update(Expr[] args) + public Expr update(Expr[] args) { getContext().checkContextMatch(args); if (isApp() && args.length != getNumArgs()) { throw new Z3Exception("Number of arguments does not match"); } - setNativeObject(Native.updateTerm(getContext().nCtx(), getNativeObject(), + return new Expr(getContext(), Native.updateTerm(getContext().nCtx(), getNativeObject(), args.length, Expr.arrayToNative(args))); } @@ -2091,36 +2091,23 @@ public class Expr extends AST **/ public int getIndex() { - if (!isVar()) + if (!isVar()) { throw new Z3Exception("Term is not a bound variable."); + } return Native.getIndexValue(getContext().nCtx(), getNativeObject()); } - /** - * Constructor for Expr - **/ - protected Expr(Context ctx) - { - super(ctx); - { - } - } - /** * Constructor for Expr * @throws Z3Exception on error **/ - protected Expr(Context ctx, long obj) - { + protected Expr(Context ctx, long obj) { super(ctx, obj); - { - } } @Override - void checkNativeObject(long obj) - { + void checkNativeObject(long obj) { if (!Native.isApp(getContext().nCtx(), obj) && Native.getAstKind(getContext().nCtx(), obj) != Z3_ast_kind.Z3_VAR_AST.toInt() && Native.getAstKind(getContext().nCtx(), obj) != Z3_ast_kind.Z3_QUANTIFIER_AST.toInt()) { diff --git a/src/api/java/FPNum.java b/src/api/java/FPNum.java index 9aeb41759..402d25ebe 100644 --- a/src/api/java/FPNum.java +++ b/src/api/java/FPNum.java @@ -28,7 +28,7 @@ public class FPNum extends FPExpr */ public boolean getSign() { Native.IntPtr res = new Native.IntPtr(); - if (Native.fpaGetNumeralSign(getContext().nCtx(), getNativeObject(), res) ^ true) + if (!Native.fpaGetNumeralSign(getContext().nCtx(), getNativeObject(), res)) throw new Z3Exception("Sign is not a Boolean value"); return res.value != 0; } @@ -53,7 +53,7 @@ public class FPNum extends FPExpr public long getSignificandUInt64() { Native.LongPtr res = new Native.LongPtr(); - if (Native.fpaGetNumeralSignificandUint64(getContext().nCtx(), getNativeObject(), res) ^ true) + if (!Native.fpaGetNumeralSignificandUint64(getContext().nCtx(), getNativeObject(), res)) throw new Z3Exception("Significand is not a 64 bit unsigned integer"); return res.value; } @@ -72,7 +72,7 @@ public class FPNum extends FPExpr */ public long getExponentInt64() { Native.LongPtr res = new Native.LongPtr(); - if (Native.fpaGetNumeralExponentInt64(getContext().nCtx(), getNativeObject(), res) ^ true) + if (!Native.fpaGetNumeralExponentInt64(getContext().nCtx(), getNativeObject(), res)) throw new Z3Exception("Exponent is not a 64 bit integer"); return res.value; } diff --git a/src/api/java/Fixedpoint.java b/src/api/java/Fixedpoint.java index 2ff10a1f3..5a7958364 100644 --- a/src/api/java/Fixedpoint.java +++ b/src/api/java/Fixedpoint.java @@ -349,16 +349,11 @@ public class Fixedpoint extends Z3Object } @Override - void incRef(long o) - { - getContext().getFixedpointDRQ().incAndClear(getContext(), o); - super.incRef(o); + void incRef(long o) { + Native.fixedpointIncRef(getContext().nCtx(), o); + getContext().getFixedpointDRQ().storeReference(getContext(), this); } @Override - void decRef(long o) - { - getContext().getFixedpointDRQ().add(o); - super.decRef(o); - } + void checkNativeObject(long obj) { } } diff --git a/src/api/java/FixedpointDecRefQueue.java b/src/api/java/FixedpointDecRefQueue.java index e65538a30..d5ae79a2b 100644 --- a/src/api/java/FixedpointDecRefQueue.java +++ b/src/api/java/FixedpointDecRefQueue.java @@ -17,7 +17,7 @@ Notes: package com.microsoft.z3; -class FixedpointDecRefQueue extends IDecRefQueue +class FixedpointDecRefQueue extends IDecRefQueue { public FixedpointDecRefQueue() { @@ -29,27 +29,10 @@ class FixedpointDecRefQueue extends IDecRefQueue super(move_limit); } - @Override - protected void incRef(Context ctx, long obj) - { - try - { - Native.fixedpointIncRef(ctx.nCtx(), obj); - } catch (Z3Exception e) - { - // OK. - } - } @Override protected void decRef(Context ctx, long obj) { - try - { - Native.fixedpointDecRef(ctx.nCtx(), obj); - } catch (Z3Exception e) - { - // OK. - } + Native.fixedpointDecRef(ctx.nCtx(), obj); } }; diff --git a/src/api/java/FuncInterp.java b/src/api/java/FuncInterp.java index 72f6bb25d..c84979aa1 100644 --- a/src/api/java/FuncInterp.java +++ b/src/api/java/FuncInterp.java @@ -73,18 +73,12 @@ public class FuncInterp extends Z3Object @Override public String toString() { - try - { - int n = getNumArgs(); - String res = "["; - Expr[] args = getArgs(); - for (int i = 0; i < n; i++) - res += args[i] + ", "; - return res + getValue() + "]"; - } catch (Z3Exception e) - { - return "Z3Exception: " + e.getMessage(); - } + int n = getNumArgs(); + String res = "["; + Expr[] args = getArgs(); + for (int i = 0; i < n; i++) + res += args[i] + ", "; + return res + getValue() + "]"; } Entry(Context ctx, long obj) @@ -93,17 +87,9 @@ public class FuncInterp extends Z3Object } @Override - void incRef(long o) - { - getContext().getFuncEntryDRQ().incAndClear(getContext(), o); - super.incRef(o); - } - - @Override - void decRef(long o) - { - getContext().getFuncEntryDRQ().add(o); - super.decRef(o); + void incRef(long o) { + Native.funcEntryIncRef(getContext().nCtx(), o);; + getContext().getFuncEntryDRQ().storeReference(getContext(), this); } } @@ -161,33 +147,27 @@ public class FuncInterp extends Z3Object **/ public String toString() { - try + String res = ""; + res += "["; + for (Entry e : getEntries()) { - String res = ""; - res += "["; - for (Entry e : getEntries()) + int n = e.getNumArgs(); + if (n > 1) + res += "["; + Expr[] args = e.getArgs(); + for (int i = 0; i < n; i++) { - int n = e.getNumArgs(); - if (n > 1) - res += "["; - Expr[] args = e.getArgs(); - for (int i = 0; i < n; i++) - { - if (i != 0) - res += ", "; - res += args[i]; - } - if (n > 1) - res += "]"; - res += " -> " + e.getValue() + ", "; + if (i != 0) + res += ", "; + res += args[i]; } - res += "else -> " + getElse(); - res += "]"; - return res; - } catch (Z3Exception e) - { - return "Z3Exception: " + e.getMessage(); + if (n > 1) + res += "]"; + res += " -> " + e.getValue() + ", "; } + res += "else -> " + getElse(); + res += "]"; + return res; } FuncInterp(Context ctx, long obj) @@ -196,16 +176,8 @@ public class FuncInterp extends Z3Object } @Override - void incRef(long o) - { - getContext().getFuncInterpDRQ().incAndClear(getContext(), o); - super.incRef(o); - } - - @Override - void decRef(long o) - { - getContext().getFuncInterpDRQ().add(o); - super.decRef(o); + void incRef(long o) { + Native.funcInterpIncRef(getContext().nCtx(), o); + getContext().getFuncInterpDRQ().storeReference(getContext(), this); } } diff --git a/src/api/java/FuncInterpDecRefQueue.java b/src/api/java/FuncInterpDecRefQueue.java index c888e9e3d..136c07b6a 100644 --- a/src/api/java/FuncInterpDecRefQueue.java +++ b/src/api/java/FuncInterpDecRefQueue.java @@ -17,7 +17,7 @@ Notes: package com.microsoft.z3; -class FuncInterpDecRefQueue extends IDecRefQueue +class FuncInterpDecRefQueue extends IDecRefQueue { public FuncInterpDecRefQueue() { @@ -30,26 +30,7 @@ class FuncInterpDecRefQueue extends IDecRefQueue } @Override - protected void incRef(Context ctx, long obj) - { - try - { - Native.funcInterpIncRef(ctx.nCtx(), obj); - } catch (Z3Exception e) - { - // OK. - } - } - - @Override - protected void decRef(Context ctx, long obj) - { - try - { - Native.funcInterpDecRef(ctx.nCtx(), obj); - } catch (Z3Exception e) - { - // OK. - } + protected void decRef(Context ctx, long obj) { + Native.funcInterpDecRef(ctx.nCtx(), obj); } }; diff --git a/src/api/java/FuncInterpEntryDecRefQueue.java b/src/api/java/FuncInterpEntryDecRefQueue.java index 7dfdaa27d..8f6741ba0 100644 --- a/src/api/java/FuncInterpEntryDecRefQueue.java +++ b/src/api/java/FuncInterpEntryDecRefQueue.java @@ -17,7 +17,7 @@ Notes: package com.microsoft.z3; -class FuncInterpEntryDecRefQueue extends IDecRefQueue +class FuncInterpEntryDecRefQueue extends IDecRefQueue { public FuncInterpEntryDecRefQueue() { @@ -30,26 +30,7 @@ class FuncInterpEntryDecRefQueue extends IDecRefQueue } @Override - protected void incRef(Context ctx, long obj) - { - try - { - Native.funcEntryIncRef(ctx.nCtx(), obj); - } catch (Z3Exception e) - { - // OK. - } - } - - @Override - protected void decRef(Context ctx, long obj) - { - try - { - Native.funcEntryDecRef(ctx.nCtx(), obj); - } catch (Z3Exception e) - { - // OK. - } + protected void decRef(Context ctx, long obj) { + Native.funcEntryDecRef(ctx.nCtx(), obj); } }; diff --git a/src/api/java/Goal.java b/src/api/java/Goal.java index e60971179..a6d41ccd2 100644 --- a/src/api/java/Goal.java +++ b/src/api/java/Goal.java @@ -222,11 +222,11 @@ public class Goal extends Z3Object **/ public BoolExpr AsBoolExpr() { int n = size(); - if (n == 0) + if (n == 0) { return getContext().mkTrue(); - else if (n == 1) + } else if (n == 1) { return getFormulas()[0]; - else { + } else { return getContext().mkAnd(getFormulas()); } } @@ -236,23 +236,14 @@ public class Goal extends Z3Object super(ctx, obj); } - Goal(Context ctx, boolean models, boolean unsatCores, boolean proofs) - - { + Goal(Context ctx, boolean models, boolean unsatCores, boolean proofs) { super(ctx, Native.mkGoal(ctx.nCtx(), (models), (unsatCores), (proofs))); } - void incRef(long o) - { - getContext().getGoalDRQ().incAndClear(getContext(), o); - super.incRef(o); + @Override + void incRef(long o) { + Native.goalIncRef(getContext().nCtx(), o); + getContext().getGoalDRQ().storeReference(getContext(), this); } - - void decRef(long o) - { - getContext().getGoalDRQ().add(o); - super.decRef(o); - } - } diff --git a/src/api/java/GoalDecRefQueue.java b/src/api/java/GoalDecRefQueue.java index be921241b..724ec003f 100644 --- a/src/api/java/GoalDecRefQueue.java +++ b/src/api/java/GoalDecRefQueue.java @@ -17,7 +17,7 @@ Notes: package com.microsoft.z3; -class GoalDecRefQueue extends IDecRefQueue +class GoalDecRefQueue extends IDecRefQueue { public GoalDecRefQueue() { @@ -30,26 +30,7 @@ class GoalDecRefQueue extends IDecRefQueue } @Override - protected void incRef(Context ctx, long obj) - { - try - { - Native.goalIncRef(ctx.nCtx(), obj); - } catch (Z3Exception e) - { - // OK. - } - } - - @Override - protected void decRef(Context ctx, long obj) - { - try - { + protected void decRef(Context ctx, long obj) { Native.goalDecRef(ctx.nCtx(), obj); - } catch (Z3Exception e) - { - // OK. - } } }; diff --git a/src/api/java/IDecRefQueue.java b/src/api/java/IDecRefQueue.java index 1a99a3d92..b0a93b552 100644 --- a/src/api/java/IDecRefQueue.java +++ b/src/api/java/IDecRefQueue.java @@ -17,13 +17,21 @@ Notes: package com.microsoft.z3; -import java.util.LinkedList; +import java.lang.ref.PhantomReference; +import java.lang.ref.Reference; +import java.lang.ref.ReferenceQueue; +import java.util.IdentityHashMap; +import java.util.Map; -public abstract class IDecRefQueue +public abstract class IDecRefQueue { - protected final Object m_lock = new Object(); - protected LinkedList m_queue = new LinkedList(); - protected int m_move_limit; + private final int m_move_limit; + + // TODO: problem: ReferenceQueue has no API to return length. + private final ReferenceQueue referenceQueue = new ReferenceQueue<>(); + private int queueSize = 0; + private final Map, Long> referenceMap = + new IdentityHashMap<>(); protected IDecRefQueue() { @@ -34,38 +42,31 @@ public abstract class IDecRefQueue { m_move_limit = move_limit; } - - public void setLimit(int l) { m_move_limit = l; } - - protected abstract void incRef(Context ctx, long obj); + /** + * An implementation of this method should decrement the reference on a + * given native object. + * This function should be always called on the {@code ctx} thread. + * + * @param ctx Z3 context. + * @param obj Pointer to a Z3 object. + */ protected abstract void decRef(Context ctx, long obj); - protected void incAndClear(Context ctx, long o) - { - incRef(ctx, o); - if (m_queue.size() >= m_move_limit) - clear(ctx); - } + public void storeReference(Context ctx, T obj) { + PhantomReference ref = new PhantomReference<>(obj, referenceQueue); + referenceMap.put(ref, obj.getNativeObject()); - protected void add(long o) - { - if (o == 0) - return; - - synchronized (m_lock) - { - m_queue.add(o); - } + // TODO: use move_limit, somehow get the size of referenceQueue. + clear(ctx); } protected void clear(Context ctx) { - synchronized (m_lock) - { - for (Long o : m_queue) - decRef(ctx, o); - m_queue.clear(); + Reference ref; + while ((ref = referenceQueue.poll()) != null) { + long z3ast = referenceMap.remove(ref); + decRef(ctx, z3ast); } } } diff --git a/src/api/java/IDisposable.java b/src/api/java/IDisposable.java deleted file mode 100644 index dae8a7262..000000000 --- a/src/api/java/IDisposable.java +++ /dev/null @@ -1,25 +0,0 @@ -/*++ -Copyright (c) 2012 Microsoft Corporation - -Module Name: - - IDisposable.java - -Abstract: - - Compatability interface (C# -> Java) - -Author: - - Christoph Wintersteiger (cwinter) 2012-03-16 - -Notes: - ---*/ - -package com.microsoft.z3; - -public abstract class IDisposable -{ - public abstract void dispose(); -} diff --git a/src/api/java/InterpolationContext.java b/src/api/java/InterpolationContext.java index 47a128643..99a63821f 100644 --- a/src/api/java/InterpolationContext.java +++ b/src/api/java/InterpolationContext.java @@ -17,11 +17,10 @@ Notes: package com.microsoft.z3; -import java.util.Map; -import java.lang.String; - import com.microsoft.z3.enumerations.Z3_lbool; +import java.util.Map; + /** * The InterpolationContext is suitable for generation of interpolants. * @@ -33,13 +32,13 @@ public class InterpolationContext extends Context /** * Constructor. **/ - public InterpolationContext() + public static InterpolationContext mkContext() { - super(); + long m_ctx; synchronized(creation_lock) { m_ctx = Native.mkInterpolationContext(0); - initContext(); } + return new InterpolationContext(m_ctx); } /** @@ -49,17 +48,21 @@ public class InterpolationContext extends Context * Remarks: * @see Context#Context **/ - public InterpolationContext(Map settings) + public static InterpolationContext mkContext(Map settings) { - super(); + long m_ctx; synchronized(creation_lock) { long cfg = Native.mkConfig(); for (Map.Entry kv : settings.entrySet()) Native.setParamValue(cfg, kv.getKey(), kv.getValue()); m_ctx = Native.mkInterpolationContext(cfg); Native.delConfig(cfg); - initContext(); } + return new InterpolationContext(m_ctx); + } + + private InterpolationContext(long m_ctx) { + super(m_ctx); } /** diff --git a/src/api/java/ListSort.java b/src/api/java/ListSort.java index 705e93579..0ff2c36cf 100644 --- a/src/api/java/ListSort.java +++ b/src/api/java/ListSort.java @@ -17,6 +17,8 @@ Notes: package com.microsoft.z3; +import com.microsoft.z3.Native.LongPtr; + /** * List sorts. **/ @@ -88,14 +90,9 @@ public class ListSort extends Sort ListSort(Context ctx, Symbol name, Sort elemSort) { - super(ctx, 0); - - Native.LongPtr inil = new Native.LongPtr(), iisnil = new Native.LongPtr(); - Native.LongPtr icons = new Native.LongPtr(), iiscons = new Native.LongPtr(); - Native.LongPtr ihead = new Native.LongPtr(), itail = new Native.LongPtr(); - - setNativeObject(Native.mkListSort(ctx.nCtx(), name.getNativeObject(), - elemSort.getNativeObject(), inil, iisnil, icons, iiscons, ihead, - itail)); + super(ctx, Native.mkListSort(ctx.nCtx(), name.getNativeObject(), + elemSort.getNativeObject(), + new LongPtr(), new Native.LongPtr(), new LongPtr(), + new LongPtr(), new LongPtr(), new LongPtr())); } }; diff --git a/src/api/java/Model.java b/src/api/java/Model.java index 1bf77d246..fc6c6046b 100644 --- a/src/api/java/Model.java +++ b/src/api/java/Model.java @@ -293,16 +293,8 @@ public class Model extends Z3Object } @Override - void incRef(long o) - { - getContext().getModelDRQ().incAndClear(getContext(), o); - super.incRef(o); - } - - @Override - void decRef(long o) - { - getContext().getModelDRQ().add(o); - super.decRef(o); + void incRef(long o) { + Native.modelIncRef(getContext().nCtx(), o); + getContext().getModelDRQ().storeReference(getContext(), this); } } diff --git a/src/api/java/ModelDecRefQueue.java b/src/api/java/ModelDecRefQueue.java index b97add310..6b141078e 100644 --- a/src/api/java/ModelDecRefQueue.java +++ b/src/api/java/ModelDecRefQueue.java @@ -17,7 +17,7 @@ Notes: package com.microsoft.z3; -class ModelDecRefQueue extends IDecRefQueue +class ModelDecRefQueue extends IDecRefQueue { public ModelDecRefQueue() { @@ -30,26 +30,7 @@ class ModelDecRefQueue extends IDecRefQueue } @Override - protected void incRef(Context ctx, long obj) - { - try - { - Native.modelIncRef(ctx.nCtx(), obj); - } catch (Z3Exception e) - { - // OK. - } - } - - @Override - protected void decRef(Context ctx, long obj) - { - try - { - Native.modelDecRef(ctx.nCtx(), obj); - } catch (Z3Exception e) - { - // OK. - } + protected void decRef(Context ctx, long obj) { + Native.modelDecRef(ctx.nCtx(), obj); } }; diff --git a/src/api/java/Optimize.java b/src/api/java/Optimize.java index 5dfe8fcf4..a5705a388 100644 --- a/src/api/java/Optimize.java +++ b/src/api/java/Optimize.java @@ -266,17 +266,8 @@ public class Optimize extends Z3Object } @Override - void incRef(long o) - { - getContext().getOptimizeDRQ().incAndClear(getContext(), o); - super.incRef(o); + void incRef(long o) { + Native.optimizeIncRef(getContext().nCtx(), o); + getContext().getOptimizeDRQ().storeReference(getContext(), this); } - - @Override - void decRef(long o) - { - getContext().getOptimizeDRQ().add(o); - super.decRef(o); - } - } diff --git a/src/api/java/OptimizeDecRefQueue.java b/src/api/java/OptimizeDecRefQueue.java index 795a8a399..a06165f3e 100644 --- a/src/api/java/OptimizeDecRefQueue.java +++ b/src/api/java/OptimizeDecRefQueue.java @@ -17,8 +17,7 @@ Notes: package com.microsoft.z3; -class OptimizeDecRefQueue extends IDecRefQueue -{ +class OptimizeDecRefQueue extends IDecRefQueue { public OptimizeDecRefQueue() { super(); @@ -30,26 +29,7 @@ class OptimizeDecRefQueue extends IDecRefQueue } @Override - protected void incRef(Context ctx, long obj) - { - try - { - Native.fixedpointIncRef(ctx.nCtx(), obj); - } catch (Z3Exception e) - { - // OK. - } - } - - @Override - protected void decRef(Context ctx, long obj) - { - try - { - Native.fixedpointDecRef(ctx.nCtx(), obj); - } catch (Z3Exception e) - { - // OK. - } + protected void decRef(Context ctx, long obj) { + Native.optimizeDecRef(ctx.nCtx(), obj); } }; diff --git a/src/api/java/ParamDescrs.java b/src/api/java/ParamDescrs.java index f265fb19e..f90e4dd99 100644 --- a/src/api/java/ParamDescrs.java +++ b/src/api/java/ParamDescrs.java @@ -92,16 +92,8 @@ public class ParamDescrs extends Z3Object } @Override - void incRef(long o) - { - getContext().getParamDescrsDRQ().incAndClear(getContext(), o); - super.incRef(o); - } - - @Override - void decRef(long o) - { - getContext().getParamDescrsDRQ().add(o); - super.decRef(o); + void incRef(long o) { + Native.paramDescrsIncRef(getContext().nCtx(), o); + getContext().getParamDescrsDRQ().storeReference(getContext(), this); } } diff --git a/src/api/java/ParamDescrsDecRefQueue.java b/src/api/java/ParamDescrsDecRefQueue.java index e3515bff6..ab7f4ddd6 100644 --- a/src/api/java/ParamDescrsDecRefQueue.java +++ b/src/api/java/ParamDescrsDecRefQueue.java @@ -17,39 +17,20 @@ Notes: package com.microsoft.z3; -class ParamDescrsDecRefQueue extends IDecRefQueue +class ParamDescrsDecRefQueue extends IDecRefQueue { public ParamDescrsDecRefQueue() { super(); } - public ParamDescrsDecRefQueue(int move_limit) - { + public ParamDescrsDecRefQueue(int move_limit) { super(move_limit); } - @Override - protected void incRef(Context ctx, long obj) - { - try - { - Native.paramDescrsIncRef(ctx.nCtx(), obj); - } catch (Z3Exception e) - { - // OK. - } - } - @Override protected void decRef(Context ctx, long obj) { - try - { - Native.paramDescrsDecRef(ctx.nCtx(), obj); - } catch (Z3Exception e) - { - // OK. - } + Native.paramDescrsDecRef(ctx.nCtx(), obj); } }; diff --git a/src/api/java/Params.java b/src/api/java/Params.java index 4be36c23d..e3b143371 100644 --- a/src/api/java/Params.java +++ b/src/api/java/Params.java @@ -124,16 +124,8 @@ public class Params extends Z3Object } @Override - void incRef(long o) - { - getContext().getParamsDRQ().incAndClear(getContext(), o); - super.incRef(o); - } - - @Override - void decRef(long o) - { - getContext().getParamsDRQ().add(o); - super.decRef(o); + void incRef(long o) { + Native.paramsIncRef(getContext().nCtx(), o); + getContext().getParamsDRQ().storeReference(getContext(), this); } } diff --git a/src/api/java/ParamsDecRefQueue.java b/src/api/java/ParamsDecRefQueue.java index f989f8015..b5281ecbc 100644 --- a/src/api/java/ParamsDecRefQueue.java +++ b/src/api/java/ParamsDecRefQueue.java @@ -17,7 +17,7 @@ Notes: package com.microsoft.z3; -class ParamsDecRefQueue extends IDecRefQueue +class ParamsDecRefQueue extends IDecRefQueue { public ParamsDecRefQueue() { @@ -30,26 +30,7 @@ class ParamsDecRefQueue extends IDecRefQueue } @Override - protected void incRef(Context ctx, long obj) - { - try - { - Native.paramsIncRef(ctx.nCtx(), obj); - } catch (Z3Exception e) - { - // OK. - } - } - - @Override - protected void decRef(Context ctx, long obj) - { - try - { - Native.paramsDecRef(ctx.nCtx(), obj); - } catch (Z3Exception e) - { - // OK. - } + protected void decRef(Context ctx, long obj) { + Native.paramsDecRef(ctx.nCtx(), obj); } }; diff --git a/src/api/java/Probe.java b/src/api/java/Probe.java index bcaa76ce6..6983613c1 100644 --- a/src/api/java/Probe.java +++ b/src/api/java/Probe.java @@ -54,14 +54,7 @@ public class Probe extends Z3Object @Override void incRef(long o) { - getContext().getProbeDRQ().incAndClear(getContext(), o); - super.incRef(o); - } - - @Override - void decRef(long o) - { - getContext().getProbeDRQ().add(o); - super.decRef(o); + Native.probeIncRef(getContext().nCtx(), o); + getContext().getProbeDRQ().storeReference(getContext(), this); } } diff --git a/src/api/java/ProbeDecRefQueue.java b/src/api/java/ProbeDecRefQueue.java index 368bd5bba..3f78c6288 100644 --- a/src/api/java/ProbeDecRefQueue.java +++ b/src/api/java/ProbeDecRefQueue.java @@ -17,7 +17,7 @@ Notes: package com.microsoft.z3; -class ProbeDecRefQueue extends IDecRefQueue +class ProbeDecRefQueue extends IDecRefQueue { public ProbeDecRefQueue() { @@ -29,27 +29,9 @@ class ProbeDecRefQueue extends IDecRefQueue super(move_limit); } - @Override - protected void incRef(Context ctx, long obj) - { - try - { - Native.probeIncRef(ctx.nCtx(), obj); - } catch (Z3Exception e) - { - // OK. - } - } - @Override protected void decRef(Context ctx, long obj) { - try - { - Native.probeDecRef(ctx.nCtx(), obj); - } catch (Z3Exception e) - { - // OK. - } + Native.probeDecRef(ctx.nCtx(), obj); } }; diff --git a/src/api/java/Quantifier.java b/src/api/java/Quantifier.java index 1b425d3e4..a78277839 100644 --- a/src/api/java/Quantifier.java +++ b/src/api/java/Quantifier.java @@ -145,68 +145,67 @@ public class Quantifier extends BoolExpr .nCtx(), getNativeObject())); } - Quantifier(Context ctx, boolean isForall, Sort[] sorts, Symbol[] names, + public static Quantifier of( + Context ctx, boolean isForall, Sort[] sorts, Symbol[] names, Expr body, int weight, Pattern[] patterns, Expr[] noPatterns, - Symbol quantifierID, Symbol skolemID) - { - super(ctx, 0); - - getContext().checkContextMatch(patterns); - getContext().checkContextMatch(noPatterns); - getContext().checkContextMatch(sorts); - getContext().checkContextMatch(names); - getContext().checkContextMatch(body); + Symbol quantifierID, Symbol skolemID + ) { + ctx.checkContextMatch(patterns); + ctx.checkContextMatch(noPatterns); + ctx.checkContextMatch(sorts); + ctx.checkContextMatch(names); + ctx.checkContextMatch(body); if (sorts.length != names.length) throw new Z3Exception( "Number of sorts does not match number of names"); - if (noPatterns == null && quantifierID == null && skolemID == null) - { - setNativeObject(Native.mkQuantifier(ctx.nCtx(), (isForall), weight, AST.arrayLength(patterns), AST + long nativeObj; + if (noPatterns == null && quantifierID == null && skolemID == null) { + nativeObj = Native.mkQuantifier(ctx.nCtx(), (isForall), weight, AST.arrayLength(patterns), AST .arrayToNative(patterns), AST.arrayLength(sorts), AST .arrayToNative(sorts), Symbol.arrayToNative(names), body - .getNativeObject())); - } else - { - setNativeObject(Native.mkQuantifierEx(ctx.nCtx(), - (isForall), weight, AST.getNativeObject(quantifierID), - AST.getNativeObject(skolemID), - AST.arrayLength(patterns), AST.arrayToNative(patterns), - AST.arrayLength(noPatterns), AST.arrayToNative(noPatterns), - AST.arrayLength(sorts), AST.arrayToNative(sorts), - Symbol.arrayToNative(names), - body.getNativeObject())); + .getNativeObject()); + } else { + nativeObj = Native.mkQuantifierEx(ctx.nCtx(), + (isForall), weight, AST.getNativeObject(quantifierID), + AST.getNativeObject(skolemID), + AST.arrayLength(patterns), AST.arrayToNative(patterns), + AST.arrayLength(noPatterns), AST.arrayToNative(noPatterns), + AST.arrayLength(sorts), AST.arrayToNative(sorts), + Symbol.arrayToNative(names), + body.getNativeObject()); } + return new Quantifier(ctx, nativeObj); } - Quantifier(Context ctx, boolean isForall, Expr[] bound, Expr body, + + public static Quantifier of(Context ctx, boolean isForall, Expr[] bound, Expr body, int weight, Pattern[] patterns, Expr[] noPatterns, Symbol quantifierID, Symbol skolemID) { - super(ctx, 0); - - getContext().checkContextMatch(noPatterns); - getContext().checkContextMatch(patterns); - // Context().CheckContextMatch(bound); - getContext().checkContextMatch(body); + ctx.checkContextMatch(noPatterns); + ctx.checkContextMatch(patterns); + // ctx.CheckContextMatch(bound); + ctx.checkContextMatch(body); + long nativeObj; if (noPatterns == null && quantifierID == null && skolemID == null) { - setNativeObject(Native.mkQuantifierConst(ctx.nCtx(), + nativeObj = Native.mkQuantifierConst(ctx.nCtx(), isForall, weight, AST.arrayLength(bound), AST.arrayToNative(bound), AST.arrayLength(patterns), - AST.arrayToNative(patterns), body.getNativeObject())); - } else - { - setNativeObject(Native.mkQuantifierConstEx(ctx.nCtx(), + AST.arrayToNative(patterns), body.getNativeObject()); + } else { + nativeObj = Native.mkQuantifierConstEx(ctx.nCtx(), isForall, weight, AST.getNativeObject(quantifierID), AST.getNativeObject(skolemID), AST.arrayLength(bound), AST.arrayToNative(bound), AST.arrayLength(patterns), AST.arrayToNative(patterns), AST.arrayLength(noPatterns), - AST.arrayToNative(noPatterns), body.getNativeObject())); + AST.arrayToNative(noPatterns), body.getNativeObject()); } + return new Quantifier(ctx, nativeObj); } Quantifier(Context ctx, long obj) diff --git a/src/api/java/Solver.java b/src/api/java/Solver.java index 431811b8d..5d538b2f3 100644 --- a/src/api/java/Solver.java +++ b/src/api/java/Solver.java @@ -127,13 +127,13 @@ public class Solver extends Z3Object * using the Boolean constants in ps. * * Remarks: - * This API is an alternative to {@link check} with assumptions for + * This API is an alternative to {@link #check()} with assumptions for * extracting unsat cores. * Both APIs can be used in the same solver. The unsat core will contain a * combination - * of the Boolean variables provided using {@link assertAndTrack} + * of the Boolean variables provided using {@code #assertAndTrack} * and the Boolean literals - * provided using {@link check} with assumptions. + * provided using {@link #check()} with assumptions. **/ public void assertAndTrack(BoolExpr[] constraints, BoolExpr[] ps) { @@ -333,16 +333,8 @@ public class Solver extends Z3Object } @Override - void incRef(long o) - { - getContext().getSolverDRQ().incAndClear(getContext(), o); - super.incRef(o); - } - - @Override - void decRef(long o) - { - getContext().getSolverDRQ().add(o); - super.decRef(o); + void incRef(long o) { + Native.solverIncRef(getContext().nCtx(), o); + getContext().getSolverDRQ().storeReference(getContext(), this); } } diff --git a/src/api/java/SolverDecRefQueue.java b/src/api/java/SolverDecRefQueue.java index f4d5fb139..106892fec 100644 --- a/src/api/java/SolverDecRefQueue.java +++ b/src/api/java/SolverDecRefQueue.java @@ -17,7 +17,7 @@ Notes: package com.microsoft.z3; -class SolverDecRefQueue extends IDecRefQueue +class SolverDecRefQueue extends IDecRefQueue { public SolverDecRefQueue() { super(); } @@ -27,26 +27,7 @@ class SolverDecRefQueue extends IDecRefQueue } @Override - protected void incRef(Context ctx, long obj) - { - try - { - Native.solverIncRef(ctx.nCtx(), obj); - } catch (Z3Exception e) - { - // OK. - } - } - - @Override - protected void decRef(Context ctx, long obj) - { - try - { - Native.solverDecRef(ctx.nCtx(), obj); - } catch (Z3Exception e) - { - // OK. - } + protected void decRef(Context ctx, long obj) { + Native.solverDecRef(ctx.nCtx(), obj); } }; diff --git a/src/api/java/Sort.java b/src/api/java/Sort.java index 30a43e7dd..0763a69a3 100644 --- a/src/api/java/Sort.java +++ b/src/api/java/Sort.java @@ -95,6 +95,7 @@ public class Sort extends AST super(ctx, obj); } + @Override void checkNativeObject(long obj) { if (Native.getAstKind(getContext().nCtx(), obj) != Z3_ast_kind.Z3_SORT_AST diff --git a/src/api/java/Statistics.java b/src/api/java/Statistics.java index 1e842a892..d2ba2bbd3 100644 --- a/src/api/java/Statistics.java +++ b/src/api/java/Statistics.java @@ -190,15 +190,9 @@ public class Statistics extends Z3Object super(ctx, obj); } - void incRef(long o) - { - getContext().getStatisticsDRQ().incAndClear(getContext(), o); - super.incRef(o); - } - - void decRef(long o) - { - getContext().getStatisticsDRQ().add(o); - super.decRef(o); + @Override + void incRef(long o) { + Native.statsIncRef(getContext().nCtx(), o); + getContext().getStatisticsDRQ().storeReference(getContext(), this); } } diff --git a/src/api/java/StatisticsDecRefQueue.java b/src/api/java/StatisticsDecRefQueue.java index 89c66a746..fecf52267 100644 --- a/src/api/java/StatisticsDecRefQueue.java +++ b/src/api/java/StatisticsDecRefQueue.java @@ -17,7 +17,7 @@ Notes: package com.microsoft.z3; -class StatisticsDecRefQueue extends IDecRefQueue +class StatisticsDecRefQueue extends IDecRefQueue { public StatisticsDecRefQueue() { @@ -29,25 +29,8 @@ class StatisticsDecRefQueue extends IDecRefQueue super(move_limit); } - protected void incRef(Context ctx, long obj) - { - try - { - Native.statsIncRef(ctx.nCtx(), obj); - } catch (Z3Exception e) - { - // OK. - } - } - - protected void decRef(Context ctx, long obj) - { - try - { - Native.statsDecRef(ctx.nCtx(), obj); - } catch (Z3Exception e) - { - // OK. - } + @Override + protected void decRef(Context ctx, long obj) { + Native.statsDecRef(ctx.nCtx(), obj); } }; diff --git a/src/api/java/StringSymbol.java b/src/api/java/StringSymbol.java index 8470e1cd4..576737ea7 100644 --- a/src/api/java/StringSymbol.java +++ b/src/api/java/StringSymbol.java @@ -48,9 +48,9 @@ public class StringSymbol extends Symbol void checkNativeObject(long obj) { if (Native.getSymbolKind(getContext().nCtx(), obj) != Z3_symbol_kind.Z3_STRING_SYMBOL - .toInt()) + .toInt()) { throw new Z3Exception("Symbol is not of String kind"); - + } super.checkNativeObject(obj); } } diff --git a/src/api/java/Symbol.java b/src/api/java/Symbol.java index beeaebb69..21925b099 100644 --- a/src/api/java/Symbol.java +++ b/src/api/java/Symbol.java @@ -62,19 +62,13 @@ public class Symbol extends Z3Object * A string representation of the symbol. **/ @Override - public String toString() - { - try - { - if (isIntSymbol()) - return Integer.toString(((IntSymbol) this).getInt()); - else if (isStringSymbol()) - return ((StringSymbol) this).getString(); - else - return "Z3Exception: Unknown symbol kind encountered."; - } catch (Z3Exception ex) - { - return "Z3Exception: " + ex.getMessage(); + public String toString() { + if (isIntSymbol()) { + return Integer.toString(((IntSymbol) this).getInt()); + } else if (isStringSymbol()) { + return ((StringSymbol) this).getString(); + } else { + return "Z3Exception: Unknown symbol kind encountered."; } } @@ -86,6 +80,11 @@ public class Symbol extends Z3Object super(ctx, obj); } + @Override + void incRef(long o) { + // Symbol does not require tracking. + } + static Symbol create(Context ctx, long obj) { switch (Z3_symbol_kind.fromInt(Native.getSymbolKind(ctx.nCtx(), obj))) diff --git a/src/api/java/Tactic.java b/src/api/java/Tactic.java index 786f8a6ec..f7e030f04 100644 --- a/src/api/java/Tactic.java +++ b/src/api/java/Tactic.java @@ -92,15 +92,10 @@ public class Tactic extends Z3Object super(ctx, Native.mkTactic(ctx.nCtx(), name)); } + @Override void incRef(long o) { - getContext().getTacticDRQ().incAndClear(getContext(), o); - super.incRef(o); - } - - void decRef(long o) - { - getContext().getTacticDRQ().add(o); - super.decRef(o); + Native.tacticIncRef(getContext().nCtx(), o); + getContext().getTacticDRQ().storeReference(getContext(), this); } } diff --git a/src/api/java/TacticDecRefQueue.java b/src/api/java/TacticDecRefQueue.java index 026760e46..079904175 100644 --- a/src/api/java/TacticDecRefQueue.java +++ b/src/api/java/TacticDecRefQueue.java @@ -17,8 +17,7 @@ Notes: package com.microsoft.z3; -class TacticDecRefQueue extends IDecRefQueue -{ +class TacticDecRefQueue extends IDecRefQueue { public TacticDecRefQueue() { super(); @@ -29,25 +28,9 @@ class TacticDecRefQueue extends IDecRefQueue super(move_limit); } - protected void incRef(Context ctx, long obj) - { - try - { - Native.tacticIncRef(ctx.nCtx(), obj); - } catch (Z3Exception e) - { - // OK. - } - } - + @Override protected void decRef(Context ctx, long obj) { - try - { - Native.tacticDecRef(ctx.nCtx(), obj); - } catch (Z3Exception e) - { - // OK. - } + Native.tacticDecRef(ctx.nCtx(), obj); } -}; +} diff --git a/src/api/java/TupleSort.java b/src/api/java/TupleSort.java index 1594b874d..ede20d260 100644 --- a/src/api/java/TupleSort.java +++ b/src/api/java/TupleSort.java @@ -59,11 +59,9 @@ public class TupleSort extends Sort TupleSort(Context ctx, Symbol name, int numFields, Symbol[] fieldNames, Sort[] fieldSorts) { - super(ctx, 0); - - Native.LongPtr t = new Native.LongPtr(); - setNativeObject(Native.mkTupleSort(ctx.nCtx(), name.getNativeObject(), + super(ctx, Native.mkTupleSort(ctx.nCtx(), name.getNativeObject(), numFields, Symbol.arrayToNative(fieldNames), - AST.arrayToNative(fieldSorts), t, new long[numFields])); + AST.arrayToNative(fieldSorts), new Native.LongPtr(), + new long[numFields])); } }; diff --git a/src/api/java/Z3Object.java b/src/api/java/Z3Object.java index dc1feecbf..6fd12bfba 100644 --- a/src/api/java/Z3Object.java +++ b/src/api/java/Z3Object.java @@ -21,88 +21,38 @@ package com.microsoft.z3; * Internal base class for interfacing with native Z3 objects. Should not be * used externally. **/ -public class Z3Object extends IDisposable -{ - /** - * Finalizer. - * @throws Throwable - **/ - protected void finalize() throws Throwable - { - try { - dispose(); - } finally { - super.finalize(); - } - } +public abstract class Z3Object { - /** - * Disposes of the underlying native Z3 object. - **/ - public void dispose() - { - if (m_n_obj != 0) - { - decRef(m_n_obj); - m_n_obj = 0; - } + private final Context m_ctx; + private final long m_n_obj; - if (m_ctx != null) - { - if (m_ctx.m_refCount.decrementAndGet() == 0) - m_ctx.dispose(); - m_ctx = null; - } - } - - private Context m_ctx = null; - private long m_n_obj = 0; - - Z3Object(Context ctx) - { - ctx.m_refCount.incrementAndGet(); - m_ctx = ctx; - } - - Z3Object(Context ctx, long obj) - { - ctx.m_refCount.incrementAndGet(); + Z3Object(Context ctx, long obj) { m_ctx = ctx; + checkNativeObject(obj); incRef(obj); m_n_obj = obj; } - void incRef(long o) - { - } + /** + * Increment reference count on {@code o}. + * + * @param o Z3 object. + */ + abstract void incRef(long o); - void decRef(long o) - { - } - - void checkNativeObject(long obj) - { - } + /** + * This function is provided for overriding, and a child class + * can insert consistency checks on {@code obj}. + * + * @param obj Z3 native object. + */ + void checkNativeObject(long obj) {} long getNativeObject() { return m_n_obj; } - void setNativeObject(long value) - { - if (value != 0) - { - checkNativeObject(value); - incRef(value); - } - if (m_n_obj != 0) - { - decRef(m_n_obj); - } - m_n_obj = value; - } - static long getNativeObject(Z3Object s) { if (s == null) @@ -121,7 +71,7 @@ public class Z3Object extends IDisposable return null; long[] an = new long[a.length]; for (int i = 0; i < a.length; i++) - an[i] = (a[i] == null) ? 0 : a[i].getNativeObject(); + an[i] = (a[i] == null) ? 0 : a[i].getNativeObject(); return an; } From 5657399d554f0c67715855840d2cee09e20c5ed1 Mon Sep 17 00:00:00 2001 From: George Karpenkov Date: Sun, 12 Jun 2016 20:39:54 +0200 Subject: [PATCH 025/536] Bugfix for incorrect order of operations. --- src/api/java/Z3Object.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/java/Z3Object.java b/src/api/java/Z3Object.java index 6fd12bfba..f982bba1c 100644 --- a/src/api/java/Z3Object.java +++ b/src/api/java/Z3Object.java @@ -29,8 +29,8 @@ public abstract class Z3Object { Z3Object(Context ctx, long obj) { m_ctx = ctx; checkNativeObject(obj); - incRef(obj); m_n_obj = obj; + incRef(obj); } /** From 2a347f04bf79a6e223899cfba6690123d388b9f3 Mon Sep 17 00:00:00 2001 From: George Karpenkov Date: Sun, 12 Jun 2016 21:00:51 +0200 Subject: [PATCH 026/536] Java API: FuncInterp.Entry should be an inner static class ...as it does not use any fields of the outer FuncInterp object. --- src/api/java/FuncInterp.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/api/java/FuncInterp.java b/src/api/java/FuncInterp.java index c84979aa1..52f09c5a4 100644 --- a/src/api/java/FuncInterp.java +++ b/src/api/java/FuncInterp.java @@ -28,8 +28,8 @@ public class FuncInterp extends Z3Object * An Entry object represents an element in the finite map used to encode a * function interpretation. **/ - public class Entry extends Z3Object - { + public static class Entry extends Z3Object { + /** * Return the (symbolic) value of this entry. * From 22ffd65d1e2a02583128a9a19a547d8b340e2547 Mon Sep 17 00:00:00 2001 From: George Karpenkov Date: Sun, 12 Jun 2016 21:01:58 +0200 Subject: [PATCH 027/536] Java API: split incRef into incRef and addToReferenceQueue One method should do one thing only, it's easy to mix things up otherwise. --- src/api/java/AST.java | 9 ++++--- src/api/java/ASTMap.java | 12 +++++---- src/api/java/ASTVector.java | 12 +++++---- src/api/java/ApplyResult.java | 11 ++++++--- src/api/java/Constructor.java | 7 ++++-- src/api/java/ConstructorList.java | 7 +++++- src/api/java/Fixedpoint.java | 8 ++++-- src/api/java/FixedpointDecRefQueue.java | 4 +-- src/api/java/FuncInterp.java | 33 +++++++++++++++---------- src/api/java/Goal.java | 11 ++++++--- src/api/java/Model.java | 11 ++++++--- src/api/java/Optimize.java | 8 ++++-- src/api/java/ParamDescrs.java | 11 ++++++--- src/api/java/Params.java | 12 ++++++--- src/api/java/Probe.java | 15 +++++------ src/api/java/Solver.java | 17 +++++++------ src/api/java/Statistics.java | 11 ++++++--- src/api/java/Symbol.java | 11 ++++++--- src/api/java/Tactic.java | 12 +++++---- src/api/java/Z3Object.java | 15 +++++++---- 20 files changed, 150 insertions(+), 87 deletions(-) diff --git a/src/api/java/AST.java b/src/api/java/AST.java index 4b5b37d46..e1cde837f 100644 --- a/src/api/java/AST.java +++ b/src/api/java/AST.java @@ -192,9 +192,12 @@ public class AST extends Z3Object implements Comparable } @Override - void incRef(long o) - { - Native.incRef(getContext().nCtx(), o); + void incRef() { + Native.incRef(getContext().nCtx(), getNativeObject()); + } + + @Override + void addToReferenceQueue() { getContext().getASTDRQ().storeReference(getContext(), this); } diff --git a/src/api/java/ASTMap.java b/src/api/java/ASTMap.java index b4ae7102a..916811cec 100644 --- a/src/api/java/ASTMap.java +++ b/src/api/java/ASTMap.java @@ -20,8 +20,7 @@ package com.microsoft.z3; /** * Map from AST to AST **/ -class ASTMap extends Z3Object -{ +class ASTMap extends Z3Object { /** * Checks whether the map contains the key {@code k}. * @param k An AST @@ -118,9 +117,12 @@ class ASTMap extends Z3Object } @Override - void incRef(long o) - { - Native.astMapIncRef(getContext().nCtx(), o); + void incRef() { + Native.astMapIncRef(getContext().nCtx(), getNativeObject()); + } + + @Override + void addToReferenceQueue() { getContext().getASTMapDRQ().storeReference(getContext(), this); } } diff --git a/src/api/java/ASTVector.java b/src/api/java/ASTVector.java index 7c5ca1067..4d9ab291a 100644 --- a/src/api/java/ASTVector.java +++ b/src/api/java/ASTVector.java @@ -20,8 +20,7 @@ package com.microsoft.z3; /** * Vectors of ASTs. **/ -public class ASTVector extends Z3Object -{ +public class ASTVector extends Z3Object { /** * The size of the vector **/ @@ -103,9 +102,12 @@ public class ASTVector extends Z3Object } @Override - void incRef(long o) - { - Native.astVectorIncRef(getContext().nCtx(), o); + void incRef() { + Native.astVectorIncRef(getContext().nCtx(), getNativeObject()); + } + + @Override + void addToReferenceQueue() { getContext().getASTVectorDRQ().storeReference(getContext(), this); } diff --git a/src/api/java/ApplyResult.java b/src/api/java/ApplyResult.java index 8b3c1daf6..6fafbd888 100644 --- a/src/api/java/ApplyResult.java +++ b/src/api/java/ApplyResult.java @@ -21,8 +21,7 @@ package com.microsoft.z3; * ApplyResult objects represent the result of an application of a tactic to a * goal. It contains the subgoals that were produced. **/ -public class ApplyResult extends Z3Object -{ +public class ApplyResult extends Z3Object { /** * The number of Subgoals. **/ @@ -74,8 +73,12 @@ public class ApplyResult extends Z3Object } @Override - void incRef(long o) { - Native.applyResultIncRef(getContext().nCtx(), o); + void incRef() { + Native.applyResultIncRef(getContext().nCtx(), getNativeObject()); + } + + @Override + void addToReferenceQueue() { getContext().getApplyResultDRQ().storeReference(getContext(), this); } } diff --git a/src/api/java/Constructor.java b/src/api/java/Constructor.java index 28558b15a..87ab86c3f 100644 --- a/src/api/java/Constructor.java +++ b/src/api/java/Constructor.java @@ -85,9 +85,12 @@ public class Constructor extends Z3Object { } @Override - void incRef(long o) { - + void incRef() { // Datatype constructors are not reference counted. + } + + @Override + void addToReferenceQueue() { getContext().getConstructorDRQ().storeReference(getContext(), this); } diff --git a/src/api/java/ConstructorList.java b/src/api/java/ConstructorList.java index 3f1835082..c79e08d9e 100644 --- a/src/api/java/ConstructorList.java +++ b/src/api/java/ConstructorList.java @@ -28,7 +28,12 @@ public class ConstructorList extends Z3Object { } @Override - void incRef(long o) { + void incRef() { + // Constructor lists are not reference counted. + } + + @Override + void addToReferenceQueue() { getContext().getConstructorListDRQ().storeReference(getContext(), this); } diff --git a/src/api/java/Fixedpoint.java b/src/api/java/Fixedpoint.java index 5a7958364..876345f1e 100644 --- a/src/api/java/Fixedpoint.java +++ b/src/api/java/Fixedpoint.java @@ -349,8 +349,12 @@ public class Fixedpoint extends Z3Object } @Override - void incRef(long o) { - Native.fixedpointIncRef(getContext().nCtx(), o); + void incRef() { + Native.fixedpointIncRef(getContext().nCtx(), getNativeObject()); + } + + @Override + void addToReferenceQueue() { getContext().getFixedpointDRQ().storeReference(getContext(), this); } diff --git a/src/api/java/FixedpointDecRefQueue.java b/src/api/java/FixedpointDecRefQueue.java index d5ae79a2b..3cba67ced 100644 --- a/src/api/java/FixedpointDecRefQueue.java +++ b/src/api/java/FixedpointDecRefQueue.java @@ -17,8 +17,7 @@ Notes: package com.microsoft.z3; -class FixedpointDecRefQueue extends IDecRefQueue -{ +class FixedpointDecRefQueue extends IDecRefQueue { public FixedpointDecRefQueue() { super(); @@ -29,7 +28,6 @@ class FixedpointDecRefQueue extends IDecRefQueue super(move_limit); } - @Override protected void decRef(Context ctx, long obj) { diff --git a/src/api/java/FuncInterp.java b/src/api/java/FuncInterp.java index 52f09c5a4..b5873d98e 100644 --- a/src/api/java/FuncInterp.java +++ b/src/api/java/FuncInterp.java @@ -22,8 +22,8 @@ package com.microsoft.z3; * Each entry in the finite map represents the value of a function given a set * of arguments. **/ -public class FuncInterp extends Z3Object -{ +public class FuncInterp extends Z3Object { + /** * An Entry object represents an element in the finite map used to encode a * function interpretation. @@ -32,10 +32,10 @@ public class FuncInterp extends Z3Object /** * Return the (symbolic) value of this entry. - * + * * @throws Z3Exception * @throws Z3Exception on error - **/ + **/ public Expr getValue() { return Expr.create(getContext(), @@ -45,7 +45,7 @@ public class FuncInterp extends Z3Object /** * The number of arguments of the entry. * @throws Z3Exception on error - **/ + **/ public int getNumArgs() { return Native.funcEntryGetNumArgs(getContext().nCtx(), getNativeObject()); @@ -53,10 +53,10 @@ public class FuncInterp extends Z3Object /** * The arguments of the function entry. - * + * * @throws Z3Exception * @throws Z3Exception on error - **/ + **/ public Expr[] getArgs() { int n = getNumArgs(); @@ -81,14 +81,17 @@ public class FuncInterp extends Z3Object return res + getValue() + "]"; } - Entry(Context ctx, long obj) - { + Entry(Context ctx, long obj) { super(ctx, obj); } @Override - void incRef(long o) { - Native.funcEntryIncRef(getContext().nCtx(), o);; + void incRef() { + Native.funcEntryIncRef(getContext().nCtx(), getNativeObject()); + } + + @Override + void addToReferenceQueue() { getContext().getFuncEntryDRQ().storeReference(getContext(), this); } } @@ -176,8 +179,12 @@ public class FuncInterp extends Z3Object } @Override - void incRef(long o) { - Native.funcInterpIncRef(getContext().nCtx(), o); + void incRef() { + Native.funcInterpIncRef(getContext().nCtx(), getNativeObject()); + } + + @Override + void addToReferenceQueue() { getContext().getFuncInterpDRQ().storeReference(getContext(), this); } } diff --git a/src/api/java/Goal.java b/src/api/java/Goal.java index a6d41ccd2..25b1fe511 100644 --- a/src/api/java/Goal.java +++ b/src/api/java/Goal.java @@ -23,8 +23,7 @@ import com.microsoft.z3.enumerations.Z3_goal_prec; * A goal (aka problem). A goal is essentially a set of formulas, that can be * solved and/or transformed using tactics and solvers. **/ -public class Goal extends Z3Object -{ +public class Goal extends Z3Object { /** * The precision of the goal. * Remarks: Goals can be transformed using over @@ -242,8 +241,12 @@ public class Goal extends Z3Object } @Override - void incRef(long o) { - Native.goalIncRef(getContext().nCtx(), o); + void incRef() { + Native.goalIncRef(getContext().nCtx(), getNativeObject()); + } + + @Override + void addToReferenceQueue() { getContext().getGoalDRQ().storeReference(getContext(), this); } } diff --git a/src/api/java/Model.java b/src/api/java/Model.java index fc6c6046b..60abb001d 100644 --- a/src/api/java/Model.java +++ b/src/api/java/Model.java @@ -22,8 +22,7 @@ import com.microsoft.z3.enumerations.Z3_sort_kind; /** * A Model contains interpretations (assignments) of constants and functions. **/ -public class Model extends Z3Object -{ +public class Model extends Z3Object { /** * Retrieves the interpretation (the assignment) of {@code a} in * the model. @@ -293,8 +292,12 @@ public class Model extends Z3Object } @Override - void incRef(long o) { - Native.modelIncRef(getContext().nCtx(), o); + void incRef() { + Native.modelIncRef(getContext().nCtx(), getNativeObject()); + } + + @Override + void addToReferenceQueue() { getContext().getModelDRQ().storeReference(getContext(), this); } } diff --git a/src/api/java/Optimize.java b/src/api/java/Optimize.java index a5705a388..ea100d1ca 100644 --- a/src/api/java/Optimize.java +++ b/src/api/java/Optimize.java @@ -266,8 +266,12 @@ public class Optimize extends Z3Object } @Override - void incRef(long o) { - Native.optimizeIncRef(getContext().nCtx(), o); + void incRef() { + Native.optimizeIncRef(getContext().nCtx(), getNativeObject()); + } + + @Override + void addToReferenceQueue() { getContext().getOptimizeDRQ().storeReference(getContext(), this); } } diff --git a/src/api/java/ParamDescrs.java b/src/api/java/ParamDescrs.java index f90e4dd99..0008515e3 100644 --- a/src/api/java/ParamDescrs.java +++ b/src/api/java/ParamDescrs.java @@ -22,8 +22,7 @@ import com.microsoft.z3.enumerations.Z3_param_kind; /** * A ParamDescrs describes a set of parameters. **/ -public class ParamDescrs extends Z3Object -{ +public class ParamDescrs extends Z3Object { /** * validate a set of parameters. **/ @@ -92,8 +91,12 @@ public class ParamDescrs extends Z3Object } @Override - void incRef(long o) { - Native.paramDescrsIncRef(getContext().nCtx(), o); + void incRef() { + Native.paramDescrsIncRef(getContext().nCtx(), getNativeObject()); + } + + @Override + void addToReferenceQueue() { getContext().getParamDescrsDRQ().storeReference(getContext(), this); } } diff --git a/src/api/java/Params.java b/src/api/java/Params.java index e3b143371..a76dd3cab 100644 --- a/src/api/java/Params.java +++ b/src/api/java/Params.java @@ -21,8 +21,7 @@ package com.microsoft.z3; /** * A ParameterSet represents a configuration in the form of Symbol/value pairs. **/ -public class Params extends Z3Object -{ +public class Params extends Z3Object { /** * Adds a parameter setting. **/ @@ -123,9 +122,14 @@ public class Params extends Z3Object super(ctx, Native.mkParams(ctx.nCtx())); } + @Override - void incRef(long o) { - Native.paramsIncRef(getContext().nCtx(), o); + void incRef() { + Native.paramsIncRef(getContext().nCtx(), getNativeObject()); + } + + @Override + void addToReferenceQueue() { getContext().getParamsDRQ().storeReference(getContext(), this); } } diff --git a/src/api/java/Probe.java b/src/api/java/Probe.java index 6983613c1..a36f3b64b 100644 --- a/src/api/java/Probe.java +++ b/src/api/java/Probe.java @@ -25,8 +25,7 @@ package com.microsoft.z3; * also be obtained using the command {@code (help-tactic)} in the SMT 2.0 * front-end. **/ -public class Probe extends Z3Object -{ +public class Probe extends Z3Object { /** * Execute the probe over the goal. * @@ -46,15 +45,17 @@ public class Probe extends Z3Object super(ctx, obj); } - Probe(Context ctx, String name) - { + Probe(Context ctx, String name) { super(ctx, Native.mkProbe(ctx.nCtx(), name)); } @Override - void incRef(long o) - { - Native.probeIncRef(getContext().nCtx(), o); + void incRef() { + Native.probeIncRef(getContext().nCtx(), getNativeObject()); + } + + @Override + void addToReferenceQueue() { getContext().getProbeDRQ().storeReference(getContext(), this); } } diff --git a/src/api/java/Solver.java b/src/api/java/Solver.java index 5d538b2f3..a98fcbf94 100644 --- a/src/api/java/Solver.java +++ b/src/api/java/Solver.java @@ -22,8 +22,7 @@ import com.microsoft.z3.enumerations.Z3_lbool; /** * Solvers. **/ -public class Solver extends Z3Object -{ +public class Solver extends Z3Object { /** * A string that describes all available solver parameters. **/ @@ -154,13 +153,13 @@ public class Solver extends Z3Object * using the Boolean constant p. * * Remarks: - * This API is an alternative to {@link check} with assumptions for + * This API is an alternative to {@link #check} with assumptions for * extracting unsat cores. * Both APIs can be used in the same solver. The unsat core will contain a * combination - * of the Boolean variables provided using {@link assertAndTrack} + * of the Boolean variables provided using {@link #assertAndTrack} * and the Boolean literals - * provided using {@link check} with assumptions. + * provided using {@link #check} with assumptions. */ public void assertAndTrack(BoolExpr constraint, BoolExpr p) { @@ -333,8 +332,12 @@ public class Solver extends Z3Object } @Override - void incRef(long o) { - Native.solverIncRef(getContext().nCtx(), o); + void incRef() { + Native.solverIncRef(getContext().nCtx(), getNativeObject()); + } + + @Override + void addToReferenceQueue() { getContext().getSolverDRQ().storeReference(getContext(), this); } } diff --git a/src/api/java/Statistics.java b/src/api/java/Statistics.java index d2ba2bbd3..356cbeadb 100644 --- a/src/api/java/Statistics.java +++ b/src/api/java/Statistics.java @@ -20,8 +20,7 @@ package com.microsoft.z3; /** * Objects of this class track statistical information about solvers. **/ -public class Statistics extends Z3Object -{ +public class Statistics extends Z3Object { /** * Statistical data is organized into pairs of [Key, Entry], where every * Entry is either a {@code DoubleEntry} or a {@code UIntEntry} @@ -191,8 +190,12 @@ public class Statistics extends Z3Object } @Override - void incRef(long o) { - Native.statsIncRef(getContext().nCtx(), o); + void incRef() { getContext().getStatisticsDRQ().storeReference(getContext(), this); } + + @Override + void addToReferenceQueue() { + Native.statsIncRef(getContext().nCtx(), getNativeObject()); + } } diff --git a/src/api/java/Symbol.java b/src/api/java/Symbol.java index 21925b099..139894be1 100644 --- a/src/api/java/Symbol.java +++ b/src/api/java/Symbol.java @@ -22,8 +22,7 @@ import com.microsoft.z3.enumerations.Z3_symbol_kind; /** * Symbols are used to name several term and type constructors. **/ -public class Symbol extends Z3Object -{ +public class Symbol extends Z3Object { /** * The kind of the symbol (int or string) **/ @@ -81,7 +80,13 @@ public class Symbol extends Z3Object } @Override - void incRef(long o) { + void incRef() { + // Symbol does not require tracking. + } + + @Override + void addToReferenceQueue() { + // Symbol does not require tracking. } diff --git a/src/api/java/Tactic.java b/src/api/java/Tactic.java index f7e030f04..11d02ca73 100644 --- a/src/api/java/Tactic.java +++ b/src/api/java/Tactic.java @@ -24,8 +24,7 @@ package com.microsoft.z3; * also be obtained using the command {@code (help-tactic)} in the SMT 2.0 * front-end. **/ -public class Tactic extends Z3Object -{ +public class Tactic extends Z3Object { /** * A string containing a description of parameters accepted by the tactic. **/ @@ -93,9 +92,12 @@ public class Tactic extends Z3Object } @Override - void incRef(long o) - { - Native.tacticIncRef(getContext().nCtx(), o); + void incRef() { + Native.tacticIncRef(getContext().nCtx(), getNativeObject()); + } + + @Override + void addToReferenceQueue() { getContext().getTacticDRQ().storeReference(getContext(), this); } } diff --git a/src/api/java/Z3Object.java b/src/api/java/Z3Object.java index f982bba1c..7c5f606d9 100644 --- a/src/api/java/Z3Object.java +++ b/src/api/java/Z3Object.java @@ -30,15 +30,20 @@ public abstract class Z3Object { m_ctx = ctx; checkNativeObject(obj); m_n_obj = obj; - incRef(obj); + incRef(); + addToReferenceQueue(); } /** - * Increment reference count on {@code o}. - * - * @param o Z3 object. + * Add to ReferenceQueue for tracking reachability on the object and + * decreasing the reference count when the object is no longer reachable. */ - abstract void incRef(long o); + abstract void addToReferenceQueue(); + + /** + * Increment reference count on {@code this}. + */ + abstract void incRef(); /** * This function is provided for overriding, and a child class From c7ff05cc78f90f3b10901e4efb5ba8be85246915 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 12 Jun 2016 15:58:12 -0700 Subject: [PATCH 028/536] enable core minimization with qsat in case it turns out to be useful Signed-off-by: Nikolaj Bjorner --- src/ast/ast_smt2_pp.cpp | 43 +++++++--- src/opt/maxres.cpp | 14 +--- src/opt/opt_context.cpp | 7 +- src/opt/opt_solver.cpp | 3 +- src/opt/opt_solver.h | 2 +- src/qe/qe_arith.cpp | 25 ++++-- src/qe/qsat.cpp | 109 +++++++++++++----------- src/sat/sat_solver/inc_sat_solver.cpp | 2 +- src/smt/smt_solver.cpp | 3 +- src/solver/check_sat_result.h | 5 ++ src/solver/combined_solver.cpp | 4 +- src/solver/mus.cpp | 114 +++++++++++++++----------- src/solver/mus.h | 9 ++ src/solver/solver.cpp | 10 ++- src/solver/solver.h | 12 ++- src/solver/tactic2solver.cpp | 5 +- 16 files changed, 235 insertions(+), 132 deletions(-) diff --git a/src/ast/ast_smt2_pp.cpp b/src/ast/ast_smt2_pp.cpp index 1a7f051a0..2e2d99a38 100644 --- a/src/ast/ast_smt2_pp.cpp +++ b/src/ast/ast_smt2_pp.cpp @@ -1125,6 +1125,21 @@ void mk_smt2_format(func_decl * f, smt2_pp_environment & env, params_ref const & pr(f, r); } +void mk_smt2_format(unsigned sz, expr * const* es, smt2_pp_environment & env, params_ref const & p, + unsigned num_vars, char const * var_prefix, + format_ref & r, sbuffer & var_names) { + smt2_printer pr(env, p); + ast_manager & m = env.get_manager(); + + format_ref_vector fmts(fm(m)); + for (unsigned i = 0; i < sz; ++i) { + format_ref fr(fm(m)); + pr(es[i], num_vars, var_prefix, fr, var_names); + fmts.push_back(fr); + } + r = mk_seq(m, fmts.c_ptr(), fmts.c_ptr() + fmts.size(), f2f()); +} + std::ostream & ast_smt2_pp(std::ostream & out, expr * n, smt2_pp_environment & env, params_ref const & p, unsigned indent, unsigned num_vars, char const * var_prefix) { ast_manager & m = env.get_manager(); @@ -1159,6 +1174,18 @@ std::ostream & ast_smt2_pp(std::ostream & out, func_decl * f, smt2_pp_environmen return out; } +std::ostream & ast_smt2_pp(std::ostream & out, unsigned sz, expr * const* es, smt2_pp_environment & env, params_ref const & p, unsigned indent, + unsigned num_vars, char const * var_prefix) { + ast_manager & m = env.get_manager(); + format_ref r(fm(m)); + sbuffer var_names; + mk_smt2_format(sz, es, env, p, num_vars, var_prefix, r, var_names); + if (indent > 0) + r = mk_indent(m, indent, r.get()); + pp(out, r.get(), m, p); + return out; +} + mk_ismt2_pp::mk_ismt2_pp(ast * t, ast_manager & m, params_ref const & p, unsigned indent, unsigned num_vars, char const * var_prefix): m_ast(t), m_manager(m), @@ -1209,19 +1236,15 @@ std::ostream& operator<<(std::ostream& out, sort_ref const& e) { } std::ostream& operator<<(std::ostream& out, expr_ref_vector const& e) { - for (unsigned i = 0; i < e.size(); ++i) { - out << mk_ismt2_pp(e[i], e.get_manager()); - if (i + 1 < e.size()) out << "; "; - } - return out; + smt2_pp_environment_dbg env(e.get_manager()); + params_ref p; + return ast_smt2_pp(out, e.size(), e.c_ptr(), env, p, 0, 0, 0); } std::ostream& operator<<(std::ostream& out, app_ref_vector const& e) { - for (unsigned i = 0; i < e.size(); ++i) { - out << mk_ismt2_pp(e[i], e.get_manager()); - if (i + 1 < e.size()) out << "; "; - } - return out; + smt2_pp_environment_dbg env(e.get_manager()); + params_ref p; + return ast_smt2_pp(out, e.size(), (expr*const*)e.c_ptr(), env, p, 0, 0, 0); } std::ostream& operator<<(std::ostream& out, func_decl_ref_vector const& e) { diff --git a/src/opt/maxres.cpp b/src/opt/maxres.cpp index 741bab4b5..b52c7d9b9 100644 --- a/src/opt/maxres.cpp +++ b/src/opt/maxres.cpp @@ -545,7 +545,7 @@ public: } m_mus.reset(); for (unsigned i = 0; i < core.size(); ++i) { - m_mus.add_soft(core[i]); + VERIFY(i == m_mus.add_soft(core[i])); } unsigned_vector mus_idx; lbool is_sat = m_mus.get_mus(mus_idx); @@ -832,12 +832,8 @@ public: tout << m_defs; tout << m_asms; ); - for (unsigned i = 0; i < m_defs.size(); ++i) { - s().assert_expr(m_defs[i].get()); - } - for (unsigned i = 0; i < m_asms.size(); ++i) { - s().assert_expr(m_asms[i].get()); - } + s().assert_expr(m_defs); + s().assert_expr(m_asms); } // else: there is only a single assignment to these soft constraints. } @@ -848,9 +844,7 @@ public: for (unsigned i = 0; i < s().get_num_assertions(); ++i) { smt_solver->assert_expr(s().get_assertion(i)); } - for (unsigned i = 0; i < core.size(); ++i) { - smt_solver->assert_expr(core[i]); - } + smt_solver->assert_expr(core); lbool is_sat = smt_solver->check_sat(0, 0); if (is_sat == l_true) { IF_VERBOSE(0, verbose_stream() << "not a core\n";); diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 5082fde37..f90b31476 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -555,10 +555,9 @@ namespace opt { m_params.set_bool("minimize_core_partial", true); // false); m_params.set_bool("minimize_core", true); m_sat_solver = mk_inc_sat_solver(m, m_params); - unsigned sz = get_solver().get_num_assertions(); - for (unsigned i = 0; i < sz; ++i) { - m_sat_solver->assert_expr(get_solver().get_assertion(i)); - } + expr_ref_vector fmls(m); + get_solver().get_assertions(fmls); + m_sat_solver->assert_expr(fmls); m_solver = m_sat_solver.get(); } diff --git a/src/opt/opt_solver.cpp b/src/opt/opt_solver.cpp index fccc7fa1c..3c2ac207c 100644 --- a/src/opt/opt_solver.cpp +++ b/src/opt/opt_solver.cpp @@ -316,8 +316,9 @@ namespace opt { return m_context.get_formulas()[idx]; } - void opt_solver::display(std::ostream & out) const { + std::ostream& opt_solver::display(std::ostream & out) const { m_context.display(out); + return out; } smt::theory_var opt_solver::add_objective(app* term) { diff --git a/src/opt/opt_solver.h b/src/opt/opt_solver.h index 3c58a4fec..e5ee5afcf 100644 --- a/src/opt/opt_solver.h +++ b/src/opt/opt_solver.h @@ -104,7 +104,7 @@ namespace opt { virtual void set_progress_callback(progress_callback * callback); virtual unsigned get_num_assertions() const; virtual expr * get_assertion(unsigned idx) const; - virtual void display(std::ostream & out) const; + virtual std::ostream& display(std::ostream & out) const; virtual ast_manager& get_manager() { return m; } void set_logic(symbol const& logic); diff --git a/src/qe/qe_arith.cpp b/src/qe/qe_arith.cpp index 38d46fefe..d071765fc 100644 --- a/src/qe/qe_arith.cpp +++ b/src/qe/qe_arith.cpp @@ -1072,18 +1072,33 @@ namespace qe { expr_ref_vector ts(m); expr_ref t(m), s(m); row const& r = rows[i]; + if (r.m_vars.size() == 0) { + continue; + } + if (r.m_vars.size() == 1 && r.m_vars[0].m_coeff.is_neg()) { + var const& v = r.m_vars[0]; + t = index2expr[v.m_id]; + if (!v.m_coeff.is_minus_one()) { + t = a.mk_mul(t, a.mk_numeral(-v.m_coeff, a.is_int(t))); + } + s = a.mk_numeral(r.m_coeff, a.is_int(t)); + switch (r.m_type) { + case opt::t_lt: t = a.mk_gt(t, s); break; + case opt::t_le: t = a.mk_ge(t, s); break; + case opt::t_eq: t = a.mk_eq(t, s); break; + } + fmls.push_back(t); + continue; + } 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())); + t = a.mk_mul(t, a.mk_numeral(v.m_coeff, a.is_int(t))); } ts.push_back(t); } - if (ts.empty()) { - continue; - } - s = a.mk_numeral(-r.m_coeff, r.m_coeff.is_int()); + s = a.mk_numeral(-r.m_coeff, a.is_int(t)); if (ts.size() == 1) { t = ts[0].get(); } diff --git a/src/qe/qsat.cpp b/src/qe/qsat.cpp index 4c6efdcd4..a409b23c2 100644 --- a/src/qe/qsat.cpp +++ b/src/qe/qsat.cpp @@ -534,34 +534,10 @@ namespace qe { m_solver->assert_expr(e); } - ptr_vector m_core; - void get_core(expr_ref_vector& core) { core.reset(); - m_core.reset(); - m_solver->get_unsat_core(m_core); - core.append(m_core.size(), m_core.c_ptr()); - -#if 0 - - mus mus(*m_solver); - for (unsigned i = 0; i < m_core.size(); ++i) { - VERIFY(i == mus.add_soft(m_core[i])); - } - unsigned_vector mus2; - core.reset(); - if (mus.get_mus(mus2) != l_undef) { - for (unsigned i = 0; i < mus2.size(); ++i) { - core.push_back(m_core[mus2[i]]); - } - } - std::cout << m_core.size() << " => " << core.size() << "\n"; -#endif - - TRACE("qe", tout << "core: " << core << "\n"; - m_solver->display(tout); - tout << "\n"; - ); + m_solver->get_unsat_core(core); + TRACE("qe", m_solver->display(tout << "core: " << core << "\n") << "\n";); } }; @@ -624,11 +600,14 @@ namespace qe { break; case l_false: switch (m_level) { - case 0: return l_false; + case 0: + return l_false; case 1: - if (m_mode == qsat_sat) return l_true; + if (m_mode == qsat_sat) { + return l_true; + } if (m_model.get()) { - project_qe(asms); + if (!project_qe(asms)) return l_undef; } else { pop(1); @@ -636,7 +615,7 @@ namespace qe { break; default: if (m_model.get()) { - project(asms); + if (!project(asms)) return l_undef; } else { pop(1); @@ -755,9 +734,42 @@ namespace qe { } } - void get_core(expr_ref_vector& core, unsigned level) { + bool get_core(expr_ref_vector& core, unsigned level) { get_kernel(level).get_core(core); m_pred_abs.pred2lit(core); + return true; + } + + bool minimize_core(expr_ref_vector& core, unsigned level) { + expr_ref_vector core1(m), core2(m), dels(m); + TRACE("qe", tout << core.size() << "\n";); + mus mus(get_kernel(level).s()); + for (unsigned i = 0; i < core.size(); ++i) { + app* a = to_app(core[i].get()); + max_level lvl = m_pred_abs.compute_level(a); + if (lvl.max() + 2 <= level) { + VERIFY(core1.size() == mus.add_soft(a)); + core1.push_back(a); + } + else { + core2.push_back(a); + mus.add_assumption(a); + } + } + TRACE("qe", tout << core1.size() << " " << core2.size() << "\n";); + if (core1.size() > 8) { + unsigned_vector core_idxs; + if (l_true != mus.get_mus(core_idxs)) { + return false; + } + TRACE("qe", tout << core1.size() << " -> " << core_idxs.size() << "\n";); + for (unsigned i = 0; i < core_idxs.size(); ++i) { + core2.push_back(core1[core_idxs[i]].get()); + } + core.reset(); + core.append(core2); + } + return true; } void check_cancel() { @@ -795,11 +807,13 @@ namespace qe { m_pred_abs.set_expr_level(b, lvl); } - void project_qe(expr_ref_vector& core) { + bool project_qe(expr_ref_vector& core) { SASSERT(m_level == 1); expr_ref fml(m); model& mdl = *m_model.get(); - get_core(core, m_level); + if (!get_core(core, m_level)) { + return false; + } SASSERT(validate_core(core)); get_vars(m_level); m_mbp(force_elim(), m_avars, mdl, core); @@ -814,10 +828,11 @@ namespace qe { m_free_vars.append(m_avars); pop(1); } + return true; } - void project(expr_ref_vector& core) { - get_core(core, m_level); + bool project(expr_ref_vector& core) { + if (!get_core(core, m_level)) return false; TRACE("qe", display(tout); display(tout << "core\n", core);); SASSERT(validate_core(core)); SASSERT(m_level >= 2); @@ -860,6 +875,7 @@ namespace qe { fml = m_pred_abs.mk_abstract(fml); get_kernel(m_level).assert_expr(fml); } + return true; } void get_vars(unsigned level) { @@ -990,14 +1006,15 @@ namespace qe { } bool validate_core(expr_ref_vector const& core) { + return true; +#if 0 TRACE("qe", tout << "Validate core\n";); solver& s = get_kernel(m_level).s(); expr_ref_vector fmls(m); fmls.append(core.size(), core.c_ptr()); - for (unsigned i = 0; i < s.get_num_assertions(); ++i) { - fmls.push_back(s.get_assertion(i)); - } + s.get_assertions(fmls); return check_fmls(fmls) || m.canceled(); +#endif } bool check_fmls(expr_ref_vector const& fmls) { @@ -1013,15 +1030,16 @@ namespace qe { } bool validate_model(expr_ref_vector const& asms) { + return true; +#if 0 TRACE("qe", tout << "Validate model\n";); solver& s = get_kernel(m_level).s(); expr_ref_vector fmls(m); - for (unsigned i = 0; i < s.get_num_assertions(); ++i) { - fmls.push_back(s.get_assertion(i)); - } + s.get_assertions(fmls); return validate_model(*m_model, asms.size(), asms.c_ptr()) && validate_model(*m_model, fmls.size(), fmls.c_ptr()); +#endif } bool validate_model(model& mdl, unsigned sz, expr* const* fmls) { @@ -1047,6 +1065,8 @@ namespace qe { // (core[model(vars)/vars] => proj) bool validate_project(model& mdl, expr_ref_vector const& core) { + return true; +#if 0 TRACE("qe", tout << "Validate projection\n";); if (!validate_model(mdl, core.size(), core.c_ptr())) return false; @@ -1090,6 +1110,7 @@ namespace qe { TRACE("qe", tout << "implication check failed, could be due to turning != into >\n";); } return true; +#endif } @@ -1159,7 +1180,6 @@ namespace qe { fml = push_not(fml); } hoist(fml); -// hoist_ite(fml); redundant provided theories understand to deal with ite terms. m_pred_abs.abstract_atoms(fml, defs); fml = m_pred_abs.mk_abstract(fml); m_ex.assert_expr(mk_and(defs)); @@ -1277,8 +1297,6 @@ 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) { @@ -1309,8 +1327,7 @@ namespace qe { 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/sat/sat_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp index 6d8b8c1d9..fb1c98a74 100644 --- a/src/sat/sat_solver/inc_sat_solver.cpp +++ b/src/sat/sat_solver/inc_sat_solver.cpp @@ -477,6 +477,6 @@ void inc_sat_display(std::ostream& out, solver& _s, unsigned sz, expr*const* sof } weights.push_back(_weights[i].get_unsigned()); } - return s.display_weighted(out, sz, soft, weights.c_ptr()); + s.display_weighted(out, sz, soft, weights.c_ptr()); } diff --git a/src/smt/smt_solver.cpp b/src/smt/smt_solver.cpp index 1778ce076..59c08006b 100644 --- a/src/smt/smt_solver.cpp +++ b/src/smt/smt_solver.cpp @@ -122,8 +122,9 @@ namespace smt { return m_context.get_formulas()[idx]; } - virtual void display(std::ostream & out) const { + virtual std::ostream& display(std::ostream & out) const { m_context.display(out); + return out; } }; diff --git a/src/solver/check_sat_result.h b/src/solver/check_sat_result.h index b981b3119..3da6b72a7 100644 --- a/src/solver/check_sat_result.h +++ b/src/solver/check_sat_result.h @@ -48,6 +48,11 @@ public: lbool status() const { return m_status; } virtual void collect_statistics(statistics & st) const = 0; virtual void get_unsat_core(ptr_vector & r) = 0; + virtual void get_unsat_core(expr_ref_vector & r) { + ptr_vector core; + get_unsat_core(core); + r.append(core.size(), core.c_ptr()); + } virtual void get_model(model_ref & m) = 0; virtual proof * get_proof() = 0; virtual std::string reason_unknown() const = 0; diff --git a/src/solver/combined_solver.cpp b/src/solver/combined_solver.cpp index 4e645116c..7db056396 100644 --- a/src/solver/combined_solver.cpp +++ b/src/solver/combined_solver.cpp @@ -262,8 +262,8 @@ public: return m_solver2->get_assumption(idx - c1); } - virtual void display(std::ostream & out) const { - m_solver1->display(out); + virtual std::ostream& display(std::ostream & out) const { + return m_solver1->display(out); } virtual void collect_statistics(statistics & st) const { diff --git a/src/solver/mus.cpp b/src/solver/mus.cpp index ebdffca13..4960a3d2a 100644 --- a/src/solver/mus.cpp +++ b/src/solver/mus.cpp @@ -26,40 +26,50 @@ Notes: struct mus::imp { - solver& m_s; + solver& m_solver; ast_manager& m; - expr_ref_vector m_cls2expr; - obj_map m_expr2cls; + expr_ref_vector m_lit2expr; + expr_ref_vector m_assumptions; + obj_map m_expr2lit; model_ref m_model; expr_ref_vector m_soft; vector m_weights; rational m_weight; imp(solver& s): - m_s(s), m(s.get_manager()), m_cls2expr(m), m_soft(m) + m_solver(s), m(s.get_manager()), m_lit2expr(m), m_assumptions(m), m_soft(m) {} void reset() { - m_cls2expr.reset(); - m_expr2cls.reset(); - } + m_lit2expr.reset(); + m_expr2lit.reset(); + m_assumptions.reset(); + } + + bool is_literal(expr* lit) const { + expr* l; + return is_uninterp_const(lit) || (m.is_not(lit, l) && is_uninterp_const(l)); + } - unsigned add_soft(expr* cls) { - SASSERT(is_uninterp_const(cls) || - (m.is_not(cls) && is_uninterp_const(to_app(cls)->get_arg(0)))); - unsigned idx = m_cls2expr.size(); - m_expr2cls.insert(cls, idx); - m_cls2expr.push_back(cls); - TRACE("opt", tout << idx << ": " << mk_pp(cls, m) << "\n"; - display_vec(tout, m_cls2expr);); + unsigned add_soft(expr* lit) { + SASSERT(is_literal(lit)); + unsigned idx = m_lit2expr.size(); + m_expr2lit.insert(lit, idx); + m_lit2expr.push_back(lit); + TRACE("opt", tout << idx << ": " << mk_pp(lit, m) << "\n" << m_lit2expr << "\n";); return idx; } + + void add_assumption(expr* lit) { + SASSERT(is_literal(lit)); + m_assumptions.push_back(lit); + } lbool get_mus(unsigned_vector& mus) { // SASSERT: mus does not have duplicates. m_model.reset(); unsigned_vector core; - for (unsigned i = 0; i < m_cls2expr.size(); ++i) { + for (unsigned i = 0; i < m_lit2expr.size(); ++i) { core.push_back(i); } if (core.size() == 1) { @@ -68,7 +78,7 @@ struct mus::imp { } mus.reset(); - if (core.size() > 64) { + if (false && core.size() > 64) { return qx(mus); } @@ -76,40 +86,40 @@ struct mus::imp { ptr_vector core_exprs; while (!core.empty()) { IF_VERBOSE(12, verbose_stream() << "(opt.mus reducing core: " << core.size() << " new core: " << mus.size() << ")\n";); - unsigned cls_id = core.back(); + unsigned lit_id = core.back(); TRACE("opt", display_vec(tout << "core: ", core); display_vec(tout << "mus: ", mus); ); core.pop_back(); - expr* cls = m_cls2expr[cls_id].get(); - expr_ref not_cls(m); - not_cls = mk_not(m, cls); + expr* lit = m_lit2expr[lit_id].get(); + expr_ref not_lit(m); + not_lit = mk_not(m, lit); lbool is_sat = l_undef; { - scoped_append _sa(*this, assumptions, core); - assumptions.push_back(not_cls); - is_sat = m_s.check_sat(assumptions); + scoped_append _sa1(*this, assumptions, core); + scoped_append _sa2(*this, assumptions, m_assumptions); + assumptions.push_back(not_lit); + is_sat = m_solver.check_sat(assumptions); } switch (is_sat) { case l_undef: return is_sat; case l_true: - assumptions.push_back(cls); - mus.push_back(cls_id); + assumptions.push_back(lit); + mus.push_back(lit_id); update_model(); break; default: core_exprs.reset(); - m_s.get_unsat_core(core_exprs); - if (!core_exprs.contains(not_cls)) { + m_solver.get_unsat_core(core_exprs); + if (!core_exprs.contains(not_lit)) { // core := core_exprs \ mus core.reset(); for (unsigned i = 0; i < core_exprs.size(); ++i) { - cls = core_exprs[i]; - cls_id = m_expr2cls.find(cls); - if (!mus.contains(cls_id)) { - core.push_back(cls_id); + lit = core_exprs[i]; + if (m_expr2lit.find(lit, lit_id) && !mus.contains(lit_id)) { + core.push_back(lit_id); } } TRACE("opt", display_vec(tout << "core exprs:", core_exprs); @@ -125,9 +135,9 @@ struct mus::imp { DEBUG_CODE( assumptions.reset(); for (unsigned i = 0; i < mus.size(); ++i) { - assumptions.push_back(m_cls2expr[mus[i]].get()); + assumptions.push_back(m_lit2expr[mus[i]].get()); } - lbool is_sat = m_s.check_sat(assumptions.size(), assumptions.c_ptr()); + lbool is_sat = m_solver.check_sat(assumptions.size(), assumptions.c_ptr()); SASSERT(is_sat == l_false); ); #endif @@ -142,7 +152,7 @@ struct mus::imp { m_fmls(fmls1), m_size(fmls1.size()) { for (unsigned i = 0; i < fmls2.size(); ++i) { - fmls1.push_back(imp.m_cls2expr[fmls2[i]].get()); + fmls1.push_back(imp.m_lit2expr[fmls2[i]].get()); } } scoped_append(imp& imp, expr_ref_vector& fmls1, uint_set const& fmls2): @@ -150,9 +160,14 @@ struct mus::imp { m_size(fmls1.size()) { uint_set::iterator it = fmls2.begin(), end = fmls2.end(); for (; it != end; ++it) { - fmls1.push_back(imp.m_cls2expr[*it].get()); + fmls1.push_back(imp.m_lit2expr[*it].get()); } } + scoped_append(imp& imp, expr_ref_vector& fmls1, expr_ref_vector const& fmls2): + m_fmls(fmls1), + m_size(fmls1.size()) { + fmls1.append(fmls2); + } ~scoped_append() { m_fmls.shrink(m_size); } @@ -160,7 +175,7 @@ struct mus::imp { void add_core(unsigned_vector const& core, expr_ref_vector& assumptions) { for (unsigned i = 0; i < core.size(); ++i) { - assumptions.push_back(m_cls2expr[core[i]].get()); + assumptions.push_back(m_lit2expr[core[i]].get()); } } @@ -199,7 +214,7 @@ struct mus::imp { if (m_soft.empty()) return; model_ref mdl; expr_ref tmp(m); - m_s.get_model(mdl); + m_solver.get_model(mdl); rational w; for (unsigned i = 0; i < m_soft.size(); ++i) { mdl->eval(m_soft[i].get(), tmp); @@ -221,7 +236,7 @@ struct mus::imp { lbool qx(unsigned_vector& mus) { uint_set core, support; - for (unsigned i = 0; i < m_cls2expr.size(); ++i) { + for (unsigned i = 0; i < m_lit2expr.size(); ++i) { core.insert(i); } lbool is_sat = qx(core, support, false); @@ -245,8 +260,9 @@ struct mus::imp { #endif if (has_support) { expr_ref_vector asms(m); - scoped_append _sa(*this, asms, support); - is_sat = m_s.check_sat(asms); + scoped_append _sa1(*this, asms, support); + scoped_append _sa2(*this, asms, m_assumptions); + is_sat = m_solver.check_sat(asms); switch (is_sat) { case l_false: { uint_set core; @@ -282,10 +298,12 @@ struct mus::imp { void get_core(uint_set& core) { ptr_vector core_exprs; - m_s.get_unsat_core(core_exprs); + unsigned lit_id; + m_solver.get_unsat_core(core_exprs); for (unsigned i = 0; i < core_exprs.size(); ++i) { - expr* cls = core_exprs[i]; - core.insert(m_expr2cls.find(cls)); + if (m_expr2lit.find(core_exprs[i], lit_id)) { + core.insert(lit_id); + } } } @@ -329,8 +347,12 @@ mus::~mus() { dealloc(m_imp); } -unsigned mus::add_soft(expr* cls) { - return m_imp->add_soft(cls); +unsigned mus::add_soft(expr* lit) { + return m_imp->add_soft(lit); +} + +void mus::add_assumption(expr* lit) { + return m_imp->add_assumption(lit); } lbool mus::get_mus(unsigned_vector& mus) { diff --git a/src/solver/mus.h b/src/solver/mus.h index d66049030..d2411b6ec 100644 --- a/src/solver/mus.h +++ b/src/solver/mus.h @@ -34,6 +34,15 @@ class mus { */ unsigned add_soft(expr* cls); + /** + Additional assumption for solver to be used along with solver context, + but not used in core computation. This facility is useful when querying + for a core over only a subset of soft constraints. It has the same + logical functionality as asserting 'lit' to the solver and pushing a scope + (and popping the scope before the solver is used for other constraints). + */ + void add_assumption(expr* lit); + lbool get_mus(unsigned_vector& mus); void reset(); diff --git a/src/solver/solver.cpp b/src/solver/solver.cpp index 59118c5ca..3bbe1c3fd 100644 --- a/src/solver/solver.cpp +++ b/src/solver/solver.cpp @@ -28,7 +28,13 @@ expr * solver::get_assertion(unsigned idx) const { return 0; } -void solver::display(std::ostream & out) const { - out << "(solver)"; +std::ostream& solver::display(std::ostream & out) const { + return out << "(solver)"; } +void solver::get_assertions(expr_ref_vector& fmls) const { + unsigned sz = get_num_assertions(); + for (unsigned i = 0; i < sz; ++i) { + fmls.push_back(get_assertion(i)); + } +} diff --git a/src/solver/solver.h b/src/solver/solver.h index 0b2578968..f320bec7c 100644 --- a/src/solver/solver.h +++ b/src/solver/solver.h @@ -79,6 +79,10 @@ public: for (unsigned i = 0; i < ts.size(); ++i) assert_expr(ts[i]); } + void assert_expr(ptr_vector const& ts) { + for (unsigned i = 0; i < ts.size(); ++i) assert_expr(ts[i]); + } + /** \brief Add a new formula \c t to the assertion stack, and "tag" it with \c a. The propositional variable \c a is used to track the use of \c t in a proof @@ -130,6 +134,11 @@ public: */ virtual expr * get_assertion(unsigned idx) const; + /** + \brief Retrieves assertions as a vector. + */ + void get_assertions(expr_ref_vector& fmls) const; + /** \brief The number of tracked assumptions (see assert_expr(t, a)). */ @@ -142,10 +151,11 @@ public: + /** \brief Display the content of this solver. */ - virtual void display(std::ostream & out) const; + virtual std::ostream& display(std::ostream & out) const; class scoped_push { solver& s; diff --git a/src/solver/tactic2solver.cpp b/src/solver/tactic2solver.cpp index 5235be230..56b246c1e 100644 --- a/src/solver/tactic2solver.cpp +++ b/src/solver/tactic2solver.cpp @@ -73,7 +73,7 @@ public: virtual unsigned get_num_assertions() const; virtual expr * get_assertion(unsigned idx) const; - virtual void display(std::ostream & out) const; + virtual std::ostream& display(std::ostream & out) const; virtual ast_manager& get_manager(); }; @@ -240,7 +240,7 @@ expr * tactic2solver::get_assertion(unsigned idx) const { return m_assertions.get(idx); } -void tactic2solver::display(std::ostream & out) const { +std::ostream& tactic2solver::display(std::ostream & out) const { ast_pp_util visitor(m_assertions.m()); visitor.collect(m_assertions); visitor.display_decls(out); @@ -254,6 +254,7 @@ void tactic2solver::display(std::ostream & out) const { } out << ")"; #endif + return out; } solver * mk_tactic2solver(ast_manager & m, From 27aa37946e56a4d9722de416791a2e40dc5d2054 Mon Sep 17 00:00:00 2001 From: George Karpenkov Date: Mon, 13 Jun 2016 12:09:34 +0200 Subject: [PATCH 029/536] Do not lock on context creation and deletion. --- src/api/java/Context.java | 24 +++++++----------------- 1 file changed, 7 insertions(+), 17 deletions(-) diff --git a/src/api/java/Context.java b/src/api/java/Context.java index 41fb027fe..e66920441 100644 --- a/src/api/java/Context.java +++ b/src/api/java/Context.java @@ -31,12 +31,7 @@ public class Context implements AutoCloseable { static final Object creation_lock = new Object(); public static Context mkContext() { - long m_ctx; - synchronized (creation_lock) { - m_ctx = Native.mkContextRc(0); - // TODO: then adding settings will not be under the lock. - } - return new Context(m_ctx); + return new Context(Native.mkContextRc(0)); } @@ -59,14 +54,11 @@ public class Context implements AutoCloseable { **/ public static Context mkContext(Map settings) { - long m_ctx; - synchronized (creation_lock) { - long cfg = Native.mkConfig(); - for (Map.Entry kv : settings.entrySet()) - Native.setParamValue(cfg, kv.getKey(), kv.getValue()); - m_ctx = Native.mkContextRc(cfg); - Native.delConfig(cfg); - } + long cfg = Native.mkConfig(); + for (Map.Entry kv : settings.entrySet()) + Native.setParamValue(cfg, kv.getKey(), kv.getValue()); + long m_ctx = Native.mkContextRc(cfg); + Native.delConfig(cfg); return new Context(m_ctx); } @@ -4047,8 +4039,6 @@ public class Context implements AutoCloseable { m_realSort = null; m_stringSort = null; - synchronized (creation_lock) { - Native.delContext(m_ctx); - } + Native.delContext(m_ctx); } } From 26d6c99aac2ecf1304f695c75540f47715e0ce6d Mon Sep 17 00:00:00 2001 From: George Karpenkov Date: Mon, 13 Jun 2016 12:11:03 +0200 Subject: [PATCH 030/536] Typo in Javadoc. --- src/api/java/IDecRefQueue.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/java/IDecRefQueue.java b/src/api/java/IDecRefQueue.java index b0a93b552..f3cea7249 100644 --- a/src/api/java/IDecRefQueue.java +++ b/src/api/java/IDecRefQueue.java @@ -46,7 +46,7 @@ public abstract class IDecRefQueue /** * An implementation of this method should decrement the reference on a * given native object. - * This function should be always called on the {@code ctx} thread. + * This function should always be called on the {@code ctx} thread. * * @param ctx Z3 context. * @param obj Pointer to a Z3 object. From a914822346179531cf36c79809e5f01842267c84 Mon Sep 17 00:00:00 2001 From: George Karpenkov Date: Mon, 13 Jun 2016 12:18:31 +0200 Subject: [PATCH 031/536] JavaAPI: DecRefQueue -- do not use move_limit for now. --- src/api/java/ASTDecRefQueue.java | 5 --- src/api/java/ApplyResultDecRefQueue.java | 5 --- src/api/java/AstMapDecRefQueue.java | 10 ++---- src/api/java/AstVectorDecRefQueue.java | 10 ++---- src/api/java/ConstructorDecRefQueue.java | 12 +++++++ src/api/java/ConstructorListDecRefQueue.java | 12 +++++++ src/api/java/Context.java | 34 ++++++++++---------- src/api/java/FixedpointDecRefQueue.java | 5 --- src/api/java/FuncInterpDecRefQueue.java | 5 --- src/api/java/FuncInterpEntryDecRefQueue.java | 10 ++---- src/api/java/GoalDecRefQueue.java | 10 ++---- src/api/java/IDecRefQueue.java | 23 ++++--------- src/api/java/ModelDecRefQueue.java | 10 ++---- src/api/java/OptimizeDecRefQueue.java | 5 --- src/api/java/ParamDescrsDecRefQueue.java | 9 ++---- src/api/java/ParamsDecRefQueue.java | 10 ++---- src/api/java/ProbeDecRefQueue.java | 5 --- src/api/java/SolverDecRefQueue.java | 10 ++---- src/api/java/StatisticsDecRefQueue.java | 10 ++---- src/api/java/TacticDecRefQueue.java | 5 --- 20 files changed, 65 insertions(+), 140 deletions(-) create mode 100644 src/api/java/ConstructorDecRefQueue.java create mode 100644 src/api/java/ConstructorListDecRefQueue.java diff --git a/src/api/java/ASTDecRefQueue.java b/src/api/java/ASTDecRefQueue.java index d462e16d5..b0a6fa217 100644 --- a/src/api/java/ASTDecRefQueue.java +++ b/src/api/java/ASTDecRefQueue.java @@ -24,11 +24,6 @@ class ASTDecRefQueue extends IDecRefQueue super(); } - public ASTDecRefQueue(int move_limit) - { - super(move_limit); - } - @Override protected void decRef(Context ctx, long obj) { Native.decRef(ctx.nCtx(), obj); diff --git a/src/api/java/ApplyResultDecRefQueue.java b/src/api/java/ApplyResultDecRefQueue.java index d28ff755e..e1a660781 100644 --- a/src/api/java/ApplyResultDecRefQueue.java +++ b/src/api/java/ApplyResultDecRefQueue.java @@ -24,11 +24,6 @@ class ApplyResultDecRefQueue extends IDecRefQueue super(); } - public ApplyResultDecRefQueue(int move_limit) - { - super(move_limit); - } - @Override protected void decRef(Context ctx, long obj) { Native.applyResultDecRef(ctx.nCtx(), obj); diff --git a/src/api/java/AstMapDecRefQueue.java b/src/api/java/AstMapDecRefQueue.java index 234b7eec4..6c96970b7 100644 --- a/src/api/java/AstMapDecRefQueue.java +++ b/src/api/java/AstMapDecRefQueue.java @@ -17,20 +17,14 @@ Notes: package com.microsoft.z3; -class ASTMapDecRefQueue extends IDecRefQueue -{ +class ASTMapDecRefQueue extends IDecRefQueue { public ASTMapDecRefQueue() { super(); } - public ASTMapDecRefQueue(int move_limit) - { - super(move_limit); - } - @Override protected void decRef(Context ctx, long obj) { Native.astMapDecRef(ctx.nCtx(), obj); } -}; +} diff --git a/src/api/java/AstVectorDecRefQueue.java b/src/api/java/AstVectorDecRefQueue.java index 3a486ee06..e7ce3e33e 100644 --- a/src/api/java/AstVectorDecRefQueue.java +++ b/src/api/java/AstVectorDecRefQueue.java @@ -17,20 +17,14 @@ Notes: package com.microsoft.z3; -class ASTVectorDecRefQueue extends IDecRefQueue -{ +class ASTVectorDecRefQueue extends IDecRefQueue { public ASTVectorDecRefQueue() { super(); } - public ASTVectorDecRefQueue(int move_limit) - { - super(move_limit); - } - @Override protected void decRef(Context ctx, long obj) { Native.astVectorDecRef(ctx.nCtx(), obj); } -}; +} diff --git a/src/api/java/ConstructorDecRefQueue.java b/src/api/java/ConstructorDecRefQueue.java new file mode 100644 index 000000000..5003dde5f --- /dev/null +++ b/src/api/java/ConstructorDecRefQueue.java @@ -0,0 +1,12 @@ +package com.microsoft.z3; + +public class ConstructorDecRefQueue extends IDecRefQueue { + public ConstructorDecRefQueue() { + super(); + } + + @Override + protected void decRef(Context ctx, long obj) { + Native.delConstructor(ctx.nCtx(), obj); + } +} diff --git a/src/api/java/ConstructorListDecRefQueue.java b/src/api/java/ConstructorListDecRefQueue.java new file mode 100644 index 000000000..1a2460731 --- /dev/null +++ b/src/api/java/ConstructorListDecRefQueue.java @@ -0,0 +1,12 @@ +package com.microsoft.z3; + +public class ConstructorListDecRefQueue extends IDecRefQueue { + public ConstructorListDecRefQueue() { + super(); + } + + @Override + protected void decRef(Context ctx, long obj) { + Native.delConstructorList(ctx.nCtx(), obj); + } +} diff --git a/src/api/java/Context.java b/src/api/java/Context.java index e66920441..1e2b5d4fa 100644 --- a/src/api/java/Context.java +++ b/src/api/java/Context.java @@ -3905,24 +3905,24 @@ public class Context implements AutoCloseable { } private ASTDecRefQueue m_AST_DRQ = new ASTDecRefQueue(); - private ASTMapDecRefQueue m_ASTMap_DRQ = new ASTMapDecRefQueue(10); - private ASTVectorDecRefQueue m_ASTVector_DRQ = new ASTVectorDecRefQueue(10); - private ApplyResultDecRefQueue m_ApplyResult_DRQ = new ApplyResultDecRefQueue(10); - private FuncInterpEntryDecRefQueue m_FuncEntry_DRQ = new FuncInterpEntryDecRefQueue(10); - private FuncInterpDecRefQueue m_FuncInterp_DRQ = new FuncInterpDecRefQueue(10); - private GoalDecRefQueue m_Goal_DRQ = new GoalDecRefQueue(10); - private ModelDecRefQueue m_Model_DRQ = new ModelDecRefQueue(10); - private ParamsDecRefQueue m_Params_DRQ = new ParamsDecRefQueue(10); - private ParamDescrsDecRefQueue m_ParamDescrs_DRQ = new ParamDescrsDecRefQueue(10); - private ProbeDecRefQueue m_Probe_DRQ = new ProbeDecRefQueue(10); - private SolverDecRefQueue m_Solver_DRQ = new SolverDecRefQueue(10); - private StatisticsDecRefQueue m_Statistics_DRQ = new StatisticsDecRefQueue(10); - private TacticDecRefQueue m_Tactic_DRQ = new TacticDecRefQueue(10); - private FixedpointDecRefQueue m_Fixedpoint_DRQ = new FixedpointDecRefQueue(10); - private OptimizeDecRefQueue m_Optimize_DRQ = new OptimizeDecRefQueue(10); - private ConstructorDecRefQueue m_Constructor_DRQ = new ConstructorDecRefQueue(10); + private ASTMapDecRefQueue m_ASTMap_DRQ = new ASTMapDecRefQueue(); + private ASTVectorDecRefQueue m_ASTVector_DRQ = new ASTVectorDecRefQueue(); + private ApplyResultDecRefQueue m_ApplyResult_DRQ = new ApplyResultDecRefQueue(); + private FuncInterpEntryDecRefQueue m_FuncEntry_DRQ = new FuncInterpEntryDecRefQueue(); + private FuncInterpDecRefQueue m_FuncInterp_DRQ = new FuncInterpDecRefQueue(); + private GoalDecRefQueue m_Goal_DRQ = new GoalDecRefQueue(); + private ModelDecRefQueue m_Model_DRQ = new ModelDecRefQueue(); + private ParamsDecRefQueue m_Params_DRQ = new ParamsDecRefQueue(); + private ParamDescrsDecRefQueue m_ParamDescrs_DRQ = new ParamDescrsDecRefQueue(); + private ProbeDecRefQueue m_Probe_DRQ = new ProbeDecRefQueue(); + private SolverDecRefQueue m_Solver_DRQ = new SolverDecRefQueue(); + private StatisticsDecRefQueue m_Statistics_DRQ = new StatisticsDecRefQueue(); + private TacticDecRefQueue m_Tactic_DRQ = new TacticDecRefQueue(); + private FixedpointDecRefQueue m_Fixedpoint_DRQ = new FixedpointDecRefQueue(); + private OptimizeDecRefQueue m_Optimize_DRQ = new OptimizeDecRefQueue(); + private ConstructorDecRefQueue m_Constructor_DRQ = new ConstructorDecRefQueue(); private ConstructorListDecRefQueue m_ConstructorList_DRQ = - new ConstructorListDecRefQueue(10); + new ConstructorListDecRefQueue(); public IDecRefQueue getConstructorDRQ() { return m_Constructor_DRQ; diff --git a/src/api/java/FixedpointDecRefQueue.java b/src/api/java/FixedpointDecRefQueue.java index 3cba67ced..69ed82092 100644 --- a/src/api/java/FixedpointDecRefQueue.java +++ b/src/api/java/FixedpointDecRefQueue.java @@ -23,11 +23,6 @@ class FixedpointDecRefQueue extends IDecRefQueue { super(); } - public FixedpointDecRefQueue(int move_limit) - { - super(move_limit); - } - @Override protected void decRef(Context ctx, long obj) { diff --git a/src/api/java/FuncInterpDecRefQueue.java b/src/api/java/FuncInterpDecRefQueue.java index 136c07b6a..d8715bd0e 100644 --- a/src/api/java/FuncInterpDecRefQueue.java +++ b/src/api/java/FuncInterpDecRefQueue.java @@ -24,11 +24,6 @@ class FuncInterpDecRefQueue extends IDecRefQueue super(); } - public FuncInterpDecRefQueue(int move_limit) - { - super(move_limit); - } - @Override protected void decRef(Context ctx, long obj) { Native.funcInterpDecRef(ctx.nCtx(), obj); diff --git a/src/api/java/FuncInterpEntryDecRefQueue.java b/src/api/java/FuncInterpEntryDecRefQueue.java index 8f6741ba0..a4d8a0690 100644 --- a/src/api/java/FuncInterpEntryDecRefQueue.java +++ b/src/api/java/FuncInterpEntryDecRefQueue.java @@ -17,20 +17,14 @@ Notes: package com.microsoft.z3; -class FuncInterpEntryDecRefQueue extends IDecRefQueue -{ +class FuncInterpEntryDecRefQueue extends IDecRefQueue { public FuncInterpEntryDecRefQueue() { super(); } - public FuncInterpEntryDecRefQueue(int move_limit) - { - super(move_limit); - } - @Override protected void decRef(Context ctx, long obj) { Native.funcEntryDecRef(ctx.nCtx(), obj); } -}; +} diff --git a/src/api/java/GoalDecRefQueue.java b/src/api/java/GoalDecRefQueue.java index 724ec003f..90bad1fb1 100644 --- a/src/api/java/GoalDecRefQueue.java +++ b/src/api/java/GoalDecRefQueue.java @@ -17,20 +17,14 @@ Notes: package com.microsoft.z3; -class GoalDecRefQueue extends IDecRefQueue -{ +class GoalDecRefQueue extends IDecRefQueue { public GoalDecRefQueue() { super(); } - public GoalDecRefQueue(int move_limit) - { - super(move_limit); - } - @Override protected void decRef(Context ctx, long obj) { Native.goalDecRef(ctx.nCtx(), obj); } -}; +} diff --git a/src/api/java/IDecRefQueue.java b/src/api/java/IDecRefQueue.java index f3cea7249..5a80adf5f 100644 --- a/src/api/java/IDecRefQueue.java +++ b/src/api/java/IDecRefQueue.java @@ -23,25 +23,16 @@ import java.lang.ref.ReferenceQueue; import java.util.IdentityHashMap; import java.util.Map; -public abstract class IDecRefQueue -{ - private final int m_move_limit; - - // TODO: problem: ReferenceQueue has no API to return length. +/** + * + * @param + */ +public abstract class IDecRefQueue { private final ReferenceQueue referenceQueue = new ReferenceQueue<>(); - private int queueSize = 0; private final Map, Long> referenceMap = new IdentityHashMap<>(); - protected IDecRefQueue() - { - m_move_limit = 1024; - } - - protected IDecRefQueue(int move_limit) - { - m_move_limit = move_limit; - } + protected IDecRefQueue() {} /** * An implementation of this method should decrement the reference on a @@ -56,8 +47,6 @@ public abstract class IDecRefQueue public void storeReference(Context ctx, T obj) { PhantomReference ref = new PhantomReference<>(obj, referenceQueue); referenceMap.put(ref, obj.getNativeObject()); - - // TODO: use move_limit, somehow get the size of referenceQueue. clear(ctx); } diff --git a/src/api/java/ModelDecRefQueue.java b/src/api/java/ModelDecRefQueue.java index 6b141078e..f1b7c3fdd 100644 --- a/src/api/java/ModelDecRefQueue.java +++ b/src/api/java/ModelDecRefQueue.java @@ -17,20 +17,14 @@ Notes: package com.microsoft.z3; -class ModelDecRefQueue extends IDecRefQueue -{ +class ModelDecRefQueue extends IDecRefQueue { public ModelDecRefQueue() { super(); } - public ModelDecRefQueue(int move_limit) - { - super(move_limit); - } - @Override protected void decRef(Context ctx, long obj) { Native.modelDecRef(ctx.nCtx(), obj); } -}; +} diff --git a/src/api/java/OptimizeDecRefQueue.java b/src/api/java/OptimizeDecRefQueue.java index a06165f3e..0acf20068 100644 --- a/src/api/java/OptimizeDecRefQueue.java +++ b/src/api/java/OptimizeDecRefQueue.java @@ -23,11 +23,6 @@ class OptimizeDecRefQueue extends IDecRefQueue { super(); } - public OptimizeDecRefQueue(int move_limit) - { - super(move_limit); - } - @Override protected void decRef(Context ctx, long obj) { Native.optimizeDecRef(ctx.nCtx(), obj); diff --git a/src/api/java/ParamDescrsDecRefQueue.java b/src/api/java/ParamDescrsDecRefQueue.java index ab7f4ddd6..ee3257db9 100644 --- a/src/api/java/ParamDescrsDecRefQueue.java +++ b/src/api/java/ParamDescrsDecRefQueue.java @@ -17,20 +17,15 @@ Notes: package com.microsoft.z3; -class ParamDescrsDecRefQueue extends IDecRefQueue -{ +class ParamDescrsDecRefQueue extends IDecRefQueue { public ParamDescrsDecRefQueue() { super(); } - public ParamDescrsDecRefQueue(int move_limit) { - super(move_limit); - } - @Override protected void decRef(Context ctx, long obj) { Native.paramDescrsDecRef(ctx.nCtx(), obj); } -}; +} diff --git a/src/api/java/ParamsDecRefQueue.java b/src/api/java/ParamsDecRefQueue.java index b5281ecbc..349713f67 100644 --- a/src/api/java/ParamsDecRefQueue.java +++ b/src/api/java/ParamsDecRefQueue.java @@ -17,20 +17,14 @@ Notes: package com.microsoft.z3; -class ParamsDecRefQueue extends IDecRefQueue -{ +class ParamsDecRefQueue extends IDecRefQueue { public ParamsDecRefQueue() { super(); } - public ParamsDecRefQueue(int move_limit) - { - super(move_limit); - } - @Override protected void decRef(Context ctx, long obj) { Native.paramsDecRef(ctx.nCtx(), obj); } -}; +} diff --git a/src/api/java/ProbeDecRefQueue.java b/src/api/java/ProbeDecRefQueue.java index 3f78c6288..b25446c0c 100644 --- a/src/api/java/ProbeDecRefQueue.java +++ b/src/api/java/ProbeDecRefQueue.java @@ -24,11 +24,6 @@ class ProbeDecRefQueue extends IDecRefQueue super(); } - public ProbeDecRefQueue(int move_limit) - { - super(move_limit); - } - @Override protected void decRef(Context ctx, long obj) { diff --git a/src/api/java/SolverDecRefQueue.java b/src/api/java/SolverDecRefQueue.java index 106892fec..efa15d939 100644 --- a/src/api/java/SolverDecRefQueue.java +++ b/src/api/java/SolverDecRefQueue.java @@ -17,17 +17,11 @@ Notes: package com.microsoft.z3; -class SolverDecRefQueue extends IDecRefQueue -{ +class SolverDecRefQueue extends IDecRefQueue { public SolverDecRefQueue() { super(); } - public SolverDecRefQueue(int move_limit) - { - super(move_limit); - } - @Override protected void decRef(Context ctx, long obj) { Native.solverDecRef(ctx.nCtx(), obj); } -}; +} diff --git a/src/api/java/StatisticsDecRefQueue.java b/src/api/java/StatisticsDecRefQueue.java index fecf52267..ed698e4ca 100644 --- a/src/api/java/StatisticsDecRefQueue.java +++ b/src/api/java/StatisticsDecRefQueue.java @@ -17,20 +17,14 @@ Notes: package com.microsoft.z3; -class StatisticsDecRefQueue extends IDecRefQueue -{ +class StatisticsDecRefQueue extends IDecRefQueue { public StatisticsDecRefQueue() { super(); } - public StatisticsDecRefQueue(int move_limit) - { - super(move_limit); - } - @Override protected void decRef(Context ctx, long obj) { Native.statsDecRef(ctx.nCtx(), obj); } -}; +} diff --git a/src/api/java/TacticDecRefQueue.java b/src/api/java/TacticDecRefQueue.java index 079904175..8f151f25c 100644 --- a/src/api/java/TacticDecRefQueue.java +++ b/src/api/java/TacticDecRefQueue.java @@ -23,11 +23,6 @@ class TacticDecRefQueue extends IDecRefQueue { super(); } - public TacticDecRefQueue(int move_limit) - { - super(move_limit); - } - @Override protected void decRef(Context ctx, long obj) { From b65d83aacfea8adacebe7d2919c55bdedb475a8c Mon Sep 17 00:00:00 2001 From: George Karpenkov Date: Mon, 13 Jun 2016 12:22:32 +0200 Subject: [PATCH 032/536] Java API: explain the phantom references mechanics in Javadoc. --- src/api/java/IDecRefQueue.java | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/api/java/IDecRefQueue.java b/src/api/java/IDecRefQueue.java index 5a80adf5f..2deb9c0f9 100644 --- a/src/api/java/IDecRefQueue.java +++ b/src/api/java/IDecRefQueue.java @@ -24,8 +24,17 @@ import java.util.IdentityHashMap; import java.util.Map; /** + * A queue to handle management of native memory. * - * @param + *

Mechanics: once an object is created, a metadata is stored for it in + * {@code referenceMap}, and a {@link PhantomReference} is created with a + * reference to {@code referenceQueue}. + * Once the object becomes strongly unreachable, the phantom reference gets + * added by JVM to the {@code referenceQueue}. + * After each object creation, we iterate through the available objects in + * {@code referenceQueue} and decrement references for them. + * + * @param Type of object stored in queue. */ public abstract class IDecRefQueue { private final ReferenceQueue referenceQueue = new ReferenceQueue<>(); From 16ad33bf399d1b9aa1e333bbb89b560ffc868632 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 13 Jun 2016 18:15:51 -0700 Subject: [PATCH 033/536] add collection of statistics #652 Signed-off-by: Nikolaj Bjorner --- contrib/cmake/src/tactic/core/CMakeLists.txt | 1 + src/tactic/probe.cpp | 16 ++++++++-------- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/contrib/cmake/src/tactic/core/CMakeLists.txt b/contrib/cmake/src/tactic/core/CMakeLists.txt index ed3a84edf..fcd26bd84 100644 --- a/contrib/cmake/src/tactic/core/CMakeLists.txt +++ b/contrib/cmake/src/tactic/core/CMakeLists.txt @@ -3,6 +3,7 @@ z3_add_component(core_tactics blast_term_ite_tactic.cpp cofactor_elim_term_ite.cpp cofactor_term_ite_tactic.cpp + collect_statistics_tactic.cpp ctx_simplify_tactic.cpp der_tactic.cpp distribute_forall_tactic.cpp diff --git a/src/tactic/probe.cpp b/src/tactic/probe.cpp index ecc27eccf..677438cdf 100644 --- a/src/tactic/probe.cpp +++ b/src/tactic/probe.cpp @@ -287,14 +287,14 @@ struct is_non_qfbv_predicate { if (fid == m.get_basic_family_id()) return; if (fid == u.get_family_id()) { - if (n->get_decl_kind() == OP_BSDIV0 || - n->get_decl_kind() == OP_BUDIV0 || - n->get_decl_kind() == OP_BSREM0 || - n->get_decl_kind() == OP_BUREM0 || - n->get_decl_kind() == OP_BSMOD0) - throw found(); - return; - } + if (n->get_decl_kind() == OP_BSDIV0 || + n->get_decl_kind() == OP_BUDIV0 || + n->get_decl_kind() == OP_BSREM0 || + n->get_decl_kind() == OP_BUREM0 || + n->get_decl_kind() == OP_BSMOD0) + throw found(); + return; + } if (is_uninterp_const(n)) return; throw found(); From b11f9050e370376e43bd76f70ce5abb11da3ff6e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 13 Jun 2016 18:20:25 -0700 Subject: [PATCH 034/536] fix bugs exposed from bad indentation warnings, #650 Signed-off-by: Nikolaj Bjorner --- src/muz/pdr/pdr_reachable_cache.cpp | 7 ++++++- src/smt/theory_fpa.cpp | 5 ++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/muz/pdr/pdr_reachable_cache.cpp b/src/muz/pdr/pdr_reachable_cache.cpp index 85100c19f..2bedc1393 100644 --- a/src/muz/pdr/pdr_reachable_cache.cpp +++ b/src/muz/pdr/pdr_reachable_cache.cpp @@ -109,7 +109,12 @@ namespace pdr { UNREACHABLE(); break; } - if (found) m_stats.m_hits++; m_stats.m_miss++; + if (found) { + m_stats.m_hits++; + } + else { + m_stats.m_miss++; + } return found; } diff --git a/src/smt/theory_fpa.cpp b/src/smt/theory_fpa.cpp index 8e96c925d..ee7559500 100644 --- a/src/smt/theory_fpa.cpp +++ b/src/smt/theory_fpa.cpp @@ -691,7 +691,10 @@ namespace smt { m_rw.reset(); m_th_rw.reset(); m_trail_stack.pop_scope(m_trail_stack.get_num_scopes()); - if (m_factory) dealloc(m_factory); m_factory = 0; + if (m_factory) { + dealloc(m_factory); + m_factory = 0; + } ast_manager & m = get_manager(); dec_ref_map_key_values(m, m_conversions); dec_ref_collection_values(m, m_is_added_to_model); From 3ea71b4b25739cae6fa432038c0251e75c2f0fdf Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Tue, 14 Jun 2016 12:49:48 +0100 Subject: [PATCH 035/536] Fixed SMT2 scanner to allow 0xFF characters. Thanks to Santiago Zanella-Beguelin for reporting this issue. --- src/parsers/smt2/smt2scanner.cpp | 25 +++++++++++++++---------- src/parsers/smt2/smt2scanner.h | 1 + 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/src/parsers/smt2/smt2scanner.cpp b/src/parsers/smt2/smt2scanner.cpp index 156cc2e5d..911f449dc 100644 --- a/src/parsers/smt2/smt2scanner.cpp +++ b/src/parsers/smt2/smt2scanner.cpp @@ -23,10 +23,12 @@ namespace smt2 { void scanner::next() { if (m_cache_input) - m_cache.push_back(m_curr); - SASSERT(m_curr != EOF); + m_cache.push_back(m_curr); + SASSERT(!m_at_eof); if (m_interactive) { m_curr = m_stream.get(); + if (m_stream.eof()) + m_at_eof = true; } else if (m_bpos < m_bend) { m_curr = m_buffer[m_bpos]; @@ -37,7 +39,7 @@ namespace smt2 { m_bend = static_cast(m_stream.gcount()); m_bpos = 0; if (m_bpos == m_bend) { - m_curr = EOF; + m_at_eof = true; } else { m_curr = m_buffer[m_bpos]; @@ -52,7 +54,7 @@ namespace smt2 { next(); while (true) { char c = curr(); - if (c == EOF) + if (m_at_eof) return; if (c == '\n') { new_line(); @@ -70,7 +72,7 @@ namespace smt2 { next(); while (true) { char c = curr(); - if (c == EOF) { + if (m_at_eof) { throw scanner_exception("unexpected end of quoted symbol", m_line, m_spos); } else if (c == '\n') { @@ -167,7 +169,7 @@ namespace smt2 { m_string.reset(); while (true) { char c = curr(); - if (c == EOF) + if (m_at_eof) throw scanner_exception("unexpected end of string", m_line, m_spos); if (c == '\n') { new_line(); @@ -237,10 +239,11 @@ namespace smt2 { } } - scanner::scanner(cmd_context & ctx, std::istream& stream, bool interactive): + scanner::scanner(cmd_context & ctx, std::istream& stream, bool interactive) : m_interactive(interactive), m_spos(0), m_curr(0), // avoid Valgrind warning + m_at_eof(false), m_line(1), m_pos(0), m_bv_size(UINT_MAX), @@ -289,9 +292,13 @@ namespace smt2 { } scanner::token scanner::scan() { - while (true) { + while (true) { signed char c = curr(); m_pos = m_spos; + + if (m_at_eof) + return EOF_TOKEN; + switch (m_normalized[(unsigned char) c]) { case ' ': next(); @@ -327,8 +334,6 @@ namespace smt2 { return read_symbol(); else return read_signed_number(); - case -1: - return EOF_TOKEN; default: { scanner_exception ex("unexpected character", m_line, m_spos); next(); diff --git a/src/parsers/smt2/smt2scanner.h b/src/parsers/smt2/smt2scanner.h index 8313c24df..3ad47dfb1 100644 --- a/src/parsers/smt2/smt2scanner.h +++ b/src/parsers/smt2/smt2scanner.h @@ -34,6 +34,7 @@ namespace smt2 { bool m_interactive; int m_spos; // position in the current line of the stream char m_curr; // current char; + bool m_at_eof; int m_line; // line int m_pos; // start position of the token From 9253ca9d863d8bcdac809593739c01348e5644b3 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 14 Jun 2016 08:10:10 -0700 Subject: [PATCH 036/536] make use of warning_msg safe for formatting. Thanks to Scott McPeak for reporting Signed-off-by: Nikolaj Bjorner --- src/api/api_config_params.cpp | 6 +++--- src/ast/ast.cpp | 2 +- src/ast/well_sorted.cpp | 2 +- src/muz/rel/dl_base.cpp | 2 +- src/parsers/smt2/smt2parser.cpp | 2 +- src/smt/theory_utvpi_def.h | 2 +- src/util/warning.cpp | 1 - 7 files changed, 8 insertions(+), 9 deletions(-) diff --git a/src/api/api_config_params.cpp b/src/api/api_config_params.cpp index 5b385a872..a04a9f12c 100644 --- a/src/api/api_config_params.cpp +++ b/src/api/api_config_params.cpp @@ -37,7 +37,7 @@ extern "C" { catch (z3_exception & ex) { // The error handler is only available for contexts // Just throw a warning. - warning_msg(ex.msg()); + warning_msg("%s", ex.msg()); } } @@ -62,7 +62,7 @@ extern "C" { catch (z3_exception & ex) { // The error handler is only available for contexts // Just throw a warning. - warning_msg(ex.msg()); + warning_msg("%s", ex.msg()); return Z3_FALSE; } } @@ -88,7 +88,7 @@ extern "C" { catch (z3_exception & ex) { // The error handler is only available for contexts // Just throw a warning. - warning_msg(ex.msg()); + warning_msg("%s", ex.msg()); } } diff --git a/src/ast/ast.cpp b/src/ast/ast.cpp index 507f75482..4e505f977 100644 --- a/src/ast/ast.cpp +++ b/src/ast/ast.cpp @@ -1965,7 +1965,7 @@ bool ast_manager::check_sorts(ast const * n) const { return true; } catch (ast_exception & ex) { - warning_msg(ex.msg()); + warning_msg("%s", ex.msg()); return false; } } diff --git a/src/ast/well_sorted.cpp b/src/ast/well_sorted.cpp index f9f04a2df..cb9ee3f61 100644 --- a/src/ast/well_sorted.cpp +++ b/src/ast/well_sorted.cpp @@ -66,7 +66,7 @@ struct well_sorted_proc { strm << "Expected sort: " << mk_pp(expected_sort, m_manager) << "\n"; strm << "Actual sort: " << mk_pp(actual_sort, m_manager) << "\n"; strm << "Function sort: " << mk_pp(decl, m_manager) << "."; - warning_msg(strm.str().c_str()); + warning_msg("%s", strm.str().c_str()); m_error = true; return; } diff --git a/src/muz/rel/dl_base.cpp b/src/muz/rel/dl_base.cpp index b7f4d6cef..f79f6c8eb 100644 --- a/src/muz/rel/dl_base.cpp +++ b/src/muz/rel/dl_base.cpp @@ -391,7 +391,7 @@ namespace datalog { std::ostringstream buffer; buffer << "creating large table of size " << upper_bound; if (p) buffer << " for relation " << p->get_name(); - warning_msg(buffer.str().c_str()); + warning_msg("%s", buffer.str().c_str()); } for(table_element i = 0; i < upper_bound; i++) { diff --git a/src/parsers/smt2/smt2parser.cpp b/src/parsers/smt2/smt2parser.cpp index 17a931cc3..00f63afd5 100644 --- a/src/parsers/smt2/smt2parser.cpp +++ b/src/parsers/smt2/smt2parser.cpp @@ -1034,7 +1034,7 @@ namespace smt2 { else { std::ostringstream str; str << "unknown attribute " << id; - warning_msg(str.str().c_str()); + warning_msg("%s", str.str().c_str()); next(); // just consume the consume_sexpr(); diff --git a/src/smt/theory_utvpi_def.h b/src/smt/theory_utvpi_def.h index d5ed4e825..ff295d5a3 100644 --- a/src/smt/theory_utvpi_def.h +++ b/src/smt/theory_utvpi_def.h @@ -250,7 +250,7 @@ namespace smt { std::stringstream msg; msg << "found non utvpi logic expression:\n" << mk_pp(n, get_manager()) << "\n"; TRACE("utvpi", tout << msg.str();); - warning_msg(msg.str().c_str()); + warning_msg("%s", msg.str().c_str()); get_context().push_trail(value_trail(m_non_utvpi_exprs)); m_non_utvpi_exprs = true; } diff --git a/src/util/warning.cpp b/src/util/warning.cpp index 1105a12f7..ed4cd8725 100644 --- a/src/util/warning.cpp +++ b/src/util/warning.cpp @@ -167,4 +167,3 @@ void warning_msg(const char * msg, ...) { va_end(args); } } - From bfe26390f01665c48f1cb2e9a297432bd0e06eba Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 14 Jun 2016 08:12:32 -0700 Subject: [PATCH 037/536] fix bug introduced when hiding unused variables in 96e157e, reported by Mikolas Janota Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/bv_trailing.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/ast/rewriter/bv_trailing.cpp b/src/ast/rewriter/bv_trailing.cpp index cf50ab0e2..31e9121ec 100644 --- a/src/ast/rewriter/bv_trailing.cpp +++ b/src/ast/rewriter/bv_trailing.cpp @@ -67,10 +67,8 @@ struct bv_trailing::imp { } expr_ref out1(m); expr_ref out2(m); - DEBUG_CODE( - const unsigned rm1 = remove_trailing(e1, min, out1, TRAILING_DEPTH); - const unsigned rm2 = remove_trailing(e2, min, out2, TRAILING_DEPTH); - SASSERT(rm1 == min && rm2 == min);); + VERIFY(min == remove_trailing(e1, min, out1, TRAILING_DEPTH)); + VERIFY(min == remove_trailing(e2, min, out2, TRAILING_DEPTH)); const bool are_eq = m.are_equal(out1, out2); result = are_eq ? m.mk_true() : m.mk_eq(out1, out2); return are_eq ? BR_DONE : BR_REWRITE2; From b086aac45ff1069159f35bd5243ca6d479963ebc Mon Sep 17 00:00:00 2001 From: George Karpenkov Date: Thu, 16 Jun 2016 18:21:55 +0200 Subject: [PATCH 038/536] Use constructors instead of static methods for Context.java. --- src/api/java/Context.java | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/src/api/java/Context.java b/src/api/java/Context.java index 1e2b5d4fa..39d35d9d3 100644 --- a/src/api/java/Context.java +++ b/src/api/java/Context.java @@ -30,8 +30,9 @@ public class Context implements AutoCloseable { private final long m_ctx; static final Object creation_lock = new Object(); - public static Context mkContext() { - return new Context(Native.mkContextRc(0)); + public Context () { + m_ctx = Native.mkContextRc(0); + init(); } @@ -52,24 +53,17 @@ public class Context implements AutoCloseable { * Note that in previous versions of Z3, this constructor was also used to set global and * module parameters. For this purpose we should now use {@code Global.setParameter} **/ - public static Context mkContext(Map settings) - { + public Context(Map settings) { long cfg = Native.mkConfig(); - for (Map.Entry kv : settings.entrySet()) + for (Map.Entry kv : settings.entrySet()) { Native.setParamValue(cfg, kv.getKey(), kv.getValue()); - long m_ctx = Native.mkContextRc(cfg); + } + m_ctx = Native.mkContextRc(cfg); Native.delConfig(cfg); - return new Context(m_ctx); + init(); } - /** - * Constructor. - **/ - protected Context(long m_ctx) - { - this.m_ctx = m_ctx; - - // Code which used to be in "initContext". + private void init() { setPrintMode(Z3_ast_print_mode.Z3_PRINT_SMTLIB2_COMPLIANT); Native.setInternalErrorHandler(m_ctx); } From 9c099d6b1bf499f5bf548279590fb4d6e9af3a8c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 20 Jun 2016 16:39:03 -0700 Subject: [PATCH 039/536] fix mb maximization logic, so far not accessible Signed-off-by: Nikolaj Bjorner --- src/math/simplex/model_based_opt.cpp | 149 ++++++++++++++++++--------- src/math/simplex/model_based_opt.h | 14 ++- src/opt/opt_context.cpp | 8 +- src/opt/opt_params.pyg | 3 +- src/qe/qe_arith.cpp | 63 ++++++++--- src/qe/qe_arith.h | 2 +- src/qe/qe_mbp.cpp | 19 +++- src/qe/qe_mbp.h | 2 +- src/qe/qsat.cpp | 127 ++++++++++++++++++++--- src/qe/qsat.h | 2 + src/smt/smt_context.h | 2 - src/smt/smt_model_checker.cpp | 36 ++++--- 12 files changed, 318 insertions(+), 109 deletions(-) diff --git a/src/math/simplex/model_based_opt.cpp b/src/math/simplex/model_based_opt.cpp index 06ba38b4a..c4e4b110e 100644 --- a/src/math/simplex/model_based_opt.cpp +++ b/src/math/simplex/model_based_opt.cpp @@ -41,7 +41,6 @@ namespace opt { bool model_based_opt::invariant() { - // variables in each row are sorted. for (unsigned i = 0; i < m_rows.size(); ++i) { if (!invariant(i, m_rows[i])) { return false; @@ -50,19 +49,21 @@ namespace opt { return true; } +#define PASSERT(_e_) if (!(_e_)) { TRACE("opt", display(tout, r);); SASSERT(_e_); } + bool model_based_opt::invariant(unsigned index, row const& r) { - rational val = r.m_coeff; vector const& vars = r.m_vars; for (unsigned i = 0; i < vars.size(); ++i) { - var const& v = vars[i]; - SASSERT(i + 1 == vars.size() || v.m_id < vars[i+1].m_id); - SASSERT(!v.m_coeff.is_zero()); - val += v.m_coeff * m_var2value[v.m_id]; + // variables in each row are sorted and have non-zero coefficients + SASSERT(i + 1 == vars.size() || vars[i].m_id < vars[i+1].m_id); + SASSERT(!vars[i].m_coeff.is_zero()); } - SASSERT(val == r.m_value); - SASSERT(r.m_type != t_eq || val.is_zero()); - SASSERT(index == 0 || r.m_type != t_lt || val.is_neg()); - SASSERT(index == 0 || r.m_type != t_le || !val.is_pos()); + + PASSERT(r.m_value == get_row_value(r)); + PASSERT(r.m_type != t_eq || r.m_value.is_zero()); + // values satisfy constraints + PASSERT(index == 0 || r.m_type != t_lt || r.m_value.is_neg()); + PASSERT(index == 0 || r.m_type != t_le || !r.m_value.is_pos()); return true; } @@ -90,20 +91,25 @@ namespace opt { // inf_eps model_based_opt::maximize() { SASSERT(invariant()); - unsigned_vector other; unsigned_vector bound_trail, bound_vars; + TRACE("opt", display(tout << "tableau\n");); while (!objective().m_vars.empty()) { - TRACE("opt", display(tout << "tableau\n");); var v = objective().m_vars.back(); unsigned x = v.m_id; rational const& coeff = v.m_coeff; unsigned bound_row_index; rational bound_coeff; - other.reset(); - if (find_bound(x, bound_row_index, bound_coeff, other, coeff.is_pos())) { + if (find_bound(x, bound_row_index, bound_coeff, coeff.is_pos())) { SASSERT(!bound_coeff.is_zero()); - for (unsigned i = 0; i < other.size(); ++i) { - resolve(bound_row_index, bound_coeff, other[i], x); + TRACE("opt", display(tout << "update: " << v << " ", objective()); + for (unsigned i = 0; i < m_above.size(); ++i) { + display(tout << "resolve: ", m_rows[m_above[i]]); + }); + for (unsigned i = 0; i < m_above.size(); ++i) { + resolve(bound_row_index, bound_coeff, m_above[i], x); + } + for (unsigned i = 0; i < m_below.size(); ++i) { + resolve(bound_row_index, bound_coeff, m_below[i], x); } // coeff*x + objective <= ub // a2*x + t2 <= 0 @@ -116,6 +122,8 @@ namespace opt { bound_vars.push_back(x); } else { + TRACE("opt", display(tout << "unbound: " << v << " ", objective());); + update_values(bound_vars, bound_trail); return inf_eps::infinity(); } } @@ -136,15 +144,33 @@ namespace opt { } + void model_based_opt::update_value(unsigned x, rational const& val) { + rational old_val = m_var2value[x]; + m_var2value[x] = val; + unsigned_vector const& row_ids = m_var2row_ids[x]; + for (unsigned i = 0; i < row_ids.size(); ++i) { + unsigned row_id = row_ids[i]; + rational coeff = get_coefficient(row_id, x); + if (coeff.is_zero()) { + continue; + } + row & r = m_rows[row_id]; + rational delta = coeff * (val - old_val); + r.m_value += delta; + SASSERT(invariant(row_id, r)); + } + } + + void model_based_opt::update_values(unsigned_vector const& bound_vars, unsigned_vector const& bound_trail) { - rational eps(0); for (unsigned i = bound_trail.size(); i > 0; ) { --i; unsigned x = bound_vars[i]; row& r = m_rows[bound_trail[i]]; rational val = r.m_coeff; - rational x_val; - rational x_coeff; + rational old_x_val = m_var2value[x]; + rational new_x_val; + rational x_coeff, eps(0); vector const& vars = r.m_vars; for (unsigned j = 0; j < vars.size(); ++j) { var const& v = vars[j]; @@ -155,28 +181,21 @@ namespace opt { val += m_var2value[v.m_id]*v.m_coeff; } } - TRACE("opt", display(tout << "v" << x << " val: " << val - << " coeff_x: " << x_coeff << " val_x: " << m_var2value[x] << " ", r); ); SASSERT(!x_coeff.is_zero()); - x_val = -val/x_coeff; - // - // - // ax + t < 0 - // <=> x < -t/a - // <=> x := -t/a - epsilon - // - if (r.m_type == t_lt) { - // Adjust epsilon to be - if (!x_val.is_zero() && (eps.is_zero() || eps >= abs(x_val))) { - eps = abs(x_val)/rational(2); - } - if (!r.m_value.is_zero() && (eps.is_zero() || eps >= abs(r.m_value))) { - eps = abs(r.m_value)/rational(2); - } + new_x_val = -val/x_coeff; + if (r.m_type == t_lt) { + eps = abs(old_x_val - new_x_val)/rational(2); + eps = std::min(rational::one(), eps); SASSERT(!eps.is_zero()); + + // + // ax + t < 0 + // <=> x < -t/a + // <=> x := -t/a - epsilon + // if (x_coeff.is_pos()) { - x_val -= eps; + new_x_val -= eps; } // // -ax + t < 0 @@ -185,27 +204,47 @@ namespace opt { // <=> x > t/a // <=> x := t/a + epsilon // - else if (x_coeff.is_neg()) { - x_val += eps; + else { + new_x_val += eps; } } - m_var2value[x] = x_val; - r.m_value = (x_val * x_coeff) + val; + TRACE("opt", display(tout << "v" << x + << " coeff_x: " << x_coeff + << " old_x_val: " << old_x_val + << " new_x_val: " << new_x_val + << " eps: " << eps << " ", r); ); + m_var2value[x] = new_x_val; - TRACE("opt", display(tout << "v" << x << " val: " << val << " coeff_x: " - << x_coeff << " val_x: " << m_var2value[x] << " ", r); ); + r.m_value = get_row_value(r); SASSERT(invariant(bound_trail[i], r)); } + + // update and check bounds for all other affected rows. + for (unsigned i = bound_trail.size(); i > 0; ) { + --i; + unsigned x = bound_vars[i]; + unsigned_vector const& row_ids = m_var2row_ids[x]; + for (unsigned j = 0; j < row_ids.size(); ++j) { + unsigned row_id = row_ids[j]; + row & r = m_rows[row_id]; + r.m_value = get_row_value(r); + SASSERT(invariant(row_id, r)); + } + } + SASSERT(invariant()); } - bool model_based_opt::find_bound(unsigned x, unsigned& bound_row_index, rational& bound_coeff, unsigned_vector& other, bool is_pos) { + bool model_based_opt::find_bound(unsigned x, unsigned& bound_row_index, rational& bound_coeff, bool is_pos) { bound_row_index = UINT_MAX; rational lub_val; rational const& x_val = m_var2value[x]; unsigned_vector const& row_ids = m_var2row_ids[x]; uint_set visited; + m_above.reset(); + m_below.reset(); for (unsigned i = 0; i < row_ids.size(); ++i) { unsigned row_id = row_ids[i]; + SASSERT(row_id != m_objective_id); if (visited.contains(row_id)) { continue; } @@ -226,24 +265,34 @@ namespace opt { else if ((value == lub_val && r.m_type == opt::t_lt) || (is_pos && value < lub_val) || (!is_pos && value > lub_val)) { - other.push_back(bound_row_index); + m_above.push_back(bound_row_index); lub_val = value; - bound_row_index = row_id; + bound_row_index = row_id; bound_coeff = a; } else { - other.push_back(row_id); + m_above.push_back(row_id); } } else { - r.m_alive = false; + m_below.push_back(row_id); } } } return bound_row_index != UINT_MAX; } - - rational model_based_opt::get_coefficient(unsigned row_id, unsigned var_id) { + + rational model_based_opt::get_row_value(row const& r) const { + vector const& vars = r.m_vars; + rational val = r.m_coeff; + for (unsigned i = 0; i < vars.size(); ++i) { + var const& v = vars[i]; + val += v.m_coeff * m_var2value[v.m_id]; + } + return val; + } + + rational model_based_opt::get_coefficient(unsigned row_id, unsigned var_id) const { row const& r = m_rows[row_id]; if (r.m_vars.empty()) { return rational::zero(); diff --git a/src/math/simplex/model_based_opt.h b/src/math/simplex/model_based_opt.h index e4ba288c8..3bbcc7bf2 100644 --- a/src/math/simplex/model_based_opt.h +++ b/src/math/simplex/model_based_opt.h @@ -65,24 +65,29 @@ namespace opt { vector m_var2value; vector m_new_vars; unsigned_vector m_lub, m_glb; + unsigned_vector m_above, m_below; bool invariant(); bool invariant(unsigned index, row const& r); row& objective() { return m_rows[0]; } - bool find_bound(unsigned x, unsigned& bound_index, rational& bound_coeff, unsigned_vector& other, bool is_pos); + bool find_bound(unsigned x, unsigned& bound_index, rational& bound_coeff, bool is_pos); - rational get_coefficient(unsigned row_id, unsigned var_id); + rational get_coefficient(unsigned row_id, unsigned var_id) const; + + rational get_row_value(row const& r) const; void resolve(unsigned row_src, rational const& a1, unsigned row_dst, unsigned x); void mul_add(bool same_sign, unsigned row_id1, rational const& c, unsigned row_id2); - void set_row(unsigned row_id, vector const& coeffs, rational const& c, ineq_type rel); - + void set_row(unsigned row_id, vector const& coeffs, rational const& c, ineq_type rel); + void update_values(unsigned_vector const& bound_vars, unsigned_vector const& bound_trail); + void update_value(unsigned x, rational const& val); + void project(unsigned var); void solve_for(unsigned row_id, unsigned x); @@ -132,5 +137,6 @@ namespace opt { std::ostream& operator<<(std::ostream& out, opt::ineq_type ie); +inline std::ostream& operator<<(std::ostream& out, opt::model_based_opt::var const v) { return out << "v" << v.m_id; } #endif diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index f90b31476..788921205 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -225,7 +225,7 @@ namespace opt { normalize(); internalize(); update_solver(); -#if 1 +#if 0 if (is_qsat_opt()) { return run_qsat_opt(); } @@ -367,6 +367,7 @@ namespace opt { lbool context::execute_box() { if (m_box_index < m_objectives.size()) { + SASSERT(m_box_index < m_box_models.size()); m_model = m_box_models[m_box_index]; ++m_box_index; return l_true; @@ -383,7 +384,9 @@ namespace opt { if (obj.m_type == O_MAXSMT) { solver::scoped_push _sp(get_solver()); r = execute(obj, false, false); - if (r == l_true) m_box_models.push_back(m_model.get()); + if (r == l_true) { + m_box_models.push_back(m_model.get()); + } } else { m_box_models.push_back(m_optsmt.get_model(j)); @@ -391,6 +394,7 @@ namespace opt { } } if (r == l_true && m_objectives.size() > 0) { + SASSERT(!m_box_models.empty()); m_model = m_box_models[0]; } return r; diff --git a/src/opt/opt_params.pyg b/src/opt/opt_params.pyg index 37b9ff372..629b3aa53 100644 --- a/src/opt/opt_params.pyg +++ b/src/opt/opt_params.pyg @@ -1,8 +1,7 @@ def_module_params('opt', description='optimization parameters', export=True, - params=(('timeout', UINT, UINT_MAX, 'set timeout'), - ('optsmt_engine', SYMBOL, 'basic', "select optimization engine: 'basic', 'farkas', 'symba'"), + params=(('optsmt_engine', SYMBOL, 'basic', "select optimization engine: 'basic', 'farkas', 'symba'"), ('maxsat_engine', SYMBOL, 'maxres', "select engine for maxsat: 'fu_malik', 'core_maxsat', 'wmax', 'pbmax', 'maxres', 'pd-maxres', 'bcd2', 'wpm2', 'sls', 'maxhs'"), ('priority', SYMBOL, 'lex', "select how to priortize objectives: 'lex' (lexicographic), 'pareto', or 'box'"), ('dump_benchmarks', BOOL, False, 'dump benchmarks for profiling'), diff --git a/src/qe/qe_arith.cpp b/src/qe/qe_arith.cpp index d071765fc..a4129d5cd 100644 --- a/src/qe/qe_arith.cpp +++ b/src/qe/qe_arith.cpp @@ -105,7 +105,10 @@ 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));); + DEBUG_CODE(expr_ref val(m); + VERIFY(model.eval(lit, val)); + CTRACE("qe", !m.is_true(val), tout << mk_pp(lit, m) << " := " << val << "\n";); + SASSERT(m.is_true(val));); bool is_not = m.is_not(lit, lit); if (is_not) { @@ -942,7 +945,7 @@ namespace qe { SASSERT(m_u < m_delta && rational(0) <= m_u); for (unsigned i = 0; i < n; ++i) { add_lit(model, lits, mk_divides(div_divisor(i), - mk_add(mk_num(div_coeff(i) * m_u), div_term(i)))); + mk_add(mk_num(div_coeff(i) * m_u), div_term(i)))); } reset_divs(); // @@ -1070,7 +1073,7 @@ namespace qe { for (unsigned i = 0; i < rows.size(); ++i) { expr_ref_vector ts(m); - expr_ref t(m), s(m); + expr_ref t(m), s(m), val(m); row const& r = rows[i]; if (r.m_vars.size() == 0) { continue; @@ -1088,6 +1091,8 @@ namespace qe { case opt::t_eq: t = a.mk_eq(t, s); break; } fmls.push_back(t); + VERIFY(model.eval(t, val)); + CTRACE("qe", !m.is_true(val), tout << "Evaluated unit " << t << " to " << val << "\n";); continue; } for (j = 0; j < r.m_vars.size(); ++j) { @@ -1111,10 +1116,16 @@ namespace qe { case opt::t_eq: t = a.mk_eq(t, s); break; } fmls.push_back(t); + + + VERIFY(model.eval(t, val)); + CTRACE("qe", !m.is_true(val), tout << "Evaluated " << t << " to " << val << "\n";); + } } - opt::inf_eps maximize(expr_ref_vector const& fmls0, model& mdl, app* t, expr_ref& bound) { + opt::inf_eps maximize(expr_ref_vector const& fmls0, model& mdl, app* t, expr_ref& ge, expr_ref& gt) { + validate_model(mdl, fmls0); m_trail.reset(); SASSERT(a.is_real(t)); expr_ref_vector fmls(fmls0); @@ -1139,11 +1150,6 @@ namespace qe { // find optimal value value = mbo.maximize(); - expr_ref val(a.mk_numeral(value.get_rational(), false), m); - if (!value.is_finite()) { - bound = m.mk_false(); - return value; - } // update model to use new values that satisfy optimality ptr_vector vars; @@ -1160,17 +1166,42 @@ namespace qe { TRACE("qe", tout << "omitting model update for non-uninterpreted constant " << mk_pp(e, m) << "\n";); } } + expr_ref val(a.mk_numeral(value.get_rational(), false), m); + expr_ref tval(m); + VERIFY (mdl.eval(t, tval)); - // update the predicate 'bound' which forces larger values. - if (value.get_infinitesimal().is_neg()) { - bound = a.mk_le(val, t); + // update the predicate 'bound' which forces larger values when 'strict' is true. + // strict: bound := valuue < t + // !strict: bound := value <= t + if (!value.is_finite()) { + ge = a.mk_ge(t, tval); + gt = m.mk_false(); + } + else if (value.get_infinitesimal().is_neg()) { + ge = a.mk_ge(t, tval); + gt = a.mk_ge(t, val); } else { - bound = a.mk_lt(val, t); - } + ge = a.mk_ge(t, val); + gt = a.mk_gt(t, val); + } + validate_model(mdl, fmls0); return value; } + bool validate_model(model& mdl, expr_ref_vector const& fmls) { + bool valid = true; + for (unsigned i = 0; i < fmls.size(); ++i) { + expr_ref val(m); + VERIFY(mdl.eval(fmls[i], val)); + if (!m.is_true(val)) { + valid = false; + TRACE("qe", tout << mk_pp(fmls[i], m) << " := " << val << "\n";); + } + } + return valid; + } + 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(); @@ -1219,8 +1250,8 @@ namespace qe { return m_imp->a.get_family_id(); } - opt::inf_eps arith_project_plugin::maximize(expr_ref_vector const& fmls, model& mdl, app* t, expr_ref& bound) { - return m_imp->maximize(fmls, mdl, t, bound); + opt::inf_eps arith_project_plugin::maximize(expr_ref_vector const& fmls, model& mdl, app* t, expr_ref& ge, expr_ref& gt) { + return m_imp->maximize(fmls, mdl, t, ge, gt); } bool arith_project(model& model, app* var, expr_ref_vector& lits) { diff --git a/src/qe/qe_arith.h b/src/qe/qe_arith.h index f71156b1e..dce9b1af4 100644 --- a/src/qe/qe_arith.h +++ b/src/qe/qe_arith.h @@ -32,7 +32,7 @@ namespace qe { 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); + opt::inf_eps maximize(expr_ref_vector const& fmls, model& mdl, app* t, expr_ref& ge, expr_ref& gt); }; bool arith_project(model& model, app* var, expr_ref_vector& lits); diff --git a/src/qe/qe_mbp.cpp b/src/qe/qe_mbp.cpp index 2bacb3a4f..219a4b45a 100644 --- a/src/qe/qe_mbp.cpp +++ b/src/qe/qe_mbp.cpp @@ -285,9 +285,9 @@ class mbp::impl { public: - opt::inf_eps maximize(expr_ref_vector const& fmls, model& mdl, app* t, expr_ref& bound) { + opt::inf_eps maximize(expr_ref_vector const& fmls, model& mdl, app* t, expr_ref& ge, expr_ref& gt) { arith_project_plugin arith(m); - return arith.maximize(fmls, mdl, t, bound); + return arith.maximize(fmls, mdl, t, ge, gt); } void extract_literals(model& model, expr_ref_vector& fmls) { @@ -428,7 +428,16 @@ public: } } + bool validate_model(model& model, expr_ref_vector const& fmls) { + expr_ref val(m); + for (unsigned i = 0; i < fmls.size(); ++i) { + VERIFY(model.eval(fmls[i], val) && m.is_true(val)); + } + return true; + } + void operator()(bool force_elim, app_ref_vector& vars, model& model, expr_ref_vector& fmls) { + SASSERT(validate_model(model, fmls)); expr_ref val(m), tmp(m); app_ref var(m); expr_ref_vector unused_fmls(m); @@ -446,6 +455,7 @@ public: } } while (!vars.empty() && !fmls.empty()) { + std::cout << "mbp: " << var << "\n"; var = vars.back(); vars.pop_back(); project_plugin* p = get_plugin(var); @@ -483,6 +493,7 @@ public: vars.reset(); } fmls.append(unused_fmls); + SASSERT(validate_model(model, fmls)); TRACE("qe", tout << vars << " " << fmls << "\n";); } @@ -508,6 +519,6 @@ void mbp::extract_literals(model& model, expr_ref_vector& lits) { m_impl->extract_literals(model, lits); } -opt::inf_eps mbp::maximize(expr_ref_vector const& fmls, model& mdl, app* t, expr_ref& bound) { - return m_impl->maximize(fmls, mdl, t, bound); +opt::inf_eps mbp::maximize(expr_ref_vector const& fmls, model& mdl, app* t, expr_ref& ge, expr_ref& gt) { + return m_impl->maximize(fmls, mdl, t, ge, gt); } diff --git a/src/qe/qe_mbp.h b/src/qe/qe_mbp.h index 6c28555b0..b195d3a35 100644 --- a/src/qe/qe_mbp.h +++ b/src/qe/qe_mbp.h @@ -79,7 +79,7 @@ namespace qe { \brief Maximize objective t under current model for constraints in fmls. */ - opt::inf_eps maximize(expr_ref_vector const& fmls, model& mdl, app* t, expr_ref& bound); + opt::inf_eps maximize(expr_ref_vector const& fmls, model& mdl, app* t, expr_ref& ge, expr_ref& gt); }; } diff --git a/src/qe/qsat.cpp b/src/qe/qsat.cpp index a409b23c2..74b6769ae 100644 --- a/src/qe/qsat.cpp +++ b/src/qe/qsat.cpp @@ -507,6 +507,26 @@ namespace qe { } } + bool pred_abs::validate_defs(model& model) const { + bool valid = true; + obj_map::iterator it = m_pred2lit.begin(), end = m_pred2lit.end(); + for (; it != end; ++it) { + expr_ref val_a(m), val_b(m); + expr* a = it->m_key; + expr* b = it->m_value; + VERIFY(model.eval(a, val_a)); + VERIFY(model.eval(b, val_b)); + if (val_a != val_b) { + TRACE("qe", + tout << mk_pp(a, m) << " := " << val_a << "\n"; + tout << mk_pp(b, m) << " := " << val_b << "\n"; + tout << m_elevel.find(a) << "\n";); + valid = false; + } + } + return valid; + } + class kernel { ast_manager& m; params_ref m_params; @@ -575,6 +595,9 @@ namespace qe { app* m_objective; opt::inf_eps* m_value; bool m_was_sat; + model_ref m_model_save; + expr_ref m_gt; + opt::inf_eps m_value_save; /** @@ -588,15 +611,23 @@ namespace qe { check_cancel(); expr_ref_vector asms(m_asms); m_pred_abs.get_assumptions(m_model.get(), asms); + if (m_model.get()) { + validate_assumptions(*m_model.get(), asms); + } TRACE("qe", tout << asms << "\n";); solver& s = get_kernel(m_level).s(); lbool res = s.check_sat(asms); switch (res) { case l_true: s.get_model(m_model); + SASSERT(validate_defs("check_sat")); + SASSERT(validate_assumptions(*m_model.get(), asms)); SASSERT(validate_model(asms)); TRACE("qe", s.display(tout); display(tout << "\n", *m_model.get()); display(tout, asms); ); push(); + if (m_level == 1 && m_mode == qsat_maximize) { + maximize_model(); + } break; case l_false: switch (m_level) { @@ -607,6 +638,7 @@ namespace qe { return l_true; } if (m_model.get()) { + SASSERT(validate_assumptions(*m_model.get(), asms)); if (!project_qe(asms)) return l_undef; } else { @@ -734,7 +766,28 @@ namespace qe { } } + bool validate_defs(char const* msg) { + if (m_model.get() && !m_pred_abs.validate_defs(*m_model.get())) { + TRACE("qe", + tout << msg << "\n"; + display(tout); + if (m_level > 0) { + get_kernel(m_level-1).s().display(tout); + } + expr_ref_vector asms(m); + m_pred_abs.get_assumptions(m_model.get(), asms); + tout << asms << "\n"; + m_pred_abs.pred2lit(asms); + tout << asms << "\n";); + return false; + } + else { + return true; + } + } + bool get_core(expr_ref_vector& core, unsigned level) { + SASSERT(validate_defs("get_core")); get_kernel(level).get_core(core); m_pred_abs.pred2lit(core); return true; @@ -814,33 +867,33 @@ namespace qe { if (!get_core(core, m_level)) { return false; } - SASSERT(validate_core(core)); + SASSERT(validate_core(mdl, core)); get_vars(m_level); + SASSERT(validate_assumptions(mdl, core)); m_mbp(force_elim(), m_avars, mdl, core); + SASSERT(validate_defs("project_qe")); if (m_mode == qsat_maximize) { - maximize(core, mdl); - pop(1); + maximize_core(core, mdl); } else { fml = negate_core(core); add_assumption(fml); m_answer.push_back(fml); m_free_vars.append(m_avars); - pop(1); } + pop(1); return true; } bool project(expr_ref_vector& core) { if (!get_core(core, m_level)) return false; TRACE("qe", display(tout); display(tout << "core\n", core);); - SASSERT(validate_core(core)); SASSERT(m_level >= 2); expr_ref fml(m); expr_ref_vector defs(m), core_save(m); max_level level; model& mdl = *m_model.get(); - + SASSERT(validate_core(mdl, core)); get_vars(m_level-1); SASSERT(validate_project(mdl, core)); m_mbp(force_elim(), m_avars, mdl, core); @@ -875,6 +928,7 @@ namespace qe { fml = m_pred_abs.mk_abstract(fml); get_kernel(m_level).assert_expr(fml); } + SASSERT(!m_model.get()); return true; } @@ -1005,7 +1059,19 @@ namespace qe { } } - bool validate_core(expr_ref_vector const& core) { + bool validate_assumptions(model& mdl, expr_ref_vector const& core) { + for (unsigned i = 0; i < core.size(); ++i) { + expr_ref val(m); + VERIFY(mdl.eval(core[i], val)); + if (!m.is_true(val)) { + TRACE("qe", tout << "component of core is not true: " << mk_pp(core[i], m) << "\n";); + return false; + } + } + return true; + } + + bool validate_core(model& mdl, expr_ref_vector const& core) { return true; #if 0 TRACE("qe", tout << "Validate core\n";); @@ -1130,7 +1196,8 @@ namespace qe { m_free_vars(m), m_objective(0), m_value(0), - m_was_sat(false) + m_was_sat(false), + m_gt(m) { reset(); } @@ -1258,6 +1325,7 @@ namespace qe { m_objective = t; m_value = &value; m_was_sat = false; + m_model_save.reset(); m_pred_abs.abstract_atoms(fml, defs); fml = m_pred_abs.mk_abstract(fml); m_ex.assert_expr(mk_and(defs)); @@ -1271,6 +1339,7 @@ namespace qe { if (!m_was_sat) { return l_false; } + mdl = m_model_save; break; case l_true: UNREACHABLE(); @@ -1286,15 +1355,49 @@ namespace qe { return l_true; } - void maximize(expr_ref_vector const& core, model& mdl) { + void maximize_core(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); - IF_VERBOSE(0, verbose_stream() << "(maximize " << *m_value << " bound: " << bound << ")\n";); - m_ex.assert_expr(bound); + *m_value = m_value_save; + IF_VERBOSE(3, verbose_stream() << "(maximize " << *m_value << ")\n";); + m_ex.assert_expr(m_gt); + m_fa.assert_expr(m_gt); + } + + void maximize_model() { + SASSERT(m_level == 1 && m_mode == qsat_maximize); + SASSERT(m_objective); + expr_ref ge(m); + expr_ref_vector asms(m), defs(m); + m_pred_abs.get_assumptions(m_model.get(), asms); + m_pred_abs.pred2lit(asms); + + SASSERT(validate_defs("maximize_model1")); + + m_value_save = m_mbp.maximize(asms, *m_model.get(), m_objective, ge, m_gt); + + SASSERT(validate_defs("maximize_model2")); + + // bound := val <= m_objective + + IF_VERBOSE(3, verbose_stream() << "(qsat-maximize-bound: " << m_value_save << ")\n";); + + max_level level; + m_pred_abs.abstract_atoms(ge, level, defs); + m_ex.assert_expr(mk_and(defs)); + m_fa.assert_expr(mk_and(defs)); + + ge = m_pred_abs.mk_abstract(ge); + + SASSERT(is_uninterp_const(ge)); + // update model with evaluation for bound. + if (is_uninterp_const(ge)) { + m_model->register_decl(to_app(ge)->get_decl(), m.mk_true()); + } + SASSERT(validate_defs("maximize_model3")); } }; diff --git a/src/qe/qsat.h b/src/qe/qsat.h index 66676da05..b6d21db1e 100644 --- a/src/qe/qsat.h +++ b/src/qe/qsat.h @@ -112,6 +112,8 @@ namespace qe { void display(std::ostream& out) const; void display(std::ostream& out, expr_ref_vector const& asms) const; void collect_statistics(statistics& st) const; + + bool validate_defs(model& model) const; }; class qmax { diff --git a/src/smt/smt_context.h b/src/smt/smt_context.h index 8b2453e31..3c260abbe 100644 --- a/src/smt/smt_context.h +++ b/src/smt/smt_context.h @@ -1406,10 +1406,8 @@ namespace smt { void internalize_instance(expr * body, proof * pr, unsigned generation) { internalize_assertion(body, pr, generation); -#ifndef SMTCOMP if (relevancy()) m_case_split_queue->internalize_instance_eh(body, generation); -#endif } bool already_internalized() const { return m_e_internalized_stack.size() > 2 || m_b_internalized_stack.size() > 1; } diff --git a/src/smt/smt_model_checker.cpp b/src/smt/smt_model_checker.cpp index 0d9c361f8..df271095f 100644 --- a/src/smt/smt_model_checker.cpp +++ b/src/smt/smt_model_checker.cpp @@ -138,8 +138,10 @@ namespace smt { } bool model_checker::add_instance(quantifier * q, model * cex, expr_ref_vector & sks, bool use_inv) { - if (cex == 0) - return false; // no model available. + if (cex == 0) { + TRACE("model_checker", tout << "no model is available\n";); + return false; + } unsigned num_decls = q->get_num_decls(); // Remark: sks were created for the flat version of q. SASSERT(sks.size() >= num_decls); @@ -153,8 +155,10 @@ namespace smt { sk_value = cex->get_const_interp(sk_d); if (sk_value == 0) { sk_value = cex->get_some_value(sk_d->get_range()); - if (sk_value == 0) + if (sk_value == 0) { + TRACE("model_checker", tout << "Could not get value for " << sk_d->get_name() << "\n";); return false; // get_some_value failed... giving up + } } if (use_inv) { unsigned sk_term_gen; @@ -166,6 +170,7 @@ namespace smt { sk_value = sk_term; } else { + TRACE("model_checker", tout << "no inverse value for " << sk_value << "\n";); return false; } } @@ -175,8 +180,10 @@ namespace smt { sk_value = sk_term; } } - if (contains_model_value(sk_value)) + if (contains_model_value(sk_value)) { + TRACE("model_checker", tout << "value is private to model: " << sk_value << "\n";); return false; + } bindings.set(num_decls - i - 1, sk_value); } @@ -286,18 +293,15 @@ namespace smt { break; model_ref cex; m_aux_context->get_model(cex); - if (add_instance(q, cex.get(), sks, true)) { - num_new_instances++; - if (num_new_instances < m_max_cexs) { - if (!add_blocking_clause(cex.get(), sks)) - break; // add_blocking_clause failed... stop the search for new counter-examples... - } - } - else { + if (!add_instance(q, cex.get(), sks, true)) { break; } - if (num_new_instances >= m_max_cexs) - break; + num_new_instances++; + if (num_new_instances >= m_max_cexs || !add_blocking_clause(cex.get(), sks)) { + TRACE("model_checker", tout << "Add blocking clause failed\n";); + // add_blocking_clause failed... stop the search for new counter-examples... + break; + } } if (num_new_instances == 0) { @@ -368,8 +372,10 @@ namespace smt { if (it == end) return true; - if (m_iteration_idx >= m_params.m_mbqi_max_iterations) + if (m_iteration_idx >= m_params.m_mbqi_max_iterations) { + IF_VERBOSE(10, verbose_stream() << "(smt.mbqi \"max instantiations reached \")" << m_iteration_idx << "\n";); return false; + } m_curr_model = md; m_value2expr.reset(); From 8c191781e70332cb399a07960567eb1bd841368f Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Wed, 22 Jun 2016 18:52:30 +0100 Subject: [PATCH 040/536] Fixed warning message --- examples/c++/example.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/c++/example.cpp b/examples/c++/example.cpp index 5635e6d12..2753e1475 100644 --- a/examples/c++/example.cpp +++ b/examples/c++/example.cpp @@ -23,7 +23,7 @@ void demorgan() { expr x = c.bool_const("x"); expr y = c.bool_const("y"); - expr conjecture = !(x && y) == (!x || !y); + expr conjecture = (!(x && y)) == (!x || !y); solver s(c); // adding the negation of the conjecture as a constraint. From 89b1d7d8da9ff4dc10f62fc0e764f6f23f3a055c Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Wed, 22 Jun 2016 18:52:40 +0100 Subject: [PATCH 041/536] Fixed test case --- src/test/qe_arith.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/test/qe_arith.cpp b/src/test/qe_arith.cpp index f14ccf3e2..f9cd9aa23 100644 --- a/src/test/qe_arith.cpp +++ b/src/test/qe_arith.cpp @@ -382,8 +382,7 @@ static void add_random_ineq( 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); + model mdl(m); arith_util a(m); for (unsigned i = 0; i < num_vars; ++i) { app_ref var(m); @@ -391,7 +390,8 @@ static void test_maximize(opt::model_based_opt& mbo, ast_manager& m, unsigned nu 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); + expr_ref ge(m), gt(m); + opt::inf_eps value1 = plugin.maximize(fmls, mdl, t, ge, gt); opt::inf_eps value2 = mbo.maximize(); std::cout << "optimal: " << value1 << " " << value2 << "\n"; mbo.display(std::cout); From fad1dffbf07abef3abd7561eb25b16e04fc6f918 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Wed, 22 Jun 2016 19:03:42 +0100 Subject: [PATCH 042/536] Added PATH info to successful build message --- scripts/mk_util.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scripts/mk_util.py b/scripts/mk_util.py index a73a0e59c..b02e6e2b7 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -2472,7 +2472,8 @@ def mk_makefile(): out.write(' %s' % c.name) out.write('\n\t@echo Z3 was successfully built.\n') out.write("\t@echo \"Z3Py scripts can already be executed in the \'%s\' directory.\"\n" % BUILD_DIR) - out.write("\t@echo \"Z3Py scripts stored in arbitrary directories can be executed if the \'%s\' directory is added to the PYTHONPATH environment variable.\"\n" % BUILD_DIR) + pathvar = "DYLD_LIBRARY_PATH" if IS_OSX else "PATH" if IS_WINDOWS else "LD_LIBRARY_PATH" + out.write("\t@echo \"Z3Py scripts stored in arbitrary directories can be executed if the \'%s\' directory is added to the PYTHONPATH and %s environment variables.\"\n" % (BUILD_DIR, pathvar)) if not IS_WINDOWS: out.write("\t@echo Use the following command to install Z3 at prefix $(PREFIX).\n") out.write('\t@echo " sudo make install"\n\n') From 5b497b62498f1308ef81db87eb1e5169bd0cff97 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 22 Jun 2016 20:25:47 -0700 Subject: [PATCH 043/536] reduce set of mainly verbose warnings raised by -Wmaybe-uninitialized and unused variable warnings from release mode builds Signed-off-by: Nikolaj Bjorner --- src/ast/dl_decl_plugin.cpp | 2 +- src/ast/fpa/fpa2bv_converter.cpp | 2 ++ src/ast/normal_forms/defined_names.cpp | 2 +- src/ast/normal_forms/pull_quant.cpp | 2 +- src/ast/rewriter/bool_rewriter.cpp | 2 +- src/ast/rewriter/rewriter_def.h | 4 ++-- src/ast/rewriter/seq_rewriter.cpp | 6 +++--- src/ast/simplifier/bit2int.cpp | 2 +- src/ast/substitution/substitution.cpp | 2 +- src/math/hilbert/heap_trie.h | 2 +- src/math/polynomial/algebraic_numbers.cpp | 4 ++-- src/math/simplex/simplex_def.h | 2 +- src/model/model_implicant.cpp | 4 ++-- src/muz/base/dl_rule_set.cpp | 4 ++-- src/muz/ddnf/ddnf.cpp | 2 +- src/muz/pdr/pdr_context.cpp | 2 +- src/muz/pdr/pdr_util.cpp | 2 +- src/muz/rel/dl_compiler.cpp | 2 +- src/muz/rel/dl_mk_partial_equiv.cpp | 2 +- src/muz/rel/dl_relation_manager.cpp | 2 +- src/muz/rel/dl_sparse_table.cpp | 3 +-- src/muz/transforms/dl_mk_loop_counter.cpp | 2 +- src/muz/transforms/dl_mk_magic_sets.cpp | 2 +- .../transforms/dl_mk_unbound_compressor.cpp | 1 - src/nlsat/tactic/nlsat_tactic.cpp | 2 +- src/opt/opt_solver.cpp | 7 +++---- src/qe/qe.cpp | 2 +- src/qe/qe_arith.cpp | 2 +- src/qe/qe_arith_plugin.cpp | 2 +- src/qe/qe_datatype_plugin.cpp | 3 +-- src/qe/qe_lite.cpp | 2 +- src/sat/sat_integrity_checker.cpp | 6 +++--- src/sat/sat_model_converter.cpp | 2 +- src/sat/sat_solver/inc_sat_solver.cpp | 2 +- src/smt/mam.cpp | 2 +- src/smt/proto_model/value_factory.h | 2 +- src/smt/qi_queue.cpp | 2 +- src/smt/theory_seq.cpp | 18 +++++++++--------- src/tactic/arith/fm_tactic.cpp | 2 +- src/tactic/bv/elim_small_bv_tactic.cpp | 3 +-- src/tactic/core/symmetry_reduce_tactic.cpp | 12 ++++++------ src/tactic/nlsat_smt/nl_purify_tactic.cpp | 3 +-- src/tactic/tactical.h | 2 +- src/util/mpf.cpp | 2 ++ 44 files changed, 68 insertions(+), 70 deletions(-) diff --git a/src/ast/dl_decl_plugin.cpp b/src/ast/dl_decl_plugin.cpp index 13416c086..46f610c18 100644 --- a/src/ast/dl_decl_plugin.cpp +++ b/src/ast/dl_decl_plugin.cpp @@ -324,7 +324,7 @@ namespace datalog { if (!is_rel_sort(r, sorts)) { return 0; } - unsigned index0; + unsigned index0 = 0; sort* last_sort = 0; SASSERT(num_params > 0); for (unsigned i = 0; i < num_params; ++i) { diff --git a/src/ast/fpa/fpa2bv_converter.cpp b/src/ast/fpa/fpa2bv_converter.cpp index d833e2381..e89664216 100644 --- a/src/ast/fpa/fpa2bv_converter.cpp +++ b/src/ast/fpa/fpa2bv_converter.cpp @@ -2267,6 +2267,7 @@ void fpa2bv_converter::mk_to_fp(func_decl * f, unsigned num, expr * const * args expr * bv = args[0]; int sz = m_bv_util.get_bv_size(bv); + (void)to_sbits; SASSERT((unsigned)sz == to_sbits + to_ebits); result = m_util.mk_fp(m_bv_util.mk_extract(sz - 1, sz - 1, bv), @@ -2399,6 +2400,7 @@ void fpa2bv_converter::mk_to_fp_float(sort * to_srt, expr * rm, expr * x, expr_r res_sig = m_bv_util.mk_zero_extend(1, res_sig); // extra zero in the front for the rounder. unsigned sig_sz = m_bv_util.get_bv_size(res_sig); + (void) sig_sz; SASSERT(sig_sz == to_sbits + 4); expr_ref exponent_overflow(m), exponent_underflow(m); diff --git a/src/ast/normal_forms/defined_names.cpp b/src/ast/normal_forms/defined_names.cpp index 16e9098fc..c1d9b36a5 100644 --- a/src/ast/normal_forms/defined_names.cpp +++ b/src/ast/normal_forms/defined_names.cpp @@ -210,7 +210,7 @@ bool defined_names::impl::mk_name(expr * e, expr_ref & new_def, proof_ref & new_ TRACE("mk_definition_bug", tout << "name for expression is already cached..., returning false...\n";); n = n_ptr; if (m_manager.proofs_enabled()) { - proof * pr_ptr; + proof * pr_ptr = 0; m_expr2proof.find(e, pr_ptr); SASSERT(pr_ptr); pr = pr_ptr; diff --git a/src/ast/normal_forms/pull_quant.cpp b/src/ast/normal_forms/pull_quant.cpp index 5158439a7..bb9b30dc5 100644 --- a/src/ast/normal_forms/pull_quant.cpp +++ b/src/ast/normal_forms/pull_quant.cpp @@ -58,7 +58,7 @@ struct pull_quant::imp { } bool found_quantifier = false; - bool forall_children; + bool forall_children = false; for (unsigned i = 0; i < num_children; i++) { expr * child = children[i]; diff --git a/src/ast/rewriter/bool_rewriter.cpp b/src/ast/rewriter/bool_rewriter.cpp index 71be3d1c2..66c5e66bc 100644 --- a/src/ast/rewriter/bool_rewriter.cpp +++ b/src/ast/rewriter/bool_rewriter.cpp @@ -572,7 +572,7 @@ bool bool_rewriter::local_ctx_simp(unsigned num_args, expr * const * args, expr_ */ br_status bool_rewriter::try_ite_value(app * ite, app * val, expr_ref & result) { - expr* cond, *t, *e; + expr* cond = 0, *t = 0, *e = 0; VERIFY(m().is_ite(ite, cond, t, e)); SASSERT(m().is_value(val)); diff --git a/src/ast/rewriter/rewriter_def.h b/src/ast/rewriter/rewriter_def.h index eaf5713ee..9c200a3e2 100644 --- a/src/ast/rewriter/rewriter_def.h +++ b/src/ast/rewriter/rewriter_def.h @@ -103,8 +103,8 @@ template template bool rewriter_tpl::visit(expr * t, unsigned max_depth) { TRACE("rewriter_visit", tout << "visiting\n" << mk_ismt2_pp(t, m()) << "\n";); - expr * new_t; - proof * new_t_pr; + expr * new_t = 0; + proof * new_t_pr = 0; if (m_cfg.get_subst(t, new_t, new_t_pr)) { TRACE("rewriter_subst", tout << "subst\n" << mk_ismt2_pp(t, m()) << "\n---->\n" << mk_ismt2_pp(new_t, m()) << "\n";); SASSERT(m().get_sort(t) == m().get_sort(new_t)); diff --git a/src/ast/rewriter/seq_rewriter.cpp b/src/ast/rewriter/seq_rewriter.cpp index 04acd7ee1..29bfe25e5 100644 --- a/src/ast/rewriter/seq_rewriter.cpp +++ b/src/ast/rewriter/seq_rewriter.cpp @@ -303,7 +303,7 @@ eautomaton* re2automaton::re2aut(expr* e) { } else if (u.re.is_full(e)) { expr_ref tt(m.mk_true(), m); - sort* seq_s, *char_s; + sort *seq_s = 0, *char_s = 0; VERIFY (u.is_re(m.get_sort(e), seq_s)); VERIFY (u.is_seq(seq_s, char_s)); sym_expr* _true = sym_expr::mk_pred(tt, char_s); @@ -794,7 +794,7 @@ br_status seq_rewriter::mk_seq_suffix(expr* a, expr* b, expr_ref& result) { bool isc1 = false; bool isc2 = false; - expr* a1, *a2, *b1, *b2; + expr *a1 = 0, *a2 = 0, *b1 = 0, *b2 = 0; if (m_util.str.is_concat(a, a1, a2) && m_util.str.is_string(a2, s1)) { isc1 = true; } @@ -1321,7 +1321,7 @@ br_status seq_rewriter::mk_re_plus(expr* a, expr_ref& result) { } br_status seq_rewriter::mk_re_opt(expr* a, expr_ref& result) { - sort* s; + sort* s = 0; VERIFY(m_util.is_re(a, s)); result = m_util.re.mk_union(m_util.re.mk_to_re(m_util.str.mk_empty(s)), a); return BR_REWRITE1; diff --git a/src/ast/simplifier/bit2int.cpp b/src/ast/simplifier/bit2int.cpp index ab4193486..08c3da774 100644 --- a/src/ast/simplifier/bit2int.cpp +++ b/src/ast/simplifier/bit2int.cpp @@ -273,7 +273,7 @@ void bit2int::visit(app* n) { // bv2int(x) <= z - bv2int(y) -> bv2int(x) + bv2int(y) <= z // - expr* e1, *e2; + expr* e1 = 0, *e2 = 0; expr_ref tmp1(m_manager), tmp2(m_manager); expr_ref tmp3(m_manager); expr_ref pos1(m_manager), neg1(m_manager); diff --git a/src/ast/substitution/substitution.cpp b/src/ast/substitution/substitution.cpp index be293c5a8..eea1938a6 100644 --- a/src/ast/substitution/substitution.cpp +++ b/src/ast/substitution/substitution.cpp @@ -146,7 +146,7 @@ void substitution::apply(unsigned num_actual_offsets, unsigned const * deltas, e bool has_new_args = false; for (unsigned i = 0; i < num_args; i++) { expr * arg = to_app(e)->get_arg(i); - expr * new_arg; + expr * new_arg = 0; VERIFY(m_apply_cache.find(expr_offset(arg, off), new_arg)); new_args.push_back(new_arg); diff --git a/src/math/hilbert/heap_trie.h b/src/math/hilbert/heap_trie.h index ab55a44c3..e288bb076 100644 --- a/src/math/hilbert/heap_trie.h +++ b/src/math/hilbert/heap_trie.h @@ -283,7 +283,7 @@ public: ++m_stats.m_num_removes; // assumption: key is in table. node* n = m_root; - node* m; + node* m = 0; for (unsigned i = 0; i < num_keys(); ++i) { n->dec_ref(); VERIFY (to_trie(n)->find(get_key(keys, i), m)); diff --git a/src/math/polynomial/algebraic_numbers.cpp b/src/math/polynomial/algebraic_numbers.cpp index f4eb8a003..986c17664 100644 --- a/src/math/polynomial/algebraic_numbers.cpp +++ b/src/math/polynomial/algebraic_numbers.cpp @@ -1035,7 +1035,7 @@ namespace algebraic_numbers { unsigned num_rem = 0; // number of remaining sequences unsigned target_i = UINT_MAX; // index of sequence that is isolating - int target_lV, target_uV; + int target_lV = 0, target_uV = 0; for (unsigned i = 0; i < num_fs; i++) { if (seqs[i] == 0) continue; // sequence was discarded because it does not contain the root. @@ -1113,7 +1113,7 @@ namespace algebraic_numbers { unsigned num_rem = 0; // number of remaining sequences unsigned target_i = UINT_MAX; // index of sequence that is isolating - int target_lV, target_uV; + int target_lV = 0, target_uV = 0; for (unsigned i = 0; i < num_fs; i++) { if (seqs[i] == 0) continue; // sequence was discarded because it does not contain the root. diff --git a/src/math/simplex/simplex_def.h b/src/math/simplex/simplex_def.h index cb86e2a85..762e8ceb2 100644 --- a/src/math/simplex/simplex_def.h +++ b/src/math/simplex/simplex_def.h @@ -540,7 +540,7 @@ namespace simplex { var_t max = get_num_vars(); var_t result = max; row r = row(m_vars[x_i].m_base2row); - int n; + int n = 0; unsigned best_col_sz = UINT_MAX; int best_so_far = INT_MAX; diff --git a/src/model/model_implicant.cpp b/src/model/model_implicant.cpp index 44c70036c..0d37a04df 100644 --- a/src/model/model_implicant.cpp +++ b/src/model/model_implicant.cpp @@ -666,8 +666,8 @@ void model_implicant::eval_eq(app* e, expr* arg1, expr* arg2) { } void model_implicant::eval_basic(app* e) { - expr* arg1, *arg2; - expr *argCond, *argThen, *argElse, *arg; + expr* arg1 = 0, *arg2 = 0; + expr *argCond = 0, *argThen = 0, *argElse = 0, *arg = 0; bool has_x = false; unsigned arity = e->get_num_args(); switch(e->get_decl_kind()) { diff --git a/src/muz/base/dl_rule_set.cpp b/src/muz/base/dl_rule_set.cpp index 5eb8e5f7e..e9b383b56 100644 --- a/src/muz/base/dl_rule_set.cpp +++ b/src/muz/base/dl_rule_set.cpp @@ -601,7 +601,7 @@ namespace datalog { return; } while (!m_stack_P.empty()) { - unsigned on_stack_num; + unsigned on_stack_num = 0; VERIFY( m_preorder_nums.find(m_stack_P.back(), on_stack_num) ); if (on_stack_num <= p_num) { break; @@ -710,7 +710,7 @@ namespace datalog { item_set::iterator eend=deps.end(); for (; eit!=eend; ++eit) { T * tgt = *eit; - unsigned tgt_comp; + unsigned tgt_comp = 0; VERIFY( m_component_nums.find(tgt, tgt_comp) ); //m_components[tgt_comp]==0 means the edge is intra-component. diff --git a/src/muz/ddnf/ddnf.cpp b/src/muz/ddnf/ddnf.cpp index e7babc719..6863a908f 100644 --- a/src/muz/ddnf/ddnf.cpp +++ b/src/muz/ddnf/ddnf.cpp @@ -836,7 +836,7 @@ namespace datalog { } void compile_eq(expr* e, expr_ref& result, var* v, unsigned hi, unsigned lo, expr* c) { - tbv* t; + tbv* t = 0; // TBD: hi, lo are ignored. VERIFY(m_expr2tbv.find(e, t)); var_ref w(m); diff --git a/src/muz/pdr/pdr_context.cpp b/src/muz/pdr/pdr_context.cpp index 3a735165a..6dc93048a 100644 --- a/src/muz/pdr/pdr_context.cpp +++ b/src/muz/pdr/pdr_context.cpp @@ -274,7 +274,7 @@ namespace pdr { for (unsigned i = 0; i < src.size(); ) { expr * curr = src[i].get(); - unsigned stored_lvl; + unsigned stored_lvl = 0; VERIFY(m_prop2level.find(curr, stored_lvl)); SASSERT(stored_lvl >= src_level); bool assumes_level; diff --git a/src/muz/pdr/pdr_util.cpp b/src/muz/pdr/pdr_util.cpp index 9af3ea8b4..934be5c63 100644 --- a/src/muz/pdr/pdr_util.cpp +++ b/src/muz/pdr/pdr_util.cpp @@ -247,7 +247,7 @@ namespace pdr { } bool test_eq(expr* e) const { - expr* lhs, *rhs; + expr* lhs = 0, *rhs = 0; VERIFY(m.is_eq(e, lhs, rhs)); if (!a.is_int_real(lhs)) { return true; diff --git a/src/muz/rel/dl_compiler.cpp b/src/muz/rel/dl_compiler.cpp index 7fb2afd9e..0d4507971 100644 --- a/src/muz/rel/dl_compiler.cpp +++ b/src/muz/rel/dl_compiler.cpp @@ -466,7 +466,7 @@ namespace datalog { //used to save on filter_identical instructions where the check is already done //by the join operation - unsigned second_tail_arg_ofs; + unsigned second_tail_arg_ofs = 0; // whether to dealloc the previous result bool dealloc = true; diff --git a/src/muz/rel/dl_mk_partial_equiv.cpp b/src/muz/rel/dl_mk_partial_equiv.cpp index d79a46720..94da7851f 100644 --- a/src/muz/rel/dl_mk_partial_equiv.cpp +++ b/src/muz/rel/dl_mk_partial_equiv.cpp @@ -109,7 +109,7 @@ namespace datalog { rule_vector const& rv = *(it->m_value); bool has_symmetry = false; bool has_transitivity = false; - unsigned i_symmetry, i_transitivity; + unsigned i_symmetry = 0, i_transitivity = 0; family_id kind = rm.get_requested_predicate_kind(p); for (unsigned i = 0; i < rv.size(); ++i) { diff --git a/src/muz/rel/dl_relation_manager.cpp b/src/muz/rel/dl_relation_manager.cpp index 0b0dae12c..7a73afd03 100644 --- a/src/muz/rel/dl_relation_manager.cpp +++ b/src/muz/rel/dl_relation_manager.cpp @@ -277,7 +277,7 @@ namespace datalog { relation_plugin & relation_manager::get_relation_plugin(family_id kind) { SASSERT(kind>=0); SASSERT(kindget_decl(); + func_decl* old_fn = 0, *new_fn = fn->get_decl(); SASSERT(fn->get_num_args() > 0); args.append(fn->get_num_args()-1, fn->get_args()); VERIFY (m_new2old.find(new_fn, old_fn)); diff --git a/src/muz/transforms/dl_mk_magic_sets.cpp b/src/muz/transforms/dl_mk_magic_sets.cpp index 48bd69255..048decaf9 100644 --- a/src/muz/transforms/dl_mk_magic_sets.cpp +++ b/src/muz/transforms/dl_mk_magic_sets.cpp @@ -264,7 +264,7 @@ namespace datalog { } - func_decl * new_head_pred; + func_decl * new_head_pred = 0; VERIFY( m_adorned_preds.find(adornment_desc(head->get_decl(), head_adornment), new_head_pred) ); app * new_head = m.mk_app(new_head_pred, head->get_args()); diff --git a/src/muz/transforms/dl_mk_unbound_compressor.cpp b/src/muz/transforms/dl_mk_unbound_compressor.cpp index 48b41af56..7d103568a 100644 --- a/src/muz/transforms/dl_mk_unbound_compressor.cpp +++ b/src/muz/transforms/dl_mk_unbound_compressor.cpp @@ -317,7 +317,6 @@ namespace datalog { unsigned tail_index = 0; while (tail_index < utail_len) { app * t = r->get_tail(tail_index); - func_decl * t_pred = t->get_decl(); add_in_progress_indices(arg_indices, t); diff --git a/src/nlsat/tactic/nlsat_tactic.cpp b/src/nlsat/tactic/nlsat_tactic.cpp index 94c57e16d..a4d65d30b 100644 --- a/src/nlsat/tactic/nlsat_tactic.cpp +++ b/src/nlsat/tactic/nlsat_tactic.cpp @@ -140,7 +140,7 @@ class nlsat_tactic : public tactic { m_solver.set_display_var(m_display_var); lbool st = m_solver.check(); - + if (st == l_undef) { } else if (st == l_true) { diff --git a/src/opt/opt_solver.cpp b/src/opt/opt_solver.cpp index 3c2ac207c..7637da1e8 100644 --- a/src/opt/opt_solver.cpp +++ b/src/opt/opt_solver.cpp @@ -345,10 +345,9 @@ 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); - } + 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.cpp b/src/qe/qe.cpp index 721e38942..4bf3c1580 100644 --- a/src/qe/qe.cpp +++ b/src/qe/qe.cpp @@ -362,7 +362,7 @@ namespace qe { } app* ite; if (find_ite(fml, ite)) { - expr* cond, *th, *el; + expr* cond = 0, *th = 0, *el = 0; VERIFY(m.is_ite(ite, cond, th, el)); expr_ref tmp1(fml, m), tmp2(fml, m); m_replace->apply_substitution(ite, th, tmp1); diff --git a/src/qe/qe_arith.cpp b/src/qe/qe_arith.cpp index a4129d5cd..c2d0016c8 100644 --- a/src/qe/qe_arith.cpp +++ b/src/qe/qe_arith.cpp @@ -673,7 +673,7 @@ namespace qe { } unsigned find_max(model& mdl, bool do_pos) { - unsigned result; + unsigned result = 0; bool new_max = true; rational max_r, r; expr_ref val(m); diff --git a/src/qe/qe_arith_plugin.cpp b/src/qe/qe_arith_plugin.cpp index 38861df65..3a909d6ba 100644 --- a/src/qe/qe_arith_plugin.cpp +++ b/src/qe/qe_arith_plugin.cpp @@ -2445,7 +2445,7 @@ public: } virtual void assign(contains_app& x, expr* fml, rational const& vl) { - nlarith::branch_conditions *brs; + nlarith::branch_conditions *brs = 0; VERIFY (m_cache.find(x.x(), fml, brs)); SASSERT(vl.is_unsigned()); SASSERT(vl.get_unsigned() < brs->size()); diff --git a/src/qe/qe_datatype_plugin.cpp b/src/qe/qe_datatype_plugin.cpp index 088d2252d..78562cf00 100644 --- a/src/qe/qe_datatype_plugin.cpp +++ b/src/qe/qe_datatype_plugin.cpp @@ -792,9 +792,8 @@ namespace qe { TRACE("qe", tout << mk_pp(x.x(), m) << " has a recognizer\n";); } else { - unsigned sz = m_datatype_util.get_datatype_num_constructors(s); SASSERT(vl.is_unsigned()); - SASSERT(vl.get_unsigned() < sz); + SASSERT(vl.get_unsigned() < m_datatype_util.get_datatype_num_constructors(s)); c = (*m_datatype_util.get_datatype_constructors(s))[vl.get_unsigned()]; } subst_constructor(x, c, fml, def); diff --git a/src/qe/qe_lite.cpp b/src/qe/qe_lite.cpp index f28a93753..2b73381a9 100644 --- a/src/qe/qe_lite.cpp +++ b/src/qe/qe_lite.cpp @@ -1667,7 +1667,7 @@ namespace fm { sbuffer xs; buffer as; rational c; - bool strict; + bool strict = false; unsigned num; expr * const * args; if (m.is_or(f)) { diff --git a/src/sat/sat_integrity_checker.cpp b/src/sat/sat_integrity_checker.cpp index c60fb86cb..8db27c7ec 100644 --- a/src/sat/sat_integrity_checker.cpp +++ b/src/sat/sat_integrity_checker.cpp @@ -70,9 +70,9 @@ namespace sat { tout << "watch_list:\n"; sat::display(tout, s.m_cls_allocator, s.get_wlist(~c[0])); tout << "\n";); - SASSERT(contains_watched(s.get_wlist(~c[0]), c[1], c[2])); - SASSERT(contains_watched(s.get_wlist(~c[1]), c[0], c[2])); - SASSERT(contains_watched(s.get_wlist(~c[2]), c[0], c[1])); + VERIFY(contains_watched(s.get_wlist(~c[0]), c[1], c[2])); + VERIFY(contains_watched(s.get_wlist(~c[1]), c[0], c[2])); + VERIFY(contains_watched(s.get_wlist(~c[2]), c[0], c[1])); } else { if (s.value(c[0]) == l_false || s.value(c[1]) == l_false) { diff --git a/src/sat/sat_model_converter.cpp b/src/sat/sat_model_converter.cpp index 3a39af31b..8901c276f 100644 --- a/src/sat/sat_model_converter.cpp +++ b/src/sat/sat_model_converter.cpp @@ -42,7 +42,7 @@ namespace sat { // if it->get_kind() == BLOCK_LIT, then it might be the case that m[it->var()] != l_undef, // and the following procedure flips its value. bool sat = false; - bool var_sign; + bool var_sign = false; literal_vector::const_iterator it2 = it->m_clauses.begin(); literal_vector::const_iterator end2 = it->m_clauses.end(); for (; it2 != end2; ++it2) { diff --git a/src/sat/sat_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp index fb1c98a74..65f62ec0e 100644 --- a/src/sat/sat_solver/inc_sat_solver.cpp +++ b/src/sat/sat_solver/inc_sat_solver.cpp @@ -381,7 +381,7 @@ private: m_core.reset(); for (unsigned i = 0; i < core.size(); ++i) { - expr* e; + expr* e = 0; VERIFY(asm2dep.find(core[i].index(), e)); m_core.push_back(e); } diff --git a/src/smt/mam.cpp b/src/smt/mam.cpp index 0d7f6a3a6..ead1ea963 100644 --- a/src/smt/mam.cpp +++ b/src/smt/mam.cpp @@ -2147,7 +2147,7 @@ namespace smt { enode_vector * best_v = 0; for (unsigned i = 0; i < num_args; i++) { enode * bare = c->m_joints[i]; - enode_vector * curr_v; + enode_vector * curr_v = 0; switch (GET_TAG(bare)) { case NULL_TAG: curr_v = 0; diff --git a/src/smt/proto_model/value_factory.h b/src/smt/proto_model/value_factory.h index 0bf0c7c98..f841e18ea 100644 --- a/src/smt/proto_model/value_factory.h +++ b/src/smt/proto_model/value_factory.h @@ -183,7 +183,7 @@ public: sort_info* s_info = s->get_info(); sort_size const* sz = s_info?&s_info->get_num_elements():0; bool has_max = false; - Number max_size; + Number max_size(0); if (sz && sz->is_finite() && sz->size() < UINT_MAX) { unsigned usz = static_cast(sz->size()); max_size = Number(usz); diff --git a/src/smt/qi_queue.cpp b/src/smt/qi_queue.cpp index 711cdc336..530d0ec88 100644 --- a/src/smt/qi_queue.cpp +++ b/src/smt/qi_queue.cpp @@ -363,7 +363,7 @@ namespace smt { << ", scope_level: " << m_context.get_scope_level() << "\n";); if (m_params.m_qi_conservative_final_check) { bool init = false; - float min_cost; + float min_cost = 0.0; unsigned sz = m_delayed_entries.size(); for (unsigned i = 0; i < sz; i++) { entry & e = m_delayed_entries[i]; diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index 9c670e751..609181538 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -2790,7 +2790,7 @@ void theory_seq::tightest_prefix(expr* s, expr* x) { (len(s) <= len(t) -> i <= len(t)-len(s)) */ void theory_seq::add_indexof_axiom(expr* i) { - expr* s, *t, *offset = 0; + expr* s = 0, *t = 0, *offset = 0; rational r; VERIFY(m_util.str.is_index(i, t, s) || m_util.str.is_index(i, t, s, offset)); @@ -2891,7 +2891,7 @@ void theory_seq::add_elim_string_axiom(expr* n) { */ void theory_seq::add_length_axiom(expr* n) { context& ctx = get_context(); - expr* x; + expr* x = 0; VERIFY(m_util.str.is_length(n, x)); if (m_util.str.is_concat(x) || m_util.str.is_unit(x) || @@ -2914,7 +2914,7 @@ void theory_seq::add_length_axiom(expr* n) { } void theory_seq::add_itos_length_axiom(expr* len) { - expr* x, *n; + expr* x = 0, *n = 0; VERIFY(m_util.str.is_length(len, x)); VERIFY(m_util.str.is_itos(x, n)); @@ -3295,7 +3295,7 @@ void theory_seq::add_extract_suffix_axiom(expr* e, expr* s, expr* i) { */ void theory_seq::add_at_axiom(expr* e) { - expr* s, *i; + expr* s = 0, *i = 0; VERIFY(m_util.str.is_at(e, s, i)); expr_ref len_e(m_util.str.mk_length(e), m); expr_ref len_s(m_util.str.mk_length(s), m); @@ -4090,7 +4090,7 @@ void theory_seq::propagate_not_prefix2(expr* e) { void theory_seq::propagate_not_suffix(expr* e) { context& ctx = get_context(); - expr* e1, *e2; + expr* e1 = 0, *e2 = 0; VERIFY(m_util.str.is_suffix(e, e1, e2)); literal lit = ctx.get_literal(e); SASSERT(ctx.get_assignment(lit) == l_false); @@ -4119,7 +4119,7 @@ void theory_seq::propagate_not_suffix(expr* e) { */ bool theory_seq::add_prefix2prefix(expr* e, bool& change) { context& ctx = get_context(); - expr* e1, *e2; + expr* e1 = 0, *e2 = 0; VERIFY(m_util.str.is_prefix(e, e1, e2)); SASSERT(ctx.get_assignment(e) == l_false); if (canonizes(false, e)) { @@ -4191,7 +4191,7 @@ bool theory_seq::add_prefix2prefix(expr* e, bool& change) { */ bool theory_seq::add_suffix2suffix(expr* e, bool& change) { context& ctx = get_context(); - expr* e1, *e2; + expr* e1 = 0, *e2 = 0; VERIFY(m_util.str.is_suffix(e, e1, e2)); SASSERT(ctx.get_assignment(e) == l_false); if (canonizes(false, e)) { @@ -4276,7 +4276,7 @@ bool theory_seq::canonizes(bool sign, expr* e) { bool theory_seq::add_contains2contains(expr* e, bool& change) { context& ctx = get_context(); - expr* e1, *e2; + expr* e1 = 0, *e2 = 0; VERIFY(m_util.str.is_contains(e, e1, e2)); SASSERT(ctx.get_assignment(e) == l_false); if (canonizes(false, e)) { @@ -4346,7 +4346,7 @@ bool theory_seq::propagate_automata() { } void theory_seq::get_concat(expr* e, ptr_vector& concats) { - expr* e1, *e2; + expr* e1 = 0, *e2 = 0; while (true) { e = m_rep.find(e); if (m_util.str.is_concat(e, e1, e2)) { diff --git a/src/tactic/arith/fm_tactic.cpp b/src/tactic/arith/fm_tactic.cpp index eae3ab5e6..5c82bbbc3 100644 --- a/src/tactic/arith/fm_tactic.cpp +++ b/src/tactic/arith/fm_tactic.cpp @@ -993,7 +993,7 @@ class fm_tactic : public tactic { sbuffer xs; buffer as; rational c; - bool strict; + bool strict = false; unsigned num; expr * const * args; if (m.is_or(f)) { diff --git a/src/tactic/bv/elim_small_bv_tactic.cpp b/src/tactic/bv/elim_small_bv_tactic.cpp index 7a83ee403..7db3a15ca 100644 --- a/src/tactic/bv/elim_small_bv_tactic.cpp +++ b/src/tactic/bv/elim_small_bv_tactic.cpp @@ -147,11 +147,10 @@ class elim_small_bv_tactic : public tactic { expr_ref body(old_body, m); for (unsigned i = num_decls-1; i != ((unsigned)-1) && !max_steps_exceeded(num_steps); i--) { sort * s = q->get_decl_sort(i); - symbol const & name = q->get_decl_name(i); unsigned bv_sz = m_util.get_bv_size(s); if (is_small_bv(s) && !max_steps_exceeded(num_steps)) { - TRACE("elim_small_bv", tout << "eliminating " << name << + TRACE("elim_small_bv", tout << "eliminating " << q->get_decl_name(i) << "; sort = " << mk_ismt2_pp(s, m) << "; body = " << mk_ismt2_pp(body, m) << std::endl;); diff --git a/src/tactic/core/symmetry_reduce_tactic.cpp b/src/tactic/core/symmetry_reduce_tactic.cpp index 0ee606da9..873dc55bc 100644 --- a/src/tactic/core/symmetry_reduce_tactic.cpp +++ b/src/tactic/core/symmetry_reduce_tactic.cpp @@ -176,7 +176,7 @@ private: app_map coloring; app_map depth; inv_app_map inv_color; - unsigned num_occs; + unsigned num_occs = 0; compute_sort_colors(fml, coloring); compute_max_depth(fml, depth); merge_colors(occs, coloring); @@ -233,7 +233,7 @@ private: typedef map pair_map; bool merge_colors(app_map const& colors1, app_map& colors2) { pair_map recolor; - unsigned num_colors = 0, v1, v2, w, old_max = 0; + unsigned num_colors = 0, v1 = 0, v2 = 0, w = 0, old_max = 0; app_map::iterator it = colors2.begin(), end = colors2.end(); for (; it != end; ++it) { app* a = it->m_key; @@ -545,7 +545,7 @@ private: term_set& cts, term_set const& consts, app_map const& occs) { SASSERT(!T.empty()); app* t = T[0]; - unsigned weight, weight1; + unsigned weight = 0, weight1 = 0; VERIFY(occs.find(t, weight)); unsigned cts_delta = compute_cts_delta(t, cts, consts); TRACE("symmetry_reduce", tout << mk_pp(t, m()) << " " << weight << " " << cts_delta << "\n";); @@ -559,9 +559,9 @@ private: TRACE("symmetry_reduce", tout << mk_pp(t1, m()) << " " << weight1 << " " << cts_delta1 << "\n";); if ((t->get_num_args() == t1->get_num_args() && (weight1 > weight || cts_delta1 < cts_delta)) || t->get_num_args() > t1->get_num_args()) { - cts_delta = cts_delta1; - weight = weight1; - t = t1; + cts_delta = cts_delta1; + weight = weight1; + t = t1; } } return t; diff --git a/src/tactic/nlsat_smt/nl_purify_tactic.cpp b/src/tactic/nlsat_smt/nl_purify_tactic.cpp index 030d0bd8c..d8b016d7b 100644 --- a/src/tactic/nlsat_smt/nl_purify_tactic.cpp +++ b/src/tactic/nlsat_smt/nl_purify_tactic.cpp @@ -154,8 +154,7 @@ public: void mk_interface_bool(func_decl * f, unsigned num, expr* const* args, expr_ref& result, proof_ref& pr) { expr_ref old_pred(m.mk_app(f, num, args), m); - polarity_t pol; - VERIFY(m_polarities.find(old_pred, pol)); + polarity_t pol = m_polarities.find(old_pred); result = m.mk_fresh_const(0, m.mk_bool_sort()); m_polarities.insert(result, pol); m_new_preds.push_back(to_app(result)); diff --git a/src/tactic/tactical.h b/src/tactic/tactical.h index 9aac3d42d..4b4274b0c 100644 --- a/src/tactic/tactical.h +++ b/src/tactic/tactical.h @@ -48,7 +48,7 @@ tactic * or_else(tactic * t1, tactic * t2, tactic * t3, tactic * t4, tactic * t5 tactic * repeat(tactic * t, unsigned max = UINT_MAX); /** \brief Fails if \c t produeces more than \c threshold subgoals. - Otherwise, it behabes like \c t. + Otherwise, it behaves like \c t. */ tactic * fail_if_branching(tactic * t, unsigned threshold = 1); diff --git a/src/util/mpf.cpp b/src/util/mpf.cpp index d77b8c33f..03b720ae1 100644 --- a/src/util/mpf.cpp +++ b/src/util/mpf.cpp @@ -1290,6 +1290,7 @@ void mpf_manager::partial_remainder(mpf & x, mpf const & y, mpf_exp_t const & ex m_mpz_manager.machine_div2k(Q_sig, sbits+3); renormalize(ebits, sbits, Q_exp, Q_sig); + (void)Q_sgn; TRACE("mpf_dbg_rem", tout << "Q_exp=" << Q_exp << std::endl; tout << "Q_sig=" << m_mpz_manager.to_string(Q_sig) << std::endl; tout << "Q=" << to_string_hexfloat(Q_sgn, Q_exp, Q_sig, ebits, sbits, 0) << std::endl;); @@ -1310,6 +1311,7 @@ void mpf_manager::partial_remainder(mpf & x, mpf const & y, mpf_exp_t const & ex 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. + (void)YQ_sgn; 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; From 8bde7b8a4cdabe15f4d72c07d172460d598ebd99 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Thu, 23 Jun 2016 19:31:00 +0100 Subject: [PATCH 044/536] Added facilities for dumping smt_params for debugging purposes --- src/ast/pattern/pattern_inference_params.cpp | 15 +++ src/ast/pattern/pattern_inference_params.h | 2 + .../rewriter/bit_blaster/bit_blaster_params.h | 7 +- .../simplifier/arith_simplifier_params.cpp | 7 ++ src/ast/simplifier/arith_simplifier_params.h | 2 + src/ast/simplifier/bv_simplifier_params.cpp | 7 ++ src/ast/simplifier/bv_simplifier_params.h | 2 + src/smt/params/dyn_ack_params.cpp | 11 +++ src/smt/params/dyn_ack_params.h | 2 + src/smt/params/preprocessor_params.cpp | 30 ++++++ src/smt/params/preprocessor_params.h | 2 + src/smt/params/qi_params.cpp | 27 ++++++ src/smt/params/qi_params.h | 4 +- src/smt/params/smt_params.cpp | 93 +++++++++++++++++++ src/smt/params/smt_params.h | 2 + src/smt/params/theory_arith_params.cpp | 48 ++++++++++ src/smt/params/theory_arith_params.h | 2 + src/smt/params/theory_array_params.cpp | 12 +++ src/smt/params/theory_array_params.h | 1 + src/smt/params/theory_bv_params.cpp | 11 +++ src/smt/params/theory_bv_params.h | 2 + src/smt/params/theory_datatype_params.h | 2 + src/smt/params/theory_pb_params.cpp | 9 ++ src/smt/params/theory_pb_params.h | 2 + 24 files changed, 300 insertions(+), 2 deletions(-) diff --git a/src/ast/pattern/pattern_inference_params.cpp b/src/ast/pattern/pattern_inference_params.cpp index 8adbdb9f1..b36d372f5 100644 --- a/src/ast/pattern/pattern_inference_params.cpp +++ b/src/ast/pattern/pattern_inference_params.cpp @@ -30,3 +30,18 @@ void pattern_inference_params::updt_params(params_ref const & _p) { m_pi_pull_quantifiers = p.pull_quantifiers(); m_pi_warnings = p.warnings(); } + +#define DISPLAY_PARAM(X) out << #X"=" << X << std::endl; + +void pattern_inference_params::display(std::ostream & out) const { + DISPLAY_PARAM(m_pi_max_multi_patterns); + DISPLAY_PARAM(m_pi_block_loop_patterns); + DISPLAY_PARAM(m_pi_arith); + DISPLAY_PARAM(m_pi_use_database); + DISPLAY_PARAM(m_pi_arith_weight); + DISPLAY_PARAM(m_pi_non_nested_arith_weight); + DISPLAY_PARAM(m_pi_pull_quantifiers); + DISPLAY_PARAM(m_pi_nopat_weight); + DISPLAY_PARAM(m_pi_avoid_skolems); + DISPLAY_PARAM(m_pi_warnings); +} \ No newline at end of file diff --git a/src/ast/pattern/pattern_inference_params.h b/src/ast/pattern/pattern_inference_params.h index a941b7dd6..0dc413399 100644 --- a/src/ast/pattern/pattern_inference_params.h +++ b/src/ast/pattern/pattern_inference_params.h @@ -46,6 +46,8 @@ struct pattern_inference_params { } void updt_params(params_ref const & _p); + + void display(std::ostream & out) const; }; #endif /* PATTERN_INFERENCE_PARAMS_H_ */ diff --git a/src/ast/rewriter/bit_blaster/bit_blaster_params.h b/src/ast/rewriter/bit_blaster/bit_blaster_params.h index ee32d005a..15ece0043 100644 --- a/src/ast/rewriter/bit_blaster/bit_blaster_params.h +++ b/src/ast/rewriter/bit_blaster/bit_blaster_params.h @@ -22,7 +22,7 @@ Revision History: struct bit_blaster_params { bool m_bb_ext_gates; bool m_bb_quantifiers; - bit_blaster_params(): + bit_blaster_params() : m_bb_ext_gates(false), m_bb_quantifiers(false) { } @@ -32,6 +32,11 @@ struct bit_blaster_params { p.register_bool_param("bb_quantifiers", m_bb_quantifiers, "convert bit-vectors to Booleans in quantifiers"); } #endif + + void display(std::ostream & out) const { + out << "m_bb_ext_gates=" << m_bb_ext_gates << std::endl; + out << "m_bb_quantifiers=" << m_bb_quantifiers << std::endl; + } }; #endif /* BIT_BLASTER_PARAMS_H_ */ diff --git a/src/ast/simplifier/arith_simplifier_params.cpp b/src/ast/simplifier/arith_simplifier_params.cpp index a3fabe02f..8584cdae0 100644 --- a/src/ast/simplifier/arith_simplifier_params.cpp +++ b/src/ast/simplifier/arith_simplifier_params.cpp @@ -24,3 +24,10 @@ void arith_simplifier_params::updt_params(params_ref const & _p) { m_arith_expand_eqs = p.arith_expand_eqs(); m_arith_process_all_eqs = p.arith_process_all_eqs(); } + +#define DISPLAY_PARAM(X) out << #X"=" << X << std::endl; + +void arith_simplifier_params::display(std::ostream & out) const { + DISPLAY_PARAM(m_arith_expand_eqs); + DISPLAY_PARAM(m_arith_process_all_eqs); +} \ No newline at end of file diff --git a/src/ast/simplifier/arith_simplifier_params.h b/src/ast/simplifier/arith_simplifier_params.h index 2ff8fe2c0..6186ee4a2 100644 --- a/src/ast/simplifier/arith_simplifier_params.h +++ b/src/ast/simplifier/arith_simplifier_params.h @@ -30,6 +30,8 @@ struct arith_simplifier_params { } void updt_params(params_ref const & _p); + + void display(std::ostream & out) const; }; #endif /* ARITH_SIMPLIFIER_PARAMS_H_ */ diff --git a/src/ast/simplifier/bv_simplifier_params.cpp b/src/ast/simplifier/bv_simplifier_params.cpp index 5d6cd363f..1ed263aa6 100644 --- a/src/ast/simplifier/bv_simplifier_params.cpp +++ b/src/ast/simplifier/bv_simplifier_params.cpp @@ -27,3 +27,10 @@ void bv_simplifier_params::updt_params(params_ref const & _p) { m_bv2int_distribute = p.bv_bv2int_distribute(); } + +#define DISPLAY_PARAM(X) out << #X"=" << X << std::endl; + +void bv_simplifier_params::display(std::ostream & out) const { + DISPLAY_PARAM(m_hi_div0); + DISPLAY_PARAM(m_bv2int_distribute); +} \ No newline at end of file diff --git a/src/ast/simplifier/bv_simplifier_params.h b/src/ast/simplifier/bv_simplifier_params.h index 50015b7ca..dafa99065 100644 --- a/src/ast/simplifier/bv_simplifier_params.h +++ b/src/ast/simplifier/bv_simplifier_params.h @@ -30,6 +30,8 @@ struct bv_simplifier_params { } void updt_params(params_ref const & _p); + + void display(std::ostream & out) const; }; #endif /* BV_SIMPLIFIER_PARAMS_H_ */ diff --git a/src/smt/params/dyn_ack_params.cpp b/src/smt/params/dyn_ack_params.cpp index 15f48bad1..b62530fbf 100644 --- a/src/smt/params/dyn_ack_params.cpp +++ b/src/smt/params/dyn_ack_params.cpp @@ -28,3 +28,14 @@ void dyn_ack_params::updt_params(params_ref const & _p) { m_dack_gc = p.dack_gc(); m_dack_gc_inv_decay = p.dack_gc_inv_decay(); } + +#define DISPLAY_PARAM(X) out << #X"=" << X << std::endl; + +void dyn_ack_params::display(std::ostream & out) const { + DISPLAY_PARAM(m_dack); + DISPLAY_PARAM(m_dack_eq); + DISPLAY_PARAM(m_dack_factor); + DISPLAY_PARAM(m_dack_threshold); + DISPLAY_PARAM(m_dack_gc); + DISPLAY_PARAM(m_dack_gc_inv_decay); +} \ No newline at end of file diff --git a/src/smt/params/dyn_ack_params.h b/src/smt/params/dyn_ack_params.h index f87e3b6df..017b7fe94 100644 --- a/src/smt/params/dyn_ack_params.h +++ b/src/smt/params/dyn_ack_params.h @@ -47,6 +47,8 @@ public: } void updt_params(params_ref const & _p); + + void display(std::ostream & out) const; }; diff --git a/src/smt/params/preprocessor_params.cpp b/src/smt/params/preprocessor_params.cpp index 9ad787c2a..7a0e96248 100644 --- a/src/smt/params/preprocessor_params.cpp +++ b/src/smt/params/preprocessor_params.cpp @@ -32,3 +32,33 @@ void preprocessor_params::updt_params(params_ref const & p) { arith_simplifier_params::updt_params(p); updt_local_params(p); } + +#define DISPLAY_PARAM(X) out << #X"=" << X << std::endl; + +void preprocessor_params::display(std::ostream & out) const { + pattern_inference_params::display(out); + bit_blaster_params::display(out); + bv_simplifier_params::display(out); + arith_simplifier_params::display(out); + + DISPLAY_PARAM(m_lift_ite); + DISPLAY_PARAM(m_ng_lift_ite); + DISPLAY_PARAM(m_pull_cheap_ite_trees); + DISPLAY_PARAM(m_pull_nested_quantifiers); + DISPLAY_PARAM(m_eliminate_term_ite); + DISPLAY_PARAM(m_eliminate_and); + DISPLAY_PARAM(m_macro_finder); + DISPLAY_PARAM(m_propagate_values); + DISPLAY_PARAM(m_propagate_booleans); + DISPLAY_PARAM(m_refine_inj_axiom); + DISPLAY_PARAM(m_eliminate_bounds); + DISPLAY_PARAM(m_simplify_bit2int); + DISPLAY_PARAM(m_nnf_cnf); + DISPLAY_PARAM(m_distribute_forall); + DISPLAY_PARAM(m_reduce_args); + DISPLAY_PARAM(m_quasi_macros); + DISPLAY_PARAM(m_restricted_quasi_macros); + DISPLAY_PARAM(m_max_bv_sharing); + DISPLAY_PARAM(m_pre_simplifier); + DISPLAY_PARAM(m_nlquant_elim); +} diff --git a/src/smt/params/preprocessor_params.h b/src/smt/params/preprocessor_params.h index 3806b26cf..4ffad48a2 100644 --- a/src/smt/params/preprocessor_params.h +++ b/src/smt/params/preprocessor_params.h @@ -83,6 +83,8 @@ public: void updt_local_params(params_ref const & p); void updt_params(params_ref const & p); + + void display(std::ostream & out) const; }; #endif /* PREPROCESSOR_PARAMS_H_ */ diff --git a/src/smt/params/qi_params.cpp b/src/smt/params/qi_params.cpp index 60fcd6fc4..a341040ce 100644 --- a/src/smt/params/qi_params.cpp +++ b/src/smt/params/qi_params.cpp @@ -36,3 +36,30 @@ void qi_params::updt_params(params_ref const & _p) { m_qi_cost = p.qi_cost(); m_qi_max_eager_multipatterns = p.qi_max_multi_patterns(); } + +#define DISPLAY_PARAM(X) out << #X"=" << X << std::endl; + +void qi_params::display(std::ostream & out) const { + DISPLAY_PARAM(m_qi_ematching); + DISPLAY_PARAM(m_qi_cost); + DISPLAY_PARAM(m_qi_new_gen); + DISPLAY_PARAM(m_qi_eager_threshold); + DISPLAY_PARAM(m_qi_lazy_threshold); + DISPLAY_PARAM(m_qi_max_eager_multipatterns); + DISPLAY_PARAM(m_qi_max_lazy_multipattern_matching); + DISPLAY_PARAM(m_qi_profile); + DISPLAY_PARAM(m_qi_profile_freq); + DISPLAY_PARAM(m_qi_quick_checker); + DISPLAY_PARAM(m_qi_lazy_quick_checker); + DISPLAY_PARAM(m_qi_promote_unsat); + DISPLAY_PARAM(m_qi_max_instances); + DISPLAY_PARAM(m_qi_lazy_instantiation); + DISPLAY_PARAM(m_qi_conservative_final_check); + DISPLAY_PARAM(m_mbqi); + DISPLAY_PARAM(m_mbqi_max_cexs); + DISPLAY_PARAM(m_mbqi_max_cexs_incr); + DISPLAY_PARAM(m_mbqi_max_iterations); + DISPLAY_PARAM(m_mbqi_trace); + DISPLAY_PARAM(m_mbqi_force_template); + DISPLAY_PARAM(m_mbqi_id); +} \ No newline at end of file diff --git a/src/smt/params/qi_params.h b/src/smt/params/qi_params.h index 00baea170..c9736909a 100644 --- a/src/smt/params/qi_params.h +++ b/src/smt/params/qi_params.h @@ -98,13 +98,15 @@ struct qi_params { m_mbqi_max_cexs_incr(1), m_mbqi_max_iterations(1000), m_mbqi_trace(false), - m_mbqi_force_template(10), + m_mbqi_force_template(10), m_mbqi_id(0) { updt_params(p); } void updt_params(params_ref const & p); + + void display(std::ostream & out) const; }; #endif /* QI_PARAMS_H_ */ diff --git a/src/smt/params/smt_params.cpp b/src/smt/params/smt_params.cpp index 8222c3d60..8a9188e2b 100644 --- a/src/smt/params/smt_params.cpp +++ b/src/smt/params/smt_params.cpp @@ -63,3 +63,96 @@ void smt_params::updt_params(context_params const & p) { m_auto_config = p.m_auto_config; m_model = p.m_model; } + +#define DISPLAY_PARAM(X) out << #X"=" << X << std::endl; + +void smt_params::display(std::ostream & out) const { + preprocessor_params::display(out); + dyn_ack_params::display(out); + qi_params::display(out); + theory_arith_params::display(out); + theory_array_params::display(out); + theory_bv_params::display(out); + theory_pb_params::display(out); + theory_datatype_params::display(out); + + DISPLAY_PARAM(m_display_proof); + DISPLAY_PARAM(m_display_dot_proof); + DISPLAY_PARAM(m_display_unsat_core); + DISPLAY_PARAM(m_check_proof); + DISPLAY_PARAM(m_eq_propagation); + DISPLAY_PARAM(m_binary_clause_opt); + DISPLAY_PARAM(m_relevancy_lvl); + DISPLAY_PARAM(m_relevancy_lemma); + DISPLAY_PARAM(m_random_seed); + DISPLAY_PARAM(m_random_var_freq); + DISPLAY_PARAM(m_inv_decay); + DISPLAY_PARAM(m_clause_decay); + DISPLAY_PARAM(m_random_initial_activity); + DISPLAY_PARAM(m_phase_selection); + DISPLAY_PARAM(m_phase_caching_on); + DISPLAY_PARAM(m_phase_caching_off); + DISPLAY_PARAM(m_minimize_lemmas); + DISPLAY_PARAM(m_max_conflicts); + DISPLAY_PARAM(m_simplify_clauses); + DISPLAY_PARAM(m_tick); + DISPLAY_PARAM(m_display_features); + DISPLAY_PARAM(m_new_core2th_eq); + DISPLAY_PARAM(m_ematching); + + DISPLAY_PARAM(m_case_split_strategy); + DISPLAY_PARAM(m_rel_case_split_order); + DISPLAY_PARAM(m_lookahead_diseq); + + DISPLAY_PARAM(m_delay_units); + DISPLAY_PARAM(m_delay_units_threshold); + + DISPLAY_PARAM(m_theory_resolve); + + DISPLAY_PARAM(m_restart_strategy); + DISPLAY_PARAM(m_restart_initial); + DISPLAY_PARAM(m_restart_factor); + DISPLAY_PARAM(m_restart_adaptive); + DISPLAY_PARAM(m_agility_factor); + DISPLAY_PARAM(m_restart_agility_threshold); + + DISPLAY_PARAM(m_lemma_gc_strategy); + DISPLAY_PARAM(m_lemma_gc_half); + DISPLAY_PARAM(m_recent_lemmas_size); + DISPLAY_PARAM(m_lemma_gc_initial); + DISPLAY_PARAM(m_lemma_gc_factor); + DISPLAY_PARAM(m_new_old_ratio); + DISPLAY_PARAM(m_new_clause_activity); + DISPLAY_PARAM(m_old_clause_activity); + DISPLAY_PARAM(m_new_clause_relevancy); + DISPLAY_PARAM(m_old_clause_relevancy); + DISPLAY_PARAM(m_inv_clause_decay); + + DISPLAY_PARAM(m_smtlib_dump_lemmas); + DISPLAY_PARAM(m_logic); + + DISPLAY_PARAM(m_profile_res_sub); + DISPLAY_PARAM(m_display_bool_var2expr); + DISPLAY_PARAM(m_display_ll_bool_var2expr); + DISPLAY_PARAM(m_abort_after_preproc); + + DISPLAY_PARAM(m_model); + DISPLAY_PARAM(m_model_compact); + DISPLAY_PARAM(m_model_on_timeout); + DISPLAY_PARAM(m_model_on_final_check); + + DISPLAY_PARAM(m_progress_sampling_freq); + + DISPLAY_PARAM(m_display_installed_theories); + DISPLAY_PARAM(m_core_validate); + + DISPLAY_PARAM(m_preprocess); + DISPLAY_PARAM(m_user_theory_preprocess_axioms); + DISPLAY_PARAM(m_user_theory_persist_axioms); + DISPLAY_PARAM(m_timeout); + DISPLAY_PARAM(m_rlimit); + DISPLAY_PARAM(m_at_labels_cex); + DISPLAY_PARAM(m_check_at_labels); + DISPLAY_PARAM(m_dump_goal_as_smt); + DISPLAY_PARAM(m_auto_config); +} \ No newline at end of file diff --git a/src/smt/params/smt_params.h b/src/smt/params/smt_params.h index 9c1eec649..366570365 100644 --- a/src/smt/params/smt_params.h +++ b/src/smt/params/smt_params.h @@ -289,6 +289,8 @@ struct smt_params : public preprocessor_params, void updt_params(params_ref const & p); void updt_params(context_params const & p); + + void display(std::ostream & out) const; }; #endif /* SMT_PARAMS_H_ */ diff --git a/src/smt/params/theory_arith_params.cpp b/src/smt/params/theory_arith_params.cpp index fef7ca2a0..1e3f29142 100644 --- a/src/smt/params/theory_arith_params.cpp +++ b/src/smt/params/theory_arith_params.cpp @@ -38,3 +38,51 @@ void theory_arith_params::updt_params(params_ref const & _p) { } +#define DISPLAY_PARAM(X) out << #X"=" << X << std::endl; + +void theory_arith_params::display(std::ostream & out) const { + DISPLAY_PARAM(m_arith_mode); + DISPLAY_PARAM(m_arith_auto_config_simplex); //!< force simplex solver in auto_config + DISPLAY_PARAM(m_arith_blands_rule_threshold); + DISPLAY_PARAM(m_arith_propagate_eqs); + DISPLAY_PARAM(m_arith_bound_prop); + DISPLAY_PARAM(m_arith_stronger_lemmas); + DISPLAY_PARAM(m_arith_skip_rows_with_big_coeffs); + DISPLAY_PARAM(m_arith_max_lemma_size); + DISPLAY_PARAM(m_arith_small_lemma_size); + DISPLAY_PARAM(m_arith_reflect); + DISPLAY_PARAM(m_arith_ignore_int); + DISPLAY_PARAM(m_arith_lazy_pivoting_lvl); + DISPLAY_PARAM(m_arith_random_seed); + DISPLAY_PARAM(m_arith_random_initial_value); + DISPLAY_PARAM(m_arith_random_lower); + DISPLAY_PARAM(m_arith_random_upper); + DISPLAY_PARAM(m_arith_adaptive); + DISPLAY_PARAM(m_arith_adaptive_assertion_threshold); + DISPLAY_PARAM(m_arith_adaptive_propagation_threshold); + DISPLAY_PARAM(m_arith_dump_lemmas); + DISPLAY_PARAM(m_arith_eager_eq_axioms); + DISPLAY_PARAM(m_arith_branch_cut_ratio); + DISPLAY_PARAM(m_arith_int_eq_branching); + DISPLAY_PARAM(m_arith_enum_const_mod); + DISPLAY_PARAM(m_arith_gcd_test); + DISPLAY_PARAM(m_arith_eager_gcd); + DISPLAY_PARAM(m_arith_adaptive_gcd); + DISPLAY_PARAM(m_arith_propagation_threshold); + DISPLAY_PARAM(m_arith_pivot_strategy); + DISPLAY_PARAM(m_arith_add_binary_bounds); + DISPLAY_PARAM(m_arith_propagation_strategy); + DISPLAY_PARAM(m_arith_eq_bounds); + DISPLAY_PARAM(m_arith_lazy_adapter); + DISPLAY_PARAM(m_arith_fixnum); + DISPLAY_PARAM(m_arith_int_only); + DISPLAY_PARAM(m_nl_arith); + DISPLAY_PARAM(m_nl_arith_gb); + DISPLAY_PARAM(m_nl_arith_gb_threshold); + DISPLAY_PARAM(m_nl_arith_gb_eqs); + DISPLAY_PARAM(m_nl_arith_gb_perturbate); + DISPLAY_PARAM(m_nl_arith_max_degree); + DISPLAY_PARAM(m_nl_arith_branching); + DISPLAY_PARAM(m_nl_arith_rounds); + DISPLAY_PARAM(m_arith_euclidean_solver); +} \ No newline at end of file diff --git a/src/smt/params/theory_arith_params.h b/src/smt/params/theory_arith_params.h index 18418d1ef..943bd711e 100644 --- a/src/smt/params/theory_arith_params.h +++ b/src/smt/params/theory_arith_params.h @@ -156,6 +156,8 @@ struct theory_arith_params { } void updt_params(params_ref const & p); + + void display(std::ostream & out) const; }; #endif /* THEORY_ARITH_PARAMS_H_ */ diff --git a/src/smt/params/theory_array_params.cpp b/src/smt/params/theory_array_params.cpp index e3c8b2448..c0015bf2c 100644 --- a/src/smt/params/theory_array_params.cpp +++ b/src/smt/params/theory_array_params.cpp @@ -25,4 +25,16 @@ void theory_array_params::updt_params(params_ref const & _p) { m_array_extensional = p.array_extensional(); } +#define DISPLAY_PARAM(X) out << #X"=" << X << std::endl; +void theory_array_params::display(std::ostream & out) const { + DISPLAY_PARAM(m_array_mode); + DISPLAY_PARAM(m_array_weak); + DISPLAY_PARAM(m_array_extensional); + DISPLAY_PARAM(m_array_laziness); + DISPLAY_PARAM(m_array_delay_exp_axiom); + DISPLAY_PARAM(m_array_cg); + DISPLAY_PARAM(m_array_always_prop_upward); + DISPLAY_PARAM(m_array_lazy_ieq); + DISPLAY_PARAM(m_array_lazy_ieq_delay); +} \ No newline at end of file diff --git a/src/smt/params/theory_array_params.h b/src/smt/params/theory_array_params.h index 85996078f..af51427c4 100644 --- a/src/smt/params/theory_array_params.h +++ b/src/smt/params/theory_array_params.h @@ -71,6 +71,7 @@ struct theory_array_params : public array_simplifier_params { } #endif + void display(std::ostream & out) const; }; diff --git a/src/smt/params/theory_bv_params.cpp b/src/smt/params/theory_bv_params.cpp index d3f386ab4..631c5765b 100644 --- a/src/smt/params/theory_bv_params.cpp +++ b/src/smt/params/theory_bv_params.cpp @@ -24,3 +24,14 @@ void theory_bv_params::updt_params(params_ref const & _p) { m_bv_reflect = p.bv_reflect(); m_bv_enable_int2bv2int = p.bv_enable_int2bv(); } + +#define DISPLAY_PARAM(X) out << #X"=" << X << std::endl; + +void theory_bv_params::display(std::ostream & out) const { + DISPLAY_PARAM(m_bv_mode); + DISPLAY_PARAM(m_bv_reflect); + DISPLAY_PARAM(m_bv_lazy_le); + DISPLAY_PARAM(m_bv_cc); + DISPLAY_PARAM(m_bv_blast_max_size); + DISPLAY_PARAM(m_bv_enable_int2bv2int); +} \ No newline at end of file diff --git a/src/smt/params/theory_bv_params.h b/src/smt/params/theory_bv_params.h index 00565969e..5830e5176 100644 --- a/src/smt/params/theory_bv_params.h +++ b/src/smt/params/theory_bv_params.h @@ -44,6 +44,8 @@ struct theory_bv_params { } void updt_params(params_ref const & p); + + void display(std::ostream & out) const; }; #endif /* THEORY_BV_PARAMS_H_ */ diff --git a/src/smt/params/theory_datatype_params.h b/src/smt/params/theory_datatype_params.h index 4dd09a596..9f801e46c 100644 --- a/src/smt/params/theory_datatype_params.h +++ b/src/smt/params/theory_datatype_params.h @@ -31,6 +31,8 @@ struct theory_datatype_params { p.register_unsigned_param("dt_lazy_splits", m_dt_lazy_splits, "How lazy datatype splits are performed: 0- eager, 1- lazy for infinite types, 2- lazy"); } #endif + + void display(std::ostream & out) const { out << "m_dt_lazy_splits=" << m_dt_lazy_splits << std::endl; } }; diff --git a/src/smt/params/theory_pb_params.cpp b/src/smt/params/theory_pb_params.cpp index 6d980fe5d..a1e13a6e7 100644 --- a/src/smt/params/theory_pb_params.cpp +++ b/src/smt/params/theory_pb_params.cpp @@ -26,3 +26,12 @@ void theory_pb_params::updt_params(params_ref const & _p) { m_pb_enable_compilation = p.pb_enable_compilation(); m_pb_enable_simplex = p.pb_enable_simplex(); } + +#define DISPLAY_PARAM(X) out << #X"=" << X << std::endl; + +void theory_pb_params::display(std::ostream & out) const { + DISPLAY_PARAM(m_pb_conflict_frequency); + DISPLAY_PARAM(m_pb_learn_complements); + DISPLAY_PARAM(m_pb_enable_compilation); + DISPLAY_PARAM(m_pb_enable_simplex); +} \ No newline at end of file diff --git a/src/smt/params/theory_pb_params.h b/src/smt/params/theory_pb_params.h index 2af4f04b7..6a129e601 100644 --- a/src/smt/params/theory_pb_params.h +++ b/src/smt/params/theory_pb_params.h @@ -35,6 +35,8 @@ struct theory_pb_params { {} void updt_params(params_ref const & p); + + void display(std::ostream & out) const; }; #endif /* THEORY_PB_PARAMS_H_ */ From c72ed3e6b4c7fdde58bb564e90dd925097c79a97 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 23 Jun 2016 21:39:28 -0700 Subject: [PATCH 045/536] update core minimization code Signed-off-by: Nikolaj Bjorner --- src/opt/maxres.cpp | 11 +- src/qe/qsat.cpp | 8 +- src/smt/params/smt_params_helper.pyg | 3 +- src/smt/smt_solver.cpp | 42 +++- src/solver/mus.cpp | 286 +++++++++++++++++++-------- src/solver/mus.h | 8 +- src/solver/solver_na2as.h | 1 + src/util/hashtable.h | 36 +++- src/util/obj_hashtable.h | 1 + 9 files changed, 287 insertions(+), 109 deletions(-) diff --git a/src/opt/maxres.cpp b/src/opt/maxres.cpp index b52c7d9b9..b6950f674 100644 --- a/src/opt/maxres.cpp +++ b/src/opt/maxres.cpp @@ -544,18 +544,11 @@ public: return l_true; } m_mus.reset(); - for (unsigned i = 0; i < core.size(); ++i) { - VERIFY(i == m_mus.add_soft(core[i])); - } - unsigned_vector mus_idx; - lbool is_sat = m_mus.get_mus(mus_idx); + m_mus.add_soft(core.size(), core.c_ptr()); + lbool is_sat = m_mus.get_mus(m_new_core); if (is_sat != l_true) { return is_sat; } - m_new_core.reset(); - for (unsigned i = 0; i < mus_idx.size(); ++i) { - m_new_core.push_back(core[mus_idx[i]]); - } core.reset(); core.append(m_new_core); return l_true; diff --git a/src/qe/qsat.cpp b/src/qe/qsat.cpp index 74b6769ae..02c6d26cd 100644 --- a/src/qe/qsat.cpp +++ b/src/qe/qsat.cpp @@ -811,14 +811,10 @@ namespace qe { } TRACE("qe", tout << core1.size() << " " << core2.size() << "\n";); if (core1.size() > 8) { - unsigned_vector core_idxs; - if (l_true != mus.get_mus(core_idxs)) { + if (l_true != mus.get_mus(core2)) { return false; } - TRACE("qe", tout << core1.size() << " -> " << core_idxs.size() << "\n";); - for (unsigned i = 0; i < core_idxs.size(); ++i) { - core2.push_back(core1[core_idxs[i]].get()); - } + TRACE("qe", tout << core1.size() << " -> " << core2.size() << "\n";); core.reset(); core.append(core2); } diff --git a/src/smt/params/smt_params_helper.pyg b/src/smt/params/smt_params_helper.pyg index a9f6ccc18..153d948f5 100644 --- a/src/smt/params/smt_params_helper.pyg +++ b/src/smt/params/smt_params_helper.pyg @@ -61,5 +61,6 @@ def_module_params(module_name='smt', ('dack.gc', UINT, 2000, 'Dynamic ackermannization garbage collection frequency (per conflict)'), ('dack.gc_inv_decay', DOUBLE, 0.8, 'Dynamic ackermannization garbage collection decay'), ('dack.threshold', UINT, 10, ' number of times the congruence rule must be used before Leibniz\'s axiom is expanded'), - ('core.validate', BOOL, False, 'validate unsat core produced by SMT context') + ('core.validate', BOOL, False, 'validate unsat core produced by SMT context'), + ('core.minimize', BOOL, False, 'minimize unsat core produced by SMT context') )) diff --git a/src/smt/smt_solver.cpp b/src/smt/smt_solver.cpp index 59c08006b..6ae7f107c 100644 --- a/src/smt/smt_solver.cpp +++ b/src/smt/smt_solver.cpp @@ -20,19 +20,25 @@ Notes: #include"smt_kernel.h" #include"reg_decl_plugins.h" #include"smt_params.h" +#include"smt_params_helper.hpp" +#include"mus.h" namespace smt { class solver : public solver_na2as { - smt_params m_params; + smt_params m_smt_params; + params_ref m_params; smt::kernel m_context; progress_callback * m_callback; symbol m_logic; + bool m_minimizing_core; public: solver(ast_manager & m, params_ref const & p, symbol const & l): solver_na2as(m), + m_smt_params(p), m_params(p), - m_context(m, m_params) { + m_context(m, m_smt_params), + m_minimizing_core(false) { m_logic = l; if (m_logic != symbol::null) m_context.set_logic(m_logic); @@ -48,7 +54,8 @@ namespace smt { } virtual void updt_params(params_ref const & p) { - m_params.updt_params(p); + m_smt_params.updt_params(p); + m_params.copy(p); m_context.updt_params(p); } @@ -77,10 +84,37 @@ namespace smt { return m_context.check(num_assumptions, assumptions); } + struct scoped_minimize_core { + solver& s; + expr_ref_vector m_assumptions; + scoped_minimize_core(solver& s): s(s), m_assumptions(s.m_assumptions) { + s.m_minimizing_core = true; + s.m_assumptions.reset(); + } + + ~scoped_minimize_core() { + s.m_minimizing_core = false; + s.m_assumptions.append(m_assumptions); + } + }; + virtual void get_unsat_core(ptr_vector & r) { unsigned sz = m_context.get_unsat_core_size(); - for (unsigned i = 0; i < sz; i++) + for (unsigned i = 0; i < sz; i++) { r.push_back(m_context.get_unsat_core_expr(i)); + } + + if (m_minimizing_core || smt_params_helper(m_params).core_minimize() == false) { + return; + } + scoped_minimize_core scm(*this); + mus mus(*this); + mus.add_soft(r.size(), r.c_ptr()); + ptr_vector r2; + if (l_true == mus.get_mus(r2)) { + r.reset(); + r.append(r2); + } } virtual void get_model(model_ref & m) { diff --git a/src/solver/mus.cpp b/src/solver/mus.cpp index 4960a3d2a..adfe42192 100644 --- a/src/solver/mus.cpp +++ b/src/solver/mus.cpp @@ -22,10 +22,13 @@ Notes: #include "mus.h" #include "ast_pp.h" #include "ast_util.h" -#include "uint_set.h" +#include "model_evaluator.h" struct mus::imp { + + typedef obj_hashtable expr_set; + solver& m_solver; ast_manager& m; expr_ref_vector m_lit2expr; @@ -56,7 +59,7 @@ struct mus::imp { unsigned idx = m_lit2expr.size(); m_expr2lit.insert(lit, idx); m_lit2expr.push_back(lit); - TRACE("opt", tout << idx << ": " << mk_pp(lit, m) << "\n" << m_lit2expr << "\n";); + TRACE("mus", tout << idx << ": " << mk_pp(lit, m) << "\n" << m_lit2expr << "\n";); return idx; } @@ -64,66 +67,61 @@ struct mus::imp { SASSERT(is_literal(lit)); m_assumptions.push_back(lit); } - - lbool get_mus(unsigned_vector& mus) { - // SASSERT: mus does not have duplicates. + + lbool get_mus(expr_ref_vector& mus) { m_model.reset(); - unsigned_vector core; - for (unsigned i = 0; i < m_lit2expr.size(); ++i) { - core.push_back(i); - } - if (core.size() == 1) { - mus.push_back(core.back()); + mus.reset(); + if (m_lit2expr.size() == 1) { + mus.push_back(m_lit2expr.back()); return l_true; } + return get_mus1(mus); + } + lbool get_mus(ptr_vector& mus) { mus.reset(); - if (false && core.size() > 64) { - return qx(mus); - } + expr_ref_vector result(m); + lbool r = get_mus(result); + mus.append(result.size(), result.c_ptr()); + return r; + } - expr_ref_vector assumptions(m); + lbool get_mus1(expr_ref_vector& mus) { + ptr_vector unknown(m_lit2expr.size(), m_lit2expr.c_ptr()); ptr_vector core_exprs; - while (!core.empty()) { - IF_VERBOSE(12, verbose_stream() << "(opt.mus reducing core: " << core.size() << " new core: " << mus.size() << ")\n";); - unsigned lit_id = core.back(); - TRACE("opt", - display_vec(tout << "core: ", core); - display_vec(tout << "mus: ", mus); - ); - core.pop_back(); - expr* lit = m_lit2expr[lit_id].get(); - expr_ref not_lit(m); - not_lit = mk_not(m, lit); + while (!unknown.empty()) { + IF_VERBOSE(12, verbose_stream() << "(mus reducing core: " << unknown.size() << " new core: " << mus.size() << ")\n";); + TRACE("mus", display_vec(tout << "core: ", unknown); display_vec(tout << "mus: ", mus);); + expr* lit = unknown.back(); + unknown.pop_back(); + expr_ref not_lit(mk_not(m, lit), m); lbool is_sat = l_undef; { - scoped_append _sa1(*this, assumptions, core); - scoped_append _sa2(*this, assumptions, m_assumptions); - assumptions.push_back(not_lit); - is_sat = m_solver.check_sat(assumptions); + scoped_append _sa1(*this, mus, unknown); + scoped_append _sa2(*this, mus, m_assumptions); + mus.push_back(not_lit); + is_sat = m_solver.check_sat(mus); } switch (is_sat) { case l_undef: return is_sat; case l_true: - assumptions.push_back(lit); - mus.push_back(lit_id); + mus.push_back(lit); update_model(); break; default: core_exprs.reset(); m_solver.get_unsat_core(core_exprs); if (!core_exprs.contains(not_lit)) { - // core := core_exprs \ mus - core.reset(); + // unknown := core_exprs \ mus + unknown.reset(); for (unsigned i = 0; i < core_exprs.size(); ++i) { - lit = core_exprs[i]; - if (m_expr2lit.find(lit, lit_id) && !mus.contains(lit_id)) { - core.push_back(lit_id); + if (!mus.contains(core_exprs[i])) { + unknown.push_back(core_exprs[i]); } } - TRACE("opt", display_vec(tout << "core exprs:", core_exprs); - display_vec(tout << "core:", core); + TRACE("mus", display_vec(tout << "core exprs:", core_exprs); + display_vec(tout << "core:", unknown); display_vec(tout << "mus:", mus); ); @@ -131,36 +129,146 @@ struct mus::imp { break; } } -#if 0 - DEBUG_CODE( - assumptions.reset(); - for (unsigned i = 0; i < mus.size(); ++i) { - assumptions.push_back(m_lit2expr[mus[i]].get()); - } - lbool is_sat = m_solver.check_sat(assumptions.size(), assumptions.c_ptr()); - SASSERT(is_sat == l_false); - ); -#endif + // SASSERT(is_core(mus)); return l_true; } + // use correction sets + lbool get_mus2(expr_ref_vector& mus) { + expr* lit = 0; + lbool is_sat; + ptr_vector unknown(m_lit2expr.size(), m_lit2expr.c_ptr()); + while (!unknown.empty()) { + IF_VERBOSE(12, verbose_stream() << "(mus reducing core: " << unknown.size() << " new core: " << mus.size() << ")\n";); + { + scoped_append _sa1(*this, mus, m_assumptions); + is_sat = get_next_mcs(mus, unknown, lit); + } + if (l_false == is_sat) { + mus.push_back(lit); + } + else { + return is_sat; + } + } + + //SASSERT(is_core(mus)); + return l_true; + } + + // find the next literal to be a member of a core. + lbool get_next_mcs(expr_ref_vector& mus, ptr_vector& unknown, expr*& core_literal) { + ptr_vector mss; + expr_ref_vector nmcs(m); + expr_set core, min_core, nmcs_set; + bool min_core_valid = false; + expr* min_lit = 0; + while (!unknown.empty()) { + expr* lit = unknown.back(); + unknown.pop_back(); + model_ref mdl; + scoped_append assume_mss(*this, mus, mss); // current satisfied literals + scoped_append assume_nmcs(*this, mus, nmcs); // current non-satisfied literals + scoped_append assume_lit(*this, mus, lit); // current unknown literal + switch (m_solver.check_sat(mus)) { + case l_true: { + TRACE("mus", tout << "literal can be satisfied: " << mk_pp(lit, m) << "\n";); + mss.push_back(lit); + m_solver.get_model(mdl); + model_evaluator eval(*mdl.get()); + for (unsigned i = 0; i < unknown.size(); ) { + expr_ref tmp(m); + eval(unknown[i], tmp); + if (m.is_true(tmp)) { + mss.push_back(unknown[i]); + unknown[i] = unknown.back(); + unknown.pop_back(); + } + else { + ++i; + } + } + break; + } + case l_false: + TRACE("mus", tout << "literal is in a core: " << mk_pp(lit, m) << "\n";); + nmcs.push_back(mk_not(m, lit)); + nmcs_set.insert(nmcs.back()); + get_core(core); + if (!core.contains(lit)) { + // The current mus is already a core. + unknown.reset(); + return l_true; + } + if (have_intersection(nmcs_set, core)) { + // can't use this core directly. Hypothetically, we + // could try to combine min_core with core and + // see if the combination produces a better minimal core. + SASSERT(min_core_valid); + break; + } + if (!min_core_valid || core.size() < min_core.size()) { + // The current core is smallest so far, so we get fewer unknowns from it. + min_core = core; + min_core_valid = true; + min_lit = lit; + } + break; + case l_undef: + return l_undef; + } + } + SASSERT(min_core_valid); + if (!min_core_valid) { + // all unknown soft constraints were satisfiable + return l_true; + } + + expr_set mss_set; + for (unsigned i = 0; i < mss.size(); ++i) { + mss_set.insert(mss[i]); + } + expr_set::iterator it = min_core.begin(), end = min_core.end(); + for (; it != end; ++it) { + if (mss_set.contains(*it) && min_lit != *it) { + unknown.push_back(*it); + } + } + core_literal = min_lit; + + return l_false; + } + + bool have_intersection(expr_set const& A, expr_set const& B) { + if (A.size() < B.size()) { + expr_set::iterator it = A.begin(), end = A.end(); + for (; it != end; ++it) { + if (B.contains(*it)) return true; + } + } + else { + expr_set::iterator it = B.begin(), end = B.end(); + for (; it != end; ++it) { + if (A.contains(*it)) return true; + } + } + return false; + } + + bool is_core(expr_ref_vector const& mus) { + return l_false == m_solver.check_sat(mus); + } + class scoped_append { expr_ref_vector& m_fmls; unsigned m_size; public: - scoped_append(imp& imp, expr_ref_vector& fmls1, unsigned_vector const& fmls2): + scoped_append(imp& imp, expr_ref_vector& fmls1, expr_set const& fmls2): m_fmls(fmls1), m_size(fmls1.size()) { - for (unsigned i = 0; i < fmls2.size(); ++i) { - fmls1.push_back(imp.m_lit2expr[fmls2[i]].get()); - } - } - scoped_append(imp& imp, expr_ref_vector& fmls1, uint_set const& fmls2): - m_fmls(fmls1), - m_size(fmls1.size()) { - uint_set::iterator it = fmls2.begin(), end = fmls2.end(); + expr_set::iterator it = fmls2.begin(), end = fmls2.end(); for (; it != end; ++it) { - fmls1.push_back(imp.m_lit2expr[*it].get()); + fmls1.push_back(*it); } } scoped_append(imp& imp, expr_ref_vector& fmls1, expr_ref_vector const& fmls2): @@ -168,17 +276,21 @@ struct mus::imp { m_size(fmls1.size()) { fmls1.append(fmls2); } + scoped_append(imp& imp, expr_ref_vector& fmls1, ptr_vector const& fmls2): + m_fmls(fmls1), + m_size(fmls1.size()) { + fmls1.append(fmls2.size(), fmls2.c_ptr()); + } + scoped_append(imp& imp, expr_ref_vector& fmls1, expr* fml): + m_fmls(fmls1), + m_size(fmls1.size()) { + fmls1.push_back(fml); + } ~scoped_append() { m_fmls.shrink(m_size); } }; - void add_core(unsigned_vector const& core, expr_ref_vector& assumptions) { - for (unsigned i = 0; i < core.size(); ++i) { - assumptions.push_back(m_lit2expr[core[i]].get()); - } - } - template void display_vec(std::ostream& out, T const& v) const { for (unsigned i = 0; i < v.size(); ++i) { @@ -234,14 +346,14 @@ struct mus::imp { } - lbool qx(unsigned_vector& mus) { - uint_set core, support; + lbool qx(expr_ref_vector& mus) { + expr_set core, support; for (unsigned i = 0; i < m_lit2expr.size(); ++i) { - core.insert(i); + core.insert(m_lit2expr[i].get()); } lbool is_sat = qx(core, support, false); if (is_sat == l_true) { - uint_set::iterator it = core.begin(), end = core.end(); + expr_set::iterator it = core.begin(), end = core.end(); mus.reset(); for (; it != end; ++it) { mus.push_back(*it); @@ -250,7 +362,7 @@ struct mus::imp { return is_sat; } - lbool qx(uint_set& assignment, uint_set& support, bool has_support) { + lbool qx(expr_set& assignment, expr_set& support, bool has_support) { lbool is_sat = l_true; #if 0 if (s.m_config.m_minimize_core_partial && s.m_stats.m_restart - m_restart > m_max_restarts) { @@ -265,7 +377,7 @@ struct mus::imp { is_sat = m_solver.check_sat(asms); switch (is_sat) { case l_false: { - uint_set core; + expr_set core; get_core(core); support &= core; assignment.reset(); @@ -280,10 +392,10 @@ struct mus::imp { break; } } - if (assignment.num_elems() == 1) { + if (assignment.size() == 1) { return l_true; } - uint_set assign2; + expr_set assign2; split(assignment, assign2); support |= assignment; is_sat = qx(assign2, support, !assignment.empty()); @@ -296,20 +408,20 @@ struct mus::imp { return is_sat; } - void get_core(uint_set& core) { + void get_core(expr_set& core) { + core.reset(); ptr_vector core_exprs; - unsigned lit_id; m_solver.get_unsat_core(core_exprs); for (unsigned i = 0; i < core_exprs.size(); ++i) { - if (m_expr2lit.find(core_exprs[i], lit_id)) { - core.insert(lit_id); + if (m_expr2lit.contains(core_exprs[i])) { + core.insert(core_exprs[i]); } } } - void unsplit(uint_set& A, uint_set& B) { - uint_set A1, B1; - uint_set::iterator it = A.begin(), end = A.end(); + void unsplit(expr_set& A, expr_set& B) { + expr_set A1, B1; + expr_set::iterator it = A.begin(), end = A.end(); for (; it != end; ++it) { if (B.contains(*it)) { B1.insert(*it); @@ -322,10 +434,10 @@ struct mus::imp { B = B1; } - void split(uint_set& lits1, uint_set& lits2) { - unsigned half = lits1.num_elems()/2; - uint_set lits3; - uint_set::iterator it = lits1.begin(), end = lits1.end(); + void split(expr_set& lits1, expr_set& lits2) { + unsigned half = lits1.size()/2; + expr_set lits3; + expr_set::iterator it = lits1.begin(), end = lits1.end(); for (unsigned i = 0; it != end; ++it, ++i) { if (i < half) { lits3.insert(*it); @@ -355,7 +467,11 @@ void mus::add_assumption(expr* lit) { return m_imp->add_assumption(lit); } -lbool mus::get_mus(unsigned_vector& mus) { +lbool mus::get_mus(ptr_vector& mus) { + return m_imp->get_mus(mus); +} + +lbool mus::get_mus(expr_ref_vector& mus) { return m_imp->get_mus(mus); } diff --git a/src/solver/mus.h b/src/solver/mus.h index d2411b6ec..f2e543f04 100644 --- a/src/solver/mus.h +++ b/src/solver/mus.h @@ -33,6 +33,10 @@ class mus { Assume also that cls is a literal. */ unsigned add_soft(expr* cls); + + void add_soft(unsigned sz, expr* const* clss) { + for (unsigned i = 0; i < sz; ++i) add_soft(clss[i]); + } /** Additional assumption for solver to be used along with solver context, @@ -43,7 +47,9 @@ class mus { */ void add_assumption(expr* lit); - lbool get_mus(unsigned_vector& mus); + lbool get_mus(ptr_vector& mus); + + lbool get_mus(expr_ref_vector& mus); void reset(); diff --git a/src/solver/solver_na2as.h b/src/solver/solver_na2as.h index 019468fd7..9aeb56fb1 100644 --- a/src/solver/solver_na2as.h +++ b/src/solver/solver_na2as.h @@ -25,6 +25,7 @@ Notes: #include"solver.h" class solver_na2as : public solver { + protected: ast_manager & m; expr_ref_vector m_assumptions; unsigned_vector m_scopes; diff --git a/src/util/hashtable.h b/src/util/hashtable.h index 488157c00..fe51963e0 100644 --- a/src/util/hashtable.h +++ b/src/util/hashtable.h @@ -556,6 +556,38 @@ public: out << "]"; } + core_hashtable& operator|=(core_hashtable const& other) { + if (this == &other) return *this; + iterator i = begin(), e = end(); + for (; i != e; ++i) { + insert(*i); + } + return *this; + } + + + core_hashtable& operator&=(core_hashtable const& other) { + if (this == &other) return *this; + core_hashtable copy(*this); + iterator i = copy.begin(), e = copy.end(); + for (; i != e; ++i) { + if (!other.contains(*i)) { + remove(*i); + } + } + return *this; + } + + core_hashtable& operator=(core_hashtable const& other) { + if (this == &other) return *this; + reset(); + core_hashtable::iterator i = other.begin(), e = other.end(); + for (; i != e; ++i) { + insert(*i); + } + return *this; + } + #ifdef Z3DEBUG bool check_invariant() { entry * curr = m_table; @@ -582,9 +614,6 @@ public: unsigned long long get_num_collision() const { return 0; } #endif - private: - - core_hashtable& operator=(core_hashtable const&); }; @@ -640,4 +669,5 @@ public: core_hashtable, HashProc, EqProc>(initial_capacity, h, e) {} }; + #endif /* HASHTABLE_H_ */ diff --git a/src/util/obj_hashtable.h b/src/util/obj_hashtable.h index 4e948d96d..383ecaeb3 100644 --- a/src/util/obj_hashtable.h +++ b/src/util/obj_hashtable.h @@ -51,6 +51,7 @@ class obj_hashtable : public core_hashtable, obj_ptr_hash, public: obj_hashtable(unsigned initial_capacity = DEFAULT_HASHTABLE_INITIAL_CAPACITY): core_hashtable, obj_ptr_hash, ptr_eq >(initial_capacity) {} + }; template From 5845e633962845424ff38571ab80f04857667b51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20R=2E=20Neuh=C3=A4u=C3=9Fer?= Date: Tue, 14 Jun 2016 14:13:44 +0200 Subject: [PATCH 046/536] Make cmake not emit -fPIC to mingw64 for Windows builds. This patch detects a mingw64 build of the shared library and does not emit -fPIC to the compiler. This is necessary to avoid a warning message, as Windows native code DLLs are generally relocatable and not position independent. --- CMakeLists.txt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ee0810295..c9a01daed 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -304,7 +304,10 @@ endif() # library. If not building a shared library ``-fPIC`` isn't needed and would add # unnecessary overhead. if (BUILD_LIBZ3_SHARED) - if (NOT MSVC) + # Avoid adding -fPIC compiler switch if we compile with MSVC (which does not + # support the flag) or if we target Windows, which generally does not use + # position independent code for native code shared libraries (DLLs). + if (NOT (MSVC OR MINGW OR WIN32)) z3_add_cxx_flag("-fPIC" REQUIRED) endif() endif() @@ -387,4 +390,3 @@ option(ENABLE_EXAMPLE_TARGETS "Build Z3 api examples" ON) if (ENABLE_EXAMPLE_TARGETS) add_subdirectory(examples) endif() - From 1fb672121c14e39ab4c86e8c74905f6515dc0041 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Fri, 24 Jun 2016 13:57:53 +0100 Subject: [PATCH 047/536] build fix for cygwin/mingw --- scripts/mk_util.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/mk_util.py b/scripts/mk_util.py index 509487e23..8fafd1caa 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -604,7 +604,7 @@ elif os.name == 'posix': IS_OPENBSD=True elif os.uname()[0][:6] == 'CYGWIN': IS_CYGWIN=True - if ("mingw" in CC): + if (CC != None and "mingw" in CC): IS_CYGWIN_MINGW=True def display_help(exit_code): From e9eb88e1b3cd993641f68add997061a831e5b315 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Fri, 24 Jun 2016 15:08:56 +0100 Subject: [PATCH 048/536] fixed java build issues. Relates to #648. --- examples/java/JavaExample.java | 2 +- src/api/java/Context.java | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/examples/java/JavaExample.java b/examples/java/JavaExample.java index 74e94617d..5c8a7508f 100644 --- a/examples/java/JavaExample.java +++ b/examples/java/JavaExample.java @@ -188,7 +188,7 @@ class JavaExample /* do something with the context */ /* be kind to dispose manually and not wait for the GC. */ - ctx.dispose(); + ctx.close(); } } diff --git a/src/api/java/Context.java b/src/api/java/Context.java index 39d35d9d3..da924026c 100644 --- a/src/api/java/Context.java +++ b/src/api/java/Context.java @@ -35,6 +35,11 @@ public class Context implements AutoCloseable { init(); } + protected Context (long m_ctx) { + this.m_ctx = m_ctx; + init(); + } + /** * Constructor. From 914bf2ff3b8e0c0bde7e05e97cd4d40272d33df5 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 24 Jun 2016 07:43:05 -0700 Subject: [PATCH 049/536] extend constant folding for bit-vector overflow/underflow operators, #657 Signed-off-by: Nikolaj Bjorner --- src/ast/array_decl_plugin.cpp | 2 +- src/ast/rewriter/bit_blaster/bit_blaster.h | 4 +- src/ast/rewriter/bv_rewriter.cpp | 96 +++++++++ src/ast/rewriter/bv_rewriter.h | 3 + src/smt/params/smt_params_helper.pyg | 3 +- src/smt/smt_solver.cpp | 45 +++- src/solver/mus.cpp | 226 ++++++++++++++++----- src/solver/mus.h | 4 + src/solver/solver_na2as.h | 1 + src/solver/tactic2solver.cpp | 5 +- 10 files changed, 332 insertions(+), 57 deletions(-) diff --git a/src/ast/array_decl_plugin.cpp b/src/ast/array_decl_plugin.cpp index 9634e17cb..4ae66707d 100644 --- a/src/ast/array_decl_plugin.cpp +++ b/src/ast/array_decl_plugin.cpp @@ -522,7 +522,7 @@ void array_decl_plugin::get_sort_names(svector& sort_names, symbol void array_decl_plugin::get_op_names(svector& op_names, symbol const & logic) { op_names.push_back(builtin_name("store",OP_STORE)); op_names.push_back(builtin_name("select",OP_SELECT)); - if (logic == symbol::null) { + if (true || logic == symbol::null) { // none of the SMT2 logics support these extensions op_names.push_back(builtin_name("const",OP_CONST_ARRAY)); op_names.push_back(builtin_name("map",OP_ARRAY_MAP)); diff --git a/src/ast/rewriter/bit_blaster/bit_blaster.h b/src/ast/rewriter/bit_blaster/bit_blaster.h index 6221eeaf9..4feeb6f5a 100644 --- a/src/ast/rewriter/bit_blaster/bit_blaster.h +++ b/src/ast/rewriter/bit_blaster/bit_blaster.h @@ -20,8 +20,8 @@ Revision History: #define BIT_BLASTER_H_ #include"bool_rewriter.h" -#include"bit_blaster_params.h" -#include"bit_blaster_tpl.h" +#include"bit_blaster/bit_blaster_params.h" +#include"bit_blaster/bit_blaster_tpl.h" #include"bv_decl_plugin.h" #include"rational.h" diff --git a/src/ast/rewriter/bv_rewriter.cpp b/src/ast/rewriter/bv_rewriter.cpp index def05f014..d876dc8cb 100644 --- a/src/ast/rewriter/bv_rewriter.cpp +++ b/src/ast/rewriter/bv_rewriter.cpp @@ -20,6 +20,7 @@ Notes: #include"bv_rewriter_params.hpp" #include"poly_rewriter_def.h" #include"ast_smt2_pp.h" +#include"bit_blaster/bit_blaster.h" void bv_rewriter::updt_local_params(params_ref const & _p) { @@ -189,6 +190,15 @@ br_status bv_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * cons return mk_bv_comp(args[0], args[1], result); case OP_MKBV: return mk_mkbv(num_args, args, result); + case OP_BUMUL_NO_OVFL: + SASSERT(num_args == 2); + return mk_bv_umul_no_ovfl(args[0], args[1], result); + case OP_BSMUL_NO_OVFL: + SASSERT(num_args == 2); + return mk_bv_smul_no_ovfl(args[0], args[1], result); + case OP_BSMUL_NO_UDFL: + SASSERT(num_args == 2); + return mk_bv_smul_no_udfl(args[0], args[1], result); default: return BR_FAILED; } @@ -1100,6 +1110,92 @@ br_status bv_rewriter::mk_concat(unsigned num_args, expr * const * args, expr_re return BR_DONE; } +br_status bv_rewriter::mk_bv_umul_no_ovfl(expr * arg1, expr * arg2, expr_ref& result) { + rational val1, val2; + unsigned bv_size; + bool is_num1 = is_numeral(arg1, val1, bv_size); + bool is_num2 = is_numeral(arg2, val2, bv_size); + if (is_num1 && (val1.is_zero() || val1.is_one())) { + result = m().mk_true(); + return BR_DONE; + } + if (is_num2 && (val2.is_zero() || val2.is_one())) { + result = m().mk_true(); + return BR_DONE; + } + if (is_num1 && is_num2) { + SASSERT(!val1.is_neg()); + SASSERT(!val2.is_neg()); + rational r = val1 * val2; + result = m().mk_bool_val(r < rational(2).expt(bv_size)); + return BR_DONE; + } + return BR_FAILED; +} + +br_status bv_rewriter::mk_bv_smul_no_ovfl(expr * arg1, expr * arg2, expr_ref& result) { + rational val1, val2; + unsigned bv_size; + bool is_num1 = is_numeral(arg1, val1, bv_size); + bool is_num2 = is_numeral(arg2, val2, bv_size); + if (is_num1 && (val1.is_zero() || val1.is_one())) { + result = m().mk_true(); + return BR_DONE; + } + if (is_num2 && (val2.is_zero() || val2.is_one())) { + result = m().mk_true(); + return BR_DONE; + } + if (is_num1 && is_num2) { + bit_blaster_params params; + bit_blaster blaster(m(), params); + SASSERT(!val1.is_neg()); + SASSERT(!val2.is_neg()); + expr_ref_vector bits1(m()), bits2(m()); + for (unsigned i = 0; i < bv_size; ++i) { + bits1.push_back(m().mk_bool_val(!val1.is_even())); + bits2.push_back(m().mk_bool_val(!val2.is_even())); + val1 = div(val1, rational(2)); + val2 = div(val2, rational(2)); + } + blaster.mk_smul_no_overflow(bits1.size(), bits1.c_ptr(), bits2.c_ptr(), result); + return BR_DONE; + } + return BR_FAILED; +} + +br_status bv_rewriter::mk_bv_smul_no_udfl(expr * arg1, expr * arg2, expr_ref& result) { + rational val1, val2; + unsigned bv_size; + bool is_num1 = is_numeral(arg1, val1, bv_size); + bool is_num2 = is_numeral(arg2, val2, bv_size); + if (is_num1 && (val1.is_zero() || val1.is_one())) { + result = m().mk_true(); + return BR_DONE; + } + if (is_num2 && (val2.is_zero() || val2.is_one())) { + result = m().mk_true(); + return BR_DONE; + } + if (is_num1 && is_num2) { + bit_blaster_params params; + bit_blaster blaster(m(), params); + SASSERT(!val1.is_neg()); + SASSERT(!val2.is_neg()); + expr_ref_vector bits1(m()), bits2(m()); + for (unsigned i = 0; i < bv_size; ++i) { + bits1.push_back(m().mk_bool_val(!val1.is_even())); + bits2.push_back(m().mk_bool_val(!val2.is_even())); + val1 = div(val1, rational(2)); + val2 = div(val2, rational(2)); + } + blaster.mk_smul_no_underflow(bits1.size(), bits1.c_ptr(), bits2.c_ptr(), result); + return BR_DONE; + } + return BR_FAILED; +} + + br_status bv_rewriter::mk_zero_extend(unsigned n, expr * arg, expr_ref & result) { if (n == 0) { result = arg; diff --git a/src/ast/rewriter/bv_rewriter.h b/src/ast/rewriter/bv_rewriter.h index 7135c52ba..0b449d006 100644 --- a/src/ast/rewriter/bv_rewriter.h +++ b/src/ast/rewriter/bv_rewriter.h @@ -114,6 +114,9 @@ class bv_rewriter : public poly_rewriter { br_status mk_bv_srem_i(expr * arg1, expr * arg2, expr_ref & result) { return mk_bv_srem_core(arg1, arg2, true, result); } br_status mk_bv_urem_i(expr * arg1, expr * arg2, expr_ref & result) { return mk_bv_urem_core(arg1, arg2, true, result); } br_status mk_bv_smod_i(expr * arg1, expr * arg2, expr_ref & result) { return mk_bv_smod_core(arg1, arg2, true, result); } + br_status mk_bv_umul_no_ovfl(expr * arg1, expr * arg2, expr_ref& result); + br_status mk_bv_smul_no_ovfl(expr * arg1, expr * arg2, expr_ref& result); + br_status mk_bv_smul_no_udfl(expr * arg1, expr * arg2, expr_ref& result); br_status mk_int2bv(unsigned bv_size, expr * arg, expr_ref & result); br_status mk_bv2int(expr * arg, expr_ref & result); br_status mk_bv_redor(expr * arg, expr_ref & result); diff --git a/src/smt/params/smt_params_helper.pyg b/src/smt/params/smt_params_helper.pyg index a9f6ccc18..153d948f5 100644 --- a/src/smt/params/smt_params_helper.pyg +++ b/src/smt/params/smt_params_helper.pyg @@ -61,5 +61,6 @@ def_module_params(module_name='smt', ('dack.gc', UINT, 2000, 'Dynamic ackermannization garbage collection frequency (per conflict)'), ('dack.gc_inv_decay', DOUBLE, 0.8, 'Dynamic ackermannization garbage collection decay'), ('dack.threshold', UINT, 10, ' number of times the congruence rule must be used before Leibniz\'s axiom is expanded'), - ('core.validate', BOOL, False, 'validate unsat core produced by SMT context') + ('core.validate', BOOL, False, 'validate unsat core produced by SMT context'), + ('core.minimize', BOOL, False, 'minimize unsat core produced by SMT context') )) diff --git a/src/smt/smt_solver.cpp b/src/smt/smt_solver.cpp index 59c08006b..d7764ac64 100644 --- a/src/smt/smt_solver.cpp +++ b/src/smt/smt_solver.cpp @@ -20,19 +20,25 @@ Notes: #include"smt_kernel.h" #include"reg_decl_plugins.h" #include"smt_params.h" +#include"smt_params_helper.hpp" +#include"mus.h" namespace smt { class solver : public solver_na2as { - smt_params m_params; + smt_params m_smt_params; + params_ref m_params; smt::kernel m_context; progress_callback * m_callback; symbol m_logic; + bool m_minimizing_core; public: solver(ast_manager & m, params_ref const & p, symbol const & l): solver_na2as(m), + m_smt_params(p), m_params(p), - m_context(m, m_params) { + m_context(m, m_smt_params), + m_minimizing_core(false) { m_logic = l; if (m_logic != symbol::null) m_context.set_logic(m_logic); @@ -48,7 +54,8 @@ namespace smt { } virtual void updt_params(params_ref const & p) { - m_params.updt_params(p); + m_smt_params.updt_params(p); + m_params.copy(p); m_context.updt_params(p); } @@ -77,10 +84,40 @@ namespace smt { return m_context.check(num_assumptions, assumptions); } + struct scoped_minimize_core { + solver& s; + expr_ref_vector m_assumptions; + scoped_minimize_core(solver& s): s(s), m_assumptions(s.m_assumptions) { + s.m_minimizing_core = true; + s.m_assumptions.reset(); + } + + ~scoped_minimize_core() { + s.m_minimizing_core = false; + s.m_assumptions.append(m_assumptions); + } + }; + virtual void get_unsat_core(ptr_vector & r) { unsigned sz = m_context.get_unsat_core_size(); - for (unsigned i = 0; i < sz; i++) + for (unsigned i = 0; i < sz; i++) { r.push_back(m_context.get_unsat_core_expr(i)); + } + + if (m_minimizing_core || smt_params_helper(m_params).core_minimize() == false) { + return; + } + scoped_minimize_core scm(*this); + mus mus(*this); + + for (unsigned i = 0; i < r.size(); ++i) { + VERIFY(i == mus.add_soft(r[i])); + } + ptr_vector r2; + if (l_true == mus.get_mus(r2)) { + r.reset(); + r.append(r2); + } } virtual void get_model(model_ref & m) { diff --git a/src/solver/mus.cpp b/src/solver/mus.cpp index 4960a3d2a..5f856cd80 100644 --- a/src/solver/mus.cpp +++ b/src/solver/mus.cpp @@ -26,6 +26,9 @@ Notes: struct mus::imp { + + typedef obj_hashtable expr_set; + solver& m_solver; ast_manager& m; expr_ref_vector m_lit2expr; @@ -64,66 +67,73 @@ struct mus::imp { SASSERT(is_literal(lit)); m_assumptions.push_back(lit); } + + lbool get_mus(ptr_vector& mus) { + unsigned_vector result; + lbool r = get_mus(result); + ids2exprs(mus, result); + return r; + } - lbool get_mus(unsigned_vector& mus) { - // SASSERT: mus does not have duplicates. + lbool get_mus(unsigned_vector& mus_ids) { + // SASSERT: mus_ids does not have duplicates. m_model.reset(); - unsigned_vector core; - for (unsigned i = 0; i < m_lit2expr.size(); ++i) { - core.push_back(i); - } - if (core.size() == 1) { - mus.push_back(core.back()); + mus_ids.reset(); + + if (m_lit2expr.size() == 1) { + mus_ids.push_back(0); return l_true; } + + return get_mus1(mus_ids); + } - mus.reset(); - if (false && core.size() > 64) { - return qx(mus); + lbool get_mus1(unsigned_vector& mus_ids) { + expr_ref_vector mus(m); + lbool result = get_mus1(mus); + for (unsigned i = 0; i < mus.size(); ++i) { + mus_ids.push_back(m_expr2lit.find(mus[i].get())); } + return result; + } - expr_ref_vector assumptions(m); + + lbool get_mus1(expr_ref_vector& mus) { + ptr_vector unknown(m_lit2expr.size(), m_lit2expr.c_ptr()); ptr_vector core_exprs; - while (!core.empty()) { - IF_VERBOSE(12, verbose_stream() << "(opt.mus reducing core: " << core.size() << " new core: " << mus.size() << ")\n";); - unsigned lit_id = core.back(); - TRACE("opt", - display_vec(tout << "core: ", core); - display_vec(tout << "mus: ", mus); - ); - core.pop_back(); - expr* lit = m_lit2expr[lit_id].get(); - expr_ref not_lit(m); - not_lit = mk_not(m, lit); + while (!unknown.empty()) { + IF_VERBOSE(12, verbose_stream() << "(opt.mus reducing core: " << unknown.size() << " new core: " << mus.size() << ")\n";); + TRACE("opt", display_vec(tout << "core: ", unknown); display_vec(tout << "mus: ", mus);); + expr* lit = unknown.back(); + unknown.pop_back(); + expr_ref not_lit(mk_not(m, lit), m); lbool is_sat = l_undef; { - scoped_append _sa1(*this, assumptions, core); - scoped_append _sa2(*this, assumptions, m_assumptions); - assumptions.push_back(not_lit); - is_sat = m_solver.check_sat(assumptions); + scoped_append _sa1(*this, mus, unknown); + scoped_append _sa2(*this, mus, m_assumptions); + mus.push_back(not_lit); + is_sat = m_solver.check_sat(mus); } switch (is_sat) { case l_undef: return is_sat; case l_true: - assumptions.push_back(lit); - mus.push_back(lit_id); + mus.push_back(lit); update_model(); break; default: core_exprs.reset(); m_solver.get_unsat_core(core_exprs); if (!core_exprs.contains(not_lit)) { - // core := core_exprs \ mus - core.reset(); + // unknown := core_exprs \ mus + unknown.reset(); for (unsigned i = 0; i < core_exprs.size(); ++i) { - lit = core_exprs[i]; - if (m_expr2lit.find(lit, lit_id) && !mus.contains(lit_id)) { - core.push_back(lit_id); + if (!mus.contains(core_exprs[i])) { + unknown.push_back(core_exprs[i]); } } TRACE("opt", display_vec(tout << "core exprs:", core_exprs); - display_vec(tout << "core:", core); + display_vec(tout << "core:", unknown); display_vec(tout << "mus:", mus); ); @@ -131,19 +141,118 @@ struct mus::imp { break; } } -#if 0 - DEBUG_CODE( - assumptions.reset(); - for (unsigned i = 0; i < mus.size(); ++i) { - assumptions.push_back(m_lit2expr[mus[i]].get()); - } - lbool is_sat = m_solver.check_sat(assumptions.size(), assumptions.c_ptr()); - SASSERT(is_sat == l_false); - ); -#endif + // SASSERT(is_core(mus)); return l_true; } + // use correction sets + lbool get_mus2(expr_ref_vector& mus) { + scoped_append _sa1(*this, mus, m_assumptions); + ptr_vector unknown(m_lit2expr.size(), m_lit2expr.c_ptr()); + while (!unknown.empty()) { + expr* lit; + lbool is_sat = get_next_mcs(mus, unknown, lit); + switch (is_sat) { + case l_undef: + return is_sat; + case l_false: + mus.push_back(lit); + break; + case l_true: + break; + } + } + return l_true; + } + + // find the next literal to be a member of a core. + lbool get_next_mcs(expr_ref_vector& mus, ptr_vector& unknown, expr*& core_literal) { + ptr_vector mss, core, min_core; + bool min_core_valid = false; + expr* min_lit = 0; + while (!unknown.empty()) { + expr* lit = unknown.back(); + unknown.pop_back(); + model_ref mdl; + scoped_append assume_mss(*this, mus, mss); + scoped_append assume_lit(*this, mus, lit); + switch (m_solver.check_sat(mus)) { + case l_true: + mss.push_back(lit); + m_solver.get_model(mdl); + for (unsigned i = 0; i < unknown.size(); ) { + expr_ref tmp(m); + if (mdl->eval(unknown[i], tmp) && m.is_true(tmp)) { + mss.push_back(unknown[i]); + unknown[i] = unknown.back(); + unknown.pop_back(); + } + else { + ++i; + } + } + break; + case l_false: + core.reset(); + m_solver.get_unsat_core(core); + // ??? + if (!core.contains(lit)) { + return l_false; + } + if (!min_core_valid || core.size() < min_core.size()) { + min_core.reset(); + min_core.append(core); + min_core_valid = true; + min_lit = lit; + } + break; + case l_undef: + return l_undef; + } + } + if (!min_core_valid) { + // ??? + UNREACHABLE(); + return l_true; + } + else { + for (unsigned i = 0; i < min_core.size(); ++i) { + if (mss.contains(min_core[i]) && min_lit != min_core[i]) { + unknown.push_back(min_core[i]); + } + } + core_literal = min_lit; + } + return l_false; + } + + expr* lit2expr(unsigned lit_id) const { + return m_lit2expr[lit_id]; + } + + void ids2exprs(ptr_vector& dst, unsigned_vector const& ids) const { + for (unsigned i = 0; i < ids.size(); ++i) { + dst.push_back(lit2expr(ids[i])); + } + } + + bool is_core(unsigned_vector const& mus_ids) { + ptr_vector mus_exprs; + ids2exprs(mus_exprs, mus_ids); + return l_false == m_solver.check_sat(mus_exprs.size(), mus_exprs.c_ptr()); + } + + // dst := A \ B + void set_difference(unsigned_vector& dst, ptr_vector const& A, unsigned_vector const& B) { + dst.reset(); + for (unsigned i = 0; i < A.size(); ++i) { + unsigned lit_id; + if (m_expr2lit.find(A[i], lit_id) && !B.contains(lit_id)) { + dst.push_back(lit_id); + } + } + } + class scoped_append { expr_ref_vector& m_fmls; unsigned m_size; @@ -152,7 +261,7 @@ struct mus::imp { m_fmls(fmls1), m_size(fmls1.size()) { for (unsigned i = 0; i < fmls2.size(); ++i) { - fmls1.push_back(imp.m_lit2expr[fmls2[i]].get()); + fmls1.push_back(imp.lit2expr(fmls2[i])); } } scoped_append(imp& imp, expr_ref_vector& fmls1, uint_set const& fmls2): @@ -160,7 +269,7 @@ struct mus::imp { m_size(fmls1.size()) { uint_set::iterator it = fmls2.begin(), end = fmls2.end(); for (; it != end; ++it) { - fmls1.push_back(imp.m_lit2expr[*it].get()); + fmls1.push_back(imp.lit2expr(*it)); } } scoped_append(imp& imp, expr_ref_vector& fmls1, expr_ref_vector const& fmls2): @@ -168,6 +277,16 @@ struct mus::imp { m_size(fmls1.size()) { fmls1.append(fmls2); } + scoped_append(imp& imp, expr_ref_vector& fmls1, ptr_vector const& fmls2): + m_fmls(fmls1), + m_size(fmls1.size()) { + fmls1.append(fmls2.size(), fmls2.c_ptr()); + } + scoped_append(imp& imp, expr_ref_vector& fmls1, expr* fml): + m_fmls(fmls1), + m_size(fmls1.size()) { + fmls1.push_back(fml); + } ~scoped_append() { m_fmls.shrink(m_size); } @@ -175,7 +294,7 @@ struct mus::imp { void add_core(unsigned_vector const& core, expr_ref_vector& assumptions) { for (unsigned i = 0; i < core.size(); ++i) { - assumptions.push_back(m_lit2expr[core[i]].get()); + assumptions.push_back(lit2expr(core[i])); } } @@ -359,6 +478,17 @@ lbool mus::get_mus(unsigned_vector& mus) { return m_imp->get_mus(mus); } +lbool mus::get_mus(ptr_vector& mus) { + return m_imp->get_mus(mus); +} + +lbool mus::get_mus(expr_ref_vector& mus) { + ptr_vector result; + lbool r = m_imp->get_mus(result); + mus.append(result.size(), result.c_ptr()); + return r; +} + void mus::reset() { m_imp->reset(); diff --git a/src/solver/mus.h b/src/solver/mus.h index d2411b6ec..bb3c6508f 100644 --- a/src/solver/mus.h +++ b/src/solver/mus.h @@ -44,6 +44,10 @@ class mus { void add_assumption(expr* lit); lbool get_mus(unsigned_vector& mus); + + lbool get_mus(ptr_vector& mus); + + lbool get_mus(expr_ref_vector& mus); void reset(); diff --git a/src/solver/solver_na2as.h b/src/solver/solver_na2as.h index 019468fd7..9aeb56fb1 100644 --- a/src/solver/solver_na2as.h +++ b/src/solver/solver_na2as.h @@ -25,6 +25,7 @@ Notes: #include"solver.h" class solver_na2as : public solver { + protected: ast_manager & m; expr_ref_vector m_assumptions; unsigned_vector m_scopes; diff --git a/src/solver/tactic2solver.cpp b/src/solver/tactic2solver.cpp index 56b246c1e..2a00d7195 100644 --- a/src/solver/tactic2solver.cpp +++ b/src/solver/tactic2solver.cpp @@ -23,6 +23,7 @@ Notes: #include"tactic.h" #include"ast_pp_util.h" #include"ast_translation.h" +#include"mus.h" /** \brief Simulates the incremental solver interface using a tactic. @@ -42,6 +43,7 @@ class tactic2solver : public solver_na2as { bool m_produce_proofs; bool m_produce_unsat_cores; statistics m_stats; + public: tactic2solver(ast_manager & m, tactic * t, params_ref const & p, bool produce_proofs, bool produce_models, bool produce_unsat_cores, symbol const & logic); virtual ~tactic2solver(); @@ -203,8 +205,9 @@ void tactic2solver::collect_statistics(statistics & st) const { } void tactic2solver::get_unsat_core(ptr_vector & r) { - if (m_result.get()) + if (m_result.get()) { m_result->get_unsat_core(r); + } } void tactic2solver::get_model(model_ref & m) { From 70301ad3c86047a5eb941be017d3f0501b1f63f1 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Fri, 24 Jun 2016 16:25:11 +0100 Subject: [PATCH 050/536] Added bv*mul_no*flow handling in bv_rewriter. Fixes #657. --- src/ast/rewriter/bv_rewriter.cpp | 60 +++++++++++++++++++++++++++++++- src/ast/rewriter/bv_rewriter.h | 3 ++ 2 files changed, 62 insertions(+), 1 deletion(-) diff --git a/src/ast/rewriter/bv_rewriter.cpp b/src/ast/rewriter/bv_rewriter.cpp index def05f014..fd2535968 100644 --- a/src/ast/rewriter/bv_rewriter.cpp +++ b/src/ast/rewriter/bv_rewriter.cpp @@ -189,6 +189,12 @@ br_status bv_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * cons return mk_bv_comp(args[0], args[1], result); case OP_MKBV: return mk_mkbv(num_args, args, result); + case OP_BSMUL_NO_OVFL: + return mk_bvsmul_no_overflow(num_args, args, result); + case OP_BUMUL_NO_OVFL: + return mk_bvumul_no_overflow(num_args, args, result); + case OP_BSMUL_NO_UDFL: + return mk_bvsmul_no_underflow(num_args, args, result); default: return BR_FAILED; } @@ -2186,6 +2192,58 @@ br_status bv_rewriter::mk_mkbv(unsigned num, expr * const * args, expr_ref & res return BR_FAILED; } +br_status bv_rewriter::mk_bvsmul_no_overflow(unsigned num, expr * const * args, expr_ref & result) { + SASSERT(num == 2); + unsigned bv_sz; + rational a0_val, a1_val; + + if (m_util.is_numeral(args[0], a0_val, bv_sz) && + m_util.is_numeral(args[1], a1_val, bv_sz)) { + rational mr = a0_val * a1_val; + rational lim = rational::power_of_two(bv_sz-1); + result = (mr < lim) ? m().mk_true() : m().mk_false(); + return BR_DONE; + } + + return BR_FAILED; +} + +br_status bv_rewriter::mk_bvumul_no_overflow(unsigned num, expr * const * args, expr_ref & result) { + SASSERT(num == 2); + unsigned bv_sz; + rational a0_val, a1_val; + + if (m_util.is_numeral(args[0], a0_val, bv_sz) && + m_util.is_numeral(args[1], a1_val, bv_sz)) { + rational mr = a0_val * a1_val; + rational lim = rational::power_of_two(bv_sz); + result = (mr < lim) ? m().mk_true() : m().mk_false(); + return BR_DONE; + } + + return BR_FAILED; +} + +br_status bv_rewriter::mk_bvsmul_no_underflow(unsigned num, expr * const * args, expr_ref & result) { + SASSERT(num == 2); + unsigned bv_sz; + rational a0_val, a1_val; + + if (m_util.is_numeral(args[0], a0_val, bv_sz) && + m_util.is_numeral(args[1], a1_val, bv_sz)) { + rational ul = rational::power_of_two(bv_sz); + rational lim = rational::power_of_two(bv_sz-1); + if (a0_val >= lim) a0_val -= ul; + if (a1_val >= lim) a1_val -= ul; + rational mr = a0_val * a1_val; + rational neg_lim = -lim; + TRACE("bv_rewriter_bvsmul_no_underflow", tout << "a0:" << a0_val << " a1:" << a1_val << " mr:" << mr << " neg_lim:" << neg_lim << std::endl;); + result = (mr >= neg_lim) ? m().mk_true() : m().mk_false(); + return BR_DONE; + } + + return BR_FAILED; +} + template class poly_rewriter; - diff --git a/src/ast/rewriter/bv_rewriter.h b/src/ast/rewriter/bv_rewriter.h index 7135c52ba..a8db05013 100644 --- a/src/ast/rewriter/bv_rewriter.h +++ b/src/ast/rewriter/bv_rewriter.h @@ -123,6 +123,9 @@ class bv_rewriter : public poly_rewriter { br_status mk_blast_eq_value(expr * lhs, expr * rhs, expr_ref & result); br_status mk_eq_concat(expr * lhs, expr * rhs, expr_ref & result); br_status mk_mkbv(unsigned num, expr * const * args, expr_ref & result); + br_status mk_bvsmul_no_overflow(unsigned num, expr * const * args, expr_ref & result); + br_status mk_bvumul_no_overflow(unsigned num, expr * const * args, expr_ref & result); + br_status mk_bvsmul_no_underflow(unsigned num, expr * const * args, expr_ref & result); bool is_minus_one_times_t(expr * arg); void mk_t1_add_t2_eq_c(expr * t1, expr * t2, expr * c, expr_ref & result); From 017165c474bdbd1e7ea3994f943c7e307a7646f5 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 24 Jun 2016 09:02:12 -0700 Subject: [PATCH 051/536] fix bug with model completion and remove spurious std::cout Signed-off-by: Nikolaj Bjorner --- src/ast/array_decl_plugin.cpp | 2 +- src/qe/qe_mbp.cpp | 3 +-- src/qe/qsat.cpp | 4 +++- src/solver/mus.cpp | 12 ------------ 4 files changed, 5 insertions(+), 16 deletions(-) diff --git a/src/ast/array_decl_plugin.cpp b/src/ast/array_decl_plugin.cpp index 4ae66707d..ab21c4c88 100644 --- a/src/ast/array_decl_plugin.cpp +++ b/src/ast/array_decl_plugin.cpp @@ -522,7 +522,7 @@ void array_decl_plugin::get_sort_names(svector& sort_names, symbol void array_decl_plugin::get_op_names(svector& op_names, symbol const & logic) { op_names.push_back(builtin_name("store",OP_STORE)); op_names.push_back(builtin_name("select",OP_SELECT)); - if (true || logic == symbol::null) { + if (logic == symbol::null || logic == symbol("HORN")) { // none of the SMT2 logics support these extensions op_names.push_back(builtin_name("const",OP_CONST_ARRAY)); op_names.push_back(builtin_name("map",OP_ARRAY_MAP)); diff --git a/src/qe/qe_mbp.cpp b/src/qe/qe_mbp.cpp index 219a4b45a..85371d8ef 100644 --- a/src/qe/qe_mbp.cpp +++ b/src/qe/qe_mbp.cpp @@ -454,8 +454,7 @@ public: (*p)(model, vars, fmls); } } - while (!vars.empty() && !fmls.empty()) { - std::cout << "mbp: " << var << "\n"; + while (!vars.empty() && !fmls.empty()) { var = vars.back(); vars.pop_back(); project_plugin* p = get_plugin(var); diff --git a/src/qe/qsat.cpp b/src/qe/qsat.cpp index 02c6d26cd..1bfd53597 100644 --- a/src/qe/qsat.cpp +++ b/src/qe/qsat.cpp @@ -158,6 +158,8 @@ namespace qe { return; } model_evaluator eval(*mdl); + eval.set_model_completion(true); + TRACE("qe", model_v2_pp(tout, *mdl);); expr_ref val(m); for (unsigned j = 0; j < m_preds[level - 1].size(); ++j) { @@ -169,7 +171,7 @@ namespace qe { if (m.is_false(val)) { m_asms.push_back(m.mk_not(p)); } - else { + else { SASSERT(m.is_true(val)); m_asms.push_back(p); } diff --git a/src/solver/mus.cpp b/src/solver/mus.cpp index a5013cd5a..81635f906 100644 --- a/src/solver/mus.cpp +++ b/src/solver/mus.cpp @@ -475,18 +475,6 @@ lbool mus::get_mus(expr_ref_vector& mus) { return m_imp->get_mus(mus); } -lbool mus::get_mus(ptr_vector& mus) { - return m_imp->get_mus(mus); -} - -lbool mus::get_mus(expr_ref_vector& mus) { - ptr_vector result; - lbool r = m_imp->get_mus(result); - mus.append(result.size(), result.c_ptr()); - return r; -} - - void mus::reset() { m_imp->reset(); } From 30cf0d19eb4d842337bf2770587a7473ee01f8d4 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 24 Jun 2016 09:11:45 -0700 Subject: [PATCH 052/536] use of mk_bool_val Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/bv_rewriter.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/ast/rewriter/bv_rewriter.cpp b/src/ast/rewriter/bv_rewriter.cpp index 66546f2f2..07e97364e 100644 --- a/src/ast/rewriter/bv_rewriter.cpp +++ b/src/ast/rewriter/bv_rewriter.cpp @@ -252,7 +252,7 @@ br_status bv_rewriter::mk_leq_core(bool is_signed, expr * a, expr * b, expr_ref r2 = m_util.norm(r2, sz, is_signed); if (is_num1 && is_num2) { - result = r1 <= r2 ? m().mk_true() : m().mk_false(); + result = m().mk_bool_val(r1 <= r2); return BR_DONE; } @@ -1785,7 +1785,7 @@ br_status bv_rewriter::mk_bit2bool(expr * lhs, expr * rhs, expr_ref & result) { if (is_numeral(lhs)) { SASSERT(is_numeral(rhs)); - result = lhs == rhs ? m().mk_true() : m().mk_false(); + result = m().mk_bool_val(lhs == rhs); return BR_DONE; } @@ -2134,7 +2134,7 @@ br_status bv_rewriter::mk_eq_core(expr * lhs, expr * rhs, expr_ref & result) { st = cancel_monomials(lhs, rhs, false, new_lhs, new_rhs); if (st != BR_FAILED) { if (is_numeral(new_lhs) && is_numeral(new_rhs)) { - result = new_lhs == new_rhs ? m().mk_true() : m().mk_false(); + result = m().mk_bool_val(new_lhs == new_rhs); return BR_DONE; } } @@ -2213,7 +2213,7 @@ br_status bv_rewriter::mk_bvsmul_no_overflow(unsigned num, expr * const * args, if (is_num1 && is_num2) { rational mr = a0_val * a1_val; rational lim = rational::power_of_two(bv_sz-1); - result = (mr < lim) ? m().mk_true() : m().mk_false(); + result = m().mk_bool_val(mr < lim); return BR_DONE; } @@ -2239,7 +2239,7 @@ br_status bv_rewriter::mk_bvumul_no_overflow(unsigned num, expr * const * args, if (is_num1 && is_num2) { rational mr = a0_val * a1_val; rational lim = rational::power_of_two(bv_sz); - result = (mr < lim) ? m().mk_true() : m().mk_false(); + result = m().mk_bool_val(mr < lim); return BR_DONE; } @@ -2270,7 +2270,7 @@ br_status bv_rewriter::mk_bvsmul_no_underflow(unsigned num, expr * const * args, rational mr = a0_val * a1_val; rational neg_lim = -lim; TRACE("bv_rewriter_bvsmul_no_underflow", tout << "a0:" << a0_val << " a1:" << a1_val << " mr:" << mr << " neg_lim:" << neg_lim << std::endl;); - result = (mr >= neg_lim) ? m().mk_true() : m().mk_false(); + result = m().mk_bool_val(mr >= neg_lim); return BR_DONE; } From ae54b9d1587a7b4c3bf627b73aed003205cd864d Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Fri, 24 Jun 2016 18:13:02 +0100 Subject: [PATCH 053/536] Fixed FP math options for x86 cmake build. Fixes #644. --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c9a01daed..40e8ae250 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -246,7 +246,7 @@ endif() # FP math ################################################################################ # FIXME: Support ARM "-mfpu=vfp -mfloat-abi=hard" -if ("${TARGET_ARCHITECTURE}" STREQUAL "x86_64") +if (("${TARGET_ARCHITECTURE}" STREQUAL "x86_64") OR ("${TARGET_ARCHITECTURE}" STREQUAL "i686")) if (("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU") OR ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")) set(SSE_FLAGS "-mfpmath=sse" "-msse" "-msse2") # FIXME: Remove "x.." when CMP0054 is set to NEW From 7fc294d3293aec74d1bf43d55c6dd08a7a764f2c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 26 Jun 2016 14:30:35 -0700 Subject: [PATCH 054/536] move arithmetical mbp functionality to model_based_opt Signed-off-by: Nikolaj Bjorner --- src/api/z3_api.h | 3 +- src/ast/arith_decl_plugin.h | 98 +++ src/math/simplex/model_based_opt.cpp | 425 +++++++++++- src/math/simplex/model_based_opt.h | 44 +- src/qe/qe_arith.cpp | 968 +++++---------------------- src/qe/qe_mbp.cpp | 2 + src/test/model_based_opt.cpp | 70 +- src/test/qe_arith.cpp | 148 ++++ 8 files changed, 909 insertions(+), 849 deletions(-) diff --git a/src/api/z3_api.h b/src/api/z3_api.h index 114490015..5d1d45f37 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -3068,7 +3068,8 @@ extern "C" { \brief Create a numeral of a given sort. \param c logical context. - \param numeral A string representing the numeral value in decimal notation. If the given sort is a real, then the numeral can be a rational, that is, a string of the form \ccode{[num]* / [num]*}. + \param numeral A string representing the numeral value in decimal notation. The string may be of the form \code{[num]*[.[num]*][E[+|-][num]+]}. + If the given sort is a real, then the numeral can be a rational, that is, a string of the form \ccode{[num]* / [num]*}. \param ty The sort of the numeral. In the current implementation, the given sort can be an int, real, finite-domain, or bit-vectors of arbitrary size. \sa Z3_mk_int diff --git a/src/ast/arith_decl_plugin.h b/src/ast/arith_decl_plugin.h index b72a55e34..7a6281b06 100644 --- a/src/ast/arith_decl_plugin.h +++ b/src/ast/arith_decl_plugin.h @@ -422,5 +422,103 @@ public: expr_ref mk_add_simplify(unsigned sz, expr* const* args); }; + +inline app_ref mk_numeral(rational const& r, app_ref const& x) { + arith_util a(x.get_manager()); + return app_ref(a.mk_numeral(r, r.is_int() && a.is_int(x)), x.get_manager()); +} + +inline app_ref operator+(app_ref const& x, app_ref const& y) { + arith_util a(x.get_manager()); + return app_ref(a.mk_add(x, y), x.get_manager()); +} + +inline app_ref operator+(app_ref const& x, rational const& y) { + return x + mk_numeral(y, x); +} + +inline app_ref operator+(app_ref const& x, int y) { + return x + rational(y); +} + +inline app_ref operator+(rational const& x, app_ref const& y) { + return mk_numeral(x, y) + y; +} + +inline app_ref operator+(int x, app_ref const& y) { + return rational(x) + y; +} + +inline app_ref operator-(app_ref const& x, app_ref const& y) { + arith_util a(x.get_manager()); + return app_ref(a.mk_sub(x, y), x.get_manager()); +} + +inline app_ref operator-(app_ref const& x, rational const& y) { + return x - mk_numeral(y, x); +} + +inline app_ref operator-(app_ref const& x, int y) { + return x - rational(y); +} + +inline app_ref operator-(rational const& x, app_ref const& y) { + return mk_numeral(x, y) - y; +} + +inline app_ref operator-(int x, app_ref const& y) { + return rational(x) - y; +} + + +inline app_ref operator*(app_ref const& x, app_ref const& y) { + arith_util a(x.get_manager()); + return app_ref(a.mk_mul(x, y), x.get_manager()); +} + +inline app_ref operator*(app_ref const& x, rational const& y) { + return x * mk_numeral(y, x); +} + +inline app_ref operator*(rational const& x, app_ref const& y) { + return mk_numeral(x, y) * y; +} + +inline app_ref operator*(app_ref const& x, int y) { + return x * rational(y); +} + +inline app_ref operator*(int x, app_ref const& y) { + return rational(x) * y; +} + +inline app_ref operator<=(app_ref const& x, app_ref const& y) { + arith_util a(x.get_manager()); + return app_ref(a.mk_le(x, y), x.get_manager()); +} + +inline app_ref operator<=(app_ref const& x, rational const& y) { + return x <= mk_numeral(y, x); +} + +inline app_ref operator<=(app_ref const& x, int y) { + return x <= rational(y); +} + +inline app_ref operator>=(app_ref const& x, app_ref const& y) { + arith_util a(x.get_manager()); + return app_ref(a.mk_ge(x, y), x.get_manager()); +} + +inline app_ref operator<(app_ref const& x, app_ref const& y) { + arith_util a(x.get_manager()); + return app_ref(a.mk_lt(x, y), x.get_manager()); +} + +inline app_ref operator>(app_ref const& x, app_ref const& y) { + arith_util a(x.get_manager()); + return app_ref(a.mk_gt(x, y), x.get_manager()); +} + #endif /* ARITH_DECL_PLUGIN_H_ */ diff --git a/src/math/simplex/model_based_opt.cpp b/src/math/simplex/model_based_opt.cpp index c4e4b110e..760c9a941 100644 --- a/src/math/simplex/model_based_opt.cpp +++ b/src/math/simplex/model_based_opt.cpp @@ -7,7 +7,7 @@ Module Name: Abstract: - Model-based optimization for linear real arithmetic. + Model-based optimization and projection for linear real, integer arithmetic. Author: @@ -26,6 +26,7 @@ std::ostream& operator<<(std::ostream& out, opt::ineq_type ie) { case opt::t_eq: return out << " = "; case opt::t_lt: return out << " < "; case opt::t_le: return out << " <= "; + case opt::t_mod: return out << " mod "; } return out; } @@ -55,8 +56,8 @@ namespace opt { vector const& vars = r.m_vars; for (unsigned i = 0; i < vars.size(); ++i) { // variables in each row are sorted and have non-zero coefficients - SASSERT(i + 1 == vars.size() || vars[i].m_id < vars[i+1].m_id); - SASSERT(!vars[i].m_coeff.is_zero()); + PASSERT(i + 1 == vars.size() || vars[i].m_id < vars[i+1].m_id); + PASSERT(!vars[i].m_coeff.is_zero()); } PASSERT(r.m_value == get_row_value(r)); @@ -64,6 +65,7 @@ namespace opt { // values satisfy constraints PASSERT(index == 0 || r.m_type != t_lt || r.m_value.is_neg()); PASSERT(index == 0 || r.m_type != t_le || !r.m_value.is_pos()); + PASSERT(index == 0 || r.m_type != t_mod || (mod(r.m_value, r.m_mod).is_zero())); return true; } @@ -117,7 +119,7 @@ namespace opt { // objective + t2*coeff/a2 <= ub mul_add(false, m_objective_id, - coeff/bound_coeff, bound_row_index); - m_rows[bound_row_index].m_alive = false; + retire_row(bound_row_index); bound_trail.push_back(bound_row_index); bound_vars.push_back(x); } @@ -281,6 +283,12 @@ namespace opt { } return bound_row_index != UINT_MAX; } + + void model_based_opt::retire_row(unsigned row_id) { + m_rows[row_id].m_alive = false; + m_retired_rows.push_back(row_id); + } + rational model_based_opt::get_row_value(row const& r) const { vector const& vars = r.m_vars; @@ -308,7 +316,7 @@ namespace opt { } if (id < var_id) { lo = mid + 1; - } + } else { hi = mid; } @@ -355,10 +363,161 @@ namespace opt { if (m_rows[row_dst].m_alive) { rational a2 = get_coefficient(row_dst, x); - mul_add(row_dst != m_objective_id && a1.is_pos() == a2.is_pos(), row_dst, -a2/a1, row_src); + if (is_int(x)) { + TRACE("opt", + tout << a1 << " " << a2 << ": "; + display(tout, m_rows[row_dst]); + display(tout, m_rows[row_src]);); + if (a1.is_pos() != a2.is_pos()) { + mul_add(x, a1, row_src, a2, row_dst); + } + else { + mul(row_dst, abs(a1)); + mul_add(false, row_dst, -abs(a2), row_src); + } + TRACE("opt", display(tout, m_rows[row_dst]);); + normalize(row_dst); + } + else { + mul_add(row_dst != m_objective_id && a1.is_pos() == a2.is_pos(), row_dst, -a2/a1, row_src); + } } } - + + // resolution for integer rows. + void model_based_opt::mul_add( + unsigned x, rational const& src_c, unsigned row_src, rational const& dst_c, unsigned row_dst) { + row& dst = m_rows[row_dst]; + row const& src = m_rows[row_src]; + SASSERT(is_int(x)); + SASSERT(t_le == dst.m_type && t_le == src.m_type); + SASSERT(src_c.is_int()); + SASSERT(dst_c.is_int()); + + rational abs_src_c = abs(src_c); + rational abs_dst_c = abs(dst_c); + rational x_val = m_var2value[x]; + rational slack = (abs_src_c - rational::one()) * (abs_dst_c - rational::one()); + rational dst_val = dst.m_value - x_val*dst_c; + rational src_val = src.m_value - x_val*src_c; + bool use_case1 = + (src_c * dst_val + dst_c * src_val + slack).is_nonpos() + || abs_src_c.is_one() + || abs_dst_c.is_one(); + + if (use_case1) { + // dst <- abs_src_c*dst + abs_dst_c*src - slack + mul(row_dst, abs_src_c); + sub(row_dst, slack); + mul_add(false, row_dst, abs_dst_c, row_src); + return; + } + + // + // create finite disjunction for |b|. + // exists x, z in [0 .. |b|-2] . b*x + s + z = 0 && ax + t <= 0 && bx + s <= 0 + // <=> + // exists x, z in [0 .. |b|-2] . b*x = -z - s && ax + t <= 0 && bx + s <= 0 + // <=> + // exists x, z in [0 .. |b|-2] . b*x = -z - s && a|b|x + |b|t <= 0 && bx + s <= 0 + // <=> + // exists x, z in [0 .. |b|-2] . b*x = -z - s && a|b|x + |b|t <= 0 && -z - s + s <= 0 + // <=> + // exists x, z in [0 .. |b|-2] . b*x = -z - s && a|b|x + |b|t <= 0 && -z <= 0 + // <=> + // exists x, z in [0 .. |b|-2] . b*x = -z - s && a|b|x + |b|t <= 0 + // <=> + // exists x, z in [0 .. |b|-2] . b*x = -z - s && a*n_sign(b)(s + z) + |b|t <= 0 + // <=> + // exists z in [0 .. |b|-2] . |b| | (z + s) && a*n_sign(b)(s + z) + |b|t <= 0 + // + + vector coeffs; + if (abs_dst_c <= abs_src_c) { + rational z = mod(dst_val, abs_dst_c); + if (!z.is_zero()) z = abs_dst_c - z; + mk_coeffs_without(coeffs, dst.m_vars, x); + add_divides(coeffs, dst.m_coeff + z, abs_dst_c); + add(row_dst, z); + mul(row_dst, src_c * n_sign(dst_c)); + mul_add(false, row_dst, abs_dst_c, row_src); + } + else { + // z := b - (s + bx) mod b + // := b - s mod b + // b | s + z <=> b | s + b - s mod b <=> b | s - s mod b + rational z = mod(src_val, abs_src_c); + if (!z.is_zero()) z = abs_src_c - z; + mk_coeffs_without(coeffs, src.m_vars, x); + add_divides(coeffs, src.m_coeff + z, abs_src_c); + mul(row_dst, abs_src_c); + add(row_dst, z * dst_c * n_sign(src_c)); + mul_add(false, row_dst, dst_c * n_sign(src_c), row_src); + } + } + + void model_based_opt::mk_coeffs_without(vector& dst, vector const src, unsigned x) { + for (unsigned i = 0; i < src.size(); ++i) { + if (src[i].m_id != x) dst.push_back(src[i]); + } + } + + + rational model_based_opt::n_sign(rational const& b) const { + return rational(b.is_pos()?-1:1); + } + + void model_based_opt::mul(unsigned dst, rational const& c) { + if (c.is_one()) return; + row& r = m_rows[dst]; + for (unsigned i = 0; i < r.m_vars.size(); ++i) { + r.m_vars[i].m_coeff *= c; + } + r.m_coeff *= c; + r.m_value *= c; + } + + void model_based_opt::add(unsigned dst, rational const& c) { + row& r = m_rows[dst]; + r.m_coeff += c; + r.m_value += c; + } + + void model_based_opt::sub(unsigned dst, rational const& c) { + row& r = m_rows[dst]; + r.m_coeff -= c; + r.m_value -= c; + } + + void model_based_opt::normalize(unsigned row_id) { + row& r = m_rows[row_id]; + if (r.m_vars.empty()) return; + if (r.m_type == t_mod) return; + rational g(abs(r.m_vars[0].m_coeff)); + bool all_int = g.is_int(); + for (unsigned i = 1; all_int && !g.is_one() && i < r.m_vars.size(); ++i) { + rational const& coeff = r.m_vars[i].m_coeff; + if (coeff.is_int()) { + g = gcd(g, abs(coeff)); + } + else { + all_int = false; + } + } + if (all_int && !r.m_coeff.is_zero()) { + if (r.m_coeff.is_int()) { + g = gcd(g, abs(r.m_coeff)); + } + else { + all_int = false; + } + } + if (all_int && !g.is_one()) { + SASSERT(!g.is_zero()); + mul(row_id, rational::one()/g); + } + } + // // set row1 <- row1 + c*row2 // @@ -452,12 +611,18 @@ namespace opt { else if (r.m_coeff.is_neg()) { out << r.m_coeff << " "; } - out << r.m_type << " 0; value: " << r.m_value << "\n"; + if (r.m_type == opt::t_mod) { + out << r.m_type << " " << r.m_mod << " = 0; value: " << r.m_value << "\n"; + } + else { + out << r.m_type << " 0; value: " << r.m_value << "\n"; + } } - unsigned model_based_opt::add_var(rational const& value) { + unsigned model_based_opt::add_var(rational const& value, bool is_int) { unsigned v = m_var2value.size(); m_var2value.push_back(value); + m_var2is_int.push_back(is_int); m_var2row_ids.push_back(unsigned_vector()); return v; } @@ -466,34 +631,65 @@ namespace opt { return m_var2value[var]; } - void model_based_opt::set_row(unsigned row_id, vector const& coeffs, rational const& c, ineq_type rel) { + void model_based_opt::set_row(unsigned row_id, vector const& coeffs, rational const& c, rational const& m, ineq_type rel) { row& r = m_rows[row_id]; rational val(c); SASSERT(r.m_vars.empty()); r.m_vars.append(coeffs.size(), coeffs.c_ptr()); + bool is_int_row = true; std::sort(r.m_vars.begin(), r.m_vars.end(), var::compare()); for (unsigned i = 0; i < coeffs.size(); ++i) { val += m_var2value[coeffs[i].m_id] * coeffs[i].m_coeff; + SASSERT(!is_int(coeffs[i].m_id) || coeffs[i].m_coeff.is_int()); + is_int_row &= is_int(coeffs[i].m_id); } r.m_alive = true; r.m_coeff = c; r.m_value = val; r.m_type = rel; + r.m_mod = m; + if (is_int_row && rel == t_lt) { + r.m_type = t_le; + r.m_coeff += rational::one(); + r.m_value += rational::one(); + } SASSERT(invariant(row_id, r)); } + unsigned model_based_opt::new_row() { + unsigned row_id = 0; + if (m_retired_rows.empty()) { + row_id = m_rows.size(); + m_rows.push_back(row()); + } + else { + row_id = m_retired_rows.back(); + m_retired_rows.pop_back(); + m_rows[row_id].reset(); + m_rows[row_id].m_alive = true; + } + return row_id; + } + void model_based_opt::add_constraint(vector const& coeffs, rational const& c, ineq_type rel) { - rational val(c); - unsigned row_id = m_rows.size(); - m_rows.push_back(row()); - set_row(row_id, coeffs, c, rel); + add_constraint(coeffs, c, rational::zero(), rel); + } + + void model_based_opt::add_divides(vector const& coeffs, rational const& c, rational const& m) { + add_constraint(coeffs, c, m, t_mod); + } + + void model_based_opt::add_constraint(vector const& coeffs, rational const& c, rational const& m, ineq_type rel) { + unsigned row_id = new_row(); + set_row(row_id, coeffs, c, m, rel); for (unsigned i = 0; i < coeffs.size(); ++i) { m_var2row_ids[coeffs[i].m_id].push_back(row_id); } + SASSERT(invariant(row_id, m_rows[row_id])); } void model_based_opt::set_objective(vector const& coeffs, rational const& c) { - set_row(m_objective_id, coeffs, c, t_le); + set_row(m_objective_id, coeffs, c, rational::zero(), t_le); } void model_based_opt::get_live_rows(vector& rows) { @@ -524,7 +720,8 @@ namespace opt { // void model_based_opt::project(unsigned x) { unsigned_vector& lub_rows = m_lub; - unsigned_vector& glb_rows = m_glb; + unsigned_vector& glb_rows = m_glb; + unsigned_vector& mod_rows = m_mod; unsigned lub_index = UINT_MAX, glb_index = UINT_MAX; bool lub_strict = false, glb_strict = false; rational lub_val, glb_val; @@ -533,6 +730,8 @@ namespace opt { uint_set visited; lub_rows.reset(); glb_rows.reset(); + mod_rows.reset(); + bool lub_is_unit = false, glb_is_unit = false; // select the lub and glb. for (unsigned i = 0; i < row_ids.size(); ++i) { unsigned row_id = row_ids[i]; @@ -552,7 +751,10 @@ namespace opt { solve_for(row_id, x); return; } - if (a.is_pos()) { + if (r.m_type == t_mod) { + mod_rows.push_back(row_id); + } + else if (a.is_pos()) { rational lub_value = x_val - (r.m_value/a); if (lub_rows.empty() || lub_value < lub_val || @@ -562,6 +764,7 @@ namespace opt { lub_strict = r.m_type == t_lt; } lub_rows.push_back(row_id); + lub_is_unit &= a.is_one(); } else { SASSERT(a.is_neg()); @@ -574,36 +777,187 @@ namespace opt { glb_strict = r.m_type == t_lt; } glb_rows.push_back(row_id); + glb_is_unit &= a.is_minus_one(); } } - unsigned row_index = (lub_rows.size() <= glb_rows.size())? lub_index : glb_index; - glb_rows.append(lub_rows); + + if (!mod_rows.empty()) { + solve_mod(x, mod_rows); + return; + } + + unsigned lub_size = lub_rows.size(); + unsigned glb_size = glb_rows.size(); + unsigned row_index = (lub_size <= glb_size) ? lub_index : glb_index; + glb_rows.append(lub_rows); + + // There are only upper or only lower bounds. 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; + retire_row(row_id); } + return; } - 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); + + // The number of matching lower and upper bounds is small. + if ((lub_size <= 2 || glb_size <= 2) && + (lub_size <= 3 && glb_size <= 3) && + (!is_int(x) || lub_is_unit || glb_is_unit)) { + for (unsigned i = 0; i < lub_size; ++i) { + unsigned row_id1 = lub_rows[i]; + bool last = i + 1 == lub_rows.size(); + rational coeff = get_coefficient(row_id1, x); + for (unsigned j = 0; j < glb_size; ++j) { + unsigned row_id2 = glb_rows[j]; + if (last) { + resolve(row_id1, coeff, row_id2, x); + } + else { + row r(m_rows[row_id2]); + m_rows.push_back(r); + resolve(row_id1, coeff, m_rows.size()-1, x); + } } } - m_rows[row_index].m_alive = false; + for (unsigned i = 0; i < lub_size; ++i) { + retire_row(lub_rows[i]); + } + return; } + + // General case. + 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); + } + } + retire_row(row_index); } + // + // compute D and u. + // + // D = lcm(d1, d2) + // u = eval(x) mod D + // + // d1 | (a1x + t1) & d2 | (a2x + t2) + // = + // d1 | (a1(D*x' + u) + t1) & d2 | (a2(D*x' + u) + t2) + // = + // d1 | (a1*u + t1) & d2 | (a2*u + t2) + // + // x := D*x' + u + // + + void model_based_opt::solve_mod(unsigned x, unsigned_vector const& mod_rows) { + SASSERT(!mod_rows.empty()); + rational D(1); + for (unsigned i = 0; i < mod_rows.size(); ++i) { + D = lcm(D, m_rows[mod_rows[i]].m_mod); + } + TRACE("opt", display(tout << "lcm: " << D << " tableau\n");); + rational val_x = m_var2value[x]; + rational u = mod(val_x, D); + SASSERT(u.is_nonneg() && u < D); + for (unsigned i = 0; i < mod_rows.size(); ++i) { + replace_var(mod_rows[i], x, u); + SASSERT(invariant(mod_rows[i], m_rows[mod_rows[i]])); + } + // + // update inequalities such that u is added to t and + // D is multiplied to coefficient of x. + // the interpretation of the new version of x is (x-u)/D + // + // a*x + t <= 0 + // a*(D*x' + u) + t <= 0 + // a*D*x' + a*u + t <= 0 + // + rational new_val = (val_x - u) / D; + SASSERT(new_val.is_int()); + unsigned y = add_var(new_val, true); + unsigned_vector const& row_ids = m_var2row_ids[x]; + uint_set visited; + for (unsigned i = 0; i < row_ids.size(); ++i) { + unsigned row_id = row_ids[i]; + if (!visited.contains(row_id)) { + // x |-> D*y + u + replace_var(row_id, x, D, y, u); + visited.insert(row_id); + } + } + project(y); + } + + // update row with: x |-> C + void model_based_opt::replace_var(unsigned row_id, unsigned x, rational const& C) { + row& r = m_rows[row_id]; + SASSERT(!get_coefficient(row_id, x).is_zero()); + unsigned sz = r.m_vars.size(); + unsigned i = 0, j = 0; + rational coeff(0); + for (; i < sz; ++i) { + if (r.m_vars[i].m_id == x) { + coeff = r.m_vars[i].m_coeff; + } + else { + if (i != j) { + r.m_vars[j] = r.m_vars[i]; + } + ++j; + } + } + if (j != sz) { + r.m_vars.shrink(j); + } + r.m_coeff += coeff*C; + r.m_value += coeff*(C - m_var2value[x]); + } + + // update row with: x |-> A*y + B + void model_based_opt::replace_var(unsigned row_id, unsigned x, rational const& A, unsigned y, rational const& B) { + row& r = m_rows[row_id]; + rational coeff = get_coefficient(row_id, x); + if (coeff.is_zero()) return; + if (!r.m_alive) return; + replace_var(row_id, x, B); + r.m_vars.push_back(var(y, coeff*A)); + r.m_value += coeff*A*m_var2value[y]; + if (!r.m_vars.empty() && r.m_vars.back().m_id > y) { + std::sort(r.m_vars.begin(), r.m_vars.end(), var::compare()); + } + m_var2row_ids[y].push_back(row_id); + SASSERT(invariant(row_id, r)); + } + + // 3x + t = 0 & 7 | (c*x + s) & ax <= u + // 3 | -t & 21 | (-ct + 3s) & a-t <= 3u + +#if 0 + void solve_for_int(unsigned row_id1, unsigned x) { + + for (unsigned i = 0; i < num_divs(); ++i) { + add_lit(model, lits, mk_divides(c*div_divisor(i), + mk_sub(mk_mul(c, div_term(i)), mk_mul(div_coeff(i), t)))); + } + } +#endif + void model_based_opt::solve_for(unsigned row_id1, unsigned x) { - rational a = get_coefficient(row_id1, x); - row& r1 = m_rows[row_id1]; + rational a = get_coefficient(row_id1, x), b; SASSERT(!a.is_zero()); - SASSERT(r1.m_type == t_eq); - SASSERT(r1.m_alive); + SASSERT(m_rows[row_id1].m_type == t_eq); + SASSERT(m_rows[row_id1].m_alive); + if (m_var2is_int[x] && !abs(a).is_one()) { + row& r1 = m_rows[row_id1]; + vector coeffs; + mk_coeffs_without(coeffs, r1.m_vars, x); + add_divides(coeffs, r1.m_coeff, abs(a)); + } unsigned_vector const& row_ids = m_var2row_ids[x]; uint_set visited; visited.insert(row_id1); @@ -611,15 +965,20 @@ namespace opt { unsigned row_id2 = row_ids[i]; if (!visited.contains(row_id2)) { visited.insert(row_id2); - resolve(row_id1, a, row_id2, x); + row const& r2 = m_rows[row_id2]; + b = get_coefficient(row_id2, x); + if (!b.is_zero()) { + resolve(row_id1, a, row_id2, x); + } } } - r1.m_alive = false; + retire_row(row_id1); } void model_based_opt::project(unsigned num_vars, unsigned const* vars) { for (unsigned i = 0; i < num_vars; ++i) { project(vars[i]); + TRACE("opt", display(tout << "After projecting: v" << vars[i] << "\n");); } } diff --git a/src/math/simplex/model_based_opt.h b/src/math/simplex/model_based_opt.h index 3bbcc7bf2..92f600522 100644 --- a/src/math/simplex/model_based_opt.h +++ b/src/math/simplex/model_based_opt.h @@ -30,7 +30,8 @@ namespace opt { enum ineq_type { t_eq, t_lt, - t_le + t_le, + t_mod }; @@ -52,9 +53,11 @@ namespace opt { row(): m_type(t_le), m_value(0), m_alive(false) {} vector m_vars; // variables with coefficients rational m_coeff; // constant in inequality + rational m_mod; // value the term divide ineq_type m_type; // inequality type rational m_value; // value of m_vars + m_coeff under interpretation of m_var2value. bool m_alive; // rows can be marked dead if they have been processed. + void reset() { m_vars.reset(); m_coeff.reset(); m_value.reset(); } }; private: @@ -63,9 +66,11 @@ namespace opt { static const unsigned m_objective_id = 0; vector m_var2row_ids; vector m_var2value; + svector m_var2is_int; vector m_new_vars; - unsigned_vector m_lub, m_glb; + unsigned_vector m_lub, m_glb, m_mod; unsigned_vector m_above, m_below; + unsigned_vector m_retired_rows; bool invariant(); bool invariant(unsigned index, row const& r); @@ -82,7 +87,29 @@ namespace opt { void mul_add(bool same_sign, unsigned row_id1, rational const& c, unsigned row_id2); - void set_row(unsigned row_id, vector const& coeffs, rational const& c, ineq_type rel); + void mul_add(unsigned x, rational const& a1, unsigned row_src, rational const& a2, unsigned row_dst); + + void mul(unsigned dst, rational const& c); + + void add(unsigned dst, rational const& c); + + void sub(unsigned dst, rational const& c); + + void set_row(unsigned row_id, vector const& coeffs, rational const& c, rational const& m, ineq_type rel); + + void add_constraint(vector const& coeffs, rational const& c, rational const& m, ineq_type r); + + void replace_var(unsigned row_id, unsigned x, rational const& A, unsigned y, rational const& B); + + void replace_var(unsigned row_id, unsigned x, rational const& C); + + void normalize(unsigned row_id); + + void mk_coeffs_without(vector& dst, vector const src, unsigned x); + + unsigned new_row(); + + rational n_sign(rational const& b) const; void update_values(unsigned_vector const& bound_vars, unsigned_vector const& bound_trail); @@ -92,12 +119,18 @@ namespace opt { void solve_for(unsigned row_id, unsigned x); + void solve_mod(unsigned x, unsigned_vector const& mod_rows); + + bool is_int(unsigned x) const { return m_var2is_int[x]; } + + void retire_row(unsigned row_id); + public: model_based_opt(); // add a fresh variable with value 'value'. - unsigned add_var(rational const& value); + unsigned add_var(rational const& value, bool is_int = false); // retrieve updated value of variable. rational get_value(unsigned var_id); @@ -106,6 +139,9 @@ namespace opt { // satisfied under the values provided to the variables. void add_constraint(vector const& coeffs, rational const& c, ineq_type r); + // add a divisibility constraint. The row should divide m. + void add_divides(vector const& coeffs, rational const& c, rational const& m); + // Set the objective function (linear). void set_objective(vector const& coeffs, rational const& c); diff --git a/src/qe/qe_arith.cpp b/src/qe/qe_arith.cpp index c2d0016c8..dab6325bc 100644 --- a/src/qe/qe_arith.cpp +++ b/src/qe/qe_arith.cpp @@ -15,7 +15,7 @@ Author: Revision History: - + Moved projection functionality to model_based_opt module. 2016-06-26 --*/ @@ -58,38 +58,15 @@ namespace qe { ast_manager& m; arith_util a; th_rewriter m_rw; - expr_ref_vector m_ineq_terms; - vector m_ineq_coeffs; - svector m_ineq_types; - 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; - bool m_pos_is_unit, m_neg_is_unit; - - sort* var_sort() const { return m.get_sort(m_var->x()); } - - bool is_int() const { return a.is_int(m_var->x()); } - - void display(std::ostream& out) const { - for (unsigned i = 0; i < num_ineqs(); ++i) { - display_ineq(out, i); - } - for (unsigned i = 0; i < num_divs(); ++i) { - display_div(out, i); - } - } void insert_mul(expr* x, rational const& v, obj_map& ts) { + TRACE("qe", tout << "Adding variable " << mk_pp(x, m) << " " << v << "\n";); 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); } } @@ -99,14 +76,14 @@ 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. // - bool linearize(opt::model_based_opt& mbo, model& model, expr* lit, expr_ref_vector& fmls, obj_map& tids) { + bool linearize(opt::model_based_opt& mbo, model_evaluator& eval, expr* lit, expr_ref_vector& fmls, obj_map& tids) { obj_map ts; rational c(0), mul(1); 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)); + eval(lit, val); CTRACE("qe", !m.is_true(val), tout << mk_pp(lit, m) << " := " << val << "\n";); SASSERT(m.is_true(val));); @@ -115,55 +92,84 @@ namespace qe { mul.neg(); } SASSERT(!m.is_not(lit)); - 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); + if ((a.is_le(lit, e1, e2) || a.is_ge(lit, e2, e1))) { + linearize(mbo, eval, mul, e1, c, fmls, ts, tids); + linearize(mbo, eval, -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)) && a.is_real(e1)) { - linearize(mbo, model, mul, e1, c, fmls, ts, tids); - linearize(mbo, model, -mul, e2, c, fmls, ts, tids); + else if ((a.is_lt(lit, e1, e2) || a.is_gt(lit, e2, e1))) { + linearize(mbo, eval, mul, e1, c, fmls, ts, tids); + linearize(mbo, eval, -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 && a.is_real(e1)) { - linearize(mbo, model, mul, e1, c, fmls, ts, tids); - linearize(mbo, model, -mul, e2, c, fmls, ts, tids); + else if (m.is_eq(lit, e1, e2) && !is_not && is_arith(e1)) { + linearize(mbo, eval, mul, e1, c, fmls, ts, tids); + linearize(mbo, eval, -mul, e2, c, fmls, ts, tids); ty = opt::t_eq; } - else if (m.is_eq(lit, e1, e2) && is_not && a.is_real(e1)) { + else if (m.is_eq(lit, e1, e2) && is_not && is_arith(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)); + eval(e1, val1); eval(e2, val2); + VERIFY(a.is_numeral(val1, r1)); + VERIFY(a.is_numeral(val2, r2)); SASSERT(r1 != r2); - if (r2 < r1) { + if (r1 < r2) { 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); + linearize(mbo, eval, mul, e1, c, fmls, ts, tids); + linearize(mbo, eval, -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))) { + expr_ref val(m); + rational r; + app* alit = to_app(lit); + vector > nums; + for (unsigned i = 0; i < alit->get_num_args(); ++i) { + eval(alit->get_arg(i), val); + VERIFY(a.is_numeral(val, r)); + nums.push_back(std::make_pair(alit->get_arg(i), r)); + } + std::sort(nums.begin(), nums.end(), compare_second()); + for (unsigned i = 0; i + 1 < nums.size(); ++i) { + SASSERT(nums[i].second < nums[i+1].second); + expr_ref fml(a.mk_lt(nums[i].first, nums[i+1].first), m); + if (!linearize(mbo, eval, fml, fmls, tids)) { + return false; + } + } + return true; } - 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_distinct(lit) && is_not && is_arith(to_app(lit)->get_arg(0))) { + // find the two arguments that are equal. + // linearize these. + map values; + bool found_eq = false; + for (unsigned i = 0; !found_eq && i < to_app(lit)->get_num_args(); ++i) { + expr* arg1 = to_app(lit)->get_arg(i), *arg2 = 0; + expr_ref val(m); + rational r; + eval(arg1, val); + VERIFY(a.is_numeral(val, r)); + if (values.find(r, arg2)) { + ty = opt::t_eq; + linearize(mbo, eval, mul, arg1, c, fmls, ts, tids); + linearize(mbo, eval, -mul, arg2, c, fmls, ts, tids); + found_eq = true; + } + else { + values.insert(r, arg1); + } + } + SASSERT(found_eq); } else { TRACE("qe", tout << "Skipping " << mk_pp(lit, m) << "\n";); return false; } -#if 0 - TBD for integers - if (ty == opt::t_lt && false) { - c += rational(1); - ty = opt::t_le; - } -#endif vars coeffs; - extract_coefficients(mbo, model, ts, tids, coeffs); + extract_coefficients(mbo, eval, ts, tids, coeffs); mbo.add_constraint(coeffs, c, ty); return true; } @@ -171,212 +177,76 @@ namespace qe { // // 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, + void linearize(opt::model_based_opt& mbo, model_evaluator& eval, rational const& mul, expr* t, rational& c, 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, fmls, ts, tids); + if (a.is_mul(t, t1, t2) && is_numeral(eval, t1, mul1)) { + linearize(mbo, eval, 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, fmls, ts, tids); + else if (a.is_mul(t, t1, t2) && is_numeral(eval, t2, mul1)) { + linearize(mbo, eval, 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, fmls, ts, tids); + linearize(mbo, eval, mul, ap->get_arg(i), c, fmls, ts, tids); } } else if (a.is_sub(t, t1, t2)) { - linearize(mbo, model, mul, t1, c, fmls, ts, tids); - linearize(mbo, model, -mul, t2, c, fmls, ts, tids); + linearize(mbo, eval, mul, t1, c, fmls, ts, tids); + linearize(mbo, eval, -mul, t2, c, fmls, ts, tids); } else if (a.is_uminus(t, t1)) { - linearize(mbo, model, -mul, t1, c, fmls, ts, tids); + linearize(mbo, eval, -mul, t1, c, fmls, ts, tids); } else if (a.is_numeral(t, mul1)) { c += mul*mul1; } else if (m.is_ite(t, t1, t2, t3)) { - VERIFY(model.eval(t1, val)); + 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(mbo, model, mul, t2, c, fmls, ts, tids); + linearize(mbo, eval, mul, t2, c, fmls, ts, tids); fmls.push_back(t1); } else { expr_ref not_t1(mk_not(m, t1), m); fmls.push_back(not_t1); - linearize(mbo, model, mul, t3, c, fmls, ts, tids); + linearize(mbo, eval, mul, t3, c, fmls, ts, tids); } } + else if (a.is_mod(t, t1, t2) && is_numeral(eval, t2, mul1)) { + rational r; + eval(t, val); + VERIFY(a.is_numeral(val, r)); + c += mul*r; + // t1 mod mul1 == r + rational c0(-r), mul0(1); + obj_map ts0; + linearize(mbo, eval, mul0, t1, c0, fmls, ts0, tids); + vars coeffs; + extract_coefficients(mbo, eval, ts0, tids, coeffs); + mbo.add_divides(coeffs, c0, mul1); + } else { insert_mul(t, mul, ts); } } - // - // 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; - expr_ref val(m); - if (t == m_var->x()) { - c += mul; - } - else if (a.is_mul(t, t1, t2) && is_numeral(model, t1, mul1)) { - is_linear(model, mul* mul1, t2, c, ts); - } - else if (a.is_mul(t, t1, t2) && is_numeral(model, t2, mul1)) { - is_linear(model, mul* mul1, t1, c, ts); - } - else if (a.is_add(t)) { - app* ap = to_app(t); - for (unsigned i = 0; i < ap->get_num_args(); ++i) { - is_linear(model, mul, ap->get_arg(i), c, ts); - } - } - else if (a.is_sub(t, t1, t2)) { - is_linear(model, mul, t1, c, ts); - is_linear(model, -mul, t2, c, ts); - } - else if (a.is_uminus(t, t1)) { - is_linear(model, -mul, t1, c, ts); - } - else if (a.is_numeral(t, mul1)) { - ts.push_back(mk_num(mul*mul1)); - } - else if (extract_mod(model, t, val)) { - ts.push_back(mk_mul(mul, val)); - } - 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)) { - is_linear(model, mul, t2, c, ts); - } - else { - is_linear(model, mul, t3, c, ts); - } - } - else if ((*m_var)(t)) { - TRACE("qe", tout << "can't project:" << mk_pp(t, m) << "\n";); - throw cant_project(); - } - else { - ts.push_back(mk_mul(mul, t)); - } - } - - // - // 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); - opt::ineq_type ty = opt::t_le; - expr* e1, *e2; - expr_ref_vector ts(m); - 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)) { - is_linear(model, mul, e1, c, ts); - is_linear(model, -mul, e2, c, ts); - ty = is_not? opt::t_lt : opt::t_le; - } - else if (a.is_lt(lit, e1, e2) || a.is_gt(lit, e2, e1)) { - is_linear(model, mul, e1, c, ts); - is_linear(model, -mul, e2, c, ts); - ty = is_not? opt::t_le: opt::t_lt; - } - else if (m.is_eq(lit, e1, e2) && !is_not && is_arith(e1)) { - is_linear(model, mul, e1, c, ts); - is_linear(model, -mul, e2, c, ts); - ty = opt::t_eq; - } - else if (m.is_distinct(lit) && !is_not && is_arith(to_app(lit)->get_arg(0))) { - expr_ref val(m); - rational r; - app* alit = to_app(lit); - vector > nums; - for (unsigned i = 0; i < alit->get_num_args(); ++i) { - VERIFY(model.eval(alit->get_arg(i), val) && a.is_numeral(val, r)); - nums.push_back(std::make_pair(alit->get_arg(i), r)); - } - std::sort(nums.begin(), nums.end(), compare_second()); - for (unsigned i = 0; i + 1 < nums.size(); ++i) { - SASSERT(nums[i].second < nums[i+1].second); - c.reset(); - ts.reset(); - is_linear(model, mul, nums[i+1].first, c, ts); - is_linear(model, -mul, nums[i].first, c, ts); - t = add(ts); - accumulate_linear(model, c, t, opt::t_lt); - } - t = mk_num(0); - c.reset(); - return true; - } - else if (m.is_distinct(lit) && is_not && is_arith(to_app(lit)->get_arg(0))) { - expr_ref eq = project_plugin::pick_equality(m, model, to_app(lit)->get_arg(0)); - return is_linear(model, eq, found_eq); - } - else if (m.is_eq(lit, e1, e2) && is_not && is_arith(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 (r1 < r2) { - std::swap(e1, e2); - } - ty = opt::t_lt; - is_linear(model, mul, e1, c, ts); - is_linear(model, -mul, e2, c, ts); - } - else { - TRACE("qe", tout << "can't project:" << mk_pp(lit, m) << "\n";); - throw cant_project(); - } - if (ty == opt::t_lt && is_int()) { - ts.push_back(mk_num(1)); - ty = opt::t_le; - } - t = add(ts); - if (ty == opt::t_eq && c.is_neg()) { - t = mk_uminus(t); - c.neg(); - } - if (ty == opt::t_eq && c > rational(1)) { - m_ineq_coeffs.push_back(-c); - m_ineq_terms.push_back(mk_uminus(t)); - m_ineq_types.push_back(opt::t_le); - m_num_neg++; - ty = opt::t_le; - } - accumulate_linear(model, c, t, ty); - found_eq = !c.is_zero() && ty == opt::t_eq; - return true; - } - - bool is_numeral(model& model, expr* t, rational& r) { + bool is_numeral(model_evaluator& eval, expr* t, rational& r) { expr* t1, *t2, *t3; rational r1, r2; expr_ref val(m); if (a.is_numeral(t, r)) return true; - if (a.is_uminus(t, t1) && is_numeral(model, t1, r)) { + if (a.is_uminus(t, t1) && is_numeral(eval, t1, r)) { r.neg(); return true; } - else if (a.is_mul(t, t1, t2) && is_numeral(model, t1, r1) && is_numeral(model, t2, r2)) { + else if (a.is_mul(t, t1, t2) && is_numeral(eval, t1, r1) && is_numeral(eval, t2, r2)) { r = r1*r2; return true; } @@ -384,21 +254,21 @@ namespace qe { app* ap = to_app(t); r = rational(1); for (unsigned i = 0; i < ap->get_num_args(); ++i) { - if (!is_numeral(model, ap->get_arg(i), r1)) return false; + if (!is_numeral(eval, ap->get_arg(i), r1)) return false; r *= r1; } return true; } else if (m.is_ite(t, t1, t2, t3)) { - VERIFY (model.eval(t1, val)); + eval(t1, val); if (m.is_true(val)) { - return is_numeral(model, t1, r); + return is_numeral(eval, t1, r); } else { - return is_numeral(model, t2, r); + return is_numeral(eval, t2, r); } } - else if (a.is_sub(t, t1, t2) && is_numeral(model, t1, r1) && is_numeral(model, t2, r2)) { + else if (a.is_sub(t, t1, t2) && is_numeral(eval, t1, r1) && is_numeral(eval, t2, r2)) { r = r1 - r2; return true; } @@ -413,564 +283,16 @@ namespace qe { } }; - void accumulate_linear(model& model, rational const& c, expr_ref& t, opt::ineq_type ty) { - if (c.is_zero()) { - switch (ty) { - case opt::t_eq: - t = a.mk_eq(t, mk_num(0)); - break; - case opt::t_lt: - t = a.mk_lt(t, mk_num(0)); - break; - case opt::t_le: - t = a.mk_le(t, mk_num(0)); - break; - } - add_lit(model, m_new_lits, t); - } - else { - m_ineq_coeffs.push_back(c); - m_ineq_terms.push_back(t); - m_ineq_types.push_back(ty); - if (ty == opt::t_eq) { - // skip - } - else if (c.is_pos()) { - ++m_num_pos; - m_pos_is_unit &= c.is_one(); - } - else { - ++m_num_neg; - m_neg_is_unit &= c.is_minus_one(); - } - } - } - bool is_arith(expr* e) { return a.is_int(e) || a.is_real(e); } - - expr_ref add(expr_ref_vector const& ts) { - switch (ts.size()) { - case 0: - return mk_num(0); - case 1: - return expr_ref(ts[0], m); - default: - return expr_ref(a.mk_add(ts.size(), ts.c_ptr()), m); - } - } - - - // e is of the form (ax + t) mod k - bool is_mod(model& model, expr* e, rational& k, expr_ref& t, rational& c) { - expr* t1, *t2; - expr_ref_vector ts(m); - if (a.is_mod(e, t1, t2) && - a.is_numeral(t2, k) && - (*m_var)(t1)) { - c.reset(); - rational mul(1); - is_linear(model, mul, t1, c, ts); - t = add(ts); - return true; - } - return false; - } - - bool extract_mod(model& model, expr* e, expr_ref& val) { - rational c, k; - expr_ref t(m); - if (is_mod(model, e, k, t, c)) { - VERIFY (model.eval(e, val)); - SASSERT (a.is_numeral(val)); - TRACE("qe", tout << "extract: " << mk_pp(e, m) << " evals: " << val << " c: " << c << " t: " << t << "\n";); - if (!c.is_zero()) { - t = mk_sub(t, val); - m_div_terms.push_back(t); - m_div_divisors.push_back(k); - m_div_coeffs.push_back(c); - } - else { - t = m.mk_eq(a.mk_mod(t, mk_num(k)), val); - add_lit(model, m_new_lits, t); - } - return true; - } - return false; - } - - bool lit_is_true(model& model, expr* e) { - expr_ref val(m); - VERIFY(model.eval(e, val)); - CTRACE("qe", !m.is_true(val), tout << "eval: " << mk_pp(e, m) << " " << val << "\n";); - return m.is_true(val); - } - - expr_ref mk_num(unsigned n) { - rational r(n); - return mk_num(r); - } - - expr_ref mk_num(rational const& r) const { - return expr_ref(a.mk_numeral(r, var_sort()), m); - } - - expr_ref mk_divides(rational const& k, expr* t) { - return expr_ref(m.mk_eq(a.mk_mod(t, mk_num(abs(k))), mk_num(0)), m); - } - - void reset() { - reset_ineqs(); - reset_divs(); - m_delta = rational(1); - m_u = rational(0); - m_new_lits.reset(); - } - - void reset_divs() { - m_div_terms.reset(); - m_div_coeffs.reset(); - m_div_divisors.reset(); - } - - void reset_ineqs() { - m_ineq_terms.reset(); - m_ineq_coeffs.reset(); - m_ineq_types.reset(); - } - - expr* ineq_term(unsigned i) const { return m_ineq_terms[i]; } - rational const& ineq_coeff(unsigned i) const { return m_ineq_coeffs[i]; } - opt::ineq_type ineq_ty(unsigned i) const { return m_ineq_types[i]; } - app_ref mk_ineq_pred(unsigned i) { - app_ref result(m); - result = to_app(mk_add(mk_mul(ineq_coeff(i), m_var->x()), ineq_term(i))); - switch (ineq_ty(i)) { - case opt::t_lt: - result = a.mk_lt(result, mk_num(0)); - break; - case opt::t_le: - result = a.mk_le(result, mk_num(0)); - break; - case opt::t_eq: - result = m.mk_eq(result, mk_num(0)); - break; - } - return result; - } - void display_ineq(std::ostream& out, unsigned i) const { - out << mk_pp(ineq_term(i), m) << " " << ineq_coeff(i) << "*" << mk_pp(m_var->x(), m); - switch (ineq_ty(i)) { - case opt::t_eq: out << " = 0\n"; break; - case opt::t_le: out << " <= 0\n"; break; - case opt::t_lt: out << " < 0\n"; break; - } - } - unsigned num_ineqs() const { return m_ineq_terms.size(); } - expr* div_term(unsigned i) const { return m_div_terms[i]; } - rational const& div_coeff(unsigned i) const { return m_div_coeffs[i]; } - rational const& div_divisor(unsigned i) const { return m_div_divisors[i]; } - void display_div(std::ostream& out, unsigned i) const { - out << div_divisor(i) << " | ( " << mk_pp(div_term(i), m) << " " << div_coeff(i) << "*" - << mk_pp(m_var->x(), m) << ")\n"; - } - unsigned num_divs() const { return m_div_terms.size(); } - - void project(model& model, expr_ref_vector& lits) { - TRACE("qe", - tout << "project: " << mk_pp(m_var->x(), m) << "\n"; - tout << lits; - model_v2_pp(tout, model); ); - - m_num_pos = 0; m_num_neg = 0; - m_pos_is_unit = true; m_neg_is_unit = true; - unsigned eq_index = 0; - reset(); - bool found_eq = false; - for (unsigned i = 0; i < lits.size(); ++i) { - bool found_eq0 = false; - expr* e = lits[i].get(); - if (!(*m_var)(e)) { - m_new_lits.push_back(e); - } - else if (!is_linear(model, e, found_eq0)) { - TRACE("qe", tout << "can't project:" << mk_pp(e, m) << "\n";); - throw cant_project(); - } - if (found_eq0 && !found_eq) { - found_eq = true; - eq_index = num_ineqs()-1; - } - } - TRACE("qe", display(tout << mk_pp(m_var->x(), m) << ":\n"); - tout << "found eq: " << found_eq << " @ " << eq_index << "\n"; - tout << "num pos: " << m_num_pos << " num neg: " << m_num_neg << " num divs " << num_divs() << "\n"; - ); - lits.reset(); - lits.append(m_new_lits); - if (found_eq) { - apply_equality(model, eq_index, lits); - return; - } - if (num_divs() == 0 && (m_num_pos == 0 || m_num_neg == 0)) { - return; - } - if (num_divs() > 0) { - apply_divides(model, lits); - TRACE("qe", display(tout << "after division " << mk_pp(m_var->x(), m) << "\n");); - } - if (m_num_pos == 0 || m_num_neg == 0) { - return; - } - if ((m_num_pos <= 2 || m_num_neg <= 2) && - (m_num_pos == 1 || m_num_neg == 1 || (m_num_pos <= 3 && m_num_neg <= 3)) && - (!is_int() || m_pos_is_unit || m_neg_is_unit)) { - - unsigned index1 = num_ineqs(); - unsigned index2 = num_ineqs(); - bool is_pos = m_num_pos <= m_num_neg; - for (unsigned i = 0; i < num_ineqs(); ++i) { - if (ineq_coeff(i).is_pos() == is_pos) { - if (index1 == num_ineqs()) { - index1 = i; - } - else { - SASSERT(index2 == num_ineqs()); - index2 = i; - } - } - } - for (unsigned i = 0; i < num_ineqs(); ++i) { - if (ineq_coeff(i).is_pos() != is_pos) { - SASSERT(index1 != num_ineqs()); - mk_lt(model, lits, i, index1); - if (index2 != num_ineqs()) { - mk_lt(model, lits, i, index2); - } - } - } - } - else { - expr_ref t(m); - bool use_pos = m_num_pos < m_num_neg; - unsigned max_t = find_max(model, use_pos); - - for (unsigned i = 0; i < num_ineqs(); ++i) { - if (i != max_t) { - if (ineq_coeff(i).is_pos() == use_pos) { - t = mk_le(i, max_t); - add_lit(model, lits, t); - } - else { - mk_lt(model, lits, i, max_t); - } - } - } - } - TRACE("qe", tout << lits;); - } - - unsigned find_max(model& mdl, bool do_pos) { - unsigned result = 0; - 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]; - SASSERT(!is_int || opt::t_le == ineq_ty(i)); - - // - // ac*x + t < 0 - // ac > 0: x + max { t/ac | ac > 0 } < 0 <=> x < - max { t/ac | ac > 0 } - // ac < 0: x + t/ac > 0 <=> x > max { - t/ac | ac < 0 } = max { t/|ac| | ac < 0 } - // - if (ac.is_pos() == do_pos) { - eval(ineq_term(i), val); - VERIFY(a.is_numeral(val, r)); - r /= abs(ac); - new_max = - new_max || - (r > max_r) || - (r == max_r && opt::t_lt == ineq_ty(i)) || - (r == max_r && is_int && ac.is_one()); - TRACE("qe", tout << "max: " << mk_pp(ineq_term(i), m) << "/" << abs(ac) << " := " << r << " " - << (new_max?"":"not ") << "new max\n";); - if (new_max) { - result = i; - max_r = r; - } - new_max = false; - } - } - SASSERT(!new_max); - return result; - } - - // ax + t <= 0 - // bx + s <= 0 - // a and b have different signs. - // Infer: a|b|x + |b|t + |a|bx + |a|s <= 0 - // e.g. |b|t + |a|s <= 0 - void mk_lt(model& model, expr_ref_vector& lits, unsigned i, unsigned j) { - rational const& ac = ineq_coeff(i); - rational const& bc = ineq_coeff(j); - SASSERT(ac.is_pos() != bc.is_pos()); - SASSERT(ac.is_neg() != bc.is_neg()); - - TRACE("qe", display_ineq(tout, i); display_ineq(tout, j);); - - if (is_int() && !abs(ac).is_one() && !abs(bc).is_one()) { - return mk_int_lt(model, lits, i, j); - } - expr* t = ineq_term(i); - expr* s = ineq_term(j); - expr_ref bt = mk_mul(abs(bc), t); - expr_ref as = mk_mul(abs(ac), s); - expr_ref ts = mk_add(bt, as); - expr_ref z = mk_num(0); - expr_ref fml(m); - if (opt::t_lt == ineq_ty(i) || opt::t_lt == ineq_ty(j)) { - fml = a.mk_lt(ts, z); - } - else { - fml = a.mk_le(ts, z); - } - add_lit(model, lits, fml); - } - - void mk_int_lt(model& model, expr_ref_vector& lits, unsigned i, unsigned j) { - TRACE("qe", display_ineq(tout, i); display_ineq(tout, j);); - - expr* t = ineq_term(i); - expr* s = ineq_term(j); - rational ac = ineq_coeff(i); - rational bc = ineq_coeff(j); - expr_ref tmp(m); - SASSERT(opt::t_le == ineq_ty(i) && opt::t_le == ineq_ty(j)); - SASSERT(ac.is_pos() == bc.is_neg()); - rational abs_a = abs(ac); - rational abs_b = abs(bc); - expr_ref as(mk_mul(abs_a, s), m); - expr_ref bt(mk_mul(abs_b, t), m); - - rational slack = (abs_a - rational(1))*(abs_b-rational(1)); - rational sval, tval; - VERIFY (model.eval(ineq_term(i), tmp) && a.is_numeral(tmp, tval)); - VERIFY (model.eval(ineq_term(j), tmp) && a.is_numeral(tmp, sval)); - bool use_case1 = ac*sval + bc*tval + slack <= rational(0); - if (use_case1) { - expr_ref_vector ts(m); - ts.push_back(as); - ts.push_back(bt); - ts.push_back(mk_num(-slack)); - tmp = a.mk_le(add(ts), mk_num(0)); - add_lit(model, lits, tmp); - return; - } - - if (abs_a < abs_b) { - std::swap(abs_a, abs_b); - std::swap(ac, bc); - std::swap(s, t); - std::swap(as, bt); - std::swap(sval, tval); - } - SASSERT(abs_a >= abs_b); - - // create finite disjunction for |b|. - // exists x, z in [0 .. |b|-2] . b*x + s + z = 0 && ax + t <= 0 && bx + s <= 0 - // <=> - // exists x, z in [0 .. |b|-2] . b*x = -z - s && ax + t <= 0 && bx + s <= 0 - // <=> - // exists x, z in [0 .. |b|-2] . b*x = -z - s && a|b|x + |b|t <= 0 && bx + s <= 0 - // <=> - // exists x, z in [0 .. |b|-2] . b*x = -z - s && a|b|x + |b|t <= 0 && -z - s + s <= 0 - // <=> - // exists x, z in [0 .. |b|-2] . b*x = -z - s && a|b|x + |b|t <= 0 && -z <= 0 - // <=> - // exists x, z in [0 .. |b|-2] . b*x = -z - s && a|b|x + |b|t <= 0 - // <=> - // exists x, z in [0 .. |b|-2] . b*x = -z - s && a*n_sign(b)(s + z) + |b|t <= 0 - // <=> - // exists z in [0 .. |b|-2] . |b| | (z + s) && a*n_sign(b)(s + z) + |b|t <= 0 - // - - rational z = mod(sval, abs_b); - if (!z.is_zero()) z = abs_b - z; - expr_ref s_plus_z(mk_add(z, s), m); - - tmp = mk_divides(abs_b, s_plus_z); - add_lit(model, lits, tmp); - tmp = a.mk_le(mk_add(mk_mul(ac*n_sign(bc), s_plus_z), - mk_mul(abs_b, t)), mk_num(0)); - add_lit(model, lits, tmp); - } - rational n_sign(rational const& b) { return rational(b.is_pos()?-1:1); } - // ax + t <= 0 - // bx + s <= 0 - // a and b have same signs. - // encode: - // t/|a| <= s/|b| - // e.g. |b|t <= |a|s - expr_ref mk_le(unsigned i, unsigned j) { - rational const& ac = ineq_coeff(i); - rational const& bc = ineq_coeff(j); - SASSERT(ac.is_pos() == bc.is_pos()); - SASSERT(ac.is_neg() == bc.is_neg()); - expr* t = ineq_term(i); - expr* s = ineq_term(j); - expr_ref bt = mk_mul(abs(bc), t); - expr_ref as = mk_mul(abs(ac), s); - if (opt::t_lt == ineq_ty(i) && opt::t_le == ineq_ty(j)) { - return expr_ref(a.mk_lt(bt, as), m); - } - else { - return expr_ref(a.mk_le(bt, as), m); - } - } - - expr_ref mk_add(expr* t1, expr* t2) { - rational r; - if (a.is_numeral(t1, r) && r.is_zero()) return expr_ref(t2, m); - if (a.is_numeral(t2, r) && r.is_zero()) return expr_ref(t1, m); - return expr_ref(a.mk_add(t1, t2), m); - } - expr_ref mk_add(rational const& r, expr* e) { - if (r.is_zero()) return expr_ref(e, m); - return mk_add(mk_num(r), e); - } - - expr_ref mk_mul(rational const& r, expr* t) { - if (r.is_one()) return expr_ref(t, m); - return expr_ref(a.mk_mul(mk_num(r), t), m); - } - - expr_ref mk_sub(expr* t1, expr* t2) { - rational r1, r2; - if (a.is_numeral(t2, r2) && r2.is_zero()) return expr_ref(t1, m); - if (a.is_numeral(t1, r1) && a.is_numeral(t2, r2)) return mk_num(r1 - r2); - return expr_ref(a.mk_sub(t1, t2), m); - } - - expr_ref mk_uminus(expr* t) { - rational r; - if (a.is_numeral(t, r)) { - return mk_num(-r); - } - return expr_ref(a.mk_uminus(t), m); - } - - void add_lit(model& model, expr_ref_vector& lits, expr* e) { - expr_ref orig(e, m), result(m); - m_rw(orig, result); - TRACE("qe", tout << mk_pp(orig, m) << " -> " << result << "\n";); - SASSERT(lit_is_true(model, orig)); - SASSERT(lit_is_true(model, result)); - if (!m.is_true(result)) { - lits.push_back(result); - } - } - - - // 3x + t = 0 & 7 | (c*x + s) & ax <= u - // 3 | -t & 21 | (-ct + 3s) & a-t <= 3u - - void apply_equality(model& model, unsigned eq_index, expr_ref_vector& lits) { - rational c = ineq_coeff(eq_index); - expr* t = ineq_term(eq_index); - SASSERT(c.is_pos()); - if (is_int()) { - add_lit(model, lits, mk_divides(c, ineq_term(eq_index))); - } - - for (unsigned i = 0; i < num_divs(); ++i) { - add_lit(model, lits, mk_divides(c*div_divisor(i), - mk_sub(mk_mul(c, div_term(i)), mk_mul(div_coeff(i), t)))); - } - for (unsigned i = 0; i < num_ineqs(); ++i) { - if (eq_index != i) { - expr_ref lhs(m), val(m); - lhs = mk_sub(mk_mul(c, ineq_term(i)), mk_mul(ineq_coeff(i), t)); - switch (ineq_ty(i)) { - case opt::t_lt: lhs = a.mk_lt(lhs, mk_num(0)); break; - case opt::t_le: lhs = a.mk_le(lhs, mk_num(0)); break; - case opt::t_eq: lhs = m.mk_eq(lhs, mk_num(0)); break; - } - TRACE("qe", tout << lhs << "\n";); - SASSERT (model.eval(lhs, val) && m.is_true(val)); - add_lit(model, lits, lhs); - } - } - } - - // - // compute D and u. - // - // D = lcm(d1, d2) - // u = eval(x) mod D - // - // d1 | (a1x + t1) & d2 | (a2x + t2) - // = - // D | (D/d1)(a1x + t1) & D | (D/d2)(a2x + t2) - // = - // D | D1(a1*u + t1) & D | D2(a2*u + t2) & x = D*x' + u & 0 <= u < D - // = - // D | D1(a1*u + t1) & D | D2(a2*u + t2) & x = D*x' + u & 0 <= u < D - // - // x := D*x' + u - // - void apply_divides(model& model, expr_ref_vector& lits) { - SASSERT(m_delta.is_one()); - unsigned n = num_divs(); - if (n == 0) { - return; - } - for (unsigned i = 0; i < n; ++i) { - m_delta = lcm(m_delta, div_divisor(i)); - } - expr_ref val(m); - rational r; - VERIFY (model.eval(m_var->x(), val) && a.is_numeral(val, r)); - m_u = mod(r, m_delta); - SASSERT(m_u < m_delta && rational(0) <= m_u); - for (unsigned i = 0; i < n; ++i) { - add_lit(model, lits, mk_divides(div_divisor(i), - mk_add(mk_num(div_coeff(i) * m_u), div_term(i)))); - } - reset_divs(); - // - // update inequalities such that u is added to t and - // D is multiplied to coefficient of x. - // the interpretation of the new version of x is (x-u)/D - // - // a*x + t <= 0 - // a*(D*x' + u) + t <= 0 - // a*D*x' + a*u + t <= 0 - for (unsigned i = 0; i < num_ineqs(); ++i) { - if (!m_u.is_zero()) { - m_ineq_terms[i] = a.mk_add(ineq_term(i), mk_num(m_ineq_coeffs[i]*m_u)); - } - m_ineq_coeffs[i] *= m_delta; - } - r = (r - m_u) / m_delta; - SASSERT(r.is_int()); - val = a.mk_numeral(r, true); - model.register_decl(m_var->x()->get_decl(), val); - TRACE("qe", model_v2_pp(tout, model);); - } - imp(ast_manager& m): - m(m), a(m), m_rw(m), m_ineq_terms(m), m_div_terms(m), m_new_lits(m), m_trail(m) { + m(m), a(m), m_rw(m), m_trail(m) { params_ref params; params.set_bool("gcd_rouding", true); m_rw.updt_params(params); @@ -984,43 +306,43 @@ namespace qe { } bool operator()(model& model, app* v, app_ref_vector& vars, expr_ref_vector& lits) { - SASSERT(a.is_real(v) || a.is_int(v)); - m_var = alloc(contains_app, m, v); - try { - project(model, lits); - } - catch (cant_project) { - TRACE("qe", tout << "can't project:" << mk_pp(v, m) << "\n";); - return false; - } - return true; + app_ref_vector vs(m); + vs.push_back(v); + (*this)(model, vs, lits); + return vs.empty(); } typedef opt::model_based_opt::var var; typedef opt::model_based_opt::row row; typedef vector vars; - 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()); + bool has_arith = false; + for (unsigned i = 0; !has_arith && i < vars.size(); ++i) { + expr* v = vars[i].get(); + has_arith |= is_arith(v); } - if (!has_real) { + if (!has_arith) { return; } + model_evaluator eval(model); + // eval.set_model_completion(true); 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)) { + expr* fml = fmls[i].get(); + if (!linearize(mbo, eval, fml, fmls, tids)) { if (i != j) { fmls[j] = fmls[i].get(); } ++j; } + else { + TRACE("qe", tout << mk_pp(fml, m) << "\n";); + } } fmls.resize(j); @@ -1036,8 +358,13 @@ namespace qe { 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()); + if (is_arith(v) && !tids.contains(v)) { + expr_ref val(m); + rational r; + eval(v, val); + a.is_numeral(val, r); + TRACE("qe", tout << mk_pp(v, m) << " " << val << "\n";); + tids.insert(v, mbo.add_var(r, a.is_int(v))); } } for (unsigned i = 0; i < fmls.size(); ++i) { @@ -1056,7 +383,7 @@ namespace qe { 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)) { + if (is_arith(v) && !fmls_mark.is_marked(v)) { real_vars.push_back(tids.find(v)); } else { @@ -1067,7 +394,14 @@ namespace qe { } } vars.resize(j); + TRACE("qe", tout << "remaining vars: " << vars << "\n"; + for (unsigned i = 0; i < real_vars.size(); ++i) { + unsigned v = real_vars[i]; + tout << "v" << v << " " << mk_pp(index2expr[v], m) << "\n"; + } + mbo.display(tout);); mbo.project(real_vars.size(), real_vars.c_ptr()); + TRACE("qe", mbo.display(tout);); vector rows; mbo.get_live_rows(rows); @@ -1078,17 +412,18 @@ namespace qe { if (r.m_vars.size() == 0) { continue; } - if (r.m_vars.size() == 1 && r.m_vars[0].m_coeff.is_neg()) { + if (r.m_vars.size() == 1 && r.m_vars[0].m_coeff.is_neg() && r.m_type != opt::t_mod) { var const& v = r.m_vars[0]; t = index2expr[v.m_id]; if (!v.m_coeff.is_minus_one()) { - t = a.mk_mul(t, a.mk_numeral(-v.m_coeff, a.is_int(t))); + t = a.mk_mul(a.mk_numeral(-v.m_coeff, a.is_int(t)), t); } s = a.mk_numeral(r.m_coeff, a.is_int(t)); switch (r.m_type) { case opt::t_lt: t = a.mk_gt(t, s); break; case opt::t_le: t = a.mk_ge(t, s); break; case opt::t_eq: t = a.mk_eq(t, s); break; + default: UNREACHABLE(); } fmls.push_back(t); VERIFY(model.eval(t, val)); @@ -1099,7 +434,7 @@ namespace qe { 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, a.is_int(t))); + t = a.mk_mul(a.mk_numeral(v.m_coeff, a.is_int(t)), t); } ts.push_back(t); } @@ -1114,10 +449,17 @@ namespace qe { 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; + case opt::t_mod: { + rational sval; + if (!a.is_numeral(s, sval) || !sval.is_zero()) { + t = a.mk_sub(t, s); + } + t = a.mk_eq(a.mk_mod(t, a.mk_numeral(r.m_mod, true)), a.mk_int(0)); + break; + } } fmls.push_back(t); - - + VERIFY(model.eval(t, val)); CTRACE("qe", !m.is_true(val), tout << "Evaluated " << t << " to " << val << "\n";); @@ -1133,18 +475,18 @@ namespace qe { opt::inf_eps value; obj_map ts; obj_map tids; - + model_evaluator eval(mdl); // extract objective function. vars coeffs; rational c(0), mul(1); - linearize(mbo, mdl, mul, t, c, fmls, ts, tids); - extract_coefficients(mbo, mdl, ts, tids, coeffs); + linearize(mbo, eval, mul, t, c, fmls, ts, tids); + extract_coefficients(mbo, eval, ts, tids, coeffs); mbo.set_objective(coeffs, c); // extract linear constraints for (unsigned i = 0; i < fmls.size(); ++i) { - linearize(mbo, mdl, fmls[i].get(), fmls, tids); + linearize(mbo, eval, fmls[i].get(), fmls, tids); } // find optimal value @@ -1168,7 +510,7 @@ namespace qe { } expr_ref val(a.mk_numeral(value.get_rational(), false), m); expr_ref tval(m); - VERIFY (mdl.eval(t, tval)); + eval(t, tval); // update the predicate 'bound' which forces larger values when 'strict' is true. // strict: bound := valuue < t @@ -1202,25 +544,31 @@ namespace qe { return valid; } - void extract_coefficients(opt::model_based_opt& mbo, model& model, obj_map const& ts, obj_map& tids, vars& coeffs) { + void extract_coefficients(opt::model_based_opt& mbo, model_evaluator& eval, obj_map const& ts, obj_map& tids, vars& coeffs) { coeffs.reset(); + eval.set_model_completion(true); obj_map::iterator it = ts.begin(), end = ts.end(); for (; it != end; ++it) { unsigned id; - if (!tids.find(it->m_key, id)) { + expr* v = it->m_key; + if (!tids.find(v, id)) { rational r; expr_ref val(m); - if (model.eval(it->m_key, val) && a.is_numeral(val, r)) { - id = mbo.add_var(r); + eval(v, val); + if (a.is_numeral(val, r)) { + id = mbo.add_var(r, a.is_int(v)); } else { TRACE("qe", tout << "extraction of coefficients cancelled\n";); return; } - tids.insert(it->m_key, id); - m_trail.push_back(it->m_key); + tids.insert(v, id); + m_trail.push_back(v); + } + CTRACE("qe", it->m_value.is_zero(), tout << mk_pp(v, m) << " has coefficeint 0\n";); + if (!it->m_value.is_zero()) { + coeffs.push_back(var(id, it->m_value)); } - coeffs.push_back(var(id, it->m_value)); } } diff --git a/src/qe/qe_mbp.cpp b/src/qe/qe_mbp.cpp index 85371d8ef..eaedc470b 100644 --- a/src/qe/qe_mbp.cpp +++ b/src/qe/qe_mbp.cpp @@ -270,6 +270,8 @@ class mbp::impl { sub(fmls[i].get(), val); m_rw(val); if (!m.is_true(val)) { + TRACE("qe", tout << mk_pp(fmls[i].get(), m) << " -> " << val << "\n";); + fmls[i] = val; if (j != i) { fmls[j] = fmls[i].get(); } diff --git a/src/test/model_based_opt.cpp b/src/test/model_based_opt.cpp index b5b8e2953..64b2df285 100644 --- a/src/test/model_based_opt.cpp +++ b/src/test/model_based_opt.cpp @@ -287,9 +287,76 @@ static void test7() { mbo.display(std::cout); } +static void test8() { + 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); + + mbo.display(std::cout); + mbo.project(1, &y); + mbo.display(std::cout); +} + + +static void test9() { + opt::model_based_opt mbo; + unsigned x0 = mbo.add_var(rational(2), true); + unsigned x = mbo.add_var(rational(1), true); + unsigned y = mbo.add_var(rational(3), true); + unsigned z = mbo.add_var(rational(4), true); + unsigned u = mbo.add_var(rational(5), true); + unsigned v = mbo.add_var(rational(6), true); + + 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); + + mbo.display(std::cout); + mbo.project(1, &y); + mbo.display(std::cout); +} + + +static void test10() { + opt::model_based_opt mbo; + unsigned x0 = mbo.add_var(rational(2), true); + unsigned x = mbo.add_var(rational(1), true); + unsigned y = mbo.add_var(rational(3), true); + unsigned z = mbo.add_var(rational(4), true); + unsigned u = mbo.add_var(rational(5), true); + unsigned v = mbo.add_var(rational(6), true); + + add_ineq(mbo, x0, 1, y, -2, 0, opt::t_le); + add_ineq(mbo, x, 1, y, -2, 0, opt::t_lt); + add_ineq(mbo, y, 3, u, -4, 0, opt::t_le); + add_ineq(mbo, y, 3, z, -5, 1, opt::t_le); + add_ineq(mbo, y, 3, v, -6, 1, opt::t_le); + + mbo.display(std::cout); + mbo.project(1, &y); + mbo.display(std::cout); + mbo.project(1, &x0); + mbo.display(std::cout); +} + // test with mix of upper and lower bounds void tst_model_based_opt() { + test10(); + return; check_random_ineqs(); test1(); test2(); @@ -298,5 +365,6 @@ void tst_model_based_opt() { test5(); test6(); test7(); - + test8(); + test9(); } diff --git a/src/test/qe_arith.cpp b/src/test/qe_arith.cpp index f9cd9aa23..79495e24f 100644 --- a/src/test/qe_arith.cpp +++ b/src/test/qe_arith.cpp @@ -438,10 +438,158 @@ static void check_random_ineqs() { } } +static void test_project() { + ast_manager m; + reg_decl_plugins(m); + qe::arith_project_plugin plugin(m); + arith_util a(m); + app_ref_vector vars(m); + expr_ref_vector lits(m), ds(m); + model mdl(m); + app_ref x(m), y(m), z(m), u(m); + x = m.mk_const(symbol("x"), a.mk_int()); + y = m.mk_const(symbol("y"), a.mk_int()); + z = m.mk_const(symbol("z"), a.mk_int()); + u = m.mk_const(symbol("u"), a.mk_int()); + func_decl_ref f(m); + sort* int_sort = a.mk_int(); + f = m.mk_func_decl(symbol("f"), 1, &int_sort, int_sort); + // test non-projection + mdl.register_decl(x->get_decl(), a.mk_int(0)); + mdl.register_decl(y->get_decl(), a.mk_int(1)); + mdl.register_decl(z->get_decl(), a.mk_int(2)); + mdl.register_decl(u->get_decl(), a.mk_int(3)); + func_interp* fi = alloc(func_interp, m, 1); + expr_ref_vector nums(m); + nums.push_back(a.mk_int(0)); + nums.push_back(a.mk_int(1)); + nums.push_back(a.mk_int(2)); + fi->insert_new_entry(nums.c_ptr(), a.mk_int(1)); + fi->insert_new_entry(nums.c_ptr()+1, a.mk_int(2)); + fi->insert_new_entry(nums.c_ptr()+2, a.mk_int(3)); + fi->set_else(a.mk_int(10)); + mdl.register_decl(f, fi); + vars.reset(); + lits.reset(); + vars.push_back(x); + lits.push_back(x <= app_ref(m.mk_app(f, (expr*)x), m)); + lits.push_back(x < y); + plugin(mdl, vars, lits); + std::cout << lits << "\n"; + + // test not-equals + vars.reset(); + lits.reset(); + vars.push_back(x); + lits.push_back(m.mk_not(m.mk_eq(x, y))); + plugin(mdl, vars, lits); + std::cout << lits << "\n"; + + // test negation of distinct using bound variables + mdl.register_decl(x->get_decl(), a.mk_int(0)); + mdl.register_decl(y->get_decl(), a.mk_int(1)); + mdl.register_decl(z->get_decl(), a.mk_int(0)); + mdl.register_decl(u->get_decl(), a.mk_int(6)); + vars.reset(); + lits.reset(); + ds.reset(); + vars.push_back(x); + vars.push_back(y); + ds.push_back(x); + ds.push_back(y); + ds.push_back(z + 2); + ds.push_back(u); + ds.push_back(z); + lits.push_back(m.mk_not(m.mk_distinct(ds.size(), ds.c_ptr()))); + plugin(mdl, vars, lits); + std::cout << lits << "\n"; + + // test negation of distinct, not using bound variables + mdl.register_decl(x->get_decl(), a.mk_int(0)); + mdl.register_decl(y->get_decl(), a.mk_int(1)); + mdl.register_decl(z->get_decl(), a.mk_int(0)); + mdl.register_decl(u->get_decl(), a.mk_int(6)); + vars.reset(); + lits.reset(); + ds.reset(); + vars.push_back(x); + vars.push_back(y); + ds.push_back(x); + ds.push_back(y); + ds.push_back(z + 2); + ds.push_back(u); + ds.push_back(z + 10); + ds.push_back(u + 4); + lits.push_back(m.mk_not(m.mk_distinct(ds.size(), ds.c_ptr()))); + plugin(mdl, vars, lits); + std::cout << lits << "\n"; + + + // test distinct + mdl.register_decl(x->get_decl(), a.mk_int(0)); + mdl.register_decl(y->get_decl(), a.mk_int(1)); + mdl.register_decl(z->get_decl(), a.mk_int(0)); + mdl.register_decl(u->get_decl(), a.mk_int(6)); + vars.reset(); + lits.reset(); + ds.reset(); + vars.push_back(x); + vars.push_back(y); + ds.push_back(x); + ds.push_back(y); + ds.push_back(z + 2); + ds.push_back(u); + lits.push_back(m.mk_distinct(ds.size(), ds.c_ptr())); + plugin(mdl, vars, lits); + std::cout << lits << "\n"; + + // equality over modulus + mdl.register_decl(y->get_decl(), a.mk_int(4)); + mdl.register_decl(z->get_decl(), a.mk_int(8)); + lits.reset(); + vars.reset(); + vars.push_back(y); + lits.push_back(m.mk_eq(a.mk_mod(y, a.mk_int(3)), a.mk_int(1))); + lits.push_back(m.mk_eq(2*y, z)); + plugin(mdl, vars, lits); + std::cout << lits << "\n"; + + // inequality test + mdl.register_decl(x->get_decl(), a.mk_int(0)); + mdl.register_decl(y->get_decl(), a.mk_int(1)); + mdl.register_decl(z->get_decl(), a.mk_int(0)); + mdl.register_decl(u->get_decl(), a.mk_int(6)); + vars.reset(); + lits.reset(); + vars.push_back(x); + vars.push_back(y); + lits.push_back(z <= (x + (2*y))); + lits.push_back(2*x < u + 3); + lits.push_back(2*y <= u); + plugin(mdl, vars, lits); + std::cout << lits << "\n"; + + // non-unit equalities + mdl.register_decl(x->get_decl(), a.mk_int(1)); + mdl.register_decl(z->get_decl(), a.mk_int(2)); + mdl.register_decl(u->get_decl(), a.mk_int(3)); + mdl.register_decl(y->get_decl(), a.mk_int(4)); + lits.reset(); + vars.reset(); + vars.push_back(x); + lits.push_back(m.mk_eq(2*x, z)); + lits.push_back(m.mk_eq(3*x, u)); + plugin(mdl, vars, lits); + std::cout << lits << "\n"; + + +} void tst_qe_arith() { + test_project(); + return; check_random_ineqs(); return; // enable_trace("qe"); From b66d457b19305986bda5b39aa9dd0fb2765cace8 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 26 Jun 2016 16:12:14 -0700 Subject: [PATCH 055/536] move arithmetical mbp functionality to model_based_opt Signed-off-by: Nikolaj Bjorner --- src/math/simplex/model_based_opt.cpp | 15 +-- src/model/model_evaluator.cpp | 7 ++ src/model/model_evaluator.h | 2 + src/qe/qe_arith.cpp | 135 +++++++++------------------ src/qe/qe_arith.h | 2 - src/qe/qe_arith_plugin.cpp | 21 +++++ 6 files changed, 76 insertions(+), 106 deletions(-) diff --git a/src/math/simplex/model_based_opt.cpp b/src/math/simplex/model_based_opt.cpp index 760c9a941..4a0669652 100644 --- a/src/math/simplex/model_based_opt.cpp +++ b/src/math/simplex/model_based_opt.cpp @@ -35,8 +35,7 @@ std::ostream& operator<<(std::ostream& out, opt::ineq_type ie) { namespace opt { - model_based_opt::model_based_opt() - { + model_based_opt::model_based_opt() { m_rows.push_back(row()); } @@ -288,7 +287,6 @@ namespace opt { m_rows[row_id].m_alive = false; m_retired_rows.push_back(row_id); } - rational model_based_opt::get_row_value(row const& r) const { vector const& vars = r.m_vars; @@ -462,7 +460,6 @@ namespace opt { } } - rational model_based_opt::n_sign(rational const& b) const { return rational(b.is_pos()?-1:1); } @@ -937,16 +934,6 @@ namespace opt { // 3x + t = 0 & 7 | (c*x + s) & ax <= u // 3 | -t & 21 | (-ct + 3s) & a-t <= 3u -#if 0 - void solve_for_int(unsigned row_id1, unsigned x) { - - for (unsigned i = 0; i < num_divs(); ++i) { - add_lit(model, lits, mk_divides(c*div_divisor(i), - mk_sub(mk_mul(c, div_term(i)), mk_mul(div_coeff(i), t)))); - } - } -#endif - void model_based_opt::solve_for(unsigned row_id1, unsigned x) { rational a = get_coefficient(row_id1, x), b; SASSERT(!a.is_zero()); diff --git a/src/model/model_evaluator.cpp b/src/model/model_evaluator.cpp index eb2259263..eb2b2f5dd 100644 --- a/src/model/model_evaluator.cpp +++ b/src/model/model_evaluator.cpp @@ -522,5 +522,12 @@ void model_evaluator::operator()(expr * t, expr_ref & result) { m_imp->operator()(t, result); } +expr_ref model_evaluator::operator()(expr * t) { + TRACE("model_evaluator", tout << mk_ismt2_pp(t, m()) << "\n";); + expr_ref result(m()); + m_imp->operator()(t, result); + return result; +} + diff --git a/src/model/model_evaluator.h b/src/model/model_evaluator.h index 7fafbe14d..3f4da5c96 100644 --- a/src/model/model_evaluator.h +++ b/src/model/model_evaluator.h @@ -41,6 +41,8 @@ public: void operator()(expr * t, expr_ref & r); + expr_ref operator()(expr* t); + void cleanup(params_ref const & p = params_ref()); void reset(params_ref const & p = params_ref()); diff --git a/src/qe/qe_arith.cpp b/src/qe/qe_arith.cpp index dab6325bc..d98f36d7d 100644 --- a/src/qe/qe_arith.cpp +++ b/src/qe/qe_arith.cpp @@ -32,33 +32,11 @@ Revision History: #include "model_evaluator.h" namespace qe { - - bool is_divides(arith_util& a, expr* e1, expr* e2, rational& k, expr_ref& p) { - expr* t1, *t2; - if (a.is_mod(e2, t1, t2) && - a.is_numeral(e1, k) && - k.is_zero() && - a.is_numeral(t2, k)) { - p = t1; - return true; - } - return false; - } - - bool is_divides(arith_util& a, expr* e, rational& k, expr_ref& t) { - expr* e1, *e2; - if (!a.get_manager().is_eq(e, e1, e2)) { - return false; - } - return is_divides(a, e1, e2, k, t) || is_divides(a, e2, e1, k, t); - } struct arith_project_plugin::imp { ast_manager& m; arith_util a; - th_rewriter m_rw; - expr_ref_vector m_trail; void insert_mul(expr* x, rational const& v, obj_map& ts) { TRACE("qe", tout << "Adding variable " << mk_pp(x, m) << " " << v << "\n";); @@ -108,9 +86,10 @@ namespace qe { ty = opt::t_eq; } else if (m.is_eq(lit, e1, e2) && is_not && is_arith(e1)) { - expr_ref val1(m), val2(m); + rational r1, r2; - eval(e1, val1); eval(e2, val2); + expr_ref val1 = eval(e1); + expr_ref val2 = eval(e2); VERIFY(a.is_numeral(val1, r1)); VERIFY(a.is_numeral(val2, r2)); SASSERT(r1 != r2); @@ -127,7 +106,7 @@ namespace qe { app* alit = to_app(lit); vector > nums; for (unsigned i = 0; i < alit->get_num_args(); ++i) { - eval(alit->get_arg(i), val); + val = eval(alit->get_arg(i)); VERIFY(a.is_numeral(val, r)); nums.push_back(std::make_pair(alit->get_arg(i), r)); } @@ -148,9 +127,8 @@ namespace qe { bool found_eq = false; for (unsigned i = 0; !found_eq && i < to_app(lit)->get_num_args(); ++i) { expr* arg1 = to_app(lit)->get_arg(i), *arg2 = 0; - expr_ref val(m); rational r; - eval(arg1, val); + expr_ref val = eval(arg1); VERIFY(a.is_numeral(val, r)); if (values.find(r, arg2)) { ty = opt::t_eq; @@ -182,10 +160,10 @@ namespace qe { expr* t1, *t2, *t3; rational mul1; expr_ref val(m); - if (a.is_mul(t, t1, t2) && is_numeral(eval, t1, mul1)) { + if (a.is_mul(t, t1, t2) && is_numeral(t1, mul1)) { linearize(mbo, eval, mul* mul1, t2, c, fmls, ts, tids); } - else if (a.is_mul(t, t1, t2) && is_numeral(eval, t2, mul1)) { + else if (a.is_mul(t, t1, t2) && is_numeral(t2, mul1)) { linearize(mbo, eval, mul* mul1, t1, c, fmls, ts, tids); } else if (a.is_add(t)) { @@ -205,7 +183,7 @@ namespace qe { c += mul*mul1; } else if (m.is_ite(t, t1, t2, t3)) { - eval(t1, val); + val = eval(t1); SASSERT(m.is_true(val) || m.is_false(val)); TRACE("qe", tout << mk_pp(t1, m) << " := " << val << "\n";); if (m.is_true(val)) { @@ -218,9 +196,9 @@ namespace qe { linearize(mbo, eval, mul, t3, c, fmls, ts, tids); } } - else if (a.is_mod(t, t1, t2) && is_numeral(eval, t2, mul1)) { + else if (a.is_mod(t, t1, t2) && is_numeral(t2, mul1)) { rational r; - eval(t, val); + val = eval(t); VERIFY(a.is_numeral(val, r)); c += mul*r; // t1 mod mul1 == r @@ -236,44 +214,38 @@ namespace qe { } } - bool is_numeral(model_evaluator& eval, expr* t, rational& r) { - expr* t1, *t2, *t3; + bool is_numeral(expr* t, rational& r) { + expr* t1, *t2; rational r1, r2; - expr_ref val(m); - if (a.is_numeral(t, r)) return true; - - if (a.is_uminus(t, t1) && is_numeral(eval, t1, r)) { - r.neg(); - return true; - } - else if (a.is_mul(t, t1, t2) && is_numeral(eval, t1, r1) && is_numeral(eval, t2, r2)) { - r = r1*r2; - return true; + if (a.is_numeral(t, r)) { + // no-op } - else if (a.is_add(t)) { + else if (a.is_uminus(t, t1) && is_numeral(t1, r)) { + r.neg(); + } + else if (a.is_mul(t)) { app* ap = to_app(t); r = rational(1); for (unsigned i = 0; i < ap->get_num_args(); ++i) { - if (!is_numeral(eval, ap->get_arg(i), r1)) return false; + if (!is_numeral(ap->get_arg(i), r1)) return false; r *= r1; } - return true; } - else if (m.is_ite(t, t1, t2, t3)) { - eval(t1, val); - if (m.is_true(val)) { - return is_numeral(eval, t1, r); - } - else { - return is_numeral(eval, t2, r); + else if (a.is_add(t)) { + app* ap = to_app(t); + r = rational(0); + for (unsigned i = 0; i < ap->get_num_args(); ++i) { + if (!is_numeral(ap->get_arg(i), r1)) return false; + r += r1; } } - else if (a.is_sub(t, t1, t2) && is_numeral(eval, t1, r1) && is_numeral(eval, t2, r2)) { + else if (a.is_sub(t, t1, t2) && is_numeral(t1, r1) && is_numeral(t2, r2)) { r = r1 - r2; - return true; } - - return false; + else { + return false; + } + return true; } struct compare_second { @@ -292,14 +264,9 @@ namespace qe { } imp(ast_manager& m): - m(m), a(m), m_rw(m), m_trail(m) { - params_ref params; - params.set_bool("gcd_rouding", true); - m_rw.updt_params(params); - } + m(m), a(m) {} - ~imp() { - } + ~imp() {} bool solve(model& model, app_ref_vector& vars, expr_ref_vector& lits) { return false; @@ -330,7 +297,6 @@ namespace qe { opt::model_based_opt mbo; obj_map tids; - m_trail.reset(); unsigned j = 0; for (unsigned i = 0; i < fmls.size(); ++i) { expr* fml = fmls[i].get(); @@ -359,9 +325,8 @@ namespace qe { app* v = vars[i].get(); var_mark.mark(v); if (is_arith(v) && !tids.contains(v)) { - expr_ref val(m); rational r; - eval(v, val); + expr_ref val = eval(v); a.is_numeral(val, r); TRACE("qe", tout << mk_pp(v, m) << " " << val << "\n";); tids.insert(v, mbo.add_var(r, a.is_int(v))); @@ -426,7 +391,7 @@ namespace qe { default: UNREACHABLE(); } fmls.push_back(t); - VERIFY(model.eval(t, val)); + val = eval(t); CTRACE("qe", !m.is_true(val), tout << "Evaluated unit " << t << " to " << val << "\n";); continue; } @@ -450,8 +415,7 @@ namespace qe { case opt::t_le: t = a.mk_le(t, s); break; case opt::t_eq: t = a.mk_eq(t, s); break; case opt::t_mod: { - rational sval; - if (!a.is_numeral(s, sval) || !sval.is_zero()) { + if (!r.m_coeff.is_zero()) { t = a.mk_sub(t, s); } t = a.mk_eq(a.mk_mod(t, a.mk_numeral(r.m_mod, true)), a.mk_int(0)); @@ -460,15 +424,13 @@ namespace qe { } fmls.push_back(t); - VERIFY(model.eval(t, val)); + val = eval(t); CTRACE("qe", !m.is_true(val), tout << "Evaluated " << t << " to " << val << "\n";); } } opt::inf_eps maximize(expr_ref_vector const& fmls0, model& mdl, app* t, expr_ref& ge, expr_ref& gt) { - validate_model(mdl, fmls0); - m_trail.reset(); SASSERT(a.is_real(t)); expr_ref_vector fmls(fmls0); opt::model_based_opt mbo; @@ -483,6 +445,8 @@ namespace qe { extract_coefficients(mbo, eval, ts, tids, coeffs); mbo.set_objective(coeffs, c); + SASSERT(validate_model(eval, fmls0)); + // extract linear constraints for (unsigned i = 0; i < fmls.size(); ++i) { @@ -509,8 +473,7 @@ namespace qe { } } expr_ref val(a.mk_numeral(value.get_rational(), false), m); - expr_ref tval(m); - eval(t, tval); + expr_ref tval = eval(t); // update the predicate 'bound' which forces larger values when 'strict' is true. // strict: bound := valuue < t @@ -527,15 +490,14 @@ namespace qe { ge = a.mk_ge(t, val); gt = a.mk_gt(t, val); } - validate_model(mdl, fmls0); + SASSERT(validate_model(eval, fmls0)); return value; } - bool validate_model(model& mdl, expr_ref_vector const& fmls) { + bool validate_model(model_evaluator& eval, expr_ref_vector const& fmls) { bool valid = true; for (unsigned i = 0; i < fmls.size(); ++i) { - expr_ref val(m); - VERIFY(mdl.eval(fmls[i], val)); + expr_ref val = eval(fmls[i]); if (!m.is_true(val)) { valid = false; TRACE("qe", tout << mk_pp(fmls[i], m) << " := " << val << "\n";); @@ -553,17 +515,10 @@ namespace qe { expr* v = it->m_key; if (!tids.find(v, id)) { rational r; - expr_ref val(m); - eval(v, val); - if (a.is_numeral(val, r)) { - id = mbo.add_var(r, a.is_int(v)); - } - else { - TRACE("qe", tout << "extraction of coefficients cancelled\n";); - return; - } + expr_ref val = eval(v); + a.is_numeral(val, r); + id = mbo.add_var(r, a.is_int(v)); tids.insert(v, id); - m_trail.push_back(v); } CTRACE("qe", it->m_value.is_zero(), tout << mk_pp(v, m) << " has coefficeint 0\n";); if (!it->m_value.is_zero()) { diff --git a/src/qe/qe_arith.h b/src/qe/qe_arith.h index dce9b1af4..616d1a8d0 100644 --- a/src/qe/qe_arith.h +++ b/src/qe/qe_arith.h @@ -37,8 +37,6 @@ namespace qe { bool arith_project(model& model, app* var, expr_ref_vector& lits); - // match e := t mod k = 0. - bool is_divides(arith_util& a, expr* e, rational& k, expr_ref& t); }; diff --git a/src/qe/qe_arith_plugin.cpp b/src/qe/qe_arith_plugin.cpp index 3a909d6ba..4281ec909 100644 --- a/src/qe/qe_arith_plugin.cpp +++ b/src/qe/qe_arith_plugin.cpp @@ -36,6 +36,27 @@ Revision History: namespace qe { + + static bool is_divides(arith_util& a, expr* e1, expr* e2, rational& k, expr_ref& p) { + expr* t1, *t2; + if (a.is_mod(e2, t1, t2) && + a.is_numeral(e1, k) && + k.is_zero() && + a.is_numeral(t2, k)) { + p = t1; + return true; + } + return false; + } + + static bool is_divides(arith_util& a, expr* e, rational& k, expr_ref& t) { + expr* e1, *e2; + if (!a.get_manager().is_eq(e, e1, e2)) { + return false; + } + return is_divides(a, e1, e2, k, t) || is_divides(a, e2, e1, k, t); + } + class bound { rational m_coeff; expr_ref m_term; From f786ab15fb1635eece9cd30b2ecd9bde58355414 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 26 Jun 2016 20:58:48 -0700 Subject: [PATCH 056/536] add example for MSS enumeration Signed-off-by: Nikolaj Bjorner --- examples/python/mus/mss.py | 150 +++++++++++++++++++++++++++++++++++++ 1 file changed, 150 insertions(+) create mode 100644 examples/python/mus/mss.py diff --git a/examples/python/mus/mss.py b/examples/python/mus/mss.py new file mode 100644 index 000000000..5c0b724df --- /dev/null +++ b/examples/python/mus/mss.py @@ -0,0 +1,150 @@ +############################################ +# Copyright (c) 2016 Microsoft Corporation +# +# MSS enumeration based on maximal resolution. +# +# Author: Nikolaj Bjorner (nbjorner) +############################################ + +""" + +The following is a procedure for enumerating maximal satisfying subsets. +It uses maximal resolution to eliminate cores from the state space. +Whenever the hard constraints are satisfiable, it finds a model that +satisfies the maximal number of soft constraints. +During this process it collects the set of cores that are encountered. +It then reduces the set of soft constraints using max-resolution in +the style of [Narodytska & Bacchus, AAAI'14]. In other words, +let F1, ..., F_k be a core among the soft constraints F1,...,F_n +Replace F1,.., F_k by + F1 or F2, F3 or (F2 & F1), F4 or (F3 & (F2 & F1)), ..., + F_k or (F_{k-1} & (...)) +Optionally, add the core ~F1 or ... or ~F_k to F +The current model M satisfies the new set F, F1,...,F_{n-1} if the core is minimal. +Whenever we modify the soft constraints by the core reduction any assignment +to the reduced set satisfies a k-1 of the original soft constraints. + +""" + +from z3 import * + +def main(): + x, y = Reals('x y') + soft_constraints = [x > 2, x < 1, x < 0, Or(x + y > 0, y < 0), Or(y >= 0, x >= 0), Or(y < 0, x < 0), Or(y > 0, x < 0)] + hard_constraints = BoolVal(True) + solver = MSSSolver(hard_constraints, soft_constraints) + for lits in enumerate_sets(solver): + print("%s" % lits) + + +def enumerate_sets(solver): + while True: + if sat == solver.s.check(): + MSS = solver.grow() + yield MSS + else: + break + +class CompareSetSize(): + def __call__(self, s1, s2): + return len(s1) < len(s2) + + +class MSSSolver: + s = Solver() + varcache = {} + idcache = {} + + def __init__(self, hard, soft): + self.n = len(soft) + self.soft = soft + self.s.add(hard) + self.soft_vars = set([self.c_var(i) for i in range(self.n)]) + self.orig_soft_vars = set([self.c_var(i) for i in range(self.n)]) + self.s.add([(self.c_var(i) == soft[i]) for i in range(self.n)]) + + def c_var(self, i): + if i not in self.varcache: + v = Bool(str(self.soft[abs(i)])) + self.idcache[v] = abs(i) + if i >= 0: + self.varcache[i] = v + else: + self.varcache[i] = Not(v) + return self.varcache[i] + + def update_unknown(self): + self.model = self.s.model() + new_unknown = set([]) + for x in self.unknown: + if is_true(self.model[x]): + self.mss.append(x) + else: + new_unknown.add(x) + self.unknown = new_unknown + + def relax_core(self, core): + assert(core <= self.soft_vars) + prev = BoolVal(True) + core_list = [x for x in core] + self.soft_vars -= core + # replace x0, x1, x2, .. by + # Or(x1, x0), Or(x2, And(x1, x0)), Or(x3, And(x2, And(x1, x0))), ... + for i in range(len(core_list)-1): + x = core_list[i] + y = core_list[i+1] + prevf = And(x, prev) + prev = Bool("%s" % prevf) + self.s.add(prev == prevf) + zf = Or(prev, y) + z = Bool("%s" % zf) + self.s.add(z == zf) + self.soft_vars.add(z) + + def resolve_core(self, core): + new_core = set([]) + for x in core: + if x in self.mcs_map: + new_core |= self.mcs_map[x] + else: + new_core.add(x) + return new_core + + + def grow(self): + self.mss = [] + self.mcs = [] + self.nmcs = [] + self.mcs_map = {} + self.unknown = self.soft_vars + self.update_unknown() + cores = [] + while len(self.unknown) > 0: + x = self.unknown.pop() + is_sat = self.s.check(self.mss + [x] + self.nmcs) + if is_sat == sat: + self.mss.append(x) + self.update_unknown() + elif is_sat == unsat: + core = self.s.unsat_core() + core = self.resolve_core(core) + self.mcs_map[x] = {y for y in core if not eq(x,y)} + self.mcs.append(x) + self.nmcs.append(Not(x)) + cores += [core] + else: + print("solver returned %s" % is_sat) + exit() + mss = [x for x in self.orig_soft_vars if is_true(self.model[x])] + mcs = [x for x in self.orig_soft_vars if not is_true(self.model[x])] + self.s.add(Or(mcs)) + core_literals = set([]) + cores.sort(CompareSetSize()) + for core in cores: + if len(core & core_literals) == 0: + self.relax_core(core) + core_literals |= core + return mss + + +main() From 014c693fa52e7333cad704a3b1bdc570af6cee7c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 27 Jun 2016 15:22:13 -0700 Subject: [PATCH 057/536] fix explain map to use negations Signed-off-by: Nikolaj Bjorner --- examples/python/mus/mss.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/python/mus/mss.py b/examples/python/mus/mss.py index 5c0b724df..b31fd92a8 100644 --- a/examples/python/mus/mss.py +++ b/examples/python/mus/mss.py @@ -104,8 +104,8 @@ class MSSSolver: def resolve_core(self, core): new_core = set([]) for x in core: - if x in self.mcs_map: - new_core |= self.mcs_map[x] + if x in self.mcs_explain: + new_core |= self.mcs_explain[x] else: new_core.add(x) return new_core @@ -115,7 +115,7 @@ class MSSSolver: self.mss = [] self.mcs = [] self.nmcs = [] - self.mcs_map = {} + self.mcs_explain = {} self.unknown = self.soft_vars self.update_unknown() cores = [] @@ -128,7 +128,7 @@ class MSSSolver: elif is_sat == unsat: core = self.s.unsat_core() core = self.resolve_core(core) - self.mcs_map[x] = {y for y in core if not eq(x,y)} + self.mcs_explain[Not(x)] = {y for y in core if not eq(x,y)} self.mcs.append(x) self.nmcs.append(Not(x)) cores += [core] From 84aec95edacf61f95e7aea6cf3d5999e6f229bed Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 28 Jun 2016 11:41:57 -0700 Subject: [PATCH 058/536] fix up use-list in 3x3 resolution case. Regression RND_3_24.smt2 Signed-off-by: Nikolaj Bjorner --- src/math/simplex/model_based_opt.cpp | 19 +++++++++++++++---- src/math/simplex/model_based_opt.h | 2 ++ 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/src/math/simplex/model_based_opt.cpp b/src/math/simplex/model_based_opt.cpp index 4a0669652..cafa6ee3a 100644 --- a/src/math/simplex/model_based_opt.cpp +++ b/src/math/simplex/model_based_opt.cpp @@ -57,6 +57,7 @@ namespace opt { // variables in each row are sorted and have non-zero coefficients PASSERT(i + 1 == vars.size() || vars[i].m_id < vars[i+1].m_id); PASSERT(!vars[i].m_coeff.is_zero()); + PASSERT(index == 0 || m_var2row_ids[vars[i].m_id].contains(index)); } PASSERT(r.m_value == get_row_value(r)); @@ -522,6 +523,7 @@ namespace opt { if (c.is_zero()) { return; } + m_new_vars.reset(); row& r1 = m_rows[row_id1]; row const& r2 = m_rows[row_id2]; @@ -650,7 +652,6 @@ namespace opt { r.m_coeff += rational::one(); r.m_value += rational::one(); } - SASSERT(invariant(row_id, r)); } unsigned model_based_opt::new_row() { @@ -668,6 +669,17 @@ namespace opt { return row_id; } + unsigned model_based_opt::copy_row(unsigned src) { + unsigned dst = new_row(); + row const& r = m_rows[src]; + set_row(dst, r.m_vars, r.m_coeff, r.m_mod, r.m_type); + for (unsigned i = 0; i < r.m_vars.size(); ++i) { + m_var2row_ids[r.m_vars[i].m_id].push_back(dst); + } + SASSERT(invariant(dst, m_rows[dst])); + return dst; + } + void model_based_opt::add_constraint(vector const& coeffs, rational const& c, ineq_type rel) { add_constraint(coeffs, c, rational::zero(), rel); } @@ -813,9 +825,8 @@ namespace opt { resolve(row_id1, coeff, row_id2, x); } else { - row r(m_rows[row_id2]); - m_rows.push_back(r); - resolve(row_id1, coeff, m_rows.size()-1, x); + unsigned row_id3 = copy_row(row_id2); + resolve(row_id1, coeff, row_id3, x); } } } diff --git a/src/math/simplex/model_based_opt.h b/src/math/simplex/model_based_opt.h index 92f600522..eb0bc2570 100644 --- a/src/math/simplex/model_based_opt.h +++ b/src/math/simplex/model_based_opt.h @@ -109,6 +109,8 @@ namespace opt { unsigned new_row(); + unsigned copy_row(unsigned row_id); + rational n_sign(rational const& b) const; void update_values(unsigned_vector const& bound_vars, unsigned_vector const& bound_trail); From e4a00f6f6ff7e9a2b61652863371d2979a95ff78 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 28 Jun 2016 17:48:11 -0700 Subject: [PATCH 059/536] re-include get_error_msg_ex per issue #660 Signed-off-by: Nikolaj Bjorner --- src/api/api_context.cpp | 4 ++++ src/api/z3_api.h | 7 +++++++ 2 files changed, 11 insertions(+) diff --git a/src/api/api_context.cpp b/src/api/api_context.cpp index bc48874a7..ceccff939 100644 --- a/src/api/api_context.cpp +++ b/src/api/api_context.cpp @@ -463,6 +463,10 @@ extern "C" { return _get_error_msg(c, err); } + Z3_API char const * Z3_get_error_msg_ex(Z3_context c, Z3_error_code err) { + return Z3_get_error_msg(c, err); + } + void Z3_API Z3_set_ast_print_mode(Z3_context c, Z3_ast_print_mode mode) { Z3_TRY; diff --git a/src/api/z3_api.h b/src/api/z3_api.h index 5d1d45f37..5ce2740d9 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -5118,6 +5118,13 @@ extern "C" { Z3_string Z3_API Z3_get_error_msg(Z3_context c, Z3_error_code err); /*@}*/ + /** + \brief Return a string describing the given error code. + Retained function name for backwards compatibility within v4.1 + */ + Z3_string Z3_API Z3_get_error_msg_ex(Z3_context c, Z3_error_code err); + /*@}*/ + /** @name Miscellaneous */ /*@{*/ From b303fd59c0a113d9bc0dd93b31b87382255cc417 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 28 Jun 2016 18:11:30 -0700 Subject: [PATCH 060/536] add some version information (and date) to log file to make it easier to trap version mismatch on log files Signed-off-by: Nikolaj Bjorner --- CMakeLists.txt | 2 +- scripts/mk_project.py | 2 +- src/api/api_log.cpp | 3 +++ src/api/z3_replayer.cpp | 4 ++++ 4 files changed, 9 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 40e8ae250..869ca4992 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -34,7 +34,7 @@ project(Z3 C CXX) set(Z3_VERSION_MAJOR 4) set(Z3_VERSION_MINOR 4) set(Z3_VERSION_PATCH 2) -set(Z3_VERSION_TWEAK 0) +set(Z3_VERSION_TWEAK 1) set(Z3_VERSION "${Z3_VERSION_MAJOR}.${Z3_VERSION_MINOR}.${Z3_VERSION_PATCH}.${Z3_VERSION_TWEAK}") message(STATUS "Z3 version ${Z3_VERSION}") diff --git a/scripts/mk_project.py b/scripts/mk_project.py index e7177000f..f7b832bb9 100644 --- a/scripts/mk_project.py +++ b/scripts/mk_project.py @@ -9,7 +9,7 @@ from mk_util import * # Z3 Project definition def init_project_def(): - set_version(4, 4, 2, 0) + set_version(4, 4, 2, 1) add_lib('util', []) add_lib('polynomial', ['util'], 'math/polynomial') add_lib('sat', ['util']) diff --git a/src/api/api_log.cpp b/src/api/api_log.cpp index 4a1ae27e5..f153cd836 100644 --- a/src/api/api_log.cpp +++ b/src/api/api_log.cpp @@ -20,6 +20,7 @@ Revision History: #include"z3.h" #include"api_log_macros.h" #include"util.h" +#include"version.h" std::ostream * g_z3_log = 0; bool g_z3_log_enabled = false; @@ -35,6 +36,8 @@ extern "C" { g_z3_log = 0; return Z3_FALSE; } + *g_z3_log << "V \"" << Z3_MAJOR_VERSION << "." << Z3_MINOR_VERSION << "." << Z3_BUILD_NUMBER << "." << Z3_REVISION_NUMBER << " " << __DATE__ << "\"\n"; + g_z3_log->flush(); return Z3_TRUE; } diff --git a/src/api/z3_replayer.cpp b/src/api/z3_replayer.cpp index b1baa6de2..826e767f2 100644 --- a/src/api/z3_replayer.cpp +++ b/src/api/z3_replayer.cpp @@ -415,6 +415,10 @@ struct z3_replayer::imp { if (c == EOF) return; switch (c) { + case 'V': + // version + next(); skip_blank(); read_string(); + break; case 'R': // reset next(); From 8aee7129f69c8852ff1bf70dc29217d874292800 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 28 Jun 2016 21:48:49 -0700 Subject: [PATCH 061/536] shortcircuit stats functions on ground terms Signed-off-by: Nikolaj Bjorner --- src/smt/mam.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/smt/mam.cpp b/src/smt/mam.cpp index ead1ea963..f5b3f34f7 100644 --- a/src/smt/mam.cpp +++ b/src/smt/mam.cpp @@ -879,6 +879,9 @@ namespace smt { */ void get_stats_core(app * n, unsigned & sz, unsigned & num_unbound_vars) { sz++; + if (n->is_ground()) { + return; + } unsigned num_args = n->get_num_args(); for (unsigned i = 0; i < num_args; i++) { expr * arg = n->get_arg(i); @@ -901,7 +904,7 @@ namespace smt { void get_stats(app * n, unsigned & sz, unsigned & num_unbound_vars) { sz = 0; num_unbound_vars = 0; - return get_stats_core(n, sz, num_unbound_vars); + get_stats_core(n, sz, num_unbound_vars); } /** @@ -1032,6 +1035,9 @@ namespace smt { */ unsigned get_num_bound_vars_core(app * n, bool & has_unbound_vars) { unsigned r = 0; + if (n->is_ground()) { + return 0; + } unsigned num_args = n->get_num_args(); for (unsigned i = 0; i < num_args; i++) { expr * arg = n->get_arg(i); From cb87991d5fd70efb257f9ade0a22ecb085025d9e Mon Sep 17 00:00:00 2001 From: George Karpenkov Date: Wed, 29 Jun 2016 13:09:05 +0200 Subject: [PATCH 062/536] Java bindings: Force cleaning the queue on context closing. --- src/api/java/Context.java | 30 +++++++++++++-------------- src/api/java/Fixedpoint.java | 33 +++++++++++------------------ src/api/java/IDecRefQueue.java | 13 ++++++++++++ src/api/java/Quantifier.java | 38 ++++++++++++++++++++++++---------- 4 files changed, 67 insertions(+), 47 deletions(-) diff --git a/src/api/java/Context.java b/src/api/java/Context.java index da924026c..b7656c5da 100644 --- a/src/api/java/Context.java +++ b/src/api/java/Context.java @@ -4017,21 +4017,21 @@ public class Context implements AutoCloseable { @Override public void close() { - m_AST_DRQ.clear(this); - m_ASTMap_DRQ.clear(this); - m_ASTVector_DRQ.clear(this); - m_ApplyResult_DRQ.clear(this); - m_FuncEntry_DRQ.clear(this); - m_FuncInterp_DRQ.clear(this); - m_Goal_DRQ.clear(this); - m_Model_DRQ.clear(this); - m_Params_DRQ.clear(this); - m_Probe_DRQ.clear(this); - m_Solver_DRQ.clear(this); - m_Optimize_DRQ.clear(this); - m_Statistics_DRQ.clear(this); - m_Tactic_DRQ.clear(this); - m_Fixedpoint_DRQ.clear(this); + m_AST_DRQ.forceClear(this); + m_ASTMap_DRQ.forceClear(this); + m_ASTVector_DRQ.forceClear(this); + m_ApplyResult_DRQ.forceClear(this); + m_FuncEntry_DRQ.forceClear(this); + m_FuncInterp_DRQ.forceClear(this); + m_Goal_DRQ.forceClear(this); + m_Model_DRQ.forceClear(this); + m_Params_DRQ.forceClear(this); + m_Probe_DRQ.forceClear(this); + m_Solver_DRQ.forceClear(this); + m_Optimize_DRQ.forceClear(this); + m_Statistics_DRQ.forceClear(this); + m_Tactic_DRQ.forceClear(this); + m_Fixedpoint_DRQ.forceClear(this); m_boolSort = null; m_intSort = null; diff --git a/src/api/java/Fixedpoint.java b/src/api/java/Fixedpoint.java index 876345f1e..ad6d5a658 100644 --- a/src/api/java/Fixedpoint.java +++ b/src/api/java/Fixedpoint.java @@ -87,12 +87,11 @@ public class Fixedpoint extends Z3Object /** * Add rule into the fixedpoint solver. - * + * + * @param name Nullable rule name. * @throws Z3Exception **/ - public void addRule(BoolExpr rule, Symbol name) - { - + public void addRule(BoolExpr rule, Symbol name) { getContext().checkContextMatch(rule); Native.fixedpointAddRule(getContext().nCtx(), getNativeObject(), rule.getNativeObject(), AST.getNativeObject(name)); @@ -103,11 +102,10 @@ public class Fixedpoint extends Z3Object * * @throws Z3Exception **/ - public void addFact(FuncDecl pred, int ... args) - { + public void addFact(FuncDecl pred, int ... args) { getContext().checkContextMatch(pred); Native.fixedpointAddFact(getContext().nCtx(), getNativeObject(), - pred.getNativeObject(), (int) args.length, args); + pred.getNativeObject(), args.length, args); } /** @@ -119,9 +117,7 @@ public class Fixedpoint extends Z3Object * * @throws Z3Exception **/ - public Status query(BoolExpr query) - { - + public Status query(BoolExpr query) { getContext().checkContextMatch(query); Z3_lbool r = Z3_lbool.fromInt(Native.fixedpointQuery(getContext().nCtx(), getNativeObject(), query.getNativeObject())); @@ -144,9 +140,7 @@ public class Fixedpoint extends Z3Object * * @throws Z3Exception **/ - public Status query(FuncDecl[] relations) - { - + public Status query(FuncDecl[] relations) { getContext().checkContextMatch(relations); Z3_lbool r = Z3_lbool.fromInt(Native.fixedpointQueryRelations(getContext() .nCtx(), getNativeObject(), AST.arrayLength(relations), AST @@ -166,8 +160,7 @@ public class Fixedpoint extends Z3Object * Creates a backtracking point. * @see #pop **/ - public void push() - { + public void push() { Native.fixedpointPush(getContext().nCtx(), getNativeObject()); } @@ -178,19 +171,17 @@ public class Fixedpoint extends Z3Object * * @see #push **/ - public void pop() - { + public void pop() { Native.fixedpointPop(getContext().nCtx(), getNativeObject()); } /** * Update named rule into in the fixedpoint solver. - * + * + * @param name Nullable rule name. * @throws Z3Exception **/ - public void updateRule(BoolExpr rule, Symbol name) - { - + public void updateRule(BoolExpr rule, Symbol name) { getContext().checkContextMatch(rule); Native.fixedpointUpdateRule(getContext().nCtx(), getNativeObject(), rule.getNativeObject(), AST.getNativeObject(name)); diff --git a/src/api/java/IDecRefQueue.java b/src/api/java/IDecRefQueue.java index 2deb9c0f9..4b515a3b6 100644 --- a/src/api/java/IDecRefQueue.java +++ b/src/api/java/IDecRefQueue.java @@ -59,6 +59,9 @@ public abstract class IDecRefQueue { clear(ctx); } + /** + * Clean all references currently in {@code referenceQueue}. + */ protected void clear(Context ctx) { Reference ref; @@ -67,4 +70,14 @@ public abstract class IDecRefQueue { decRef(ctx, z3ast); } } + + /** + * Clean all references stored in {@code referenceMap}, + * regardless of whether they are in {@code referenceMap} or not. + */ + public void forceClear(Context ctx) { + for (long ref : referenceMap.values()) { + decRef(ctx, ref); + } + } } diff --git a/src/api/java/Quantifier.java b/src/api/java/Quantifier.java index a78277839..bc2537107 100644 --- a/src/api/java/Quantifier.java +++ b/src/api/java/Quantifier.java @@ -145,20 +145,28 @@ public class Quantifier extends BoolExpr .nCtx(), getNativeObject())); } + /** + * Create a quantified expression. + * + * @param patterns Nullable patterns + * @param noPatterns Nullable noPatterns + * @param quantifierID Nullable quantifierID + * @param skolemID Nullable skolemID + */ public static Quantifier of( Context ctx, boolean isForall, Sort[] sorts, Symbol[] names, Expr body, int weight, Pattern[] patterns, Expr[] noPatterns, - Symbol quantifierID, Symbol skolemID - ) { + Symbol quantifierID, Symbol skolemID) { ctx.checkContextMatch(patterns); ctx.checkContextMatch(noPatterns); ctx.checkContextMatch(sorts); ctx.checkContextMatch(names); ctx.checkContextMatch(body); - if (sorts.length != names.length) + if (sorts.length != names.length) { throw new Z3Exception( "Number of sorts does not match number of names"); + } long nativeObj; if (noPatterns == null && quantifierID == null && skolemID == null) { @@ -180,18 +188,26 @@ public class Quantifier extends BoolExpr } + /** + * @param ctx Context to create the quantifier on. + * @param isForall Quantifier type. + * @param bound Bound variables. + * @param body Body of the quantifier. + * @param weight Weight. + * @param patterns Nullable array of patterns. + * @param noPatterns Nullable array of noPatterns. + * @param quantifierID Nullable quantifier identifier. + * @param skolemID Nullable skolem identifier. + */ public static Quantifier of(Context ctx, boolean isForall, Expr[] bound, Expr body, int weight, Pattern[] patterns, Expr[] noPatterns, - Symbol quantifierID, Symbol skolemID) - { + Symbol quantifierID, Symbol skolemID) { ctx.checkContextMatch(noPatterns); ctx.checkContextMatch(patterns); - // ctx.CheckContextMatch(bound); ctx.checkContextMatch(body); long nativeObj; - if (noPatterns == null && quantifierID == null && skolemID == null) - { + if (noPatterns == null && quantifierID == null && skolemID == null) { nativeObj = Native.mkQuantifierConst(ctx.nCtx(), isForall, weight, AST.arrayLength(bound), AST.arrayToNative(bound), AST.arrayLength(patterns), @@ -214,11 +230,11 @@ public class Quantifier extends BoolExpr } @Override - void checkNativeObject(long obj) - { + void checkNativeObject(long obj) { if (Native.getAstKind(getContext().nCtx(), obj) != Z3_ast_kind.Z3_QUANTIFIER_AST - .toInt()) + .toInt()) { throw new Z3Exception("Underlying object is not a quantifier"); + } super.checkNativeObject(obj); } } From 0fdf01e410295cd36a508f3ad9e71d26962d6579 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 29 Jun 2016 04:53:28 -0700 Subject: [PATCH 063/536] avoid crash on box models under cancellation. Issue # SASSERT(!m_box_models.empty()); Signed-off-by: Nikolaj Bjorner --- src/opt/maxres.cpp | 15 ++++++++------- src/opt/opt_context.cpp | 18 +++++++++++------- 2 files changed, 19 insertions(+), 14 deletions(-) diff --git a/src/opt/maxres.cpp b/src/opt/maxres.cpp index b6950f674..7e4acd979 100644 --- a/src/opt/maxres.cpp +++ b/src/opt/maxres.cpp @@ -189,9 +189,10 @@ public: trace_bounds(m_trace_id.c_str()); } +#define RUNDEF() { std::cout << __LINE__ << "\n"; return l_undef; } lbool mus_solver() { lbool is_sat = l_true; - if (!init()) return l_undef; + if (!init()) RUNDEF(); init_local(); trace(); while (m_lower < m_upper) { @@ -203,7 +204,7 @@ public: ); is_sat = check_sat_hill_climb(m_asms); if (m.canceled()) { - return l_undef; + RUNDEF(); } switch (is_sat) { case l_true: @@ -219,7 +220,7 @@ public: } break; case l_undef: - return l_undef; + RUNDEF(); default: break; } @@ -229,14 +230,14 @@ public: } lbool primal_dual_solver() { - if (!init()) return l_undef; + if (!init()) RUNDEF(); init_local(); trace(); exprs cs; while (m_lower < m_upper) { lbool is_sat = check_sat_hill_climb(m_asms); if (m.canceled()) { - return l_undef; + RUNDEF(); } switch (is_sat) { case l_true: @@ -259,7 +260,7 @@ public: } break; case l_undef: - return l_undef; + RUNDEF(); default: break; } @@ -339,7 +340,7 @@ public: case s_primal_dual: return primal_dual_solver(); } - return l_undef; + RUNDEF(); } virtual void collect_statistics(statistics& st) const { diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 788921205..7a59c1ddb 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -366,12 +366,16 @@ namespace opt { } lbool context::execute_box() { - if (m_box_index < m_objectives.size()) { - SASSERT(m_box_index < m_box_models.size()); + if (m_box_index < m_box_models.size()) { m_model = m_box_models[m_box_index]; ++m_box_index; return l_true; } + if (m_box_index < m_objectives.size()) { + m_model = 0; + ++m_box_index; + return l_undef; + } if (m_box_index != UINT_MAX && m_box_index >= m_objectives.size()) { m_box_index = UINT_MAX; return l_false; @@ -384,17 +388,14 @@ namespace opt { if (obj.m_type == O_MAXSMT) { solver::scoped_push _sp(get_solver()); r = execute(obj, false, false); - if (r == l_true) { - m_box_models.push_back(m_model.get()); - } + m_box_models.push_back(m_model.get()); } else { m_box_models.push_back(m_optsmt.get_model(j)); ++j; } } - if (r == l_true && m_objectives.size() > 0) { - SASSERT(!m_box_models.empty()); + if (r == l_true && m_box_models.size() > 0) { m_model = m_box_models[0]; } return r; @@ -498,6 +499,9 @@ namespace opt { } std::string context::reason_unknown() const { + if (m.canceled()) { + return Z3_CANCELED_MSG; + } if (m_solver.get()) { return m_solver->reason_unknown(); } From 5d5004193b7011beafbd2bc2f76c985aa1ba1939 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 29 Jun 2016 04:54:31 -0700 Subject: [PATCH 064/536] avoid crash on box models under cancellation. Issue #654 Signed-off-by: Nikolaj Bjorner --- src/opt/maxres.cpp | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/opt/maxres.cpp b/src/opt/maxres.cpp index 7e4acd979..b6950f674 100644 --- a/src/opt/maxres.cpp +++ b/src/opt/maxres.cpp @@ -189,10 +189,9 @@ public: trace_bounds(m_trace_id.c_str()); } -#define RUNDEF() { std::cout << __LINE__ << "\n"; return l_undef; } lbool mus_solver() { lbool is_sat = l_true; - if (!init()) RUNDEF(); + if (!init()) return l_undef; init_local(); trace(); while (m_lower < m_upper) { @@ -204,7 +203,7 @@ public: ); is_sat = check_sat_hill_climb(m_asms); if (m.canceled()) { - RUNDEF(); + return l_undef; } switch (is_sat) { case l_true: @@ -220,7 +219,7 @@ public: } break; case l_undef: - RUNDEF(); + return l_undef; default: break; } @@ -230,14 +229,14 @@ public: } lbool primal_dual_solver() { - if (!init()) RUNDEF(); + if (!init()) return l_undef; init_local(); trace(); exprs cs; while (m_lower < m_upper) { lbool is_sat = check_sat_hill_climb(m_asms); if (m.canceled()) { - RUNDEF(); + return l_undef; } switch (is_sat) { case l_true: @@ -260,7 +259,7 @@ public: } break; case l_undef: - RUNDEF(); + return l_undef; default: break; } @@ -340,7 +339,7 @@ public: case s_primal_dual: return primal_dual_solver(); } - RUNDEF(); + return l_undef; } virtual void collect_statistics(statistics& st) const { From c2f9d35d59094c9d7da81f4b63864d199283724f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 29 Jun 2016 16:53:28 -0700 Subject: [PATCH 065/536] throw exceptions when internalizing expressions with free variables, issue #663 Signed-off-by: Nikolaj Bjorner --- src/smt/smt_internalizer.cpp | 6 +++--- src/smt/theory_arith_core.h | 22 ++++++++++++++++++---- 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/src/smt/smt_internalizer.cpp b/src/smt/smt_internalizer.cpp index df80d3281..45bd75ab7 100644 --- a/src/smt/smt_internalizer.cpp +++ b/src/smt/smt_internalizer.cpp @@ -321,10 +321,10 @@ namespace smt { void context::internalize(expr * n, bool gate_ctx) { TRACE("internalize", tout << "internalizing:\n" << mk_pp(n, m_manager) << "\n";); TRACE("internalize_bug", tout << "internalizing:\n" << mk_bounded_pp(n, m_manager) << "\n";); + if (is_var(n)) { + throw default_exception("Formulas should not contain unbound variables"); + } if (m_manager.is_bool(n)) { - if (is_var(n)) { - throw default_exception("Formulas should not contain unbound variables"); - } SASSERT(is_quantifier(n) || is_app(n)); internalize_formula(n, gate_ctx); } diff --git a/src/smt/theory_arith_core.h b/src/smt/theory_arith_core.h index 8dfe8498f..8e7765ee9 100644 --- a/src/smt/theory_arith_core.h +++ b/src/smt/theory_arith_core.h @@ -268,7 +268,7 @@ namespace smt { } rational _val; expr* arg1, *arg2; - if (m_util.is_mul(m, arg1, arg2) && m_util.is_numeral(arg1, _val)) { + if (m_util.is_mul(m, arg1, arg2) && m_util.is_numeral(arg1, _val) && is_app(arg1) && is_app(arg2)) { SASSERT(m->get_num_args() == 2); numeral val(_val); theory_var v = internalize_term_core(to_app(arg2)); @@ -297,6 +297,11 @@ namespace smt { scoped_row_vars _sc(m_row_vars, m_row_vars_top); unsigned num_args = n->get_num_args(); for (unsigned i = 0; i < num_args; i++) { + if (is_var(n->get_arg(i))) { + std::ostringstream strm; + strm << mk_pp(n, get_manager()) << " contains a free variable"; + throw default_exception(strm.str()); + } internalize_internal_monomial(to_app(n->get_arg(i)), r_id); } enode * e = mk_enode(n); @@ -356,6 +361,11 @@ namespace smt { SASSERT(!val.is_one()); unsigned r_id = mk_row(); scoped_row_vars _sc(m_row_vars, m_row_vars_top); + if (is_var(m->get_arg(1))) { + std::ostringstream strm; + strm << mk_pp(m, get_manager()) << " contains a free variable"; + throw default_exception(strm.str()); + } if (reflection_enabled()) internalize_term_core(to_app(m->get_arg(0))); theory_var v = internalize_mul_core(to_app(m->get_arg(1))); @@ -1204,6 +1214,9 @@ namespace smt { kind = A_UPPER; else kind = A_LOWER; + if (!is_app(n->get_arg(0)) || !is_app(n->get_arg(1))) { + return false; + } app * lhs = to_app(n->get_arg(0)); app * rhs = to_app(n->get_arg(1)); expr * rhs2; @@ -1245,10 +1258,11 @@ namespace smt { template void theory_arith::internalize_eq_eh(app * atom, bool_var v) { - if (m_params.m_arith_eager_eq_axioms) { + expr* _lhs, *_rhs; + if (m_params.m_arith_eager_eq_axioms && get_manager().is_eq(atom, _lhs, _rhs) && is_app(_lhs) && is_app(_rhs)) { context & ctx = get_context(); - app * lhs = to_app(atom->get_arg(0)); - app * rhs = to_app(atom->get_arg(1)); + app * lhs = to_app(_lhs); + app * rhs = to_app(_rhs); enode * n1 = ctx.get_enode(lhs); enode * n2 = ctx.get_enode(rhs); // The expression atom may be a theory axiom. In this case, it may not be in simplified form. From e518d4a5fe3b824d5e9deb3d16eb1faa248a52d8 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 29 Jun 2016 17:02:36 -0700 Subject: [PATCH 066/536] typename conventions, issue #664 Signed-off-by: Nikolaj Bjorner --- src/util/hashtable.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util/hashtable.h b/src/util/hashtable.h index fe51963e0..fbf36242b 100644 --- a/src/util/hashtable.h +++ b/src/util/hashtable.h @@ -581,7 +581,7 @@ public: core_hashtable& operator=(core_hashtable const& other) { if (this == &other) return *this; reset(); - core_hashtable::iterator i = other.begin(), e = other.end(); + iterator i = other.begin(), e = other.end(); for (; i != e; ++i) { insert(*i); } From 4c786c5f700e6ba6362370ba9b5f77ae1bb88b0c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 1 Jul 2016 08:15:50 -0700 Subject: [PATCH 067/536] add n-ary disjunction and conjunction Signed-off-by: Nikolaj Bjorner --- src/api/api_ast.cpp | 2 +- src/api/c++/z3++.h | 18 ++++++++++++++++++ src/smt/smt_context.cpp | 6 +++++- src/smt/smt_context_pp.cpp | 3 +++ src/smt/smt_failure.h | 1 + src/smt/smt_model_checker.cpp | 4 ++-- src/smt/tactic/smt_tactic.cpp | 7 +++++-- 7 files changed, 35 insertions(+), 6 deletions(-) diff --git a/src/api/api_ast.cpp b/src/api/api_ast.cpp index 1f16b2d35..cfe082802 100644 --- a/src/api/api_ast.cpp +++ b/src/api/api_ast.cpp @@ -335,7 +335,7 @@ extern "C" { Z3_bool Z3_API Z3_is_app(Z3_context c, Z3_ast a) { LOG_Z3_is_app(c, a); RESET_ERROR_CODE(); - return is_app(reinterpret_cast(a)); + return a != 0 && is_app(reinterpret_cast(a)); } Z3_app Z3_API Z3_to_app(Z3_context c, Z3_ast a) { diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index 9fb664819..98a1a76ea 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -802,6 +802,9 @@ namespace z3 { friend expr implies(expr const & a, bool b); friend expr implies(bool a, expr const & b); + friend expr or(expr_vector const& args); + friend expr and(expr_vector const& args); + friend expr ite(expr const & c, expr const & t, expr const & e); friend expr distinct(expr_vector const& args); @@ -947,6 +950,7 @@ namespace z3 { inline expr implies(expr const & a, bool b) { return implies(a, a.ctx().bool_val(b)); } inline expr implies(bool a, expr const & b) { return implies(b.ctx().bool_val(a), b); } + inline expr pw(expr const & a, expr const & b) { assert(a.is_arith() && b.is_arith()); check_context(a, b); @@ -1497,6 +1501,20 @@ namespace z3 { return expr(ctx, r); } + inline expr or(expr_vector const& args) { + array _args(args); + Z3_ast r = Z3_mk_or(args.ctx(), _args.size(), _args.ptr()); + args.check_error(); + return expr(args.ctx(), r); + } + inline expr and(expr_vector const& args) { + array _args(args); + Z3_ast r = Z3_mk_and(args.ctx(), _args.size(), _args.ptr()); + args.check_error(); + return expr(args.ctx(), r); + } + + class func_entry : public object { Z3_func_entry m_entry; void init(Z3_func_entry e) { diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index 046e2028e..5b60b6893 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -2996,6 +2996,8 @@ namespace smt { // in a consistent context. if (inconsistent()) return; + if (get_cancel_flag()) + return; push_scope(); for (unsigned i = 0; i < num_assumptions; i++) { expr * curr_assumption = assumptions[i]; @@ -3337,6 +3339,7 @@ namespace smt { break; } if (cmr == quantifier_manager::UNKNOWN) { + IF_VERBOSE(1, verbose_stream() << "(smt.giveup quantifiers)\n";); // giving up m_last_search_failure = QUANTIFIERS; status = l_undef; @@ -3487,6 +3490,7 @@ namespace smt { } if (resource_limits_exceeded() && !inconsistent()) { + m_last_search_failure = RESOURCE_LIMIT; return l_undef; } } @@ -4109,7 +4113,7 @@ namespace smt { m_fingerprints.display(tout); ); failure fl = get_last_search_failure(); - if (fl == MEMOUT || fl == CANCELED || fl == TIMEOUT || fl == NUM_CONFLICTS) { + if (fl == MEMOUT || fl == CANCELED || fl == TIMEOUT || fl == NUM_CONFLICTS || fl == RESOURCE_LIMIT) { return; } diff --git a/src/smt/smt_context_pp.cpp b/src/smt/smt_context_pp.cpp index a3079f52b..b0138f70c 100644 --- a/src/smt/smt_context_pp.cpp +++ b/src/smt/smt_context_pp.cpp @@ -39,6 +39,8 @@ namespace smt { return out << "CANCELED"; case NUM_CONFLICTS: return out << "NUM_CONFLICTS"; + case RESOURCE_LIMIT: + return out << "RESOURCE_LIMIT"; case THEORY: if (!m_incomplete_theories.empty()) { ptr_vector::const_iterator it = m_incomplete_theories.begin(); @@ -78,6 +80,7 @@ namespace smt { r += "))"; break; } + case RESOURCE_LIMIT: r = "(resource limits reached)"; break; case QUANTIFIERS: r = "(incomplete quantifiers)"; break; case UNKNOWN: r = m_unknown; break; } diff --git a/src/smt/smt_failure.h b/src/smt/smt_failure.h index 171c0bf6d..9e332ac89 100644 --- a/src/smt/smt_failure.h +++ b/src/smt/smt_failure.h @@ -32,6 +32,7 @@ namespace smt { CANCELED, //!< External cancel flag was set NUM_CONFLICTS, //!< Maximum number of conflicts was reached THEORY, //!< Theory is incomplete + RESOURCE_LIMIT, QUANTIFIERS //!< Logical context contains universal quantifiers. }; diff --git a/src/smt/smt_model_checker.cpp b/src/smt/smt_model_checker.cpp index df271095f..980270ded 100644 --- a/src/smt/smt_model_checker.cpp +++ b/src/smt/smt_model_checker.cpp @@ -112,7 +112,6 @@ namespace smt { if (!m_curr_model->eval(q->get_expr(), tmp, true)) { return; } - //std::cout << tmp << "\n"; TRACE("model_checker", tout << "q after applying interpretation:\n" << mk_ismt2_pp(tmp, m) << "\n";); ptr_buffer subst_args; unsigned num_decls = q->get_num_decls(); @@ -373,7 +372,8 @@ namespace smt { return true; if (m_iteration_idx >= m_params.m_mbqi_max_iterations) { - IF_VERBOSE(10, verbose_stream() << "(smt.mbqi \"max instantiations reached \")" << m_iteration_idx << "\n";); + IF_VERBOSE(1, verbose_stream() << "(smt.mbqi \"max instantiations " << m_iteration_idx << " reached\")\n";); + m_context->set_reason_unknown("max mbqi instantiations reached"); return false; } diff --git a/src/smt/tactic/smt_tactic.cpp b/src/smt/tactic/smt_tactic.cpp index 7fa3328fb..baaaf7bb0 100644 --- a/src/smt/tactic/smt_tactic.cpp +++ b/src/smt/tactic/smt_tactic.cpp @@ -293,8 +293,11 @@ public: if (m_ctx->canceled()) { throw tactic_exception(Z3_CANCELED_MSG); } - if (m_fail_if_inconclusive) - throw tactic_exception("smt tactic failed to show goal to be sat/unsat"); + if (m_fail_if_inconclusive) { + std::stringstream strm; + strm << "smt tactic failed to show goal to be sat/unsat " << m_ctx->last_failure_as_string(); + throw tactic_exception(strm.str().c_str()); + } result.push_back(in.get()); if (m_candidate_models) { switch (m_ctx->last_failure()) { From 654780bb4b2ee6a0f793aeb5fd2eaefffc296b8e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 1 Jul 2016 09:26:01 -0700 Subject: [PATCH 068/536] check that model is availble before evaluation, issue #595 Signed-off-by: Nikolaj Bjorner --- src/interp/iz3base.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/interp/iz3base.cpp b/src/interp/iz3base.cpp index 57188e5ca..100f16559 100755 --- a/src/interp/iz3base.cpp +++ b/src/interp/iz3base.cpp @@ -280,6 +280,10 @@ bool iz3base::is_sat(const std::vector &q, ast &_proof, std::vector &v else if(vars.size()) { model_ref(_m); s.get_model(_m); + if (!_m.get()) { + SASSERT(l_undef == res); + throw iz3_exception("interpolation cannot proceed without a model"); + } for(unsigned i = 0; i < vars.size(); i++){ expr_ref r(m()); _m.get()->eval(to_expr(vars[i].raw()),r,true); From 0d0d504d62735616bf38c8b2671ea91d68fb5fd2 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 1 Jul 2016 14:46:44 -0700 Subject: [PATCH 069/536] change names of reserved identifiers. Issue #666 Signed-off-by: Nikolaj Bjorner --- src/api/c++/z3++.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index 98a1a76ea..e0c520f5b 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -802,8 +802,8 @@ namespace z3 { friend expr implies(expr const & a, bool b); friend expr implies(bool a, expr const & b); - friend expr or(expr_vector const& args); - friend expr and(expr_vector const& args); + friend expr mk_or(expr_vector const& args); + friend expr mk_and(expr_vector const& args); friend expr ite(expr const & c, expr const & t, expr const & e); @@ -1501,13 +1501,13 @@ namespace z3 { return expr(ctx, r); } - inline expr or(expr_vector const& args) { + inline expr mk_or(expr_vector const& args) { array _args(args); Z3_ast r = Z3_mk_or(args.ctx(), _args.size(), _args.ptr()); args.check_error(); return expr(args.ctx(), r); } - inline expr and(expr_vector const& args) { + inline expr mk_and(expr_vector const& args) { array _args(args); Z3_ast r = Z3_mk_and(args.ctx(), _args.size(), _args.ptr()); args.check_error(); From e9e10f1d5c2f24a6e36165a018d25630b4ace7b3 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 3 Jul 2016 10:38:54 -0700 Subject: [PATCH 070/536] checking cancel flag to refine the behavior around issue #595 Signed-off-by: Nikolaj Bjorner --- src/interp/iz3base.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/interp/iz3base.cpp b/src/interp/iz3base.cpp index 100f16559..c530ca0f6 100755 --- a/src/interp/iz3base.cpp +++ b/src/interp/iz3base.cpp @@ -267,12 +267,15 @@ bool iz3base::is_sat(const std::vector &q, ast &_proof, std::vector &v p.set_bool("model", true); p.set_bool("unsat_core", true); scoped_ptr sf = mk_smt_solver_factory(); - ::solver *m_solver = (*sf)(m(), p, true, true, true, ::symbol::null); - ::solver &s = *m_solver; + scoped_ptr<::solver> solver = (*sf)(m(), p, true, true, true, ::symbol::null); + ::solver &s = *solver.get(); for(unsigned i = 0; i < q.size(); i++) s.assert_expr(to_expr(q[i].raw())); lbool res = s.check_sat(0,0); + if (m().canceled()) { + throw iz3_exception(Z3_CANCELED_MSG); + } if(res == l_false){ ::ast *proof = s.get_proof(); _proof = cook(proof); @@ -290,7 +293,7 @@ bool iz3base::is_sat(const std::vector &q, ast &_proof, std::vector &v vars[i] = cook(r.get()); } } - dealloc(m_solver); + solver = 0; return res != l_false; } From bdbf1c9bf4054f12311434e065ff9c4b4c45a5d2 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 8 Jul 2016 10:45:19 -0700 Subject: [PATCH 071/536] add support for default semantics for stoi (non-integer strings map to -1). Issue #670 Signed-off-by: Nikolaj Bjorner --- src/smt/theory_seq.cpp | 31 ++++++++++++++++++++++++++----- src/smt/theory_seq.h | 2 ++ 2 files changed, 28 insertions(+), 5 deletions(-) diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index 609181538..0702bac69 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -2197,16 +2197,37 @@ bool theory_seq::check_int_string() { if (m_util.str.is_itos(e) && add_itos_axiom(e)) { change = true; } - else if (m_util.str.is_stoi(e, n)) { - // not (yet) handled. - // we would check that in the current proto-model - // the string at 'n', when denoting integer would map to the - // proper integer. + else if (m_util.str.is_stoi(e, n) && add_stoi_axiom(e)) { + change = true; } } return change; } +bool theory_seq::add_stoi_axiom(expr* e) { + context& ctx = get_context(); + expr* n; + rational val; + VERIFY(m_util.str.is_stoi(e, n)); + if (get_value(e, val) && !m_stoi_axioms.contains(val)) { + m_stoi_axioms.insert(val); + if (!val.is_minus_one()) { + 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); + literal eq1 = mk_eq(e, n1, false); + literal eq2 = mk_eq(n, e1, false); + add_axiom(~eq1, eq2); + add_axiom(~eq2, eq1); + ctx.force_phase(eq1); + ctx.force_phase(eq2); + m_trail_stack.push(insert_map(m_stoi_axioms, val)); + m_trail_stack.push(push_replay(alloc(replay_axiom, m, e))); + return true; + } + } + return false; +} + bool theory_seq::add_itos_axiom(expr* e) { context& ctx = get_context(); rational val; diff --git a/src/smt/theory_seq.h b/src/smt/theory_seq.h index 136a84520..c1e179f67 100644 --- a/src/smt/theory_seq.h +++ b/src/smt/theory_seq.h @@ -308,6 +308,7 @@ namespace smt { bool m_incomplete; // is the solver (clearly) incomplete for the fragment. expr_ref_vector m_int_string; rational_set m_itos_axioms; + rational_set m_stoi_axioms; obj_hashtable m_length; // is length applied scoped_ptr_vector m_replay; // set of actions to replay model_generator* m_mg; @@ -493,6 +494,7 @@ namespace smt { void add_elim_string_axiom(expr* n); void add_at_axiom(expr* n); void add_in_re_axiom(expr* n); + bool add_stoi_axiom(expr* n); bool add_itos_axiom(expr* n); void add_itos_length_axiom(expr* n); literal mk_literal(expr* n); From d5ee7e24bcd5bab2bae7d898877b2fc490a9e396 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 8 Jul 2016 11:50:39 -0700 Subject: [PATCH 072/536] add simplification for equalities between itos and constant strings, Issue #589 Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/seq_rewriter.cpp | 55 +++++++++++++++++++++++++++++++ src/ast/rewriter/seq_rewriter.h | 5 +++ src/ast/seq_decl_plugin.cpp | 10 ------ src/ast/seq_decl_plugin.h | 1 - 4 files changed, 60 insertions(+), 11 deletions(-) diff --git a/src/ast/rewriter/seq_rewriter.cpp b/src/ast/rewriter/seq_rewriter.cpp index 29bfe25e5..3a447d0f5 100644 --- a/src/ast/rewriter/seq_rewriter.cpp +++ b/src/ast/rewriter/seq_rewriter.cpp @@ -1515,6 +1515,11 @@ bool seq_rewriter::reduce_eq(expr_ref_vector& ls, expr_ref_vector& rs, expr_ref_ unsigned szl = ls.size() - head1, szr = rs.size() - head2; expr* const* _ls = ls.c_ptr() + head1, * const* _rs = rs.c_ptr() + head2; + if (solve_itos(szl, _ls, szr, _rs, lhs, rhs, is_sat)) { + ls.reset(); rs.reset(); + change = true; + return is_sat; + } if (length_constrained(szl, _ls, szr, _rs, lhs, rhs, is_sat)) { ls.reset(); rs.reset(); @@ -1679,6 +1684,56 @@ bool seq_rewriter::min_length(unsigned n, expr* const* es, unsigned& len) { return bounded; } +bool seq_rewriter::is_string(unsigned n, expr* const* es, zstring& s) const { + zstring s1; + expr* e; + bv_util bv(m()); + rational val; + unsigned sz; + for (unsigned i = 0; i < n; ++i) { + if (m_util.str.is_string(es[i], s1)) { + s = s + s1; + } + else if (m_util.str.is_unit(es[i], e) && bv.is_numeral(e, val, sz)) { + s = s + zstring(val.get_unsigned()); + } + else { + return false; + } + } + return true; +} + +bool seq_rewriter::solve_itos(unsigned szl, expr* const* ls, unsigned szr, expr* const* rs, + expr_ref_vector& lhs, expr_ref_vector& rhs, bool& is_sat) { + + expr* l, *r; + if (szl == 1 && m_util.str.is_itos(ls[0], l)) { + if (szr == 1 && m_util.str.is_itos(rs[0], r)) { + lhs.push_back(l); + rhs.push_back(r); + is_sat = true; + return true; + } + zstring s; + if (is_string(szr, rs, s)) { + std::string s1 = s.encode(); + rational r(s1.c_str()); + if (s1 == r.to_string()) { + lhs.push_back(l); + rhs.push_back(m_autil.mk_numeral(r, true)); + return true; + } + } + } + + if (szr == 1 && m_util.str.is_itos(rs[0], r)) { + return solve_itos(szr, rs, szl, ls, rhs, lhs, is_sat); + } + + return false; +} + bool seq_rewriter::length_constrained(unsigned szl, expr* const* l, unsigned szr, expr* const* r, expr_ref_vector& lhs, expr_ref_vector& rhs, bool& is_sat) { is_sat = true; diff --git a/src/ast/rewriter/seq_rewriter.h b/src/ast/rewriter/seq_rewriter.h index 040bae1b4..82579d53a 100644 --- a/src/ast/rewriter/seq_rewriter.h +++ b/src/ast/rewriter/seq_rewriter.h @@ -125,15 +125,20 @@ class seq_rewriter { expr_ref_vector& lhs, expr_ref_vector& rhs, bool& is_sat); bool length_constrained(unsigned n, expr* const* l, unsigned m, expr* const* r, expr_ref_vector& lhs, expr_ref_vector& rhs, bool& is_sat); + bool solve_itos(unsigned n, expr* const* l, unsigned m, expr* const* r, + expr_ref_vector& lhs, expr_ref_vector& rhs, bool& is_sat); bool min_length(unsigned n, expr* const* es, unsigned& len); expr* concat_non_empty(unsigned n, expr* const* es); + bool is_string(unsigned n, expr* const* es, zstring& s) const; + void add_next(u_map& next, expr_ref_vector& trail, unsigned idx, expr* cond); bool is_sequence(expr* e, expr_ref_vector& seq); bool is_sequence(eautomaton& aut, expr_ref_vector& seq); bool is_epsilon(expr* e) const; void split_units(expr_ref_vector& lhs, expr_ref_vector& rhs); + public: seq_rewriter(ast_manager & m, params_ref const & p = params_ref()): m_util(m), m_autil(m), m_re2aut(m), m_es(m), m_lhs(m), m_rhs(m) { diff --git a/src/ast/seq_decl_plugin.cpp b/src/ast/seq_decl_plugin.cpp index 21af0773a..dc7307741 100644 --- a/src/ast/seq_decl_plugin.cpp +++ b/src/ast/seq_decl_plugin.cpp @@ -822,16 +822,6 @@ app* seq_util::str::mk_char(char ch) { return mk_char(s, 0); } -bool seq_util::str::is_char(expr* n, zstring& c) const { - if (u.is_char(n)) { - c = zstring(to_app(n)->get_decl()->get_parameter(0).get_symbol().bare_str()); - return true; - } - else { - return false; - } -} - bool seq_util::str::is_string(expr const* n, zstring& s) const { if (is_string(n)) { s = zstring(to_app(n)->get_decl()->get_parameter(0).get_symbol().bare_str()); diff --git a/src/ast/seq_decl_plugin.h b/src/ast/seq_decl_plugin.h index 78672182a..fbbcba5de 100644 --- a/src/ast/seq_decl_plugin.h +++ b/src/ast/seq_decl_plugin.h @@ -250,7 +250,6 @@ public: } bool is_string(expr const* n, zstring& s) const; - bool is_char(expr* n, zstring& s) const; bool is_empty(expr const* n) const { symbol s; return is_app_of(n, m_fid, OP_SEQ_EMPTY) || (is_string(n, s) && !s.is_numerical() && *s.bare_str() == 0); From 6eaab00e83097a290cc2d6e43c4885c9a4a505c6 Mon Sep 17 00:00:00 2001 From: Fabian Wolff Date: Sat, 9 Jul 2016 11:46:43 +0200 Subject: [PATCH 073/536] Fix spelling errors --- src/ast/dl_decl_plugin.cpp | 2 +- src/ast/normal_forms/pull_quant.cpp | 4 ++-- src/ast/pp_params.pyg | 2 +- src/cmd_context/cmd_util.cpp | 2 +- src/cmd_context/cmd_util.h | 2 +- src/cmd_context/tactic_cmds.cpp | 2 +- src/math/subpaving/subpaving_t.h | 2 +- src/muz/base/dl_util.h | 2 +- src/muz/fp/datalog_parser.cpp | 4 ++-- src/smt/params/smt_params_helper.pyg | 2 +- src/smt/smt_context_pp.cpp | 4 ++-- src/tactic/arith/diff_neq_tactic.h | 2 +- src/tactic/probe.h | 2 +- src/tactic/sls/sls_tracker.h | 2 +- src/util/mpff.h | 2 +- 15 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/ast/dl_decl_plugin.cpp b/src/ast/dl_decl_plugin.cpp index 46f610c18..f7d6d9d1c 100644 --- a/src/ast/dl_decl_plugin.cpp +++ b/src/ast/dl_decl_plugin.cpp @@ -461,7 +461,7 @@ namespace datalog { return 0; } if (!ps.is_ast() || !is_sort(ps.get_ast()) || !is_fin_sort(to_sort(ps.get_ast()))) { - m_manager->raise_exception("second paramter should be a finite domain sort"); + m_manager->raise_exception("second parameter should be a finite domain sort"); return 0; } sort* s = to_sort(ps.get_ast()); diff --git a/src/ast/normal_forms/pull_quant.cpp b/src/ast/normal_forms/pull_quant.cpp index bb9b30dc5..74c7cafde 100644 --- a/src/ast/normal_forms/pull_quant.cpp +++ b/src/ast/normal_forms/pull_quant.cpp @@ -125,8 +125,8 @@ struct pull_quant::imp { // of nested_q->get_expr(). m_shift(nested_q->get_expr(), nested_q->get_num_decls(), // bound for shift1/shift2 - num_decls - nested_q->get_num_decls(), // shift1 (shift by this ammount if var idx >= bound) - shift_amount, // shift2 (shift by this ammount if var idx < bound) + num_decls - nested_q->get_num_decls(), // shift1 (shift by this amount if var idx >= bound) + shift_amount, // shift2 (shift by this amount if var idx < bound) adjusted_child); TRACE("pull_quant", tout << "shifted bound: " << nested_q->get_num_decls() << " shift1: " << shift_amount << " shift2: " << (num_decls - nested_q->get_num_decls()) << "\n" << mk_pp(nested_q->get_expr(), m_manager) << diff --git a/src/ast/pp_params.pyg b/src/ast/pp_params.pyg index d831cada9..46273b140 100644 --- a/src/ast/pp_params.pyg +++ b/src/ast/pp_params.pyg @@ -15,5 +15,5 @@ def_module_params('pp', ('flat_assoc', BOOL, True, 'flat associative operators (when pretty printing SMT2 terms/formulas)'), ('fixed_indent', BOOL, False, 'use a fixed indentation for applications'), ('single_line', BOOL, False, 'ignore line breaks when true'), - ('bounded', BOOL, False, 'ignore characters exceeding max widht'), + ('bounded', BOOL, False, 'ignore characters exceeding max width'), ('simplify_implies', BOOL, True, 'simplify nested implications for pretty printing'))) diff --git a/src/cmd_context/cmd_util.cpp b/src/cmd_context/cmd_util.cpp index 083493751..9774c75ff 100644 --- a/src/cmd_context/cmd_util.cpp +++ b/src/cmd_context/cmd_util.cpp @@ -6,7 +6,7 @@ Module Name: cmd_util.cpp Abstract: - Macros for definining new SMT2 front-end cmds. + Macros for defining new SMT2 front-end cmds. Author: diff --git a/src/cmd_context/cmd_util.h b/src/cmd_context/cmd_util.h index f0660af37..e575783f5 100644 --- a/src/cmd_context/cmd_util.h +++ b/src/cmd_context/cmd_util.h @@ -6,7 +6,7 @@ Module Name: cmd_util.h Abstract: - Macros for definining new SMT2 front-end cmds. + Macros for defining new SMT2 front-end cmds. Author: diff --git a/src/cmd_context/tactic_cmds.cpp b/src/cmd_context/tactic_cmds.cpp index f044c9736..86900e175 100644 --- a/src/cmd_context/tactic_cmds.cpp +++ b/src/cmd_context/tactic_cmds.cpp @@ -97,7 +97,7 @@ void help_tactic(cmd_context & ctx) { buf << "- (or-else +) tries the given tactics in sequence until one of them succeeds (i.e., the first that doesn't fail).\n"; buf << "- (par-or +) executes the given tactics in parallel until one of them succeeds (i.e., the first that doesn't fail).\n"; buf << "- (par-then ) executes tactic1 and then tactic2 to every subgoal produced by tactic1. All subgoals are processed in parallel.\n"; - buf << "- (try-for ) excutes the given tactic for at most milliseconds, it fails if the execution takes more than milliseconds.\n"; + buf << "- (try-for ) executes the given tactic for at most milliseconds, it fails if the execution takes more than milliseconds.\n"; buf << "- (if ) if evaluates to true, then execute the first tactic. Otherwise execute the second.\n"; buf << "- (when ) shorthand for (if skip).\n"; buf << "- (fail-if ) fail if evaluates to true.\n"; diff --git a/src/math/subpaving/subpaving_t.h b/src/math/subpaving/subpaving_t.h index a6aa3cf32..ccef1a318 100644 --- a/src/math/subpaving/subpaving_t.h +++ b/src/math/subpaving/subpaving_t.h @@ -354,7 +354,7 @@ public: }; /** - \brief Watched element (aka occurence) can be: + \brief Watched element (aka occurrence) can be: - A clause - A definition (i.e., a variable) diff --git a/src/muz/base/dl_util.h b/src/muz/base/dl_util.h index 78ce453ec..b1719577b 100644 --- a/src/muz/base/dl_util.h +++ b/src/muz/base/dl_util.h @@ -591,7 +591,7 @@ namespace datalog { /** - \brief Remove the first occurence of \c el from \c v and return \c true. If + \brief Remove the first occurrence of \c el from \c v and return \c true. If \c el is not present in \c v, return \c false. The order of elements in \c v is not preserved. */ diff --git a/src/muz/fp/datalog_parser.cpp b/src/muz/fp/datalog_parser.cpp index 41c0f77af..b51af7d53 100644 --- a/src/muz/fp/datalog_parser.cpp +++ b/src/muz/fp/datalog_parser.cpp @@ -480,7 +480,7 @@ protected: str2sort m_sort_dict; - // true if an error occured during the current call to the parse_stream + // true if an error occurred during the current call to the parse_stream // function bool m_error; public: @@ -896,7 +896,7 @@ protected: tok = m_lexer->next_token(); if (tok != TK_COLON) { tok = unexpected(tok, - "Expecting colon in declaration (first occurence of a predicate must be a declaration)"); + "Expecting colon in declaration (first occurrence of a predicate must be a declaration)"); return tok; } tok = m_lexer->next_token(); diff --git a/src/smt/params/smt_params_helper.pyg b/src/smt/params/smt_params_helper.pyg index 153d948f5..35652608c 100644 --- a/src/smt/params/smt_params_helper.pyg +++ b/src/smt/params/smt_params_helper.pyg @@ -13,7 +13,7 @@ def_module_params(module_name='smt', ('restart_factor', DOUBLE, 1.1, 'when using geometric (or inner-outer-geometric) progression of restarts, it specifies the constant used to multiply the currect restart threshold'), ('case_split', UINT, 1, '0 - case split based on variable activity, 1 - similar to 0, but delay case splits created during the search, 2 - similar to 0, but cache the relevancy, 3 - case split based on relevancy (structural splitting), 4 - case split on relevancy and activity, 5 - case split on relevancy and current goal'), ('delay_units', BOOL, False, 'if true then z3 will not restart when a unit clause is learned'), - ('delay_units_threshold', UINT, 32, 'maximum number of learned unit clauses before restarting, ingored if delay_units is false'), + ('delay_units_threshold', UINT, 32, 'maximum number of learned unit clauses before restarting, ignored if delay_units is false'), ('pull_nested_quantifiers', BOOL, False, 'pull nested quantifiers'), ('refine_inj_axioms', BOOL, True, 'refine injectivity axioms'), ('timeout', UINT, UINT_MAX, 'timeout (in milliseconds) (0 means immediate timeout)'), diff --git a/src/smt/smt_context_pp.cpp b/src/smt/smt_context_pp.cpp index b0138f70c..ff45c5089 100644 --- a/src/smt/smt_context_pp.cpp +++ b/src/smt/smt_context_pp.cpp @@ -253,7 +253,7 @@ namespace smt { void context::display_app_enode_map(std::ostream & out) const { if (!m_e_internalized_stack.empty()) { - out << "expresion -> enode:\n"; + out << "expression -> enode:\n"; unsigned sz = m_e_internalized_stack.size(); for (unsigned i = 0; i < sz; i++) { expr * n = m_e_internalized_stack.get(i); @@ -265,7 +265,7 @@ namespace smt { void context::display_expr_bool_var_map(std::ostream & out) const { if (!m_b_internalized_stack.empty()) { - out << "expresion -> bool_var:\n"; + out << "expression -> bool_var:\n"; unsigned sz = m_b_internalized_stack.size(); for (unsigned i = 0; i < sz; i++) { expr * n = m_b_internalized_stack.get(i); diff --git a/src/tactic/arith/diff_neq_tactic.h b/src/tactic/arith/diff_neq_tactic.h index 5a5c24000..205fb7bb5 100644 --- a/src/tactic/arith/diff_neq_tactic.h +++ b/src/tactic/arith/diff_neq_tactic.h @@ -29,6 +29,6 @@ class tactic; tactic * mk_diff_neq_tactic(ast_manager & m, params_ref const & p = params_ref()); /* - ADD_TACTIC("diff-neq", "specialized solver for integer arithmetic problems that contain only atoms of the form (<= k x) (<= x k) and (not (= (- x y) k)), where x and y are constants and k is a numberal, and all constants are bounded.", "mk_diff_neq_tactic(m, p)") + ADD_TACTIC("diff-neq", "specialized solver for integer arithmetic problems that contain only atoms of the form (<= k x) (<= x k) and (not (= (- x y) k)), where x and y are constants and k is a numeral, and all constants are bounded.", "mk_diff_neq_tactic(m, p)") */ #endif diff --git a/src/tactic/probe.h b/src/tactic/probe.h index a4754f8ed..3f7229d36 100644 --- a/src/tactic/probe.h +++ b/src/tactic/probe.h @@ -62,7 +62,7 @@ probe * mk_depth_probe(); probe * mk_size_probe(); /* - ADD_PROBE("memory", "ammount of used memory in megabytes.", "mk_memory_probe()") + ADD_PROBE("memory", "amount of used memory in megabytes.", "mk_memory_probe()") ADD_PROBE("depth", "depth of the input goal.", "mk_depth_probe()") ADD_PROBE("size", "number of assertions in the given goal.", "mk_size_probe()") */ diff --git a/src/tactic/sls/sls_tracker.h b/src/tactic/sls/sls_tracker.h index 39d76bee6..dfdbd4685 100644 --- a/src/tactic/sls/sls_tracker.h +++ b/src/tactic/sls/sls_tracker.h @@ -464,7 +464,7 @@ public: if (!m_weights.contains(e)) m_weights.insert(e, m_paws_init); - // positive/negative occurences used for early pruning + // positive/negative occurrences used for early pruning setup_occs(as[i]); } diff --git a/src/util/mpff.h b/src/util/mpff.h index a4cab898c..eadfa0390 100644 --- a/src/util/mpff.h +++ b/src/util/mpff.h @@ -94,7 +94,7 @@ class mpff_manager { // // - All values of type int, unsigned, int64 and uint64 can be precisely represented as mpff numerals. // - // - Hardware float and double values (corresponding to rationals) can also be precisely represented as mpff numberals. + // - Hardware float and double values (corresponding to rationals) can also be precisely represented as mpff numerals. // That is, NaN, +oo and -oo are not supported by this module. // // - An exception (mpff_manager::exception) is thrown if overflow occurs. This can happen because the exponent is From 53b3edc8cc06b493b113d768ad0458a5ef23cfda Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 9 Jul 2016 05:18:26 -0700 Subject: [PATCH 074/536] add cases for recognizing ALL. Issue #674 Signed-off-by: Nikolaj Bjorner --- src/api/api_ast.cpp | 2 +- src/cmd_context/cmd_context.cpp | 5 ++++- src/interp/iz3mgr.h | 1 - 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/api/api_ast.cpp b/src/api/api_ast.cpp index cfe082802..31535e5f4 100644 --- a/src/api/api_ast.cpp +++ b/src/api/api_ast.cpp @@ -989,7 +989,7 @@ extern "C" { case OP_TO_INT: return Z3_OP_TO_INT; case OP_IS_INT: return Z3_OP_IS_INT; default: - UNREACHABLE(); + //UNREACHABLE(); return Z3_OP_UNINTERPRETED; } } diff --git a/src/cmd_context/cmd_context.cpp b/src/cmd_context/cmd_context.cpp index 55b61d0da..5f9de116d 100644 --- a/src/cmd_context/cmd_context.cpp +++ b/src/cmd_context/cmd_context.cpp @@ -546,6 +546,7 @@ bool cmd_context::logic_has_arith_core(symbol const & s) const { s == "QF_FPBV" || s == "QF_BVFP" || s == "QF_S" || + s == "ALL" || s == "HORN"; } @@ -566,6 +567,7 @@ bool cmd_context::logic_has_bv_core(symbol const & s) const { s == "QF_BVRE" || s == "QF_FPBV" || s == "QF_BVFP" || + s == "ALL" || s == "HORN"; } @@ -609,6 +611,7 @@ bool cmd_context::logic_has_array_core(symbol const & s) const { s == "AUFNIRA" || s == "AUFBV" || s == "ABV" || + s == "ALL" || s == "QF_ABV" || s == "QF_AUFBV" || s == "HORN"; @@ -702,7 +705,7 @@ void cmd_context::init_external_manager() { } bool cmd_context::supported_logic(symbol const & s) const { - return s == "QF_UF" || s == "UF" || + return s == "QF_UF" || s == "UF" || logic_has_arith_core(s) || logic_has_bv_core(s) || logic_has_array_core(s) || logic_has_seq_core(s) || logic_has_horn(s) || logic_has_fpa_core(s); diff --git a/src/interp/iz3mgr.h b/src/interp/iz3mgr.h index 85fbbdb3a..424b95359 100755 --- a/src/interp/iz3mgr.h +++ b/src/interp/iz3mgr.h @@ -45,7 +45,6 @@ #include"scoped_ctrl_c.h" #include"cancel_eh.h" #include"scoped_timer.h" -//# include"pp_params.hpp" /* A wrapper around an ast manager, providing convenience methods. */ From 3d73fe55c71e1a875f3e0691fa8e7f205bcf548f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 9 Jul 2016 05:31:49 -0700 Subject: [PATCH 075/536] track assumptions when calling check-sat. regression detected by Tjark Weber running core extraction Signed-off-by: Nikolaj Bjorner --- src/cmd_context/cmd_context.cpp | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/cmd_context/cmd_context.cpp b/src/cmd_context/cmd_context.cpp index 5f9de116d..d4c7a1a54 100644 --- a/src/cmd_context/cmd_context.cpp +++ b/src/cmd_context/cmd_context.cpp @@ -1473,7 +1473,19 @@ void cmd_context::check_sat(unsigned num_assumptions, expr * const * assumptions scoped_timer timer(timeout, &eh); scoped_rlimit _rlimit(m().limit(), rlimit); try { - r = m_solver->check_sat(num_assumptions, assumptions); + if (produce_unsat_cores()) { + expr_ref_vector asms(m()); + asms.append(num_assumptions, assumptions); + for (unsigned i = 0; i < m_assertion_names.size(); ++i) { + if (m_assertion_names[i]) { + asms.push_back(m_assertion_names[i]); + } + } + r = m_solver->check_sat(asms); + } + else { + r = m_solver->check_sat(num_assumptions, assumptions); + } } catch (z3_error & ex) { throw ex; From d7d22cad0229cfecd310839e3d2ba4cb102beaf8 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 9 Jul 2016 05:38:03 -0700 Subject: [PATCH 076/536] undo comment Signed-off-by: Nikolaj Bjorner --- src/api/api_ast.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/api_ast.cpp b/src/api/api_ast.cpp index 31535e5f4..cfe082802 100644 --- a/src/api/api_ast.cpp +++ b/src/api/api_ast.cpp @@ -989,7 +989,7 @@ extern "C" { case OP_TO_INT: return Z3_OP_TO_INT; case OP_IS_INT: return Z3_OP_IS_INT; default: - //UNREACHABLE(); + UNREACHABLE(); return Z3_OP_UNINTERPRETED; } } From 8f862f8fedab42a79d424707b9159fd577bcc9f3 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 9 Jul 2016 12:35:11 -0700 Subject: [PATCH 077/536] fix core extraction for QF_BV theory/inc_sat_solver based on regressions pointed out by Matthias Heizmann and Tjark Weber Signed-off-by: Nikolaj Bjorner --- src/cmd_context/cmd_context.cpp | 2 +- src/sat/sat_solver/inc_sat_solver.cpp | 15 ++++++++++++--- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/cmd_context/cmd_context.cpp b/src/cmd_context/cmd_context.cpp index d4c7a1a54..d773a3066 100644 --- a/src/cmd_context/cmd_context.cpp +++ b/src/cmd_context/cmd_context.cpp @@ -1476,7 +1476,7 @@ void cmd_context::check_sat(unsigned num_assumptions, expr * const * assumptions if (produce_unsat_cores()) { expr_ref_vector asms(m()); asms.append(num_assumptions, assumptions); - for (unsigned i = 0; i < m_assertion_names.size(); ++i) { + for (unsigned i = 0; false && i < m_assertion_names.size(); ++i) { if (m_assertion_names[i]) { asms.push_back(m_assertion_names[i]); } diff --git a/src/sat/sat_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp index 65f62ec0e..766ed52be 100644 --- a/src/sat/sat_solver/inc_sat_solver.cpp +++ b/src/sat/sat_solver/inc_sat_solver.cpp @@ -135,7 +135,6 @@ public: lbool r = internalize_formulas(); if (r != l_true) return r; r = internalize_assumptions(sz, assumptions, dep2asm); - SASSERT(sz == m_asms.size()); if (r != l_true) return r; r = m_solver.check(m_asms.size(), m_asms.c_ptr(), m_weights.c_ptr(), max_weight); @@ -147,7 +146,7 @@ public: break; case l_false: // TBD: expr_dependency core is not accounted for. - if (sz > 0) { + if (!m_asms.empty()) { extract_core(dep2asm); } break; @@ -314,7 +313,7 @@ private: } lbool internalize_assumptions(unsigned sz, expr* const* asms, dep2asm_t& dep2asm) { - if (sz == 0) { + if (sz == 0 && get_num_assumptions() == 0) { m_asms.shrink(0); return l_true; } @@ -322,6 +321,9 @@ private: for (unsigned i = 0; i < sz; ++i) { g->assert_expr(asms[i], m.mk_leaf(asms[i])); } + for (unsigned i = 0; i < get_num_assumptions(); ++i) { + g->assert_expr(get_assumption(i), m.mk_leaf(get_assumption(i))); + } lbool res = internalize_goal(g, dep2asm); if (res == l_true) { extract_assumptions(sz, asms, dep2asm); @@ -355,6 +357,13 @@ private: ++j; } } + for (unsigned i = 0; i < get_num_assumptions(); ++i) { + if (dep2asm.find(get_assumption(i), lit)) { + SASSERT(lit.var() <= m_solver.num_vars()); + m_asms.push_back(lit); + } + } + SASSERT(dep2asm.size() == m_asms.size()); } From 0a6b03808cdfbad3057d9e2402584bae4e405f9d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 9 Jul 2016 12:35:54 -0700 Subject: [PATCH 078/536] fix core extraction for QF_BV theory/inc_sat_solver based on regressions pointed out by Matthias Heizmann and Tjark Weber Signed-off-by: Nikolaj Bjorner --- src/cmd_context/cmd_context.cpp | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/src/cmd_context/cmd_context.cpp b/src/cmd_context/cmd_context.cpp index d773a3066..5f9de116d 100644 --- a/src/cmd_context/cmd_context.cpp +++ b/src/cmd_context/cmd_context.cpp @@ -1473,19 +1473,7 @@ void cmd_context::check_sat(unsigned num_assumptions, expr * const * assumptions scoped_timer timer(timeout, &eh); scoped_rlimit _rlimit(m().limit(), rlimit); try { - if (produce_unsat_cores()) { - expr_ref_vector asms(m()); - asms.append(num_assumptions, assumptions); - for (unsigned i = 0; false && i < m_assertion_names.size(); ++i) { - if (m_assertion_names[i]) { - asms.push_back(m_assertion_names[i]); - } - } - r = m_solver->check_sat(asms); - } - else { - r = m_solver->check_sat(num_assumptions, assumptions); - } + r = m_solver->check_sat(num_assumptions, assumptions); } catch (z3_error & ex) { throw ex; From f96cfeae9e2564347f0ac72e6b5a8ae351cd21fe Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 9 Jul 2016 13:28:39 -0700 Subject: [PATCH 079/536] fix build failures under linux Signed-off-by: Nikolaj Bjorner --- src/interp/iz3base.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/interp/iz3base.cpp b/src/interp/iz3base.cpp index c530ca0f6..d0f8c3a75 100755 --- a/src/interp/iz3base.cpp +++ b/src/interp/iz3base.cpp @@ -267,7 +267,7 @@ bool iz3base::is_sat(const std::vector &q, ast &_proof, std::vector &v p.set_bool("model", true); p.set_bool("unsat_core", true); scoped_ptr sf = mk_smt_solver_factory(); - scoped_ptr<::solver> solver = (*sf)(m(), p, true, true, true, ::symbol::null); + scoped_ptr< ::solver > solver = (*sf)(m(), p, true, true, true, ::symbol::null); ::solver &s = *solver.get(); for(unsigned i = 0; i < q.size(); i++) From 63f89f8c453c3e9010f91ffcf2f504e165b77cd0 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 12 Jul 2016 15:12:40 -0700 Subject: [PATCH 080/536] add sin/cos conversions for #680 Signed-off-by: Nikolaj Bjorner --- src/ast/arith_decl_plugin.h | 7 ++ src/tactic/arith/purify_arith_tactic.cpp | 121 +++++++++++++++++++++-- 2 files changed, 118 insertions(+), 10 deletions(-) diff --git a/src/ast/arith_decl_plugin.h b/src/ast/arith_decl_plugin.h index 7a6281b06..71e54c0a3 100644 --- a/src/ast/arith_decl_plugin.h +++ b/src/ast/arith_decl_plugin.h @@ -284,6 +284,13 @@ public: bool is_int_real(sort const * s) const { return s->get_family_id() == m_afid; } bool is_int_real(expr const * n) const { return is_int_real(get_sort(n)); } + bool is_sin(expr const* n) const { return is_app_of(n, m_afid, OP_SIN); } + bool is_cos(expr const* n) const { return is_app_of(n, m_afid, OP_COS); } + bool is_tan(expr const* n) const { return is_app_of(n, m_afid, OP_TAN); } + bool is_asin(expr const* n) const { return is_app_of(n, m_afid, OP_ASIN); } + bool is_acos(expr const* n) const { return is_app_of(n, m_afid, OP_ACOS); } + bool is_atan(expr const* n) const { return is_app_of(n, m_afid, OP_ATAN); } + MATCH_UNARY(is_uminus); MATCH_UNARY(is_to_real); MATCH_UNARY(is_to_int); diff --git a/src/tactic/arith/purify_arith_tactic.cpp b/src/tactic/arith/purify_arith_tactic.cpp index a41c6939e..f41eb017b 100644 --- a/src/tactic/arith/purify_arith_tactic.cpp +++ b/src/tactic/arith/purify_arith_tactic.cpp @@ -28,6 +28,7 @@ Revision History: #include"simplify_tactic.h" #include"th_rewriter.h" #include"filter_model_converter.h" +#include"extension_model_converter.h" #include"ast_smt2_pp.h" #include"expr_replacer.h" @@ -102,17 +103,26 @@ Rules struct purify_arith_proc { arith_util & m_util; + goal & m_goal; bool m_produce_proofs; bool m_elim_root_objs; bool m_elim_inverses; bool m_complete; - purify_arith_proc(arith_util & u, bool produce_proofs, bool elim_root_objs, bool elim_inverses, bool complete): + ast_mark m_unsafe_exprs; + bool m_unsafe_found; + obj_map > m_sin_cos; + expr_ref_vector m_pinned; + + purify_arith_proc(goal & g, arith_util & u, bool produce_proofs, bool elim_root_objs, bool elim_inverses, bool complete): m_util(u), + m_goal(g), m_produce_proofs(produce_proofs), m_elim_root_objs(elim_root_objs), m_elim_inverses(elim_inverses), - m_complete(complete) { + m_complete(complete), + m_unsafe_found(false), + m_pinned(m()) { } arith_util & u() { @@ -123,6 +133,56 @@ struct purify_arith_proc { return u().get_manager(); } + struct find_unsafe_proc { + purify_arith_proc& m_owner; + find_unsafe_proc(purify_arith_proc& o) : m_owner(o) {} + void operator()(app* a) { + if (!m_owner.u().is_sin(a) && + !m_owner.u().is_cos(a)) { + for (unsigned i = 0; i < a->get_num_args(); ++i) { + m_owner.m_unsafe_exprs.mark(a->get_arg(i), true); + } + } + } + void operator()(quantifier *q) {} + void operator()(var* v) {} + }; + + void find_unsafe() { + if (m_unsafe_found) return; + find_unsafe_proc proc(*this); + expr_fast_mark1 visited; + unsigned sz = m_goal.size(); + for (unsigned i = 0; i < sz; i++) { + expr * curr = m_goal.form(i); + for_each_expr_core(proc, visited, curr); + } + m_unsafe_found = true; + } + + bool convert_basis(expr* theta, expr*& x, expr*& y) { + if (!is_uninterp_const(theta)) { + return false; + } + find_unsafe(); + if (m_unsafe_exprs.is_marked(theta)) { + return false; + } + std::pair pair; + if (!m_sin_cos.find(to_app(theta), pair)) { + pair.first = m().mk_fresh_const(0, m_util.mk_real()); + pair.second = m().mk_fresh_const(0, m_util.mk_real()); + m_sin_cos.insert(to_app(theta), pair); + m_pinned.push_back(pair.first); + m_pinned.push_back(pair.second); + // TBD for model conversion + } + x = pair.first; + y = pair.second; + return true; + } + + struct rw_cfg : public default_rewriter_cfg { purify_arith_proc & m_owner; obj_map m_app2fresh; @@ -167,6 +227,8 @@ struct purify_arith_proc { expr * mk_real_zero() { return u().mk_numeral(rational(0), false); } + expr * mk_real_one() { return u().mk_numeral(rational(1), false); } + bool already_processed(app * t, expr_ref & result, proof_ref & result_pr) { expr * r; if (m_app2fresh.find(t, r)) { @@ -436,6 +498,30 @@ struct purify_arith_proc { push_cnstr_pr(result_pr); } + br_status process_sin_cos(bool first, func_decl *f, expr * theta, expr_ref & result, proof_ref & result_pr) { + expr* x, *y; + if (m_owner.convert_basis(theta, x, y)) { + result = first ? x : y; + app_ref t(m().mk_app(f, theta), m()); + mk_def_proof(result, t, result_pr); + cache_result(t, result, result_pr); + push_cnstr(EQ(mk_real_one(), u().mk_add(u().mk_mul(x, x), u().mk_mul(y, y)))); + push_cnstr_pr(result_pr); + return BR_DONE; + } + else { + return BR_FAILED; + } + } + + br_status process_sin(func_decl *f, expr * theta, expr_ref & result, proof_ref & result_pr) { + return process_sin_cos(true, f, theta, result, result_pr); + } + + br_status process_cos(func_decl *f, expr * theta, expr_ref & result, proof_ref & result_pr) { + return process_sin_cos(false, f, theta, result, result_pr); + } + br_status process_asin(func_decl * f, expr * x, expr_ref & result, proof_ref & result_pr) { if (!elim_inverses()) return BR_FAILED; @@ -566,6 +652,10 @@ struct purify_arith_proc { return process_asin(f, args[0], result, result_pr); case OP_ACOS: return process_acos(f, args[0], result, result_pr); + case OP_SIN: + return process_sin(f, args[0], result, result_pr); + case OP_COS: + return process_cos(f, args[0], result, result_pr); case OP_ATAN: return process_atan(f, args[0], result, result_pr); default: @@ -649,26 +739,26 @@ struct purify_arith_proc { } } - void operator()(goal & g, model_converter_ref & mc, bool produce_models) { + void operator()(model_converter_ref & mc, bool produce_models) { rw r(*this); // purify expr_ref new_curr(m()); proof_ref new_pr(m()); - unsigned sz = g.size(); + unsigned sz = m_goal.size(); for (unsigned i = 0; i < sz; i++) { - expr * curr = g.form(i); + expr * curr = m_goal.form(i); r(curr, new_curr, new_pr); if (m_produce_proofs) { - proof * pr = g.pr(i); + proof * pr = m_goal.pr(i); new_pr = m().mk_modus_ponens(pr, new_pr); } - g.update(i, new_curr, new_pr, g.dep(i)); + m_goal.update(i, new_curr, new_pr, m_goal.dep(i)); } // add cnstraints sz = r.cfg().m_new_cnstrs.size(); for (unsigned i = 0; i < sz; i++) { - g.assert_expr(r.cfg().m_new_cnstrs.get(i), m_produce_proofs ? r.cfg().m_new_cnstr_prs.get(i) : 0, 0); + m_goal.assert_expr(r.cfg().m_new_cnstrs.get(i), m_produce_proofs ? r.cfg().m_new_cnstr_prs.get(i) : 0, 0); } // add filter_model_converter to eliminate auxiliary variables from model @@ -684,6 +774,17 @@ struct purify_arith_proc { fmc->insert(v->get_decl()); } } + if (produce_models && !m_sin_cos.empty()) { + extension_model_converter* emc = alloc(extension_model_converter, m()); + mc = concat(mc.get(), emc); + obj_map >::iterator it = m_sin_cos.begin(), end = m_sin_cos.end(); + for (; it != end; ++it) { + emc->insert(it->m_key->get_decl(), m_util.mk_asin(it->m_value.first)); + } + + } + // given values for x, y find value for theta + // x, y are rational } }; @@ -731,9 +832,9 @@ public: bool elim_root_objs = m_params.get_bool("elim_root_objects", true); bool elim_inverses = m_params.get_bool("elim_inverses", true); bool complete = m_params.get_bool("complete", true); - purify_arith_proc proc(m_util, produce_proofs, elim_root_objs, elim_inverses, complete); + purify_arith_proc proc(*(g.get()), m_util, produce_proofs, elim_root_objs, elim_inverses, complete); - proc(*(g.get()), mc, produce_models); + proc(mc, produce_models); g->inc_depth(); result.push_back(g.get()); From cfbe16639f9fd1445ab6595fc68bbb895011dc69 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Wed, 13 Jul 2016 15:35:14 +0100 Subject: [PATCH 081/536] Bugfix for fpa2bv translation --- src/ast/fpa/fpa2bv_converter.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ast/fpa/fpa2bv_converter.cpp b/src/ast/fpa/fpa2bv_converter.cpp index e89664216..d3257ac55 100644 --- a/src/ast/fpa/fpa2bv_converter.cpp +++ b/src/ast/fpa/fpa2bv_converter.cpp @@ -3641,11 +3641,11 @@ void fpa2bv_converter::unpack(expr * e, expr_ref & sgn, expr_ref & sig, expr_ref // the maximum shift is `sbits', because after that the mantissa // would be zero anyways. So we can safely cut the shift variable down, // as long as we check the higher bits. - expr_ref sh(m), is_sh_zero(m), sl(m), sbits_s(m), short_shift(m); - zero_s = m_bv_util.mk_numeral(0, sbits-1); + expr_ref zero_ems(m), sh(m), is_sh_zero(m), sl(m), sbits_s(m), short_shift(m); + zero_ems = m_bv_util.mk_numeral(0, ebits - sbits); sbits_s = m_bv_util.mk_numeral(sbits, sbits); sh = m_bv_util.mk_extract(ebits-1, sbits, shift); - m_simp.mk_eq(zero_s, sh, is_sh_zero); + m_simp.mk_eq(zero_ems, sh, is_sh_zero); short_shift = m_bv_util.mk_extract(sbits-1, 0, shift); m_simp.mk_ite(is_sh_zero, short_shift, sbits_s, sl); denormal_sig = m_bv_util.mk_bv_shl(denormal_sig, sl); From 3bea00efe3dc3d62a4cf16077cb7e825ad123ea1 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Wed, 13 Jul 2016 15:35:29 +0100 Subject: [PATCH 082/536] added smt_params trace --- src/smt/smt_quantifier.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/smt/smt_quantifier.cpp b/src/smt/smt_quantifier.cpp index ad2c25e63..a5e15a201 100644 --- a/src/smt/smt_quantifier.cpp +++ b/src/smt/smt_quantifier.cpp @@ -147,6 +147,7 @@ namespace smt { } m_qi_queue.init_search_eh(); m_plugin->init_search_eh(); + TRACE("smt_params", m_params.display(tout); ); } void assign_eh(quantifier * q) { From a21d701fa1066d34d906b06d0bcd2f5b8d975f0f Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Wed, 13 Jul 2016 15:36:21 +0100 Subject: [PATCH 083/536] tabs --- src/tactic/ufbv/ufbv_tactic.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/tactic/ufbv/ufbv_tactic.cpp b/src/tactic/ufbv/ufbv_tactic.cpp index 9d16d7f9a..b5a4ca3a3 100644 --- a/src/tactic/ufbv/ufbv_tactic.cpp +++ b/src/tactic/ufbv/ufbv_tactic.cpp @@ -40,12 +40,12 @@ tactic * mk_ufbv_preprocessor_tactic(ast_manager & m, params_ref const & p) { no_elim_and.set_bool("elim_and", false); return and_then( - mk_trace_tactic("ufbv_pre"), + mk_trace_tactic("ufbv_pre"), and_then(mk_simplify_tactic(m, p), mk_propagate_values_tactic(m, p), and_then(using_params(mk_macro_finder_tactic(m, no_elim_and), no_elim_and), - mk_simplify_tactic(m, p)), - and_then(mk_snf_tactic(m, p), mk_simplify_tactic(m, p)), + mk_simplify_tactic(m, p)), + and_then(mk_snf_tactic(m, p), mk_simplify_tactic(m, p)), mk_elim_and_tactic(m, p), mk_solve_eqs_tactic(m, p), and_then(mk_der_fp_tactic(m, p), mk_simplify_tactic(m, p)), @@ -56,7 +56,7 @@ tactic * mk_ufbv_preprocessor_tactic(ast_manager & m, params_ref const & p) { and_then(mk_quasi_macros_tactic(m, p), mk_simplify_tactic(m, p)), and_then(mk_der_fp_tactic(m, p), mk_simplify_tactic(m, p)), mk_simplify_tactic(m, p)), - mk_trace_tactic("ufbv_post")); + mk_trace_tactic("ufbv_post")); } tactic * mk_ufbv_tactic(ast_manager & m, params_ref const & p) { From 9f99482f076c8c1b9a9f006b7225a9e824ce7534 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 13 Jul 2016 10:29:31 -0700 Subject: [PATCH 084/536] fix model generation for cos/sin transformation. Issue #680 Signed-off-by: Nikolaj Bjorner --- src/tactic/arith/purify_arith_tactic.cpp | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/tactic/arith/purify_arith_tactic.cpp b/src/tactic/arith/purify_arith_tactic.cpp index f41eb017b..9e06a42d1 100644 --- a/src/tactic/arith/purify_arith_tactic.cpp +++ b/src/tactic/arith/purify_arith_tactic.cpp @@ -170,8 +170,8 @@ struct purify_arith_proc { } std::pair pair; if (!m_sin_cos.find(to_app(theta), pair)) { - pair.first = m().mk_fresh_const(0, m_util.mk_real()); - pair.second = m().mk_fresh_const(0, m_util.mk_real()); + pair.first = m().mk_fresh_const(0, u().mk_real()); + pair.second = m().mk_fresh_const(0, u().mk_real()); m_sin_cos.insert(to_app(theta), pair); m_pinned.push_back(pair.first); m_pinned.push_back(pair.second); @@ -680,6 +680,8 @@ struct purify_arith_proc { } }; + expr * mk_real_zero() { return u().mk_numeral(rational(0), false); } + struct rw : public rewriter_tpl { rw_cfg m_cfg; rw(purify_arith_proc & o): @@ -779,13 +781,15 @@ struct purify_arith_proc { mc = concat(mc.get(), emc); obj_map >::iterator it = m_sin_cos.begin(), end = m_sin_cos.end(); for (; it != end; ++it) { - emc->insert(it->m_key->get_decl(), m_util.mk_asin(it->m_value.first)); + emc->insert(it->m_key->get_decl(), + u().mk_add(u().mk_asin(it->m_value.first), + m().mk_ite(u().mk_ge(it->m_value.second, mk_real_zero()), mk_real_zero(), u().mk_pi()))); } } - // given values for x, y find value for theta - // x, y are rational } + + }; class purify_arith_tactic : public tactic { From 247e94a7c04dc651c4cba5d8a0b214f37435492b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 13 Jul 2016 10:34:12 -0700 Subject: [PATCH 085/536] fix model generation for cos/sin transformation. Issue #680 Signed-off-by: Nikolaj Bjorner --- src/tactic/arith/purify_arith_tactic.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tactic/arith/purify_arith_tactic.cpp b/src/tactic/arith/purify_arith_tactic.cpp index 9e06a42d1..346153adb 100644 --- a/src/tactic/arith/purify_arith_tactic.cpp +++ b/src/tactic/arith/purify_arith_tactic.cpp @@ -782,8 +782,8 @@ struct purify_arith_proc { obj_map >::iterator it = m_sin_cos.begin(), end = m_sin_cos.end(); for (; it != end; ++it) { emc->insert(it->m_key->get_decl(), - u().mk_add(u().mk_asin(it->m_value.first), - m().mk_ite(u().mk_ge(it->m_value.second, mk_real_zero()), mk_real_zero(), u().mk_pi()))); + u().mk_add(u().mk_acos(it->m_value.second), + m().mk_ite(u().mk_ge(it->m_value.first, mk_real_zero()), mk_real_zero(), u().mk_pi()))); } } From 3a70b6aab46ef640be396b3c2a74a718389d380f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 13 Jul 2016 11:12:27 -0700 Subject: [PATCH 086/536] fix model generation, add rewrite rules for sin(acos(x)) reduction to help model validation. Issue #680 Signed-off-by: Nikolaj Bjorner --- src/ast/arith_decl_plugin.h | 14 ++++++++++++-- src/ast/rewriter/arith_rewriter.cpp | 19 ++++++++++++++----- src/tactic/arith/purify_arith_tactic.cpp | 4 ++-- 3 files changed, 28 insertions(+), 9 deletions(-) diff --git a/src/ast/arith_decl_plugin.h b/src/ast/arith_decl_plugin.h index 71e54c0a3..9ccf02d0d 100644 --- a/src/ast/arith_decl_plugin.h +++ b/src/ast/arith_decl_plugin.h @@ -290,6 +290,8 @@ public: bool is_asin(expr const* n) const { return is_app_of(n, m_afid, OP_ASIN); } bool is_acos(expr const* n) const { return is_app_of(n, m_afid, OP_ACOS); } bool is_atan(expr const* n) const { return is_app_of(n, m_afid, OP_ATAN); } + bool is_pi(expr * arg) { return is_app_of(arg, m_afid, OP_PI); } + bool is_e(expr * arg) { return is_app_of(arg, m_afid, OP_E); } MATCH_UNARY(is_uminus); MATCH_UNARY(is_to_real); @@ -307,8 +309,13 @@ public: MATCH_BINARY(is_idiv); MATCH_BINARY(is_power); - bool is_pi(expr * arg) { return is_app_of(arg, m_afid, OP_PI); } - bool is_e(expr * arg) { return is_app_of(arg, m_afid, OP_E); } + MATCH_UNARY(is_sin); + MATCH_UNARY(is_asin); + MATCH_UNARY(is_cos); + MATCH_UNARY(is_acos); + MATCH_UNARY(is_tan); + MATCH_UNARY(is_atan); + }; class arith_util : public arith_recognizers { @@ -355,6 +362,9 @@ public: app * mk_int(int i) { return mk_numeral(rational(i), true); } + app * mk_real(int i) { + return mk_numeral(rational(i), false); + } app * mk_le(expr * arg1, expr * arg2) const { return m_manager.mk_app(m_afid, OP_LE, arg1, arg2); } app * mk_ge(expr * arg1, expr * arg2) const { return m_manager.mk_app(m_afid, OP_GE, arg1, arg2); } app * mk_lt(expr * arg1, expr * arg2) const { return m_manager.mk_app(m_afid, OP_LT, arg1, arg2); } diff --git a/src/ast/rewriter/arith_rewriter.cpp b/src/ast/rewriter/arith_rewriter.cpp index c9a2d2379..8f8c9a2bc 100644 --- a/src/ast/rewriter/arith_rewriter.cpp +++ b/src/ast/rewriter/arith_rewriter.cpp @@ -1196,11 +1196,17 @@ expr * arith_rewriter::mk_sin_value(rational const & k) { } br_status arith_rewriter::mk_sin_core(expr * arg, expr_ref & result) { - if (is_app_of(arg, get_fid(), OP_ASIN)) { + expr * m, *x; + if (m_util.is_asin(arg, x)) { // sin(asin(x)) == x - result = to_app(arg)->get_arg(0); + result = x; return BR_DONE; } + if (m_util.is_acos(arg, x)) { + // sin(acos(x)) == sqrt(1 - x^2) + result = m_util.mk_power(m_util.mk_sub(m_util.mk_real(1), m_util.mk_mul(x,x)), m_util.mk_numeral(rational(1,2), false)); + return BR_REWRITE_FULL; + } rational k; if (is_numeral(arg, k) && k.is_zero()) { // sin(0) == 0 @@ -1214,7 +1220,6 @@ br_status arith_rewriter::mk_sin_core(expr * arg, expr_ref & result) { return BR_REWRITE_FULL; } - expr * m; if (is_pi_offset(arg, k, m)) { rational k_prime = mod(floor(k), rational(2)) + k - floor(k); SASSERT(k_prime >= rational(0) && k_prime < rational(2)); @@ -1250,11 +1255,15 @@ br_status arith_rewriter::mk_sin_core(expr * arg, expr_ref & result) { } br_status arith_rewriter::mk_cos_core(expr * arg, expr_ref & result) { - if (is_app_of(arg, get_fid(), OP_ACOS)) { + expr* x; + if (m_util.is_acos(arg, x)) { // cos(acos(x)) == x - result = to_app(arg)->get_arg(0); + result = x; return BR_DONE; } + if (m_util.is_asin(arg, x)) { + // cos(asin(x)) == ... + } rational k; if (is_numeral(arg, k) && k.is_zero()) { diff --git a/src/tactic/arith/purify_arith_tactic.cpp b/src/tactic/arith/purify_arith_tactic.cpp index 346153adb..d0891b28b 100644 --- a/src/tactic/arith/purify_arith_tactic.cpp +++ b/src/tactic/arith/purify_arith_tactic.cpp @@ -782,8 +782,8 @@ struct purify_arith_proc { obj_map >::iterator it = m_sin_cos.begin(), end = m_sin_cos.end(); for (; it != end; ++it) { emc->insert(it->m_key->get_decl(), - u().mk_add(u().mk_acos(it->m_value.second), - m().mk_ite(u().mk_ge(it->m_value.first, mk_real_zero()), mk_real_zero(), u().mk_pi()))); + m().mk_ite(u().mk_ge(it->m_value.first, mk_real_zero()), u().mk_acos(it->m_value.second), + u().mk_add(u().mk_acos(u().mk_uminus(it->m_value.second)), u().mk_pi()))); } } From 3989d238c0c42ae5218b3fd74cf305d3f3b4a0ca Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 13 Jul 2016 20:32:18 -0700 Subject: [PATCH 087/536] fix bugs exposed in #677. to_int(x) has the semantics that to_int(x) <= x, and to_int(x) is the largest integer satisfying this inequality. The encoding in purify_arith had it the other way x <= to_int(x) contrary to how to_int(x) is handled elsewhere. Another bug in theory_arith for mixed-integer linear case was also exposed. Fractional bounds on expressions of the form to_int(x), and more generally on integer rows were not rounded prior to internalization Signed-off-by: Nikolaj Bjorner --- src/ast/macros/macro_finder.cpp | 17 ++++++-------- src/ast/macros/macro_finder.h | 2 +- src/ast/macros/macro_util.cpp | 30 +++++++++++++++++------- src/ast/macros/macro_util.h | 11 +++++---- src/nlsat/tactic/nlsat_tactic.cpp | 18 ++++++++++++-- src/smt/theory_arith_core.h | 27 ++++++++++++++------- src/smt/theory_arith_int.h | 4 ++-- src/tactic/arith/purify_arith_tactic.cpp | 9 ++++--- 8 files changed, 78 insertions(+), 40 deletions(-) diff --git a/src/ast/macros/macro_finder.cpp b/src/ast/macros/macro_finder.cpp index 35cb5891f..e43adee02 100644 --- a/src/ast/macros/macro_finder.cpp +++ b/src/ast/macros/macro_finder.cpp @@ -22,13 +22,13 @@ Revision History: #include"ast_pp.h" #include"ast_ll_pp.h" -bool macro_finder::is_macro(expr * n, app * & head, expr * & def) { +bool macro_finder::is_macro(expr * n, app_ref & head, expr_ref & def) { if (!is_quantifier(n) || !to_quantifier(n)->is_forall()) return false; TRACE("macro_finder", tout << "processing: " << mk_pp(n, m_manager) << "\n";); expr * body = to_quantifier(n)->get_expr(); unsigned num_decls = to_quantifier(n)->get_num_decls(); - return m_util.is_simple_macro(body, num_decls, head, def); + return m_util.is_ite_macro(body, num_decls, head, def); } /** @@ -171,23 +171,20 @@ bool macro_finder::expand_macros(unsigned num, expr * const * exprs, proof * con for (unsigned i = 0; i < num; i++) { expr * n = exprs[i]; proof * pr = m_manager.proofs_enabled() ? prs[i] : 0; - expr_ref new_n(m_manager); + expr_ref new_n(m_manager), def(m_manager); proof_ref new_pr(m_manager); m_macro_manager.expand_macros(n, pr, new_n, new_pr); - app * head = 0; - expr * def = 0; - app * t = 0; + app_ref head(m_manager), t(m_manager); if (is_macro(new_n, head, def) && m_macro_manager.insert(head->get_decl(), to_quantifier(new_n.get()), new_pr)) { - TRACE("macro_finder_found", tout << "found new macro: " << head->get_decl()->get_name() << "\n" << mk_pp(new_n, m_manager) << "\n";); + TRACE("macro_finder_found", tout << "found new macro: " << head->get_decl()->get_name() << "\n" << new_n << "\n";); found_new_macro = true; } else if (is_arith_macro(new_n, new_pr, new_exprs, new_prs)) { - TRACE("macro_finder_found", tout << "found new arith macro:\n" << mk_pp(new_n, m_manager) << "\n";); + TRACE("macro_finder_found", tout << "found new arith macro:\n" << new_n << "\n";); found_new_macro = true; } else if (m_util.is_pseudo_predicate_macro(new_n, head, t, def)) { - TRACE("macro_finder_found", tout << "found new pseudo macro:\n" << mk_pp(head, m_manager) << "\n" << mk_pp(t, m_manager) << "\n" << - mk_pp(def, m_manager) << "\n";); + TRACE("macro_finder_found", tout << "found new pseudo macro:\n" << head << "\n" << t << "\n" << def << "\n";); pseudo_predicate_macro2macro(m_manager, head, t, def, to_quantifier(new_n), new_pr, new_exprs, new_prs); found_new_macro = true; } diff --git a/src/ast/macros/macro_finder.h b/src/ast/macros/macro_finder.h index 541ec80b7..04ec11939 100644 --- a/src/ast/macros/macro_finder.h +++ b/src/ast/macros/macro_finder.h @@ -41,7 +41,7 @@ class macro_finder { bool expand_macros(unsigned num, expr * const * exprs, proof * const * prs, expr_ref_vector & new_exprs, proof_ref_vector & new_prs); bool is_arith_macro(expr * n, proof * pr, expr_ref_vector & new_exprs, proof_ref_vector & new_prs); - bool is_macro(expr * n, app * & head, expr * & def); + bool is_macro(expr * n, app_ref & head, expr_ref & def); bool is_pseudo_head(expr * n, unsigned num_decls, app * & head, app * & t); bool is_pseudo_predicate_macro(expr * n, app * & head, app * & t, expr * & def); diff --git a/src/ast/macros/macro_util.cpp b/src/ast/macros/macro_util.cpp index de55de632..4fb8b3db6 100644 --- a/src/ast/macros/macro_util.cpp +++ b/src/ast/macros/macro_util.cpp @@ -176,7 +176,7 @@ bool macro_util::is_macro_head(expr * n, unsigned num_decls) const { def will contain t */ -bool macro_util::is_left_simple_macro(expr * n, unsigned num_decls, app * & head, expr * & def) const { +bool macro_util::is_left_simple_macro(expr * n, unsigned num_decls, app_ref & head, expr_ref & def) const { if (m_manager.is_eq(n) || m_manager.is_iff(n)) { expr * lhs = to_app(n)->get_arg(0); expr * rhs = to_app(n)->get_arg(1); @@ -189,6 +189,22 @@ bool macro_util::is_left_simple_macro(expr * n, unsigned num_decls, app * & head return false; } +bool macro_util::is_ite_macro(expr * n, unsigned num_decls, app_ref& head, expr_ref& def) const { + if (is_simple_macro(n, num_decls, head, def)) { + return true; + } + expr* c, *t, *e; + expr_ref def1(m_manager), def2(m_manager); + app_ref head2(m_manager); + if (m_manager.is_ite(n, c, t, e) && + is_ite_macro(t, num_decls, head, def1) && + is_ite_macro(e, num_decls, head2, def2) && head == head2) { + def = m_manager.mk_ite(c, def1, def2); + return true; + } + return false; +} + /** \brief Return true if n is of the form @@ -206,7 +222,7 @@ bool macro_util::is_left_simple_macro(expr * n, unsigned num_decls, app * & head def will contain t */ -bool macro_util::is_right_simple_macro(expr * n, unsigned num_decls, app * & head, expr * & def) const { +bool macro_util::is_right_simple_macro(expr * n, unsigned num_decls, app_ref & head, expr_ref & def) const { if (m_manager.is_eq(n) || m_manager.is_iff(n)) { expr * lhs = to_app(n)->get_arg(0); expr * rhs = to_app(n)->get_arg(1); @@ -302,7 +318,7 @@ bool macro_util::is_arith_macro(expr * n, unsigned num_decls, app_ref & head, ex /** \brief Auxiliary function for is_pseudo_predicate_macro. It detects the pattern (= (f X) t) */ -bool macro_util::is_pseudo_head(expr * n, unsigned num_decls, app * & head, app * & t) { +bool macro_util::is_pseudo_head(expr * n, unsigned num_decls, app_ref & head, app_ref & t) { if (!m_manager.is_eq(n)) return false; expr * lhs = to_app(n)->get_arg(0); @@ -332,7 +348,7 @@ bool macro_util::is_pseudo_head(expr * n, unsigned num_decls, app * & head, app \brief Returns true if n if of the form (forall (X) (iff (= (f X) t) def[X])) where t is a ground term, (f X) is the head. */ -bool macro_util::is_pseudo_predicate_macro(expr * n, app * & head, app * & t, expr * & def) { +bool macro_util::is_pseudo_predicate_macro(expr * n, app_ref & head, app_ref & t, expr_ref & def) { if (!is_quantifier(n) || !to_quantifier(n)->is_forall()) return false; TRACE("macro_util", tout << "processing: " << mk_pp(n, m_manager) << "\n";); @@ -870,9 +886,8 @@ void macro_util::collect_arith_macro_candidates(expr * atom, unsigned num_decls, THEN M'(atom) = true */ void macro_util::collect_macro_candidates_core(expr * atom, unsigned num_decls, macro_candidates & r) { - if (m_manager.is_eq(atom) || m_manager.is_iff(atom)) { - expr * lhs = to_app(atom)->get_arg(0); - expr * rhs = to_app(atom)->get_arg(1); + expr* lhs, *rhs; + if (m_manager.is_eq(atom, lhs, rhs) || m_manager.is_iff(atom, lhs, rhs)) { if (is_quasi_macro_head(lhs, num_decls) && !is_forbidden(to_app(lhs)->get_decl()) && !occurs(to_app(lhs)->get_decl(), rhs) && @@ -884,7 +899,6 @@ void macro_util::collect_macro_candidates_core(expr * atom, unsigned num_decls, else if (is_hint_atom(lhs, rhs)) { insert_quasi_macro(to_app(lhs), num_decls, rhs, 0, false, true, true, r); } - if (is_quasi_macro_head(rhs, num_decls) && !is_forbidden(to_app(rhs)->get_decl()) && diff --git a/src/ast/macros/macro_util.h b/src/ast/macros/macro_util.h index 2a1581162..bb1b4777b 100644 --- a/src/ast/macros/macro_util.h +++ b/src/ast/macros/macro_util.h @@ -102,11 +102,12 @@ public: basic_simplifier_plugin * get_basic_simp() const; bool is_macro_head(expr * n, unsigned num_decls) const; - bool is_left_simple_macro(expr * n, unsigned num_decls, app * & head, expr * & def) const; - bool is_right_simple_macro(expr * n, unsigned num_decls, app * & head, expr * & def) const; - bool is_simple_macro(expr * n, unsigned num_decls, app * & head, expr * & def) const { + bool is_left_simple_macro(expr * n, unsigned num_decls, app_ref & head, expr_ref & def) const; + bool is_right_simple_macro(expr * n, unsigned num_decls, app_ref & head, expr_ref & def) const; + bool is_simple_macro(expr * n, unsigned num_decls, app_ref& head, expr_ref & def) const { return is_left_simple_macro(n, num_decls, head, def) || is_right_simple_macro(n, num_decls, head, def); } + bool is_ite_macro(expr * n, unsigned num_decls, app_ref& head, expr_ref& def) const; bool is_arith_macro(expr * n, unsigned num_decls, app_ref & head, expr_ref & def, bool & inv) const; bool is_arith_macro(expr * n, unsigned num_decls, app_ref & head, expr_ref & def) const { @@ -114,8 +115,8 @@ public: return is_arith_macro(n, num_decls, head, def, inv); } - bool is_pseudo_head(expr * n, unsigned num_decls, app * & head, app * & t); - bool is_pseudo_predicate_macro(expr * n, app * & head, app * & t, expr * & def); + bool is_pseudo_head(expr * n, unsigned num_decls, app_ref & head, app_ref & t); + bool is_pseudo_predicate_macro(expr * n, app_ref & head, app_ref & t, expr_ref & def); bool is_quasi_macro_head(expr * n, unsigned num_decls) const; void quasi_macro_head_to_macro_head(app * qhead, unsigned num_decls, app_ref & head, expr_ref & cond) const; diff --git a/src/nlsat/tactic/nlsat_tactic.cpp b/src/nlsat/tactic/nlsat_tactic.cpp index a4d65d30b..14b2a6d32 100644 --- a/src/nlsat/tactic/nlsat_tactic.cpp +++ b/src/nlsat/tactic/nlsat_tactic.cpp @@ -25,6 +25,7 @@ Notes: #include"ast_smt2_pp.h" #include"z3_exception.h" #include"algebraic_numbers.h" +#include"ast_pp.h" class nlsat_tactic : public tactic { struct expr_display_var_proc : public nlsat::display_var_proc { @@ -78,9 +79,21 @@ class nlsat_tactic : public tactic { } return false; } + + bool eval_model(model& model, goal& g) { + unsigned sz = g.size(); + for (unsigned i = 0; i < sz; i++) { + expr_ref val(m); + if (model.eval(g.form(i), val) && !m.is_true(val)) { + TRACE("nlsat", tout << mk_pp(g.form(i), m) << " -> " << val << "\n";); + return false; + } + } + return true; + } // Return false if nlsat assigned noninteger value to an integer variable. - bool mk_model(expr_ref_vector & b2a, expr_ref_vector & x2t, model_converter_ref & mc) { + bool mk_model(goal & g, expr_ref_vector & b2a, expr_ref_vector & x2t, model_converter_ref & mc) { bool ok = true; model_ref md = alloc(model, m); arith_util util(m); @@ -110,6 +123,7 @@ class nlsat_tactic : public tactic { continue; // don't care md->register_decl(to_app(a)->get_decl(), val == l_true ? m.mk_true() : m.mk_false()); } + DEBUG_CODE(eval_model(*md.get(), g);); mc = model2model_converter(md.get()); return ok; } @@ -151,7 +165,7 @@ class nlsat_tactic : public tactic { if (!contains_unsupported(b2a, x2t)) { // If mk_model is false it means that the model produced by nlsat // assigns noninteger values to integer variables - if (mk_model(b2a, x2t, mc)) { + if (mk_model(*g.get(), b2a, x2t, mc)) { // result goal is trivially SAT g->reset(); } diff --git a/src/smt/theory_arith_core.h b/src/smt/theory_arith_core.h index 8e7765ee9..07d30222b 100644 --- a/src/smt/theory_arith_core.h +++ b/src/smt/theory_arith_core.h @@ -1235,6 +1235,14 @@ namespace smt { ctx.set_var_theory(bv, get_id()); rational _k; VERIFY(m_util.is_numeral(rhs, _k)); + if (is_int(v) && !_k.is_int()) { + if (kind == A_UPPER) { + _k = floor(_k); + } + else { + _k = ceil(_k); + } + } inf_numeral k(_k); atom * a = alloc(atom, bv, v, k, kind); mk_bound_axioms(a); @@ -1399,22 +1407,22 @@ namespace smt { final_check_status result = FC_DONE; final_check_status ok; do { - TRACE("final_check_arith", tout << "m_final_check_idx: " << m_final_check_idx << ", result: " << result << "\n";); + TRACE("arith", tout << "m_final_check_idx: " << m_final_check_idx << ", result: " << result << "\n";); switch (m_final_check_idx) { case 0: ok = check_int_feasibility(); - TRACE("final_check_arith", tout << "check_int_feasibility(), ok: " << ok << "\n";); + TRACE("arith", tout << "check_int_feasibility(), ok: " << ok << "\n";); break; case 1: if (assume_eqs_core()) ok = FC_CONTINUE; else ok = FC_DONE; - TRACE("final_check_arith", tout << "assume_eqs(), ok: " << ok << "\n";); + TRACE("arith", tout << "assume_eqs(), ok: " << ok << "\n";); break; default: ok = process_non_linear(); - TRACE("final_check_arith", tout << "non_linear(), ok: " << ok << "\n";); + TRACE("arith", tout << "non_linear(), ok: " << ok << "\n";); break; } m_final_check_idx = (m_final_check_idx + 1) % 3; @@ -1425,7 +1433,7 @@ namespace smt { result = FC_GIVEUP; break; case FC_CONTINUE: - TRACE("final_check_arith", + TRACE("arith", tout << "continue arith..." << (get_context().inconsistent()?"inconsistent\n":"\n");); return FC_CONTINUE; @@ -1442,7 +1450,7 @@ namespace smt { template final_check_status theory_arith::final_check_eh() { TRACE("arith_eq_adapter_info", m_arith_eq_adapter.display_already_processed(tout);); - TRACE("arith_final_check", display(tout);); + TRACE("arith", display(tout);); if (!propagate_core()) return FC_CONTINUE; @@ -1459,7 +1467,7 @@ namespace smt { m_liberal_final_check = false; m_changed_assignment = false; result = final_check_core(); - TRACE("final_check_arith", tout << "result: " << result << "\n";); + TRACE("arith", tout << "result: " << result << "\n";); return result; } @@ -2416,6 +2424,7 @@ namespace smt { theory_var v = b->get_var(); inf_numeral const & k = b->get_value(); + TRACE("arith", display_bound(tout, b); tout << "v" << v << " <= " << k << "\n";); bound * u = upper(v); bound * l = lower(v); @@ -2456,7 +2465,7 @@ namespace smt { template bool theory_arith::assert_bound(bound * b) { - TRACE("assert_bound", display_bound(tout, b);); + TRACE("assert_bound", display_bound(tout, b); display(tout);); theory_var v = b->get_var(); if (b->is_atom()) { @@ -2478,7 +2487,7 @@ namespace smt { break; } - TRACE("arith_assert", tout << "result: " << result << "\n"; display(tout);); + TRACE("arith_bound", tout << "result: " << result << "\n"; display(tout);); return result; } diff --git a/src/smt/theory_arith_int.h b/src/smt/theory_arith_int.h index 72e1f1bc2..d3b1f0f10 100644 --- a/src/smt/theory_arith_int.h +++ b/src/smt/theory_arith_int.h @@ -1267,11 +1267,11 @@ namespace smt { final_check_status theory_arith::check_int_feasibility() { TRACE("arith_int_detail", get_context().display(tout);); if (!has_infeasible_int_var()) { - TRACE("arith_int_incomp", tout << "FC_DONE 1...\n"; display(tout);); + TRACE("arith", tout << "FC_DONE 1...\n"; display(tout);); return FC_DONE; } - TRACE("arith_int_fracs", + TRACE("arith", int num = get_num_vars(); for (theory_var v = 0; v < num; v++) { if (is_int(v) && !get_value(v).is_int()) { diff --git a/src/tactic/arith/purify_arith_tactic.cpp b/src/tactic/arith/purify_arith_tactic.cpp index f41eb017b..95cea5138 100644 --- a/src/tactic/arith/purify_arith_tactic.cpp +++ b/src/tactic/arith/purify_arith_tactic.cpp @@ -378,12 +378,13 @@ struct purify_arith_proc { cache_result(t, result, result_pr); expr * x = args[0]; - // to-real(k) - x >= 0 - expr * diff = u().mk_add(u().mk_to_real(k), u().mk_mul(u().mk_numeral(rational(-1), false), x)); + // x - to-real(k) >= 0 + + expr * diff = u().mk_add(x, u().mk_mul(u().mk_numeral(rational(-1), false), u().mk_to_real(k))); push_cnstr(u().mk_ge(diff, mk_real_zero())); push_cnstr_pr(result_pr); - // not(to-real(k) - x >= 1) + // not(x - to-real(k) >= 1) push_cnstr(NOT(u().mk_ge(diff, u().mk_numeral(rational(1), false)))); push_cnstr_pr(result_pr); } @@ -757,6 +758,7 @@ struct purify_arith_proc { // add cnstraints sz = r.cfg().m_new_cnstrs.size(); + TRACE("purify_arith", tout << r.cfg().m_new_cnstrs << "\n";); for (unsigned i = 0; i < sz; i++) { m_goal.assert_expr(r.cfg().m_new_cnstrs.get(i), m_produce_proofs ? r.cfg().m_new_cnstr_prs.get(i) : 0, 0); } @@ -827,6 +829,7 @@ public: SASSERT(g->is_well_sorted()); mc = 0; pc = 0; core = 0; tactic_report report("purify-arith", *g); + TRACE("purify_arith", g->display(tout);); bool produce_proofs = g->proofs_enabled(); bool produce_models = g->models_enabled(); bool elim_root_objs = m_params.get_bool("elim_root_objects", true); From b080e3a216b7127d36be5562f46a00ab4f25e65e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 13 Jul 2016 22:26:21 -0700 Subject: [PATCH 088/536] garbage collect all api::object references when calling del_context. Request issue #679 Signed-off-by: Nikolaj Bjorner --- src/api/api_algebraic.cpp | 2 +- src/api/api_ast.cpp | 2 +- src/api/api_ast_map.cpp | 4 ++-- src/api/api_ast_map.h | 2 +- src/api/api_ast_vector.cpp | 4 ++-- src/api/api_ast_vector.h | 6 +++++- src/api/api_context.cpp | 30 ++++++++++++++++++++++++++++++ src/api/api_context.h | 6 ++++++ src/api/api_datalog.cpp | 12 ++++++------ src/api/api_datalog.h | 3 ++- src/api/api_goal.cpp | 4 ++-- src/api/api_goal.h | 1 + src/api/api_interp.cpp | 6 +++--- src/api/api_model.cpp | 6 +++--- src/api/api_model.h | 6 +++--- src/api/api_opt.cpp | 10 +++++----- src/api/api_params.cpp | 2 +- src/api/api_polynomial.cpp | 2 +- src/api/api_solver.cpp | 20 ++++++++++---------- src/api/api_solver.h | 2 +- src/api/api_stats.h | 1 + src/api/api_tactic.cpp | 14 +++++++------- src/api/api_tactic.h | 9 ++++++++- src/api/api_util.h | 13 ++++++++++--- src/util/hashtable.h | 4 +++- 25 files changed, 115 insertions(+), 56 deletions(-) diff --git a/src/api/api_algebraic.cpp b/src/api/api_algebraic.cpp index bee39aa2a..2e14a1bd8 100644 --- a/src/api/api_algebraic.cpp +++ b/src/api/api_algebraic.cpp @@ -378,7 +378,7 @@ extern "C" { vector_var2anum v2a(as); _am.isolate_roots(_p, v2a, roots); } - Z3_ast_vector_ref* result = alloc(Z3_ast_vector_ref, mk_c(c)->m()); + Z3_ast_vector_ref* result = alloc(Z3_ast_vector_ref, *mk_c(c), mk_c(c)->m()); mk_c(c)->save_object(result); for (unsigned i = 0; i < roots.size(); i++) { result->m_ast_vector.push_back(au(c).mk_numeral(roots.get(i), false)); diff --git a/src/api/api_ast.cpp b/src/api/api_ast.cpp index cfe082802..9955cbc8f 100644 --- a/src/api/api_ast.cpp +++ b/src/api/api_ast.cpp @@ -721,7 +721,7 @@ extern "C" { Z3_TRY; LOG_Z3_simplify_get_param_descrs(c); RESET_ERROR_CODE(); - Z3_param_descrs_ref * d = alloc(Z3_param_descrs_ref); + Z3_param_descrs_ref * d = alloc(Z3_param_descrs_ref, *mk_c(c)); mk_c(c)->save_object(d); th_rewriter::get_param_descrs(d->m_descrs); Z3_param_descrs r = of_param_descrs(d); diff --git a/src/api/api_ast_map.cpp b/src/api/api_ast_map.cpp index d9e08ec3e..aa52faa98 100644 --- a/src/api/api_ast_map.cpp +++ b/src/api/api_ast_map.cpp @@ -34,7 +34,7 @@ extern "C" { Z3_TRY; LOG_Z3_mk_ast_map(c); RESET_ERROR_CODE(); - Z3_ast_map_ref * m = alloc(Z3_ast_map_ref, mk_c(c)->m()); + Z3_ast_map_ref * m = alloc(Z3_ast_map_ref, *mk_c(c), mk_c(c)->m()); mk_c(c)->save_object(m); Z3_ast_map r = of_ast_map(m); RETURN_Z3(r); @@ -137,7 +137,7 @@ extern "C" { Z3_TRY; LOG_Z3_ast_map_keys(c, m); RESET_ERROR_CODE(); - Z3_ast_vector_ref * v = alloc(Z3_ast_vector_ref, to_ast_map(m)->m); + Z3_ast_vector_ref * v = alloc(Z3_ast_vector_ref, *mk_c(c), to_ast_map(m)->m); mk_c(c)->save_object(v); obj_map::iterator it = to_ast_map_ref(m).begin(); obj_map::iterator end = to_ast_map_ref(m).end(); diff --git a/src/api/api_ast_map.h b/src/api/api_ast_map.h index 8e4f24623..dc1cf90ad 100644 --- a/src/api/api_ast_map.h +++ b/src/api/api_ast_map.h @@ -24,7 +24,7 @@ Revision History: struct Z3_ast_map_ref : public api::object { ast_manager & m; obj_map m_map; - Z3_ast_map_ref(ast_manager & _m):m(_m) {} + Z3_ast_map_ref(api::context& c, ast_manager & _m): api::object(c), m(_m) {} virtual ~Z3_ast_map_ref(); }; diff --git a/src/api/api_ast_vector.cpp b/src/api/api_ast_vector.cpp index e1d4d78ff..5a1d974c1 100644 --- a/src/api/api_ast_vector.cpp +++ b/src/api/api_ast_vector.cpp @@ -29,7 +29,7 @@ extern "C" { Z3_TRY; LOG_Z3_mk_ast_vector(c); RESET_ERROR_CODE(); - Z3_ast_vector_ref * v = alloc(Z3_ast_vector_ref, mk_c(c)->m()); + Z3_ast_vector_ref * v = alloc(Z3_ast_vector_ref, *mk_c(c), mk_c(c)->m()); mk_c(c)->save_object(v); Z3_ast_vector r = of_ast_vector(v); RETURN_Z3(r); @@ -111,7 +111,7 @@ extern "C" { RETURN_Z3(0); } ast_translation translator(mk_c(c)->m(), mk_c(t)->m()); - Z3_ast_vector_ref * new_v = alloc(Z3_ast_vector_ref, mk_c(t)->m()); + Z3_ast_vector_ref * new_v = alloc(Z3_ast_vector_ref, *mk_c(c), mk_c(t)->m()); mk_c(t)->save_object(new_v); unsigned sz = to_ast_vector_ref(v).size(); for (unsigned i = 0; i < sz; i++) { diff --git a/src/api/api_ast_vector.h b/src/api/api_ast_vector.h index 20efa21c5..4fcf8ffb8 100644 --- a/src/api/api_ast_vector.h +++ b/src/api/api_ast_vector.h @@ -20,9 +20,13 @@ Revision History: #include"api_util.h" +namespace api { + class context; +}; + struct Z3_ast_vector_ref : public api::object { ast_ref_vector m_ast_vector; - Z3_ast_vector_ref(ast_manager & m):m_ast_vector(m) {} + Z3_ast_vector_ref(api::context& c, ast_manager & m): api::object(c), m_ast_vector(m) {} virtual ~Z3_ast_vector_ref() {} }; diff --git a/src/api/api_context.cpp b/src/api/api_context.cpp index ceccff939..43c95ecdd 100644 --- a/src/api/api_context.cpp +++ b/src/api/api_context.cpp @@ -32,6 +32,28 @@ void install_tactics(tactic_manager & ctx); namespace api { + object::object(context& c): m_ref_count(0), m_context(c) { this->m_id = m_context.add_object(this); } + + void object::inc_ref() { m_ref_count++; } + + void object::dec_ref() { SASSERT(m_ref_count > 0); m_ref_count--; if (m_ref_count == 0) m_context.del_object(this); } + + unsigned context::add_object(api::object* o) { + unsigned id = m_allocated_objects.size(); + if (!m_free_object_ids.empty()) { + id = m_free_object_ids.back(); + m_free_object_ids.pop_back(); + } + m_allocated_objects.insert(id, o); + return id; + } + + void context::del_object(api::object* o) { + m_free_object_ids.push_back(o->id()); + m_allocated_objects.remove(o->id()); + dealloc(o); + } + static void default_error_handler(Z3_context ctx, Z3_error_code c) { printf("Error: %s\n", Z3_get_error_msg(ctx, c)); exit(1); @@ -106,6 +128,14 @@ namespace api { context::~context() { reset_parser(); + m_last_obj = 0; + u_map::iterator it = m_allocated_objects.begin(); + while (it != m_allocated_objects.end()) { + //warning_msg("Junk: %d", it->m_key); + m_allocated_objects.remove(it->m_key); + dealloc(it->m_value); + it = m_allocated_objects.begin(); + } } void context::interrupt() { diff --git a/src/api/api_context.h b/src/api/api_context.h index fa6754120..7cba15c44 100644 --- a/src/api/api_context.h +++ b/src/api/api_context.h @@ -35,6 +35,7 @@ Revision History: #include"tactic_manager.h" #include"context_params.h" #include"api_polynomial.h" +#include"hashtable.h" namespace smtlib { class parser; @@ -69,6 +70,8 @@ namespace api { ast_ref_vector m_ast_trail; //!< used when m_user_ref_count == false ref m_last_obj; //!< reference to the last API object returned by the APIs + u_map m_allocated_objects; // !< table containing current set of allocated API objects + unsigned_vector m_free_object_ids; // !< free list of identifiers available for allocated objects. family_id m_basic_fid; family_id m_array_fid; @@ -141,6 +144,9 @@ namespace api { // Sign an error if solver is searching void check_searching(); + unsigned add_object(api::object* o); + void del_object(api::object* o); + Z3_ast_print_mode get_print_mode() const { return m_print_mode; } void set_print_mode(Z3_ast_print_mode m) { m_print_mode = m; } diff --git a/src/api/api_datalog.cpp b/src/api/api_datalog.cpp index be9f5894f..903fedd0f 100644 --- a/src/api/api_datalog.cpp +++ b/src/api/api_datalog.cpp @@ -223,7 +223,7 @@ extern "C" { Z3_TRY; LOG_Z3_mk_fixedpoint(c); RESET_ERROR_CODE(); - Z3_fixedpoint_ref * d = alloc(Z3_fixedpoint_ref); + Z3_fixedpoint_ref * d = alloc(Z3_fixedpoint_ref, *mk_c(c)); d->m_datalog = alloc(api::fixedpoint_context, mk_c(c)->m(), mk_c(c)->fparams()); mk_c(c)->save_object(d); Z3_fixedpoint r = of_datalog(d); @@ -369,7 +369,7 @@ extern "C" { return 0; } - Z3_ast_vector_ref* v = alloc(Z3_ast_vector_ref, m); + Z3_ast_vector_ref* v = alloc(Z3_ast_vector_ref, *mk_c(c), m); mk_c(c)->save_object(v); for (unsigned i = 0; i < coll.m_queries.size(); ++i) { v->m_ast_vector.push_back(coll.m_queries[i].get()); @@ -421,7 +421,7 @@ extern "C" { Z3_TRY; LOG_Z3_fixedpoint_get_statistics(c, d); RESET_ERROR_CODE(); - Z3_stats_ref * st = alloc(Z3_stats_ref); + Z3_stats_ref * st = alloc(Z3_stats_ref, (*mk_c(c))); to_fixedpoint_ref(d)->ctx().collect_statistics(st->m_stats); mk_c(c)->save_object(st); Z3_stats r = of_stats(st); @@ -460,7 +460,7 @@ extern "C" { Z3_TRY; LOG_Z3_fixedpoint_get_rules(c, d); ast_manager& m = mk_c(c)->m(); - Z3_ast_vector_ref* v = alloc(Z3_ast_vector_ref, m); + Z3_ast_vector_ref* v = alloc(Z3_ast_vector_ref, *mk_c(c), m); mk_c(c)->save_object(v); expr_ref_vector rules(m), queries(m); svector names; @@ -483,7 +483,7 @@ extern "C" { Z3_TRY; LOG_Z3_fixedpoint_get_assertions(c, d); ast_manager& m = mk_c(c)->m(); - Z3_ast_vector_ref* v = alloc(Z3_ast_vector_ref, m); + Z3_ast_vector_ref* v = alloc(Z3_ast_vector_ref, *mk_c(c), m); mk_c(c)->save_object(v); unsigned num_asserts = to_fixedpoint_ref(d)->ctx().get_num_assertions(); for (unsigned i = 0; i < num_asserts; ++i) { @@ -568,7 +568,7 @@ extern "C" { Z3_TRY; LOG_Z3_fixedpoint_get_param_descrs(c, f); RESET_ERROR_CODE(); - Z3_param_descrs_ref * d = alloc(Z3_param_descrs_ref); + Z3_param_descrs_ref * d = alloc(Z3_param_descrs_ref, *mk_c(c)); mk_c(c)->save_object(d); to_fixedpoint_ref(f)->collect_param_descrs(d->m_descrs); Z3_param_descrs r = of_param_descrs(d); diff --git a/src/api/api_datalog.h b/src/api/api_datalog.h index 8317426c1..8c095d546 100644 --- a/src/api/api_datalog.h +++ b/src/api/api_datalog.h @@ -30,13 +30,14 @@ typedef void (*reduce_assign_callback_fptr)(void*, func_decl*, unsigned, expr*co namespace api { class fixedpoint_context; + class context; }; struct Z3_fixedpoint_ref : public api::object { api::fixedpoint_context * m_datalog; params_ref m_params; - Z3_fixedpoint_ref():m_datalog(0) {} + Z3_fixedpoint_ref(api::context& c): api::object(c), m_datalog(0) {} virtual ~Z3_fixedpoint_ref() { dealloc(m_datalog); } }; diff --git a/src/api/api_goal.cpp b/src/api/api_goal.cpp index 10164f5b9..ed4816e09 100644 --- a/src/api/api_goal.cpp +++ b/src/api/api_goal.cpp @@ -32,7 +32,7 @@ extern "C" { SET_ERROR_CODE(Z3_INVALID_ARG); RETURN_Z3(0); } - Z3_goal_ref * g = alloc(Z3_goal_ref); + Z3_goal_ref * g = alloc(Z3_goal_ref, *mk_c(c)); g->m_goal = alloc(goal, mk_c(c)->m(), proofs != 0, models != 0, unsat_cores != 0); mk_c(c)->save_object(g); Z3_goal r = of_goal(g); @@ -156,7 +156,7 @@ extern "C" { LOG_Z3_goal_translate(c, g, target); RESET_ERROR_CODE(); ast_translation translator(mk_c(c)->m(), mk_c(target)->m()); - Z3_goal_ref * _r = alloc(Z3_goal_ref); + Z3_goal_ref * _r = alloc(Z3_goal_ref, *mk_c(c)); _r->m_goal = to_goal_ref(g)->translate(translator); mk_c(target)->save_object(_r); Z3_goal r = of_goal(_r); diff --git a/src/api/api_goal.h b/src/api/api_goal.h index c3d4d44f2..1e47b832a 100644 --- a/src/api/api_goal.h +++ b/src/api/api_goal.h @@ -23,6 +23,7 @@ Revision History: struct Z3_goal_ref : public api::object { goal_ref m_goal; + Z3_goal_ref(api::context& c) : api::object(c) {} virtual ~Z3_goal_ref() {} }; diff --git a/src/api/api_interp.cpp b/src/api/api_interp.cpp index 1e201c5b3..b14f3db72 100644 --- a/src/api/api_interp.cpp +++ b/src/api/api_interp.cpp @@ -212,7 +212,7 @@ extern "C" { LOG_Z3_get_interpolant(c, pf, pat, p); RESET_ERROR_CODE(); - Z3_ast_vector_ref * v = alloc(Z3_ast_vector_ref, mk_c(c)->m()); + Z3_ast_vector_ref * v = alloc(Z3_ast_vector_ref, *mk_c(c), mk_c(c)->m()); mk_c(c)->save_object(v); ast *_pf = to_ast(pf); @@ -303,7 +303,7 @@ extern "C" { if (_status == l_false){ // copy result back - v = alloc(Z3_ast_vector_ref, mk_c(c)->m()); + v = alloc(Z3_ast_vector_ref, *mk_c(c), mk_c(c)->m()); mk_c(c)->save_object(v); for (unsigned i = 0; i < interp.size(); i++){ v->m_ast_vector.push_back(interp[i]); @@ -314,7 +314,7 @@ extern "C" { model_ref mr; m_solver.get()->get_model(mr); if(mr.get()){ - Z3_model_ref *tmp_val = alloc(Z3_model_ref); + Z3_model_ref *tmp_val = alloc(Z3_model_ref, *mk_c(c)); tmp_val->m_model = mr.get(); mk_c(c)->save_object(tmp_val); *model = of_model(tmp_val); diff --git a/src/api/api_model.cpp b/src/api/api_model.cpp index 10ede0922..67c0f2f08 100644 --- a/src/api/api_model.cpp +++ b/src/api/api_model.cpp @@ -86,7 +86,7 @@ extern "C" { SET_ERROR_CODE(Z3_INVALID_ARG); RETURN_Z3(0); } - Z3_func_interp_ref * fi = alloc(Z3_func_interp_ref, to_model_ref(m)); + Z3_func_interp_ref * fi = alloc(Z3_func_interp_ref, *mk_c(c), to_model_ref(m)); fi->m_func_interp = _fi; mk_c(c)->save_object(fi); RETURN_Z3(of_func_interp(fi)); @@ -192,7 +192,7 @@ extern "C" { RETURN_Z3(0); } ptr_vector const & universe = to_model_ref(m)->get_universe(to_sort(s)); - Z3_ast_vector_ref * v = alloc(Z3_ast_vector_ref, mk_c(c)->m()); + Z3_ast_vector_ref * v = alloc(Z3_ast_vector_ref, *mk_c(c), mk_c(c)->m()); mk_c(c)->save_object(v); unsigned sz = universe.size(); for (unsigned i = 0; i < sz; i++) { @@ -262,7 +262,7 @@ extern "C" { SET_ERROR_CODE(Z3_IOB); RETURN_Z3(0); } - Z3_func_entry_ref * e = alloc(Z3_func_entry_ref, to_func_interp(f)->m_model.get()); + Z3_func_entry_ref * e = alloc(Z3_func_entry_ref, *mk_c(c), to_func_interp(f)->m_model.get()); e->m_func_interp = to_func_interp_ref(f); e->m_func_entry = to_func_interp_ref(f)->get_entry(i); mk_c(c)->save_object(e); diff --git a/src/api/api_model.h b/src/api/api_model.h index 719326aaf..9a53b59bc 100644 --- a/src/api/api_model.h +++ b/src/api/api_model.h @@ -23,7 +23,7 @@ Revision History: struct Z3_model_ref : public api::object { model_ref m_model; - Z3_model_ref() {} + Z3_model_ref(api::context& c): api::object(c) {} virtual ~Z3_model_ref() {} }; @@ -34,7 +34,7 @@ inline model * to_model_ref(Z3_model s) { return to_model(s)->m_model.get(); } struct Z3_func_interp_ref : public api::object { model_ref m_model; // must have it to prevent reference to m_func_interp to be killed. func_interp * m_func_interp; - Z3_func_interp_ref(model * m):m_model(m), m_func_interp(0) {} + Z3_func_interp_ref(api::context& c, model * m): api::object(c), m_model(m), m_func_interp(0) {} virtual ~Z3_func_interp_ref() {} }; @@ -46,7 +46,7 @@ struct Z3_func_entry_ref : public api::object { model_ref m_model; // must have it to prevent reference to m_func_entry to be killed. func_interp * m_func_interp; func_entry const * m_func_entry; - Z3_func_entry_ref(model * m):m_model(m), m_func_interp(0), m_func_entry(0) {} + Z3_func_entry_ref(api::context& c, model * m):api::object(c), m_model(m), m_func_interp(0), m_func_entry(0) {} virtual ~Z3_func_entry_ref() {} }; diff --git a/src/api/api_opt.cpp b/src/api/api_opt.cpp index 87510293f..c0a311929 100644 --- a/src/api/api_opt.cpp +++ b/src/api/api_opt.cpp @@ -31,7 +31,7 @@ extern "C" { struct Z3_optimize_ref : public api::object { opt::context* m_opt; - Z3_optimize_ref():m_opt(0) {} + Z3_optimize_ref(api::context& c): api::object(c), m_opt(0) {} virtual ~Z3_optimize_ref() { dealloc(m_opt); } }; inline Z3_optimize_ref * to_optimize(Z3_optimize o) { return reinterpret_cast(o); } @@ -42,7 +42,7 @@ extern "C" { Z3_TRY; LOG_Z3_mk_optimize(c); RESET_ERROR_CODE(); - Z3_optimize_ref * o = alloc(Z3_optimize_ref); + Z3_optimize_ref * o = alloc(Z3_optimize_ref, *mk_c(c)); o->m_opt = alloc(opt::context,mk_c(c)->m()); mk_c(c)->save_object(o); RETURN_Z3(of_optimize(o)); @@ -158,7 +158,7 @@ extern "C" { RESET_ERROR_CODE(); model_ref _m; to_optimize_ptr(o)->get_model(_m); - Z3_model_ref * m_ref = alloc(Z3_model_ref); + Z3_model_ref * m_ref = alloc(Z3_model_ref, *mk_c(c)); if (_m) { m_ref->m_model = _m; } @@ -186,7 +186,7 @@ extern "C" { Z3_TRY; LOG_Z3_optimize_get_param_descrs(c, o); RESET_ERROR_CODE(); - Z3_param_descrs_ref * d = alloc(Z3_param_descrs_ref); + Z3_param_descrs_ref * d = alloc(Z3_param_descrs_ref, *mk_c(c)); mk_c(c)->save_object(d); to_optimize_ptr(o)->collect_param_descrs(d->m_descrs); Z3_param_descrs r = of_param_descrs(d); @@ -240,7 +240,7 @@ extern "C" { Z3_TRY; LOG_Z3_optimize_get_statistics(c, d); RESET_ERROR_CODE(); - Z3_stats_ref * st = alloc(Z3_stats_ref); + Z3_stats_ref * st = alloc(Z3_stats_ref, *mk_c(c)); to_optimize_ptr(d)->collect_statistics(st->m_stats); mk_c(c)->save_object(st); Z3_stats r = of_stats(st); diff --git a/src/api/api_params.cpp b/src/api/api_params.cpp index f2dab4d77..1efaffca8 100644 --- a/src/api/api_params.cpp +++ b/src/api/api_params.cpp @@ -30,7 +30,7 @@ extern "C" { Z3_TRY; LOG_Z3_mk_params(c); RESET_ERROR_CODE(); - Z3_params_ref * p = alloc(Z3_params_ref); + Z3_params_ref * p = alloc(Z3_params_ref, *mk_c(c)); mk_c(c)->save_object(p); Z3_params r = of_params(p); RETURN_Z3(r); diff --git a/src/api/api_polynomial.cpp b/src/api/api_polynomial.cpp index c68427960..979d2ea50 100644 --- a/src/api/api_polynomial.cpp +++ b/src/api/api_polynomial.cpp @@ -53,7 +53,7 @@ extern "C" { SET_ERROR_CODE(Z3_INVALID_ARG); return 0; } - Z3_ast_vector_ref* result = alloc(Z3_ast_vector_ref, mk_c(c)->m()); + Z3_ast_vector_ref* result = alloc(Z3_ast_vector_ref, *mk_c(c), mk_c(c)->m()); mk_c(c)->save_object(result); if (converter.is_var(to_expr(x))) { expr2var const & mapping = converter.get_mapping(); diff --git a/src/api/api_solver.cpp b/src/api/api_solver.cpp index be03e5daf..06bba37fc 100644 --- a/src/api/api_solver.cpp +++ b/src/api/api_solver.cpp @@ -58,7 +58,7 @@ extern "C" { Z3_TRY; LOG_Z3_mk_simple_solver(c); RESET_ERROR_CODE(); - Z3_solver_ref * s = alloc(Z3_solver_ref, mk_smt_solver_factory()); + Z3_solver_ref * s = alloc(Z3_solver_ref, *mk_c(c), mk_smt_solver_factory()); mk_c(c)->save_object(s); Z3_solver r = of_solver(s); RETURN_Z3(r); @@ -69,7 +69,7 @@ extern "C" { Z3_TRY; LOG_Z3_mk_solver(c); RESET_ERROR_CODE(); - Z3_solver_ref * s = alloc(Z3_solver_ref, mk_smt_strategic_solver_factory()); + Z3_solver_ref * s = alloc(Z3_solver_ref, *mk_c(c), mk_smt_strategic_solver_factory()); mk_c(c)->save_object(s); Z3_solver r = of_solver(s); RETURN_Z3(r); @@ -80,7 +80,7 @@ extern "C" { Z3_TRY; LOG_Z3_mk_solver_for_logic(c, logic); RESET_ERROR_CODE(); - Z3_solver_ref * s = alloc(Z3_solver_ref, mk_smt_strategic_solver_factory(to_symbol(logic))); + Z3_solver_ref * s = alloc(Z3_solver_ref, *mk_c(c), mk_smt_strategic_solver_factory(to_symbol(logic))); mk_c(c)->save_object(s); Z3_solver r = of_solver(s); RETURN_Z3(r); @@ -91,7 +91,7 @@ extern "C" { Z3_TRY; LOG_Z3_mk_solver_from_tactic(c, t); RESET_ERROR_CODE(); - Z3_solver_ref * s = alloc(Z3_solver_ref, mk_tactic2solver_factory(to_tactic_ref(t))); + Z3_solver_ref * s = alloc(Z3_solver_ref, *mk_c(c), mk_tactic2solver_factory(to_tactic_ref(t))); mk_c(c)->save_object(s); Z3_solver r = of_solver(s); RETURN_Z3(r); @@ -103,7 +103,7 @@ extern "C" { LOG_Z3_solver_translate(c, s, target); RESET_ERROR_CODE(); params_ref const& p = to_solver(s)->m_params; - Z3_solver_ref * sr = alloc(Z3_solver_ref, 0); + Z3_solver_ref * sr = alloc(Z3_solver_ref, *mk_c(c), 0); init_solver(c, s); sr->m_solver = to_solver(s)->m_solver->translate(mk_c(target)->m(), p); mk_c(target)->save_object(sr); @@ -134,7 +134,7 @@ extern "C" { Z3_TRY; LOG_Z3_solver_get_param_descrs(c, s); RESET_ERROR_CODE(); - Z3_param_descrs_ref * d = alloc(Z3_param_descrs_ref); + Z3_param_descrs_ref * d = alloc(Z3_param_descrs_ref, *mk_c(c)); mk_c(c)->save_object(d); bool initialized = to_solver(s)->m_solver.get() != 0; if (!initialized) @@ -255,7 +255,7 @@ extern "C" { LOG_Z3_solver_get_assertions(c, s); RESET_ERROR_CODE(); init_solver(c, s); - Z3_ast_vector_ref * v = alloc(Z3_ast_vector_ref, mk_c(c)->m()); + Z3_ast_vector_ref * v = alloc(Z3_ast_vector_ref, *mk_c(c), mk_c(c)->m()); mk_c(c)->save_object(v); unsigned sz = to_solver_ref(s)->get_num_assertions(); for (unsigned i = 0; i < sz; i++) { @@ -323,7 +323,7 @@ extern "C" { SET_ERROR_CODE(Z3_INVALID_USAGE); RETURN_Z3(0); } - Z3_model_ref * m_ref = alloc(Z3_model_ref); + Z3_model_ref * m_ref = alloc(Z3_model_ref, *mk_c(c)); m_ref->m_model = _m; mk_c(c)->save_object(m_ref); RETURN_Z3(of_model(m_ref)); @@ -352,7 +352,7 @@ extern "C" { init_solver(c, s); ptr_vector core; to_solver_ref(s)->get_unsat_core(core); - Z3_ast_vector_ref * v = alloc(Z3_ast_vector_ref, mk_c(c)->m()); + Z3_ast_vector_ref * v = alloc(Z3_ast_vector_ref, *mk_c(c), mk_c(c)->m()); mk_c(c)->save_object(v); for (unsigned i = 0; i < core.size(); i++) { v->m_ast_vector.push_back(core[i]); @@ -375,7 +375,7 @@ extern "C" { LOG_Z3_solver_get_statistics(c, s); RESET_ERROR_CODE(); init_solver(c, s); - Z3_stats_ref * st = alloc(Z3_stats_ref); + Z3_stats_ref * st = alloc(Z3_stats_ref, *mk_c(c)); to_solver_ref(s)->collect_statistics(st->m_stats); get_memory_statistics(st->m_stats); get_rlimit_statistics(mk_c(c)->m().limit(), st->m_stats); diff --git a/src/api/api_solver.h b/src/api/api_solver.h index 5ed7a15f7..ea59ccf33 100644 --- a/src/api/api_solver.h +++ b/src/api/api_solver.h @@ -26,7 +26,7 @@ struct Z3_solver_ref : public api::object { ref m_solver; params_ref m_params; symbol m_logic; - Z3_solver_ref(solver_factory * f):m_solver_factory(f), m_solver(0), m_logic(symbol::null) {} + Z3_solver_ref(api::context& c, solver_factory * f): api::object(c), m_solver_factory(f), m_solver(0), m_logic(symbol::null) {} virtual ~Z3_solver_ref() {} }; diff --git a/src/api/api_stats.h b/src/api/api_stats.h index e0e370336..1c0c0c82e 100644 --- a/src/api/api_stats.h +++ b/src/api/api_stats.h @@ -23,6 +23,7 @@ Revision History: struct Z3_stats_ref : public api::object { statistics m_stats; + Z3_stats_ref(api::context& c): api::object(c) {} virtual ~Z3_stats_ref() {} }; diff --git a/src/api/api_tactic.cpp b/src/api/api_tactic.cpp index 78e042528..7068619c1 100644 --- a/src/api/api_tactic.cpp +++ b/src/api/api_tactic.cpp @@ -25,13 +25,13 @@ Revision History: #include"cancel_eh.h" #include"scoped_timer.h" -Z3_apply_result_ref::Z3_apply_result_ref(ast_manager & m):m_core(m) { +Z3_apply_result_ref::Z3_apply_result_ref(api::context& c, ast_manager & m): api::object(c), m_core(m) { } extern "C" { #define RETURN_TACTIC(_t_) { \ - Z3_tactic_ref * _ref_ = alloc(Z3_tactic_ref); \ + Z3_tactic_ref * _ref_ = alloc(Z3_tactic_ref, *mk_c(c)); \ _ref_->m_tactic = _t_; \ mk_c(c)->save_object(_ref_); \ Z3_tactic _result_ = of_tactic(_ref_); \ @@ -39,7 +39,7 @@ extern "C" { } #define RETURN_PROBE(_t_) { \ - Z3_probe_ref * _ref_ = alloc(Z3_probe_ref); \ + Z3_probe_ref * _ref_ = alloc(Z3_probe_ref, *mk_c(c)); \ _ref_->m_probe = _t_; \ mk_c(c)->save_object(_ref_); \ Z3_probe _result_ = of_probe(_ref_); \ @@ -367,7 +367,7 @@ extern "C" { Z3_TRY; LOG_Z3_tactic_get_param_descrs(c, t); RESET_ERROR_CODE(); - Z3_param_descrs_ref * d = alloc(Z3_param_descrs_ref); + Z3_param_descrs_ref * d = alloc(Z3_param_descrs_ref, *mk_c(c)); mk_c(c)->save_object(d); to_tactic_ref(t)->collect_param_descrs(d->m_descrs); Z3_param_descrs r = of_param_descrs(d); @@ -404,7 +404,7 @@ extern "C" { static Z3_apply_result _tactic_apply(Z3_context c, Z3_tactic t, Z3_goal g, params_ref p) { goal_ref new_goal; new_goal = alloc(goal, *to_goal_ref(g)); - Z3_apply_result_ref * ref = alloc(Z3_apply_result_ref, mk_c(c)->m()); + Z3_apply_result_ref * ref = alloc(Z3_apply_result_ref, (*mk_c(c)), mk_c(c)->m()); mk_c(c)->save_object(ref); unsigned timeout = p.get_uint("timeout", UINT_MAX); @@ -505,7 +505,7 @@ extern "C" { SET_ERROR_CODE(Z3_IOB); RETURN_Z3(0); } - Z3_goal_ref * g = alloc(Z3_goal_ref); + Z3_goal_ref * g = alloc(Z3_goal_ref, *mk_c(c)); g->m_goal = to_apply_result(r)->m_subgoals[i]; mk_c(c)->save_object(g); Z3_goal result = of_goal(g); @@ -524,7 +524,7 @@ extern "C" { model_ref new_m = to_model_ref(m)->copy(); if (to_apply_result(r)->m_mc) to_apply_result(r)->m_mc->operator()(new_m, i); - Z3_model_ref * m_ref = alloc(Z3_model_ref); + Z3_model_ref * m_ref = alloc(Z3_model_ref, *mk_c(c)); m_ref->m_model = new_m; mk_c(c)->save_object(m_ref); RETURN_Z3(of_model(m_ref)); diff --git a/src/api/api_tactic.h b/src/api/api_tactic.h index 6f8d83fd9..373b85b39 100644 --- a/src/api/api_tactic.h +++ b/src/api/api_tactic.h @@ -21,13 +21,20 @@ Revision History: #include"api_goal.h" #include"tactical.h" +namespace api { + class context; +} + + struct Z3_tactic_ref : public api::object { tactic_ref m_tactic; + Z3_tactic_ref(api::context& c): api::object(c) {} virtual ~Z3_tactic_ref() {} }; struct Z3_probe_ref : public api::object { probe_ref m_probe; + Z3_probe_ref(api::context& c):api::object(c) {} virtual ~Z3_probe_ref() {} }; @@ -44,7 +51,7 @@ struct Z3_apply_result_ref : public api::object { model_converter_ref m_mc; proof_converter_ref m_pc; expr_dependency_ref m_core; - Z3_apply_result_ref(ast_manager & m); + Z3_apply_result_ref(api::context& c, ast_manager & m); virtual ~Z3_apply_result_ref() {} }; diff --git a/src/api/api_util.h b/src/api/api_util.h index 3b7baeac0..7857e7c38 100644 --- a/src/api/api_util.h +++ b/src/api/api_util.h @@ -31,15 +31,20 @@ Revision History: #define CHECK_REF_COUNT(a) (reinterpret_cast(a)->get_ref_count() > 0) namespace api { + class context; + // Generic wrapper for ref-count objects exposed by the API class object { unsigned m_ref_count; + unsigned m_id; + context& m_context; public: - object():m_ref_count(0) {} + object(context& c); virtual ~object() {} unsigned ref_count() const { return m_ref_count; } - void inc_ref() { m_ref_count++; } - void dec_ref() { SASSERT(m_ref_count > 0); m_ref_count--; if (m_ref_count == 0) dealloc(this); } + unsigned id() const { return m_id; } + void inc_ref(); + void dec_ref(); }; }; @@ -82,6 +87,7 @@ inline lbool to_lbool(Z3_lbool b) { return static_cast(b); } struct Z3_params_ref : public api::object { params_ref m_params; + Z3_params_ref(api::context& c): api::object(c) {} virtual ~Z3_params_ref() {} }; @@ -91,6 +97,7 @@ inline params_ref to_param_ref(Z3_params p) { return p == 0 ? params_ref() : to_ struct Z3_param_descrs_ref : public api::object { param_descrs m_descrs; + Z3_param_descrs_ref(api::context& c): api::object(c) {} virtual ~Z3_param_descrs_ref() {} }; diff --git a/src/util/hashtable.h b/src/util/hashtable.h index fbf36242b..ddf40f39f 100644 --- a/src/util/hashtable.h +++ b/src/util/hashtable.h @@ -645,7 +645,6 @@ public: ptr_addr_hashtable(unsigned initial_capacity = DEFAULT_HASHTABLE_INITIAL_CAPACITY): core_hashtable, ptr_hash, ptr_eq >(initial_capacity) {} - // Using iterators to traverse the elements of this kind of hashtable will produce non-determinism. iterator begin() const { UNREACHABLE(); } @@ -653,6 +652,9 @@ public: iterator end() const { UNREACHABLE(); } + + // NB. Using iterators to traverse the elements of this kind of hashtable will produce non-determinism. + }; /** From 4720d578a4e70decfab8afb5c49b008f1ca4a01d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 14 Jul 2016 09:05:16 -0700 Subject: [PATCH 089/536] add proper garbage collection to ast_manager. Issue #679 Signed-off-by: Nikolaj Bjorner --- src/ast/ast.cpp | 70 ++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 55 insertions(+), 15 deletions(-) diff --git a/src/ast/ast.cpp b/src/ast/ast.cpp index 4e505f977..f15039b9e 100644 --- a/src/ast/ast.cpp +++ b/src/ast/ast.cpp @@ -1386,6 +1386,14 @@ void ast_manager::init() { inc_ref(m_false); } +template +static void mark_array_ref(ast_mark& mark, unsigned sz, T * const * a) { + for(unsigned i = 0; i < sz; i++) { + mark.mark(a[i], true); + } +} + + ast_manager::~ast_manager() { SASSERT(is_format_manager() || !m_family_manager.has_family(symbol("format"))); @@ -1405,26 +1413,58 @@ ast_manager::~ast_manager() { if (*it) dealloc(*it); } - DEBUG_CODE({ - if (!m_ast_table.empty()) - std::cout << "ast_manager LEAKED: " << m_ast_table.size() << std::endl; - }); -#if 1 - DEBUG_CODE({ + while (!m_ast_table.empty()) { + DEBUG_CODE(std::cout << "ast_manager LEAKED: " << m_ast_table.size() << std::endl;); + ptr_vector roots; + ast_mark mark; ast_table::iterator it_a = m_ast_table.begin(); ast_table::iterator end_a = m_ast_table.end(); for (; it_a != end_a; ++it_a) { - ast* a = (*it_a); - std::cout << "Leaked: "; - if (is_sort(a)) { - std::cout << to_sort(a)->get_name() << "\n"; - } - else { - std::cout << mk_ll_pp(a, *this, false) << "id: " << a->get_id() << "\n"; + ast* n = (*it_a); + switch (n->get_kind()) { + case AST_SORT: + break; + case AST_FUNC_DECL: + mark_array_ref(mark, to_func_decl(n)->get_arity(), to_func_decl(n)->get_domain()); + mark.mark(to_func_decl(n)->get_range(), true); + break; + case AST_APP: + mark.mark(to_app(n)->get_decl(), true); + mark_array_ref(mark, to_app(n)->get_num_args(), to_app(n)->get_args()); + break; + case AST_VAR: + mark.mark(to_var(n)->get_sort(), true); + break; + case AST_QUANTIFIER: + mark_array_ref(mark, to_quantifier(n)->get_num_decls(), to_quantifier(n)->get_decl_sorts()); + mark.mark(to_quantifier(n)->get_expr(), true); + mark_array_ref(mark, to_quantifier(n)->get_num_patterns(), to_quantifier(n)->get_patterns()); + mark_array_ref(mark, to_quantifier(n)->get_num_no_patterns(), to_quantifier(n)->get_no_patterns()); + break; + } + } + it_a = m_ast_table.begin(); + for (; it_a != end_a; ++it_a) { + ast* n = *it_a; + if (!mark.is_marked(n)) { + roots.push_back(n); } + } + SASSERT(!roots.empty()); + for (unsigned i = 0; i < roots.size(); ++i) { + ast* a = roots[i]; + DEBUG_CODE( + std::cout << "Leaked: "; + if (is_sort(a)) { + std::cout << to_sort(a)->get_name() << "\n"; + } + else { + std::cout << mk_ll_pp(a, *this, false) << "id: " << a->get_id() << "\n"; + }); + + dec_ref(a); } - }); -#endif + } if (m_format_manager != 0) dealloc(m_format_manager); if (m_trace_stream_owner) { From 3a83788b97084321a85b82de8bf3a001fb1e1cb8 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 14 Jul 2016 09:46:09 -0700 Subject: [PATCH 090/536] remove unfinished ite-macro finder, tune ast GC to ensure nodes are roots only once Signed-off-by: Nikolaj Bjorner --- src/ast/ast.cpp | 4 ++-- src/ast/macros/macro_finder.cpp | 2 +- src/ast/macros/macro_util.cpp | 15 --------------- src/ast/macros/macro_util.h | 1 - 4 files changed, 3 insertions(+), 19 deletions(-) diff --git a/src/ast/ast.cpp b/src/ast/ast.cpp index f15039b9e..a3aebe80a 100644 --- a/src/ast/ast.cpp +++ b/src/ast/ast.cpp @@ -1461,8 +1461,8 @@ ast_manager::~ast_manager() { else { std::cout << mk_ll_pp(a, *this, false) << "id: " << a->get_id() << "\n"; }); - - dec_ref(a); + a->m_ref_count = 0; + delete_node(a); } } if (m_format_manager != 0) diff --git a/src/ast/macros/macro_finder.cpp b/src/ast/macros/macro_finder.cpp index e43adee02..ee211c44f 100644 --- a/src/ast/macros/macro_finder.cpp +++ b/src/ast/macros/macro_finder.cpp @@ -28,7 +28,7 @@ bool macro_finder::is_macro(expr * n, app_ref & head, expr_ref & def) { TRACE("macro_finder", tout << "processing: " << mk_pp(n, m_manager) << "\n";); expr * body = to_quantifier(n)->get_expr(); unsigned num_decls = to_quantifier(n)->get_num_decls(); - return m_util.is_ite_macro(body, num_decls, head, def); + return m_util.is_simple_macro(body, num_decls, head, def); } /** diff --git a/src/ast/macros/macro_util.cpp b/src/ast/macros/macro_util.cpp index 4fb8b3db6..ce8834cc7 100644 --- a/src/ast/macros/macro_util.cpp +++ b/src/ast/macros/macro_util.cpp @@ -189,21 +189,6 @@ bool macro_util::is_left_simple_macro(expr * n, unsigned num_decls, app_ref & he return false; } -bool macro_util::is_ite_macro(expr * n, unsigned num_decls, app_ref& head, expr_ref& def) const { - if (is_simple_macro(n, num_decls, head, def)) { - return true; - } - expr* c, *t, *e; - expr_ref def1(m_manager), def2(m_manager); - app_ref head2(m_manager); - if (m_manager.is_ite(n, c, t, e) && - is_ite_macro(t, num_decls, head, def1) && - is_ite_macro(e, num_decls, head2, def2) && head == head2) { - def = m_manager.mk_ite(c, def1, def2); - return true; - } - return false; -} /** \brief Return true if n is of the form diff --git a/src/ast/macros/macro_util.h b/src/ast/macros/macro_util.h index bb1b4777b..18b00c1f7 100644 --- a/src/ast/macros/macro_util.h +++ b/src/ast/macros/macro_util.h @@ -107,7 +107,6 @@ public: bool is_simple_macro(expr * n, unsigned num_decls, app_ref& head, expr_ref & def) const { return is_left_simple_macro(n, num_decls, head, def) || is_right_simple_macro(n, num_decls, head, def); } - bool is_ite_macro(expr * n, unsigned num_decls, app_ref& head, expr_ref& def) const; bool is_arith_macro(expr * n, unsigned num_decls, app_ref & head, expr_ref & def, bool & inv) const; bool is_arith_macro(expr * n, unsigned num_decls, app_ref & head, expr_ref & def) const { From 4f5b0667ef387b18d73c0cb10c4b9d19ebb09dc4 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 14 Jul 2016 12:34:18 -0700 Subject: [PATCH 091/536] fix rounding mode for pseudo-boolean constraint creation, Issue #683 Signed-off-by: Nikolaj Bjorner --- src/ast/pb_decl_plugin.cpp | 64 ++++++++++++++++++++------------------ src/ast/pb_decl_plugin.h | 3 ++ src/opt/opt_context.cpp | 7 +++-- 3 files changed, 41 insertions(+), 33 deletions(-) diff --git a/src/ast/pb_decl_plugin.cpp b/src/ast/pb_decl_plugin.cpp index f4e3fdf97..e87bc15ac 100644 --- a/src/ast/pb_decl_plugin.cpp +++ b/src/ast/pb_decl_plugin.cpp @@ -18,6 +18,7 @@ Revision History: --*/ #include "pb_decl_plugin.h" +#include "ast_util.h" pb_decl_plugin::pb_decl_plugin(): m_at_most_sym("at-most"), @@ -99,29 +100,47 @@ void pb_decl_plugin::get_op_names(svector & op_names, symbol const } } -app * pb_util::mk_le(unsigned num_args, rational const * coeffs, expr * const * args, rational const& k) { - vector params; - params.push_back(parameter(k)); +void pb_util::normalize(unsigned num_args, rational const* coeffs, rational const& k) { + rational d(1); for (unsigned i = 0; i < num_args; ++i) { - params.push_back(parameter(coeffs[i])); + d = lcm(d, denominator(coeffs[i])); + } + m_coeffs.reset(); + for (unsigned i = 0; i < num_args; ++i) { + m_coeffs.push_back(d*coeffs[i]); + } + m_k = d*k; +} + +app * pb_util::mk_le(unsigned num_args, rational const * coeffs, expr * const * args, rational const& k) { + normalize(num_args, coeffs, k); + vector params; + params.push_back(parameter(floor(m_k))); + for (unsigned i = 0; i < num_args; ++i) { + params.push_back(parameter(m_coeffs[i])); } return m.mk_app(m_fid, OP_PB_LE, params.size(), params.c_ptr(), num_args, args, m.mk_bool_sort()); } app * pb_util::mk_ge(unsigned num_args, rational const * coeffs, expr * const * args, rational const& k) { + normalize(num_args, coeffs, k); vector params; - params.push_back(parameter(k)); + params.push_back(parameter(ceil(m_k))); for (unsigned i = 0; i < num_args; ++i) { - params.push_back(parameter(coeffs[i])); + params.push_back(parameter(m_coeffs[i])); } return m.mk_app(m_fid, OP_PB_GE, params.size(), params.c_ptr(), num_args, args, m.mk_bool_sort()); } app * pb_util::mk_eq(unsigned num_args, rational const * coeffs, expr * const * args, rational const& k) { + normalize(num_args, coeffs, k); + if (!m_k.is_int()) { + return m.mk_false(); + } vector params; - params.push_back(parameter(k)); + params.push_back(parameter(m_k)); for (unsigned i = 0; i < num_args; ++i) { - params.push_back(parameter(coeffs[i])); + params.push_back(parameter(m_coeffs[i])); } return m.mk_app(m_fid, OP_PB_EQ, params.size(), params.c_ptr(), num_args, args, m.mk_bool_sort()); } @@ -132,33 +151,18 @@ app * pb_util::mk_eq(unsigned num_args, rational const * coeffs, expr * const * // <=> // a(1-x) + b(1-y) >= -k + a + b + 1 app * pb_util::mk_lt(unsigned num_args, rational const * _coeffs, expr * const * _args, rational const& _k) { - vector coeffs; - rational k(_k); + normalize(num_args, _coeffs, _k); expr_ref_vector args(m); - expr* f; - rational d(denominator(k)); for (unsigned i = 0; i < num_args; ++i) { - coeffs.push_back(_coeffs[i]); - d = lcm(d, denominator(coeffs[i])); - if (m.is_not(_args[i], f)) { - args.push_back(f); - } - else { - args.push_back(m.mk_not(_args[i])); - } + args.push_back(mk_not(m, _args[i])); } - if (!d.is_one()) { - k *= d; - for (unsigned i = 0; i < num_args; ++i) { - coeffs[i] *= d; - } - } - k.neg(); - k += rational::one(); + m_k = floor(m_k); + m_k.neg(); + m_k += rational::one(); for (unsigned i = 0; i < num_args; ++i) { - k += coeffs[i]; + m_k += m_coeffs[i]; } - return mk_ge(num_args, coeffs.c_ptr(), args.c_ptr(), k); + return mk_ge(num_args, m_coeffs.c_ptr(), args.c_ptr(), m_k); } diff --git a/src/ast/pb_decl_plugin.h b/src/ast/pb_decl_plugin.h index d4264b9b9..e1b16f0c9 100644 --- a/src/ast/pb_decl_plugin.h +++ b/src/ast/pb_decl_plugin.h @@ -79,6 +79,9 @@ public: class pb_util { ast_manager & m; family_id m_fid; + vector m_coeffs; + rational m_k; + void normalize(unsigned num_args, rational const* coeffs, rational const& k); public: pb_util(ast_manager& m):m(m), m_fid(m.mk_family_id("pb")) {} ast_manager & get_manager() const { return m; } diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 7a59c1ddb..4de602ec4 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -241,6 +241,7 @@ namespace opt { s.get_labels(m_labels); } if (is_sat != l_true) { + TRACE("opt", tout << m_hard_constraints << "\n";); return is_sat; } IF_VERBOSE(1, verbose_stream() << "(optimize:sat)\n";); @@ -415,7 +416,7 @@ namespace opt { expr_ref context::mk_gt(unsigned i, model_ref& mdl) { expr_ref result = mk_le(i, mdl); - result = m.mk_not(result); + result = mk_not(m, result); return result; } @@ -776,7 +777,7 @@ namespace opt { weights[i].neg(); } else { - terms[i] = m.mk_not(terms[i].get()); + terms[i] = mk_not(m, terms[i].get()); } } TRACE("opt", @@ -805,7 +806,7 @@ namespace opt { for (unsigned i = 0; i < weights.size(); ++i) { if (weights[i].is_neg()) { weights[i].neg(); - terms[i] = m.mk_not(terms[i].get()); + terms[i] = mk_not(m, terms[i].get()); } offset += weights[i]; } From 6f971a3a868fe7ca02036f8c027f7eae390c6720 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 15 Jul 2016 11:44:38 -0700 Subject: [PATCH 092/536] add object z3 objects to target context during translation, to fix build regression failure on z3test.py Signed-off-by: Nikolaj Bjorner --- src/api/api_ast_vector.cpp | 2 +- src/api/api_context.cpp | 2 +- src/api/api_goal.cpp | 2 +- src/api/api_solver.cpp | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/api/api_ast_vector.cpp b/src/api/api_ast_vector.cpp index 5a1d974c1..40df13708 100644 --- a/src/api/api_ast_vector.cpp +++ b/src/api/api_ast_vector.cpp @@ -111,7 +111,7 @@ extern "C" { RETURN_Z3(0); } ast_translation translator(mk_c(c)->m(), mk_c(t)->m()); - Z3_ast_vector_ref * new_v = alloc(Z3_ast_vector_ref, *mk_c(c), mk_c(t)->m()); + Z3_ast_vector_ref * new_v = alloc(Z3_ast_vector_ref, *mk_c(t), mk_c(t)->m()); mk_c(t)->save_object(new_v); unsigned sz = to_ast_vector_ref(v).size(); for (unsigned i = 0; i < sz; i++) { diff --git a/src/api/api_context.cpp b/src/api/api_context.cpp index 43c95ecdd..45ed06ae9 100644 --- a/src/api/api_context.cpp +++ b/src/api/api_context.cpp @@ -131,7 +131,7 @@ namespace api { m_last_obj = 0; u_map::iterator it = m_allocated_objects.begin(); while (it != m_allocated_objects.end()) { - //warning_msg("Junk: %d", it->m_key); + DEBUG_CODE(warning_msg("Uncollected memory: %d: %s", it->m_key, typeid(*it->m_value).name());); m_allocated_objects.remove(it->m_key); dealloc(it->m_value); it = m_allocated_objects.begin(); diff --git a/src/api/api_goal.cpp b/src/api/api_goal.cpp index ed4816e09..295e1d939 100644 --- a/src/api/api_goal.cpp +++ b/src/api/api_goal.cpp @@ -156,7 +156,7 @@ extern "C" { LOG_Z3_goal_translate(c, g, target); RESET_ERROR_CODE(); ast_translation translator(mk_c(c)->m(), mk_c(target)->m()); - Z3_goal_ref * _r = alloc(Z3_goal_ref, *mk_c(c)); + Z3_goal_ref * _r = alloc(Z3_goal_ref, *mk_c(target)); _r->m_goal = to_goal_ref(g)->translate(translator); mk_c(target)->save_object(_r); Z3_goal r = of_goal(_r); diff --git a/src/api/api_solver.cpp b/src/api/api_solver.cpp index 06bba37fc..518fa5384 100644 --- a/src/api/api_solver.cpp +++ b/src/api/api_solver.cpp @@ -103,7 +103,7 @@ extern "C" { LOG_Z3_solver_translate(c, s, target); RESET_ERROR_CODE(); params_ref const& p = to_solver(s)->m_params; - Z3_solver_ref * sr = alloc(Z3_solver_ref, *mk_c(c), 0); + Z3_solver_ref * sr = alloc(Z3_solver_ref, *mk_c(target), 0); init_solver(c, s); sr->m_solver = to_solver(s)->m_solver->translate(mk_c(target)->m(), p); mk_c(target)->save_object(sr); From f3d657ebd1d902fd89972054a263011bc8b510b5 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 15 Jul 2016 12:09:23 -0700 Subject: [PATCH 093/536] add tptp5 example to cmake, adding output SZS directives for Geoff Signed-off-by: Nikolaj Bjorner --- contrib/cmake/examples/CMakeLists.txt | 1 + examples/tptp/tptp5.cpp | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/contrib/cmake/examples/CMakeLists.txt b/contrib/cmake/examples/CMakeLists.txt index b8cecbe63..49ea72fdc 100644 --- a/contrib/cmake/examples/CMakeLists.txt +++ b/contrib/cmake/examples/CMakeLists.txt @@ -1,2 +1,3 @@ add_subdirectory(c) add_subdirectory(c++) +add_subdirectory(tptp) diff --git a/examples/tptp/tptp5.cpp b/examples/tptp/tptp5.cpp index 2773b6cc9..5f45f6c1c 100644 --- a/examples/tptp/tptp5.cpp +++ b/examples/tptp/tptp5.cpp @@ -2408,7 +2408,9 @@ static void prove_tptp() { } if (g_generate_proof) { try { + std::cout << "SZS output start Proof\n"; display_proof(ctx, fmls, solver); + std::cout << "SZS output end Proof\n"; } catch (failure_ex& ex) { std::cerr << "Proof display could not be completed: " << ex.msg << "\n"; @@ -2434,7 +2436,9 @@ static void prove_tptp() { std::cout << "SZS status Satisfiable\n"; } if (g_generate_model) { + std::cout << "SZS output start Model\n"; display_model(ctx, solver.get_model()); + std::cout << "SZS output end Model\n"; } break; case z3::unknown: From 64674386de2f956e0f1991dccee26bc85d42325e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 15 Jul 2016 13:39:50 -0700 Subject: [PATCH 094/536] fix ubuntu build failure Signed-off-by: Nikolaj Bjorner --- src/api/api_context.cpp | 1 + src/math/simplex/model_based_opt.cpp | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/api_context.cpp b/src/api/api_context.cpp index 45ed06ae9..a5804bd45 100644 --- a/src/api/api_context.cpp +++ b/src/api/api_context.cpp @@ -17,6 +17,7 @@ Author: Revision History: --*/ +#include #include"api_context.h" #include"smtparser.h" #include"version.h" diff --git a/src/math/simplex/model_based_opt.cpp b/src/math/simplex/model_based_opt.cpp index cafa6ee3a..c31eabb62 100644 --- a/src/math/simplex/model_based_opt.cpp +++ b/src/math/simplex/model_based_opt.cpp @@ -963,7 +963,6 @@ namespace opt { unsigned row_id2 = row_ids[i]; if (!visited.contains(row_id2)) { visited.insert(row_id2); - row const& r2 = m_rows[row_id2]; b = get_coefficient(row_id2, x); if (!b.is_zero()) { resolve(row_id1, a, row_id2, x); From cf48eb5f724c73acea6ee536ed2ce8eca679a415 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 17 Jul 2016 19:16:15 -0400 Subject: [PATCH 095/536] mark also ast in parameters as GC roots. Issue #676 Signed-off-by: Nikolaj Bjorner --- src/api/python/z3.py | 132 +++++++++++++++++++++++-------------------- src/ast/ast.cpp | 10 ++++ 2 files changed, 81 insertions(+), 61 deletions(-) diff --git a/src/api/python/z3.py b/src/api/python/z3.py index ff6e91c4a..ca02975f1 100644 --- a/src/api/python/z3.py +++ b/src/api/python/z3.py @@ -156,7 +156,7 @@ class Context: Z3_set_param_value(conf, str(key).upper(), _to_param_value(value)) prev = None for a in args: - if prev == None: + if prev is None: prev = a else: Z3_set_param_value(conf, str(prev), _to_param_value(a)) @@ -171,6 +171,7 @@ class Context: def __del__(self): self.lib.Z3_del_context(self.ctx) + self.ctx = None def ref(self): """Return a reference to the actual C pointer to the Z3 context.""" @@ -203,12 +204,12 @@ def main_ctx(): False """ global _main_ctx - if _main_ctx == None: + if _main_ctx is None: _main_ctx = Context() return _main_ctx def _get_ctx(ctx): - if ctx == None: + if ctx is None: return main_ctx() else: return ctx @@ -230,7 +231,7 @@ def set_param(*args, **kws): Z3_global_param_set(str(key).upper(), _to_param_value(value)) prev = None for a in args: - if prev == None: + if prev is None: prev = a else: Z3_global_param_set(str(prev), _to_param_value(a)) @@ -278,7 +279,8 @@ class AstRef(Z3PPObject): Z3_inc_ref(self.ctx.ref(), self.as_ast()) def __del__(self): - Z3_dec_ref(self.ctx.ref(), self.as_ast()) + if self.ctx.ref() is not None: + Z3_dec_ref(self.ctx.ref(), self.as_ast()) def __str__(self): return obj_to_string(self) @@ -416,12 +418,12 @@ def _ctx_from_ast_arg_list(args, default_ctx=None): ctx = None for a in args: if is_ast(a) or is_probe(a): - if ctx == None: + if ctx is None: ctx = a.ctx else: if __debug__: _z3_assert(ctx == a.ctx, "Context mismatch") - if ctx == None: + if ctx is None: ctx = default_ctx return ctx @@ -533,7 +535,7 @@ class SortRef(AstRef): >>> p.sort() == IntSort() False """ - if other == None: + if other is None: return False return Z3_is_eq_sort(self.ctx_ref(), self.ast, other.ast) @@ -806,10 +808,10 @@ class ExprRef(AstRef): >>> b = Int('b') >>> a == b a == b - >>> a == None + >>> a is None False """ - if other == None: + if other is None: return False a, b = _coerce_exprs(self, other) return BoolRef(Z3_mk_eq(self.ctx_ref(), a.as_ast(), b.as_ast()), self.ctx) @@ -827,10 +829,10 @@ class ExprRef(AstRef): >>> b = Int('b') >>> a != b a != b - >>> a != None + >>> a is not None True """ - if other == None: + if other is None: return True a, b = _coerce_exprs(self, other) _args, sz = _to_ast_array((a, b)) @@ -953,7 +955,7 @@ def _to_expr_ref(a, ctx): def _coerce_expr_merge(s, a): if is_expr(a): s1 = a.sort() - if s == None: + if s is None: return s1 if s1.eq(s): return s @@ -1169,7 +1171,7 @@ def Distinct(*args): args = _get_args(args) ctx = _ctx_from_ast_arg_list(args) if __debug__: - _z3_assert(ctx != None, "At least one of the arguments must be a Z3 expression") + _z3_assert(ctx is not None, "At least one of the arguments must be a Z3 expression") args = _coerce_expr_list(args, ctx) _args, sz = _to_ast_array(args) return BoolRef(Z3_mk_distinct(ctx.ref(), sz, _args), ctx) @@ -1547,8 +1549,8 @@ def And(*args): args = _get_args(args) ctx_args = _ctx_from_ast_arg_list(args, ctx) if __debug__: - _z3_assert(ctx_args == None or ctx_args == ctx, "context mismatch") - _z3_assert(ctx != None, "At least one of the arguments must be a Z3 expression or probe") + _z3_assert(ctx_args is None or ctx_args == ctx, "context mismatch") + _z3_assert(ctx is not None, "At least one of the arguments must be a Z3 expression or probe") if _has_probe(args): return _probe_and(args, ctx) else: @@ -1577,8 +1579,8 @@ def Or(*args): args = _get_args(args) ctx_args = _ctx_from_ast_arg_list(args, ctx) if __debug__: - _z3_assert(ctx_args == None or ctx_args == ctx, "context mismatch") - _z3_assert(ctx != None, "At least one of the arguments must be a Z3 expression or probe") + _z3_assert(ctx_args is None or ctx_args == ctx, "context mismatch") + _z3_assert(ctx is not None, "At least one of the arguments must be a Z3 expression or probe") if _has_probe(args): return _probe_or(args, ctx) else: @@ -4346,7 +4348,8 @@ class ScopedConstructor: self.c = c self.ctx = ctx def __del__(self): - Z3_del_constructor(self.ctx.ref(), self.c) + if self.ctx.ref() is not None: + Z3_del_constructor(self.ctx.ref(), self.c) class ScopedConstructorList: """Auxiliary object used to create Z3 datatypes.""" @@ -4354,7 +4357,8 @@ class ScopedConstructorList: self.c = c self.ctx = ctx def __del__(self): - Z3_del_constructor_list(self.ctx.ref(), self.c) + if self.ctx.ref() is not None: + Z3_del_constructor_list(self.ctx.ref(), self.c) def CreateDatatypes(*ds): """Create mutually recursive Z3 datatypes using 1 or more Datatype helper objects. @@ -4588,7 +4592,8 @@ class ParamsRef: Z3_params_inc_ref(self.ctx.ref(), self.params) def __del__(self): - Z3_params_dec_ref(self.ctx.ref(), self.params) + if self.ctx.ref() is not None: + Z3_params_dec_ref(self.ctx.ref(), self.params) def set(self, name, val): """Set parameter name with value val.""" @@ -4626,7 +4631,7 @@ def args2params(arguments, keywords, ctx=None): prev = None r = ParamsRef(ctx) for a in arguments: - if prev == None: + if prev is None: prev = a else: r.set(prev, a) @@ -4646,7 +4651,8 @@ class ParamDescrsRef: Z3_param_descrs_inc_ref(self.ctx.ref(), self.descr) def __del__(self): - Z3_param_descrs_dec_ref(self.ctx.ref(), self.descr) + if self.ctx.ref() is not None: + Z3_param_descrs_dec_ref(self.ctx.ref(), self.descr) def size(self): """Return the size of in the parameter description `self`. @@ -4698,15 +4704,15 @@ class Goal(Z3PPObject): def __init__(self, models=True, unsat_cores=False, proofs=False, ctx=None, goal=None): if __debug__: - _z3_assert(goal == None or ctx != None, "If goal is different from None, then ctx must be also different from None") + _z3_assert(goal is None or ctx is not None, "If goal is different from None, then ctx must be also different from None") self.ctx = _get_ctx(ctx) self.goal = goal - if self.goal == None: + if self.goal is None: self.goal = Z3_mk_goal(self.ctx.ref(), models, unsat_cores, proofs) Z3_goal_inc_ref(self.ctx.ref(), self.goal) def __del__(self): - if self.goal != None: + if self.goal is not None and self.ctx.ref() is not None: Z3_goal_dec_ref(self.ctx.ref(), self.goal) def depth(self): @@ -4958,17 +4964,17 @@ class AstVector(Z3PPObject): def __init__(self, v=None, ctx=None): self.vector = None - if v == None: + if v is None: self.ctx = _get_ctx(ctx) self.vector = Z3_mk_ast_vector(self.ctx.ref()) else: self.vector = v - assert ctx != None + assert ctx is not None self.ctx = ctx Z3_ast_vector_inc_ref(self.ctx.ref(), self.vector) def __del__(self): - if self.vector != None: + if self.vector is not None and self.ctx.ref() is not None: Z3_ast_vector_dec_ref(self.ctx.ref(), self.vector) def __len__(self): @@ -5093,17 +5099,17 @@ class AstMap: def __init__(self, m=None, ctx=None): self.map = None - if m == None: + if m is None: self.ctx = _get_ctx(ctx) self.map = Z3_mk_ast_map(self.ctx.ref()) else: self.map = m - assert ctx != None + assert ctx is not None self.ctx = ctx Z3_ast_map_inc_ref(self.ctx.ref(), self.map) def __del__(self): - if self.map != None: + if self.map is not None and self.ctx.ref() is not None: Z3_ast_map_dec_ref(self.ctx.ref(), self.map) def __len__(self): @@ -5218,7 +5224,8 @@ class FuncEntry: Z3_func_entry_inc_ref(self.ctx.ref(), self.entry) def __del__(self): - Z3_func_entry_dec_ref(self.ctx.ref(), self.entry) + if self.ctx.ref() is not None: + Z3_func_entry_dec_ref(self.ctx.ref(), self.entry) def num_args(self): """Return the number of arguments in the given entry. @@ -5319,11 +5326,11 @@ class FuncInterp(Z3PPObject): def __init__(self, f, ctx): self.f = f self.ctx = ctx - if self.f != None: + if self.f is not None: Z3_func_interp_inc_ref(self.ctx.ref(), self.f) def __del__(self): - if self.f != None: + if self.f is not None and self.ctx.ref() is not None: Z3_func_interp_dec_ref(self.ctx.ref(), self.f) def else_value(self): @@ -5427,13 +5434,14 @@ class ModelRef(Z3PPObject): """Model/Solution of a satisfiability problem (aka system of constraints).""" def __init__(self, m, ctx): - assert ctx != None + assert ctx is not None self.model = m self.ctx = ctx Z3_model_inc_ref(self.ctx.ref(), self.model) def __del__(self): - Z3_model_dec_ref(self.ctx.ref(), self.model) + if self.ctx.ref() is not None: + Z3_model_dec_ref(self.ctx.ref(), self.model) def __repr__(self): return obj_to_string(self) @@ -5708,7 +5716,8 @@ class Statistics: Z3_stats_inc_ref(self.ctx.ref(), self.stats) def __del__(self): - Z3_stats_dec_ref(self.ctx.ref(), self.stats) + if self.ctx.ref() is not None: + Z3_stats_dec_ref(self.ctx.ref(), self.stats) def __repr__(self): if in_html_mode(): @@ -5870,17 +5879,17 @@ class Solver(Z3PPObject): """Solver API provides methods for implementing the main SMT 2.0 commands: push, pop, check, get-model, etc.""" def __init__(self, solver=None, ctx=None): - assert solver == None or ctx != None + assert solver is None or ctx is not None self.ctx = _get_ctx(ctx) self.solver = None - if solver == None: + if solver is None: self.solver = Z3_mk_solver(self.ctx.ref()) else: self.solver = solver Z3_solver_inc_ref(self.ctx.ref(), self.solver) def __del__(self): - if self.solver != None: + if self.solver is not None and self.ctx.ref() is not None: Z3_solver_dec_ref(self.ctx.ref(), self.solver) def set(self, *args, **keys): @@ -6257,10 +6266,10 @@ class Fixedpoint(Z3PPObject): """Fixedpoint API provides methods for solving with recursive predicates""" def __init__(self, fixedpoint=None, ctx=None): - assert fixedpoint == None or ctx != None + assert fixedpoint is None or ctx is not None self.ctx = _get_ctx(ctx) self.fixedpoint = None - if fixedpoint == None: + if fixedpoint is None: self.fixedpoint = Z3_mk_fixedpoint(self.ctx.ref()) else: self.fixedpoint = fixedpoint @@ -6268,7 +6277,7 @@ class Fixedpoint(Z3PPObject): self.vars = [] def __del__(self): - if self.fixedpoint != None: + if self.fixedpoint is not None and self.ctx.ref() is not None: Z3_fixedpoint_dec_ref(self.ctx.ref(), self.fixedpoint) def set(self, *args, **keys): @@ -6323,10 +6332,10 @@ class Fixedpoint(Z3PPObject): >>> s.query(b) sat """ - if name == None: + if name is None: name = "" name = to_symbol(name, self.ctx) - if body == None: + if body is None: head = self.abstract(head) Z3_fixedpoint_add_rule(self.ctx.ref(), self.fixedpoint, head.as_ast(), name) else: @@ -6374,7 +6383,7 @@ class Fixedpoint(Z3PPObject): def update_rule(self, head, body, name): """update rule""" - if name == None: + if name is None: name = "" name = to_symbol(name, self.ctx) body = _get_args(body) @@ -6626,7 +6635,7 @@ class Optimize(Z3PPObject): Z3_optimize_inc_ref(self.ctx.ref(), self.optimize) def __del__(self): - if self.optimize != None: + if self.optimize is not None and self.ctx.ref() is not None: Z3_optimize_dec_ref(self.ctx.ref(), self.optimize) def set(self, *args, **keys): @@ -6668,7 +6677,7 @@ class Optimize(Z3PPObject): weight = "%d" % weight if not isinstance(weight, str): raise Z3Exception("weight should be a string or an integer") - if id == None: + if id is None: id = "" id = to_symbol(id, self.ctx) v = Z3_optimize_assert_soft(self.ctx.ref(), self.optimize, arg.as_ast(), weight, id) @@ -6746,7 +6755,8 @@ class ApplyResult(Z3PPObject): Z3_apply_result_inc_ref(self.ctx.ref(), self.result) def __del__(self): - Z3_apply_result_dec_ref(self.ctx.ref(), self.result) + if self.ctx.ref() is not None: + Z3_apply_result_dec_ref(self.ctx.ref(), self.result) def __len__(self): """Return the number of subgoals in `self`. @@ -6873,7 +6883,7 @@ class Tactic: Z3_tactic_inc_ref(self.ctx.ref(), self.tactic) def __del__(self): - if self.tactic != None: + if self.tactic is not None and self.ctx.ref() is not None: Z3_tactic_dec_ref(self.ctx.ref(), self.tactic) def solver(self): @@ -7145,7 +7155,7 @@ class Probe: Z3_probe_inc_ref(self.ctx.ref(), self.probe) def __del__(self): - if self.probe != None: + if self.probe is not None and self.ctx.ref() is not None: Z3_probe_dec_ref(self.ctx.ref(), self.probe) def __lt__(self, other): @@ -7470,7 +7480,7 @@ def Sum(*args): _z3_assert(len(args) > 0, "Non empty list of arguments expected") ctx = _ctx_from_ast_arg_list(args) if __debug__: - _z3_assert(ctx != None, "At least one of the arguments must be a Z3 expression") + _z3_assert(ctx is not None, "At least one of the arguments must be a Z3 expression") args = _coerce_expr_list(args, ctx) if is_bv(args[0]): return _reduce(lambda a, b: a + b, args, 0) @@ -7495,7 +7505,7 @@ def Product(*args): _z3_assert(len(args) > 0, "Non empty list of arguments expected") ctx = _ctx_from_ast_arg_list(args) if __debug__: - _z3_assert(ctx != None, "At least one of the arguments must be a Z3 expression") + _z3_assert(ctx is not None, "At least one of the arguments must be a Z3 expression") args = _coerce_expr_list(args, ctx) if is_bv(args[0]): return _reduce(lambda a, b: a * b, args, 1) @@ -7514,7 +7524,7 @@ def AtMost(*args): _z3_assert(len(args) > 1, "Non empty list of arguments expected") ctx = _ctx_from_ast_arg_list(args) if __debug__: - _z3_assert(ctx != None, "At least one of the arguments must be a Z3 expression") + _z3_assert(ctx is not None, "At least one of the arguments must be a Z3 expression") args1 = _coerce_expr_list(args[:-1], ctx) k = args[-1] _args, sz = _to_ast_array(args1) @@ -7532,7 +7542,7 @@ def PbLe(args, k): _z3_assert(len(args) > 0, "Non empty list of arguments expected") ctx = _ctx_from_ast_arg_list(args) if __debug__: - _z3_assert(ctx != None, "At least one of the arguments must be a Z3 expression") + _z3_assert(ctx is not None, "At least one of the arguments must be a Z3 expression") args = _coerce_expr_list(args, ctx) _args, sz = _to_ast_array(args) _coeffs = (ctypes.c_int * len(coeffs))() @@ -7822,7 +7832,7 @@ def tree_interpolant(pat,p=None,ctx=None): ctx = _get_ctx(_ctx_from_ast_arg_list([f], ctx)) ptr = (AstVectorObj * 1)() mptr = (Model * 1)() - if p == None: + if p is None: p = ParamsRef(ctx) res = Z3_compute_interpolant(ctx.ref(),f.as_ast(),p.params,ptr,mptr) if res == Z3_L_FALSE: @@ -7857,7 +7867,7 @@ def binary_interpolant(a,b,p=None,ctx=None): """ f = And(Interpolant(a),b) ti = tree_interpolant(f,p,ctx) - return ti[0] if ti != None else None + return ti[0] if ti is not None else None def sequence_interpolant(v,p=None,ctx=None): """Compute interpolant for a sequence of formulas. @@ -7951,7 +7961,7 @@ def _coerce_fp_expr_list(alist, ctx): first_fp_sort = None for a in alist: if is_fp(a): - if first_fp_sort == None: + if first_fp_sort is None: first_fp_sort = a.sort() elif first_fp_sort == a.sort(): pass # OK, same as before @@ -8561,10 +8571,10 @@ def FPVal(sig, exp=None, fps=None, ctx=None): if is_fp_sort(exp): fps = exp exp = None - elif fps == None: + elif fps is None: fps = _dflt_fps(ctx) _z3_assert(is_fp_sort(fps), "sort mismatch") - if exp == None: + if exp is None: exp = 0 val = _to_float_str(sig) if val == "NaN" or val == "nan": diff --git a/src/ast/ast.cpp b/src/ast/ast.cpp index a3aebe80a..d8a6c47bc 100644 --- a/src/ast/ast.cpp +++ b/src/ast/ast.cpp @@ -1393,6 +1393,14 @@ static void mark_array_ref(ast_mark& mark, unsigned sz, T * const * a) { } } +static void mark_array_ref(ast_mark& mark, unsigned sz, parameter const * a) { + for(unsigned i = 0; i < sz; i++) { + if (a[i].is_ast()) { + mark.mark(a[i].get_ast(), true); + } + } +} + ast_manager::~ast_manager() { SASSERT(is_format_manager() || !m_family_manager.has_family(symbol("format"))); @@ -1423,8 +1431,10 @@ ast_manager::~ast_manager() { ast* n = (*it_a); switch (n->get_kind()) { case AST_SORT: + mark_array_ref(mark, to_sort(n)->get_info()->get_num_parameters(), to_sort(n)->get_info()->get_parameters()); break; case AST_FUNC_DECL: + mark_array_ref(mark, to_func_decl(n)->get_info()->get_num_parameters(), to_func_decl(n)->get_info()->get_parameters()); mark_array_ref(mark, to_func_decl(n)->get_arity(), to_func_decl(n)->get_domain()); mark.mark(to_func_decl(n)->get_range(), true); break; From 6559fd817d168b2945cc33120cbc4f71ae927890 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 20 Jul 2016 10:53:53 -0700 Subject: [PATCH 096/536] Fix bit-blasting discrepancy. #690 Signed-off-by: Nikolaj Bjorner --- src/smt/theory_bv.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/smt/theory_bv.cpp b/src/smt/theory_bv.cpp index 2945c8c93..a53580b73 100644 --- a/src/smt/theory_bv.cpp +++ b/src/smt/theory_bv.cpp @@ -312,6 +312,7 @@ namespace smt { SASSERT(v != null_theory_var); unsigned sz = bits.size(); SASSERT(get_bv_size(n) == sz); + m_bits[v].reset(); for (unsigned i = 0; i < sz; i++) { expr * bit = bits.get(i); expr_ref s_bit(m); @@ -809,6 +810,7 @@ namespace smt { theory_var v = e->get_th_var(get_id()); unsigned num_args = n->get_num_args(); unsigned i = num_args; + m_bits[v].reset(); while (i > 0) { i--; theory_var arg = get_arg_var(e, i); @@ -830,6 +832,7 @@ namespace smt { unsigned end = n->get_decl()->get_parameter(0).get_int(); SASSERT(start <= end); literal_vector & arg_bits = m_bits[arg]; + m_bits[v].reset(); for (unsigned i = start; i <= end; ++i) add_bit(v, arg_bits[i]); find_wpos(v); @@ -1533,6 +1536,7 @@ namespace smt { } void theory_bv::unmerge_eh(theory_var v1, theory_var v2) { + // v1 was the root of the equivalence class // I must remove the zero_one_bits that are from v2. From 5f39c4371ccc692c5f369328a62abf53d7ff17ba Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 20 Jul 2016 11:54:39 -0700 Subject: [PATCH 097/536] fix proof generation for unit resolution. Issue #691 Signed-off-by: Nikolaj Bjorner --- src/ast/ast.cpp | 5 ++++- src/smt/smt_internalizer.cpp | 9 ++++----- src/smt/smt_justification.cpp | 2 ++ 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/ast/ast.cpp b/src/ast/ast.cpp index d8a6c47bc..d138685ed 100644 --- a/src/ast/ast.cpp +++ b/src/ast/ast.cpp @@ -2991,7 +2991,10 @@ proof * ast_manager::mk_unit_resolution(unsigned num_proofs, proof * const * pro for (unsigned i = 0; i < num_proofs; i++) tout << mk_pp(get_fact(proofs[i]), *this) << "\n"; tout << "===>\n"; tout << mk_pp(new_fact, *this) << "\n";); - SASSERT(num_proofs == cls_sz || (num_proofs == cls_sz + 1 && is_false(new_fact))); + // + // typically: num_proofs == cls_sz || (num_proofs == cls_sz + 1 && is_false(new_fact)) + // but formula could have repeated literals that are merged in the clausal representation. + // unsigned num_matches = 0; for (unsigned i = 0; i < cls_sz; i++) { expr * lit = cls->get_arg(i); diff --git a/src/smt/smt_internalizer.cpp b/src/smt/smt_internalizer.cpp index 45bd75ab7..a17271e4e 100644 --- a/src/smt/smt_internalizer.cpp +++ b/src/smt/smt_internalizer.cpp @@ -1045,15 +1045,13 @@ namespace smt { bool context::simplify_aux_clause_literals(unsigned & num_lits, literal * lits, literal_buffer & simp_lits) { std::sort(lits, lits + num_lits); literal prev = null_literal; - unsigned i = 0; unsigned j = 0; - for (; i < num_lits; i++) { + for (unsigned i = 0; i < num_lits; i++) { literal curr = lits[i]; lbool val = get_assignment(curr); - if (val == l_false) - simp_lits.push_back(~curr); switch(val) { case l_false: + simp_lits.push_back(~curr); break; // ignore literal case l_undef: if (curr == ~prev) @@ -1295,8 +1293,9 @@ namespace smt { SASSERT(get_assignment(simp_lits[i]) == l_true); } }); - if (old_num_lits != num_lits) + if (!simp_lits.empty()) { j = mk_justification(unit_resolution_justification(m_region, j, simp_lits.size(), simp_lits.c_ptr())); + } break; } case CLS_AUX_LEMMA: { diff --git a/src/smt/smt_justification.cpp b/src/smt/smt_justification.cpp index de3594fcc..c091f6973 100644 --- a/src/smt/smt_justification.cpp +++ b/src/smt/smt_justification.cpp @@ -52,6 +52,7 @@ namespace smt { tout << lits[i] << " "; } tout << "\n";); + SASSERT(m_num_literals > 0); } unit_resolution_justification::unit_resolution_justification(justification * js, @@ -68,6 +69,7 @@ namespace smt { tout << lits[i] << " "; } tout << "\n";); + SASSERT(num_lits != 0); } unit_resolution_justification::~unit_resolution_justification() { From fe34e8bf0034cd7e49a94b7ba2e2ac2fc4ba7447 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 20 Jul 2016 12:13:54 -0700 Subject: [PATCH 098/536] Add OP_INTERNAL to handle cases of function symbols that don't have external semantics (at least in a way that is supported by means of building terms) Issue #688 Signed-off-by: Nikolaj Bjorner --- src/api/api_ast.cpp | 28 ++++++++++------------------ src/api/z3_api.h | 4 ++++ 2 files changed, 14 insertions(+), 18 deletions(-) diff --git a/src/api/api_ast.cpp b/src/api/api_ast.cpp index 9955cbc8f..eda6831b5 100644 --- a/src/api/api_ast.cpp +++ b/src/api/api_ast.cpp @@ -964,8 +964,7 @@ extern "C" { case PR_TH_LEMMA: return Z3_OP_PR_TH_LEMMA; case PR_HYPER_RESOLVE: return Z3_OP_PR_HYPER_RESOLVE; default: - UNREACHABLE(); - return Z3_OP_UNINTERPRETED; + return Z3_OP_INTERNAL; } } if (mk_c(c)->get_arith_fid() == _d->get_family_id()) { @@ -989,8 +988,7 @@ extern "C" { case OP_TO_INT: return Z3_OP_TO_INT; case OP_IS_INT: return Z3_OP_IS_INT; default: - UNREACHABLE(); - return Z3_OP_UNINTERPRETED; + return Z3_OP_INTERNAL; } } if (mk_c(c)->get_array_fid() == _d->get_family_id()) { @@ -1008,8 +1006,7 @@ extern "C" { case OP_AS_ARRAY: return Z3_OP_AS_ARRAY; case OP_ARRAY_EXT: return Z3_OP_ARRAY_EXT; default: - UNREACHABLE(); - return Z3_OP_UNINTERPRETED; + return Z3_OP_INTERNAL; } } @@ -1075,8 +1072,7 @@ extern "C" { case OP_BUREM_I: return Z3_OP_BUREM_I; case OP_BSMOD_I: return Z3_OP_BSMOD_I; default: - UNREACHABLE(); - return Z3_OP_UNINTERPRETED; + return Z3_OP_INTERNAL; } } if (mk_c(c)->get_dt_fid() == _d->get_family_id()) { @@ -1086,8 +1082,7 @@ extern "C" { case OP_DT_ACCESSOR: return Z3_OP_DT_ACCESSOR; case OP_DT_UPDATE_FIELD: return Z3_OP_DT_UPDATE_FIELD; default: - UNREACHABLE(); - return Z3_OP_UNINTERPRETED; + return Z3_OP_INTERNAL; } } if (mk_c(c)->get_datalog_fid() == _d->get_family_id()) { @@ -1108,8 +1103,7 @@ extern "C" { case datalog::OP_DL_CONSTANT: return Z3_OP_FD_CONSTANT; case datalog::OP_DL_LT: return Z3_OP_FD_LT; default: - UNREACHABLE(); - return Z3_OP_UNINTERPRETED; + return Z3_OP_INTERNAL; } } @@ -1135,7 +1129,7 @@ extern "C" { case Z3_OP_RE_CONCAT: return Z3_OP_RE_CONCAT; case Z3_OP_RE_UNION: return Z3_OP_RE_UNION; default: - return Z3_OP_UNINTERPRETED; + return Z3_OP_INTERNAL; } } @@ -1195,8 +1189,7 @@ extern "C" { case OP_FPA_INTERNAL_TO_IEEE_BV_UNSPECIFIED: return Z3_OP_UNINTERPRETED; default: - UNREACHABLE(); - return Z3_OP_UNINTERPRETED; + return Z3_OP_INTERNAL; } } @@ -1205,8 +1198,7 @@ extern "C" { case OP_LABEL: return Z3_OP_LABEL; case OP_LABEL_LIT: return Z3_OP_LABEL_LIT; default: - UNREACHABLE(); - return Z3_OP_UNINTERPRETED; + return Z3_OP_INTERNAL; } } @@ -1215,7 +1207,7 @@ extern "C" { case OP_PB_LE: return Z3_OP_PB_LE; case OP_PB_GE: return Z3_OP_PB_GE; case OP_AT_MOST_K: return Z3_OP_PB_AT_MOST; - default: UNREACHABLE(); + default: return Z3_OP_INTERNAL; } } diff --git a/src/api/z3_api.h b/src/api/z3_api.h index 5ce2740d9..41ca923bb 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -945,6 +945,8 @@ typedef enum - Z3_OP_FPA_TO_IEEE_BV: Floating-point conversion to IEEE-754 bit-vector + - Z3_OP_INTERNAL: internal (often interpreted) symbol, but no additional information is exposed. Tools may use the string representation of the function declaration to obtain more information. + - Z3_OP_UNINTERPRETED: kind used for uninterpreted symbols. */ typedef enum { @@ -1217,6 +1219,8 @@ typedef enum { Z3_OP_FPA_MIN_I, Z3_OP_FPA_MAX_I, + Z3_OP_INTERNAL, + Z3_OP_UNINTERPRETED } Z3_decl_kind; From 60711bb0cd4365de375524a4cd7239304dfdded0 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 20 Jul 2016 12:18:07 -0700 Subject: [PATCH 099/536] deal with model construction, issue #684. fix model construction for ite #678. WIth this version, issue #686 does not repro Signed-off-by: Nikolaj Bjorner --- src/cmd_context/cmd_context.cpp | 4 +++- src/smt/theory_seq.cpp | 38 +++++++++++++++++++++++++++------ src/smt/theory_seq.h | 1 + src/smt/theory_seq_empty.h | 16 ++++++++++++++ 4 files changed, 51 insertions(+), 8 deletions(-) diff --git a/src/cmd_context/cmd_context.cpp b/src/cmd_context/cmd_context.cpp index 5f9de116d..2811153c0 100644 --- a/src/cmd_context/cmd_context.cpp +++ b/src/cmd_context/cmd_context.cpp @@ -1634,6 +1634,7 @@ void cmd_context::validate_model() { scoped_ctrl_c ctrlc(eh); ptr_vector::const_iterator it = begin_assertions(); ptr_vector::const_iterator end = end_assertions(); + bool invalid_model = false; for (; it != end; ++it) { expr * a = *it; if (is_ground(a)) { @@ -1654,9 +1655,10 @@ void cmd_context::validate_model() { continue; } TRACE("model_validate", model_smt2_pp(tout, *this, *(md.get()), 0);); - throw cmd_exception("an invalid model was generated"); + invalid_model = true; } } + throw cmd_exception("an invalid model was generated"); } } diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index 0702bac69..8b6c5baba 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -196,6 +196,7 @@ theory_seq::theory_seq(ast_manager& m): theory(m.mk_family_id("seq")), m(m), m_rep(m, m_dm), + m_reset_cache(false), m_eq_id(0), m_find(*this), m_factory(0), @@ -242,6 +243,10 @@ void theory_seq::init(context* ctx) { } final_check_status theory_seq::final_check_eh() { + if (m_reset_cache) { + m_rep.reset_cache(); + m_reset_cache = false; + } m_new_propagation = false; TRACE("seq", display(tout << "level: " << get_context().get_scope_level() << "\n");); if (simplify_and_solve_eqs()) { @@ -1366,7 +1371,7 @@ bool theory_seq::solve_unit_eq(expr* l, expr* r, dependency* deps) { bool theory_seq::occurs(expr* a, expr_ref_vector const& b) { for (unsigned i = 0; i < b.size(); ++i) { - if (a == b[i]) return true; + if (a == b[i] || m.is_ite(b[i])) return true; } return false; } @@ -1379,7 +1384,7 @@ bool theory_seq::occurs(expr* a, expr* b) { m_todo.push_back(b); while (!m_todo.empty()) { b = m_todo.back(); - if (a == b) { + if (a == b || m.is_ite(b)) { m_todo.reset(); return true; } @@ -2421,6 +2426,11 @@ 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(), mg.get_model()); mg.register_factory(m_factory); + for (unsigned j = 0; j < m_nqs.size(); ++j) { + ne const& n = m_nqs[j]; + m_factory->register_value(n.l()); + m_factory->register_value(n.r()); + } for (unsigned j = 0; j < m_nqs.size(); ++j) { ne const& n = m_nqs[j]; for (unsigned i = 0; i < n.ls().size(); ++i) { @@ -2452,6 +2462,13 @@ public: virtual void get_dependencies(buffer & result) { result.append(m_dependencies.size(), m_dependencies.c_ptr()); } + + void add_buffer(svector& sbuffer, zstring const& zs) { + for (unsigned l = 0; l < zs.length(); ++l) { + sbuffer.push_back(zs[l]); + } + } + virtual app * mk_value(model_generator & mg, ptr_vector & values) { SASSERT(values.size() == m_dependencies.size()); expr_ref_vector args(th.m); @@ -2470,12 +2487,16 @@ public: sbuffer.push_back(val.get_unsigned()); } else { + dependency* deps = 0; + expr_ref tmp = th.canonize(m_strings[k], deps); zstring zs; - if (th.m_util.str.is_string(m_strings[k++], zs)) { - for (unsigned l = 0; l < zs.length(); ++l) { - sbuffer.push_back(zs[l]); - } + if (th.m_util.str.is_string(tmp, zs)) { + add_buffer(sbuffer, zs); } + else { + TRACE("seq", tout << "Not a string: " << tmp << "\n";); + } + ++k; } } result = th.m_util.str.mk_string(zstring(sbuffer.size(), sbuffer.c_ptr())); @@ -2657,7 +2678,10 @@ expr_ref theory_seq::expand(expr* e0, dependency*& eqs) { result = expand(e3, deps); break; case l_undef: - result = e; + result = e; + m_reset_cache = true; + TRACE("seq", tout << "undef: " << result << "\n"; + tout << lit << "@ level: " << ctx.get_scope_level() << "\n";); break; } } diff --git a/src/smt/theory_seq.h b/src/smt/theory_seq.h index c1e179f67..187573623 100644 --- a/src/smt/theory_seq.h +++ b/src/smt/theory_seq.h @@ -294,6 +294,7 @@ namespace smt { ast_manager& m; dependency_manager m_dm; solution_map m_rep; // unification representative. + bool m_reset_cache; // invalidate cache. scoped_vector m_eqs; // set of current equations. scoped_vector m_nqs; // set of current disequalities. scoped_vector m_ncs; // set of non-contains constraints. diff --git a/src/smt/theory_seq_empty.h b/src/smt/theory_seq_empty.h index 27c72cc97..3f6c7f3e2 100644 --- a/src/smt/theory_seq_empty.h +++ b/src/smt/theory_seq_empty.h @@ -126,6 +126,22 @@ namespace smt { symbol sym; if (u.str.is_string(n, sym)) { m_strings.insert(sym); + if (sym.str().find(m_unique_delim) != std::string::npos) { + add_new_delim(); + } + } + } + private: + + void add_new_delim() { + bool found = true; + while (found) { + found = false; + m_unique_delim += "!"; + symbol_set::iterator it = m_strings.begin(), end = m_strings.end(); + for (; it != end && !found; ++it) { + found = it->str().find(m_unique_delim) != std::string::npos; + } } } }; From b56837e09b78179c0810a0cca46e83f34097c097 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 20 Jul 2016 13:11:22 -0700 Subject: [PATCH 100/536] fix build break: throw only on invalid model Signed-off-by: Nikolaj Bjorner --- src/cmd_context/cmd_context.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/cmd_context/cmd_context.cpp b/src/cmd_context/cmd_context.cpp index 2811153c0..153d02e42 100644 --- a/src/cmd_context/cmd_context.cpp +++ b/src/cmd_context/cmd_context.cpp @@ -1658,7 +1658,9 @@ void cmd_context::validate_model() { invalid_model = true; } } - throw cmd_exception("an invalid model was generated"); + if (invalid_model) { + throw cmd_exception("an invalid model was generated"); + } } } From f522d995d1c0d4bdb7ce4206e571b0921db44f05 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 20 Jul 2016 19:03:25 -0700 Subject: [PATCH 101/536] apply 'to-real' coercion only on integers. bug reported by Geoff Signed-off-by: Nikolaj Bjorner --- examples/tptp/tptp5.cpp | 5 +- src/opt/bcd2.cpp | 405 -------------- src/opt/bcd2.h | 28 - src/opt/fu_malik.cpp | 237 --------- src/opt/fu_malik.h | 37 -- src/opt/hitting_sets.cpp | 1088 -------------------------------------- src/opt/hitting_sets.h | 52 -- src/opt/maxhs.cpp | 556 ------------------- src/opt/maxhs.h | 29 - src/opt/maxsmt.cpp | 12 - src/opt/opt_params.pyg | 2 +- 11 files changed, 5 insertions(+), 2446 deletions(-) delete mode 100644 src/opt/bcd2.cpp delete mode 100644 src/opt/bcd2.h delete mode 100644 src/opt/fu_malik.cpp delete mode 100644 src/opt/fu_malik.h delete mode 100644 src/opt/hitting_sets.cpp delete mode 100644 src/opt/hitting_sets.h delete mode 100644 src/opt/maxhs.cpp delete mode 100644 src/opt/maxhs.h diff --git a/examples/tptp/tptp5.cpp b/examples/tptp/tptp5.cpp index 5f45f6c1c..a180d4ca9 100644 --- a/examples/tptp/tptp5.cpp +++ b/examples/tptp/tptp5.cpp @@ -828,7 +828,10 @@ class env { } else if (!strcmp(ch,"$to_real")) { check_arity(terms.size(), 1); - r = to_real(terms[0]); + r = terms[0]; + if (r.get_sort().is_int()) { + r = to_real(terms[0]); + } } else if (!strcmp(ch,"$is_int")) { check_arity(terms.size(), 1); diff --git a/src/opt/bcd2.cpp b/src/opt/bcd2.cpp deleted file mode 100644 index a373b652b..000000000 --- a/src/opt/bcd2.cpp +++ /dev/null @@ -1,405 +0,0 @@ -/*++ -Copyright (c) 2014 Microsoft Corporation - -Module Name: - - bcd2.cpp - -Abstract: - - bcd2 based MaxSAT. - -Author: - - Nikolaj Bjorner (nbjorner) 2014-4-17 - -Notes: - ---*/ -#include "bcd2.h" -#include "pb_decl_plugin.h" -#include "uint_set.h" -#include "ast_pp.h" - - -namespace opt { - // ------------------------------------------------------ - // Morgado, Heras, Marques-Silva 2013 - // (initial version without model-based optimizations) - // - class bcd2 : public maxsmt_solver_base { - struct wcore { - expr* m_r; - unsigned_vector m_R; - rational m_lower; - rational m_mid; - rational m_upper; - }; - typedef obj_hashtable expr_set; - - pb_util pb; - expr_ref_vector m_soft_aux; - obj_map m_relax2index; // expr |-> index - obj_map m_soft2index; // expr |-> index - expr_ref_vector m_trail; - expr_ref_vector m_soft_constraints; - expr_set m_asm_set; - vector m_cores; - vector m_sigmas; - rational m_den; // least common multiplier of original denominators - bool m_enable_lazy; // enable adding soft constraints lazily (called 'mgbcd2') - unsigned_vector m_lazy_soft; // soft constraints to add lazily. - - void set2asms(expr_set const& set, expr_ref_vector & es) const { - es.reset(); - expr_set::iterator it = set.begin(), end = set.end(); - for (; it != end; ++it) { - es.push_back(m.mk_not(*it)); - } - } - void bcd2_init_soft(weights_t& weights, expr_ref_vector const& soft) { - - // normalize weights to be integral: - m_den = rational::one(); - for (unsigned i = 0; i < m_weights.size(); ++i) { - m_den = lcm(m_den, denominator(m_weights[i])); - } - if (!m_den.is_one()) { - for (unsigned i = 0; i < m_weights.size(); ++i) { - m_weights[i] = m_den*m_weights[i]; - SASSERT(m_weights[i].is_int()); - } - } - } - void init_bcd() { - m_trail.reset(); - m_asm_set.reset(); - m_cores.reset(); - m_sigmas.reset(); - m_lazy_soft.reset(); - for (unsigned i = 0; i < m_soft.size(); ++i) { - m_sigmas.push_back(m_weights[i]); - m_soft_aux.push_back(mk_fresh()); - if (m_enable_lazy) { - m_lazy_soft.push_back(i); - } - else { - enable_soft_constraint(i); - } - } - m_upper += rational(1); - } - - void process_sat() { - svector assignment; - update_assignment(assignment); - if (check_lazy_soft(assignment)) { - update_sigmas(); - } - } - - public: - bcd2(maxsat_context& c, - weights_t& ws, expr_ref_vector const& soft): - maxsmt_solver_base(c, ws, soft), - pb(m), - m_soft_aux(m), - m_trail(m), - m_soft_constraints(m), - m_enable_lazy(true) { - bcd2_init_soft(ws, soft); - } - - virtual ~bcd2() {} - - virtual lbool operator()() { - expr_ref fml(m), r(m); - lbool is_sat = l_undef; - expr_ref_vector asms(m); - init(); - init_bcd(); - if (m.canceled()) { - normalize_bounds(); - return l_undef; - } - process_sat(); - while (m_lower < m_upper) { - trace_bounds("bcd2"); - assert_soft(); - solver::scoped_push _scope2(s()); - TRACE("opt", display(tout);); - assert_cores(); - set2asms(m_asm_set, asms); - if (m.canceled()) { - normalize_bounds(); - return l_undef; - } - is_sat = s().check_sat(asms.size(), asms.c_ptr()); - switch(is_sat) { - case l_undef: - normalize_bounds(); - return l_undef; - case l_true: - process_sat(); - break; - case l_false: { - ptr_vector unsat_core; - uint_set subC, soft; - s().get_unsat_core(unsat_core); - core2indices(unsat_core, subC, soft); - SASSERT(unsat_core.size() == subC.num_elems() + soft.num_elems()); - if (soft.num_elems() == 0 && subC.num_elems() == 1) { - unsigned s = *subC.begin(); - wcore& c_s = m_cores[s]; - c_s.m_lower = refine(c_s.m_R, c_s.m_mid); - c_s.m_mid = div(c_s.m_lower + c_s.m_upper, rational(2)); - } - else { - wcore c_s; - rational delta = min_of_delta(subC); - rational lower = sum_of_lower(subC); - union_Rs(subC, c_s.m_R); - r = mk_fresh(); - relax(subC, soft, c_s.m_R, delta); - c_s.m_lower = refine(c_s.m_R, lower + delta - rational(1)); - c_s.m_upper = rational::one(); - c_s.m_upper += sum_of_sigmas(c_s.m_R); - c_s.m_mid = div(c_s.m_lower + c_s.m_upper, rational(2)); - c_s.m_r = r; - m_asm_set.insert(r); - subtract(m_cores, subC); - m_relax2index.insert(r, m_cores.size()); - m_cores.push_back(c_s); - } - break; - } - } - m_lower = compute_lower(); - } - normalize_bounds(); - return l_true; - } - - - private: - - void enable_soft_constraint(unsigned i) { - expr_ref fml(m); - expr* r = m_soft_aux[i].get(); - m_soft2index.insert(r, i); - fml = m.mk_or(r, m_soft[i]); - m_soft_constraints.push_back(fml); - m_asm_set.insert(r); - SASSERT(m_weights[i].is_int()); - } - - void assert_soft() { - for (unsigned i = 0; i < m_soft_constraints.size(); ++i) { - s().assert_expr(m_soft_constraints[i].get()); - } - m_soft_constraints.reset(); - } - - bool check_lazy_soft(svector const& assignment) { - bool all_satisfied = true; - for (unsigned i = 0; i < m_lazy_soft.size(); ++i) { - unsigned j = m_lazy_soft[i]; - if (!assignment[j]) { - enable_soft_constraint(j); - m_lazy_soft[i] = m_lazy_soft.back(); - m_lazy_soft.pop_back(); - --i; - all_satisfied = false; - } - } - return all_satisfied; - } - - void normalize_bounds() { - m_lower /= m_den; - m_upper /= m_den; - } - - expr* mk_fresh() { - expr* r = mk_fresh_bool("r"); - m_trail.push_back(r); - return r; - } - - void update_assignment(svector& new_assignment) { - expr_ref val(m); - rational new_upper(0); - model_ref model; - new_assignment.reset(); - s().get_model(model); - for (unsigned i = 0; i < m_soft.size(); ++i) { - new_assignment.push_back(model->eval(m_soft[i], val) && m.is_true(val)); - if (!new_assignment[i]) { - new_upper += m_weights[i]; - } - } - if (new_upper < m_upper) { - m_upper = new_upper; - m_model = model; - m_assignment.reset(); - m_assignment.append(new_assignment); - } - } - - void update_sigmas() { - for (unsigned i = 0; i < m_cores.size(); ++i) { - wcore& c_i = m_cores[i]; - unsigned_vector const& R = c_i.m_R; - c_i.m_upper.reset(); - for (unsigned j = 0; j < R.size(); ++j) { - unsigned r_j = R[j]; - if (!m_assignment[r_j]) { - c_i.m_upper += m_weights[r_j]; - m_sigmas[r_j] = m_weights[r_j]; - } - else { - m_sigmas[r_j].reset(); - } - } - c_i.m_mid = div(c_i.m_lower + c_i.m_upper, rational(2)); - } - } - - /** - * Minimum of two (positive) numbers. Zero is treated as +infinity. - */ - rational min_z(rational const& a, rational const& b) { - if (a.is_zero()) return b; - if (b.is_zero()) return a; - if (a < b) return a; - return b; - } - - rational min_of_delta(uint_set const& subC) { - rational delta(0); - for (uint_set::iterator it = subC.begin(); it != subC.end(); ++it) { - unsigned j = *it; - wcore const& core = m_cores[j]; - rational new_delta = rational(1) + core.m_upper - core.m_mid; - SASSERT(new_delta.is_pos()); - delta = min_z(delta, new_delta); - } - return delta; - } - - rational sum_of_lower(uint_set const& subC) { - rational lower(0); - for (uint_set::iterator it = subC.begin(); it != subC.end(); ++it) { - lower += m_cores[*it].m_lower; - } - return lower; - } - - rational sum_of_sigmas(unsigned_vector const& R) { - rational sum(0); - for (unsigned i = 0; i < R.size(); ++i) { - sum += m_sigmas[R[i]]; - } - return sum; - } - void union_Rs(uint_set const& subC, unsigned_vector& R) { - for (uint_set::iterator it = subC.begin(); it != subC.end(); ++it) { - R.append(m_cores[*it].m_R); - } - } - rational compute_lower() { - rational result(0); - for (unsigned i = 0; i < m_cores.size(); ++i) { - result += m_cores[i].m_lower; - } - return result; - } - void subtract(vector& cores, uint_set const& subC) { - unsigned j = 0; - for (unsigned i = 0; i < cores.size(); ++i) { - if (subC.contains(i)) { - m_asm_set.remove(cores[i].m_r); - } - else { - if (j != i) { - cores[j] = cores[i]; - } - ++j; - } - } - cores.resize(j); - for (unsigned i = 0; i < cores.size(); ++i) { - m_relax2index.insert(cores[i].m_r, i); - } - } - void core2indices(ptr_vector const& core, uint_set& subC, uint_set& soft) { - for (unsigned i = 0; i < core.size(); ++i) { - unsigned j; - expr* a; - VERIFY(m.is_not(core[i], a)); - if (m_relax2index.find(a, j)) { - subC.insert(j); - } - else { - VERIFY(m_soft2index.find(a, j)); - soft.insert(j); - } - } - } - rational refine(unsigned_vector const& idx, rational v) { - return v + rational(1); - } - void relax(uint_set& subC, uint_set& soft, unsigned_vector& R, rational& delta) { - for (uint_set::iterator it = soft.begin(); it != soft.end(); ++it) { - R.push_back(*it); - delta = min_z(delta, m_weights[*it]); - m_asm_set.remove(m_soft_aux[*it].get()); - } - } - void assert_cores() { - for (unsigned i = 0; i < m_cores.size(); ++i) { - assert_core(m_cores[i]); - } - } - void assert_core(wcore const& core) { - expr_ref fml(m); - vector ws; - ptr_vector rs; - rational w(0); - for (unsigned j = 0; j < core.m_R.size(); ++j) { - unsigned idx = core.m_R[j]; - ws.push_back(m_weights[idx]); - w += ws.back(); - rs.push_back(m_soft_aux[idx].get()); - } - w.neg(); - w += core.m_mid; - ws.push_back(w); - rs.push_back(core.m_r); - fml = pb.mk_le(ws.size(), ws.c_ptr(), rs.c_ptr(), core.m_mid); - s().assert_expr(fml); - } - void display(std::ostream& out) { - out << "[" << m_lower << ":" << m_upper << "]\n"; - s().display(out); - out << "\n"; - for (unsigned i = 0; i < m_cores.size(); ++i) { - wcore const& c = m_cores[i]; - out << mk_pp(c.m_r, m) << ": "; - for (unsigned j = 0; j < c.m_R.size(); ++j) { - out << c.m_R[j] << " (" << m_sigmas[c.m_R[j]] << ") "; - } - out << "[" << c.m_lower << ":" << c.m_mid << ":" << c.m_upper << "]\n"; - } - for (unsigned i = 0; i < m_soft.size(); ++i) { - out << mk_pp(m_soft[i], m) << " " << m_weights[i] << "\n"; - } - } - }; - - maxsmt_solver_base* mk_bcd2( - maxsat_context& c, weights_t& ws, expr_ref_vector const& soft) { - return alloc(bcd2, c, ws, soft); - } - -} diff --git a/src/opt/bcd2.h b/src/opt/bcd2.h deleted file mode 100644 index 50b7215e3..000000000 --- a/src/opt/bcd2.h +++ /dev/null @@ -1,28 +0,0 @@ -/*++ -Copyright (c) 2014 Microsoft Corporation - -Module Name: - - bcd2.h - -Abstract: - - Bcd2 based MaxSAT. - -Author: - - Nikolaj Bjorner (nbjorner) 2014-4-17 - -Notes: - ---*/ - -#ifndef BCD2_H_ -#define BCD2_H_ - -#include "maxsmt.h" - -namespace opt { - maxsmt_solver_base* mk_bcd2(maxsat_context& c, weights_t& ws, expr_ref_vector const& soft); -} -#endif diff --git a/src/opt/fu_malik.cpp b/src/opt/fu_malik.cpp deleted file mode 100644 index 48ef50cbc..000000000 --- a/src/opt/fu_malik.cpp +++ /dev/null @@ -1,237 +0,0 @@ -/*++ -Copyright (c) 2013 Microsoft Corporation - -Module Name: - - fu_malik.cpp - -Abstract: - Fu & Malik built-in optimization method. - Adapted from sample code in C. - -Author: - - Anh-Dung Phan (t-anphan) 2013-10-15 - -Notes: - ---*/ - -#include "fu_malik.h" -#include "qfbv_tactic.h" -#include "tactic2solver.h" -#include "goal.h" -#include "probe.h" -#include "tactic.h" -#include "ast_pp.h" -#include "model_smt2_pp.h" -#include "opt_context.h" - -/** - \brief Fu & Malik procedure for MaxSAT. This procedure is based on - unsat core extraction and the at-most-one constraint. - - Return the number of soft-constraints that can be - satisfied. Return -1 if the hard-constraints cannot be - satisfied. That is, the formula cannot be satisfied even if all - soft-constraints are ignored. - - For more information on the Fu & Malik procedure: - - Z. Fu and S. Malik, On solving the partial MAX-SAT problem, in International - Conference on Theory and Applications of Satisfiability Testing, 2006. -*/ -namespace opt { - - class fu_malik : public maxsmt_solver_base { - filter_model_converter& m_fm; - expr_ref_vector m_aux_soft; - expr_ref_vector m_aux; - model_ref m_model; - - public: - fu_malik(maxsat_context& c, weights_t& ws, expr_ref_vector const& soft): - maxsmt_solver_base(c, ws, soft), - m_fm(c.fm()), - m_aux_soft(soft), - m_aux(m) - { - m_upper = rational(m_aux_soft.size() + 1); - m_lower.reset(); - m_assignment.resize(m_aux_soft.size(), false); - } - - /** - \brief One step of the Fu&Malik algorithm. - - Input: soft constraints + aux-vars (aka answer literals) - Output: done/not-done when not done return updated set of soft-constraints and aux-vars. - - if SAT --> terminates - - if UNSAT - * compute unsat core - * add blocking variable to soft-constraints in the core - - replace soft-constraint with the one with the blocking variable - - we should also add an aux-var - - replace aux-var with a new one - * add at-most-one constraint with blocking - */ - - typedef obj_hashtable expr_set; - - void set2vector(expr_set const& set, expr_ref_vector & es) const { - es.reset(); - expr_set::iterator it = set.begin(), end = set.end(); - for (; it != end; ++it) { - es.push_back(*it); - } - } - - void collect_statistics(statistics& st) const { - st.update("opt-fm-num-steps", m_aux_soft.size() + 2 - m_upper.get_unsigned()); - } - - void set_union(expr_set const& set1, expr_set const& set2, expr_set & set) const { - set.reset(); - expr_set::iterator it = set1.begin(), end = set1.end(); - for (; it != end; ++it) { - set.insert(*it); - } - it = set2.begin(); - end = set2.end(); - for (; it != end; ++it) { - set.insert(*it); - } - } - - lbool step() { - IF_VERBOSE(1, verbose_stream() << "(opt.max_sat step " << m_aux_soft.size() + 2 - m_upper.get_unsigned() << ")\n";); - expr_ref_vector assumptions(m), block_vars(m); - for (unsigned i = 0; i < m_aux_soft.size(); ++i) { - assumptions.push_back(m.mk_not(m_aux[i].get())); - } - lbool is_sat = s().check_sat(assumptions.size(), assumptions.c_ptr()); - if (is_sat != l_false) { - return is_sat; - } - - ptr_vector core; - s().get_unsat_core(core); - - SASSERT(!core.empty()); - - // Update soft-constraints and aux_vars - for (unsigned i = 0; i < m_aux_soft.size(); ++i) { - - bool found = false; - for (unsigned j = 0; !found && j < core.size(); ++j) { - found = assumptions[i].get() == core[j]; - } - if (!found) { - continue; - } - app_ref block_var(m), tmp(m); - block_var = m.mk_fresh_const("block_var", m.mk_bool_sort()); - m_aux[i] = m.mk_fresh_const("aux", m.mk_bool_sort()); - m_fm.insert(block_var->get_decl()); - m_fm.insert(to_app(m_aux[i].get())->get_decl()); - m_aux_soft[i] = m.mk_or(m_aux_soft[i].get(), block_var); - block_vars.push_back(block_var); - tmp = m.mk_or(m_aux_soft[i].get(), m_aux[i].get()); - s().assert_expr(tmp); - } - SASSERT (!block_vars.empty()); - assert_at_most_one(block_vars); - IF_VERBOSE(1, verbose_stream() << "(opt.max_sat # of non-blocked soft constraints: " << m_aux_soft.size() - block_vars.size() << ")\n";); - return l_false; - } - - void assert_at_most_one(expr_ref_vector const& block_vars) { - expr_ref has_one(m), has_zero(m), at_most_one(m); - mk_at_most_one(block_vars.size(), block_vars.c_ptr(), has_one, has_zero); - at_most_one = m.mk_or(has_one, has_zero); - s().assert_expr(at_most_one); - } - - void mk_at_most_one(unsigned n, expr* const * vars, expr_ref& has_one, expr_ref& has_zero) { - SASSERT(n != 0); - if (n == 1) { - has_one = vars[0]; - has_zero = m.mk_not(vars[0]); - } - else { - unsigned mid = n/2; - expr_ref has_one1(m), has_one2(m), has_zero1(m), has_zero2(m); - mk_at_most_one(mid, vars, has_one1, has_zero1); - mk_at_most_one(n-mid, vars+mid, has_one2, has_zero2); - has_one = m.mk_or(m.mk_and(has_one1, has_zero2), m.mk_and(has_one2, has_zero1)); - has_zero = m.mk_and(has_zero1, has_zero2); - } - } - - - // TBD: bug when cancel flag is set, fu_malik returns is_sat == l_true instead of l_undef - virtual lbool operator()() { - lbool is_sat = l_true; - if (m_aux_soft.empty()) { - return is_sat; - } - solver::scoped_push _sp(s()); - expr_ref tmp(m); - - TRACE("opt", - tout << "soft constraints:\n"; - for (unsigned i = 0; i < m_aux_soft.size(); ++i) { - tout << mk_pp(m_aux_soft[i].get(), m) << "\n"; - }); - - for (unsigned i = 0; i < m_aux_soft.size(); ++i) { - m_aux.push_back(m.mk_fresh_const("p", m.mk_bool_sort())); - m_fm.insert(to_app(m_aux.back())->get_decl()); - tmp = m.mk_or(m_aux_soft[i].get(), m_aux[i].get()); - s().assert_expr(tmp); - } - - do { - is_sat = step(); - --m_upper; - } - while (is_sat == l_false); - - if (is_sat == l_true) { - // Get a list satisfying m_aux_soft - s().get_model(m_model); - m_lower = m_upper; - m_assignment.reset(); - for (unsigned i = 0; i < m_soft.size(); ++i) { - expr_ref val(m); - if (!m_model->eval(m_soft[i], val)) return l_undef; - TRACE("opt", tout << val << "\n";); - m_assignment.push_back(m.is_true(val)); - } - TRACE("opt", tout << "maxsat cost: " << m_upper << "\n"; - model_smt2_pp(tout, m, *m_model, 0);); - } - // We are done and soft_constraints has - // been updated with the max-sat assignment. - return is_sat; - } - - virtual void get_model(model_ref& mdl) { - mdl = m_model.get(); - } - - virtual rational get_lower() const { - return rational(m_aux_soft.size())-m_upper; - } - - virtual rational get_upper() const { - return rational(m_aux_soft.size())-m_lower; - } - }; - - maxsmt_solver_base* mk_fu_malik(maxsat_context& c, weights_t & ws, expr_ref_vector const& soft) { - return alloc(fu_malik, c, ws, soft); - } - -}; - diff --git a/src/opt/fu_malik.h b/src/opt/fu_malik.h deleted file mode 100644 index 52e960b5e..000000000 --- a/src/opt/fu_malik.h +++ /dev/null @@ -1,37 +0,0 @@ -/*++ -Copyright (c) 2013 Microsoft Corporation - -Module Name: - - fu_malik.h - -Abstract: - - Fu&Malik built-in optimization method. - Adapted from sample code in C. - -Author: - - Anh-Dung Phan (t-anphan) 2013-10-15 - -Notes: - - Takes solver with hard constraints added. - Returns a maximal satisfying subset of soft_constraints - that are still consistent with the solver state. - ---*/ -#ifndef OPT_FU_MALIK_H_ -#define OPT_FU_MALIK_H_ - -#include "opt_solver.h" -#include "maxsmt.h" - -namespace opt { - - maxsmt_solver_base* mk_fu_malik(maxsat_context& c, weights_t & ws, expr_ref_vector const& soft); - - -}; - -#endif diff --git a/src/opt/hitting_sets.cpp b/src/opt/hitting_sets.cpp deleted file mode 100644 index 678d7924e..000000000 --- a/src/opt/hitting_sets.cpp +++ /dev/null @@ -1,1088 +0,0 @@ -/*++ -Copyright (c) 2014 Microsoft Corporation - -Module Name: - - hitting_sets.h - -Abstract: - - Hitting set approximations. - -Author: - - Nikolaj Bjorner (nbjorner) 2014-06-06 - -Notes: - ---*/ -#include "vector.h" -#include "util.h" -#include "hitting_sets.h" -#include "simplex.h" -#include "sparse_matrix_def.h" -#include "simplex_def.h" - -typedef simplex::simplex Simplex; -typedef simplex::sparse_matrix sparse_matrix; - - -namespace opt { - - struct hitting_sets::imp { - class justification { - public: - enum kind_t { AXIOM, DECISION, CLAUSE }; - private: - kind_t m_kind; - unsigned m_value; - bool m_pos; - public: - explicit justification(kind_t k):m_kind(k), m_value(0), m_pos(false) {} - explicit justification(unsigned v, bool pos):m_kind(CLAUSE), m_value(v), m_pos(pos) {} - justification(justification const& other): - m_kind(other.m_kind), m_value(other.m_value), m_pos(other.m_pos) {} - justification& operator=(justification const& other) { - m_kind = other.m_kind; - m_value = other.m_value; - m_pos = other.m_pos; - return *this; - } - unsigned clause() const { return m_value; } - bool is_axiom() const { return m_kind == AXIOM; } - bool is_decision() const { return m_kind == DECISION; } - bool is_clause() const { return m_kind == CLAUSE; } - kind_t kind() const { return m_kind; } - bool pos() const { return m_pos; } - }; - - class set { - unsigned m_num_elems; - unsigned m_elems[0]; - set(): m_num_elems(0) {} - public: - - static set* mk(small_object_allocator& alloc, unsigned sz, unsigned const* elems) { - unsigned size = (sz+1)*sizeof(unsigned); - void * mem = alloc.allocate(size); - set* result = new (mem) set(); - result->m_num_elems = sz; - memcpy(result->m_elems, elems, sizeof(unsigned)*sz); - return result; - } - - inline unsigned operator[](unsigned idx) const { - SASSERT(idx < m_num_elems); - return m_elems[idx]; - } - - inline unsigned& operator[](unsigned idx) { - SASSERT(idx < m_num_elems); - return m_elems[idx]; - } - - unsigned size() const { return m_num_elems; } - - unsigned alloc_size() const { return (m_num_elems + 1)*sizeof(unsigned); } - - bool empty() const { return 0 == size(); } - }; - - reslimit& m_limit; - rational m_lower; - rational m_upper; - vector m_weights; - vector m_weights_inv; - rational m_max_weight; - rational m_denominator; - small_object_allocator m_alloc; - ptr_vector m_T; - ptr_vector m_F; - svector m_value; - svector m_model; - vector m_tuse_list; - vector m_fuse_list; - - // Custom CDCL solver. - svector m_justification; - vector m_twatch; - vector m_fwatch; - unsigned_vector m_level; - unsigned_vector m_trail; // trail of assigned literals - unsigned m_qhead; // queue head - justification m_conflict_j; // conflict justification - unsigned m_conflict_l; // conflict literal - bool m_inconsistent; - unsigned m_scope_lvl; - rational m_weight; // current weight of assignment. - unsigned_vector m_indices; - unsigned_vector m_scores; - vector m_scored_weights; - svector m_score_updated; - bool m_enable_simplex; - struct compare_scores { - imp* m_imp; - compare_scores():m_imp(0) {} - bool operator()(int v1, int v2) const { - return m_imp->m_scored_weights[v1] > m_imp->m_scored_weights[v2]; - } - }; - compare_scores m_compare_scores; - heap m_heap; - svector m_mark; - struct scope { - unsigned m_trail_lim; - }; - vector m_scopes; - unsigned_vector m_lemma; - unsigned m_conflict_lvl; - - // simplex - unsynch_mpz_manager m; - Simplex m_simplex; - unsigned m_weights_var; - - static unsigned const null_idx = UINT_MAX; - - imp(reslimit& lim): - m_limit(lim), - m_max_weight(0), - m_denominator(1), - m_alloc("hitting-sets"), - m_qhead(0), - m_conflict_j(justification(justification::AXIOM)), - m_inconsistent(false), - m_scope_lvl(0), - m_compare_scores(), - m_heap(0, m_compare_scores), - m_simplex(lim), - m_weights_var(0) { - m_enable_simplex = true; - m_compare_scores.m_imp = this; - } - ~imp() { - for (unsigned i = 0; i < m_T.size(); ++i) { - m_alloc.deallocate(m_T[i]->alloc_size(), m_T[i]); - } - for (unsigned i = 0; i < m_F.size(); ++i) { - m_alloc.deallocate(m_F[i]->alloc_size(), m_F[i]); - } - } - - void add_weight(rational const& w) { - SASSERT(w.is_pos()); - unsigned var = m_weights.size(); - m_simplex.ensure_var(var); - m_simplex.set_lower(var, mpq_inf(mpq(0),mpq(0))); - m_simplex.set_upper(var, mpq_inf(mpq(1),mpq(0))); - m_weights.push_back(w); - m_weights_inv.push_back(rational::one()); - m_value.push_back(l_undef); - m_justification.push_back(justification(justification::DECISION)); - m_tuse_list.push_back(unsigned_vector()); - m_fuse_list.push_back(unsigned_vector()); - m_twatch.push_back(unsigned_vector()); - m_fwatch.push_back(unsigned_vector()); - m_level.push_back(0); - m_indices.push_back(var); - m_model.push_back(l_undef); - m_mark.push_back(false); - m_scores.push_back(0); - m_scored_weights.push_back(rational(0)); - m_score_updated.push_back(true); - m_max_weight += w; - } - - justification add_exists_false(unsigned sz, unsigned const* S) { - return add_exists(sz, S, true); - } - - justification add_exists_true(unsigned sz, unsigned const* S) { - return add_exists(sz, S, false); - } - - justification add_exists(unsigned sz, unsigned const* S, bool sign) { - vector& use_list = sign?m_fuse_list:m_tuse_list; - lbool val = sign?l_false:l_true; - justification j(justification::AXIOM); - ptr_vector& Sets = sign?m_F:m_T; - vector& watch = sign?m_fwatch:m_twatch; - init_weights(); - if (sz == 0) { - set_conflict(0, justification(justification::AXIOM)); - } - else if (sz == 1) { - IF_VERBOSE(2, verbose_stream() << "unit literal : " << S[0] << " " << val << "\n";); - assign(S[0], val, justification(justification::AXIOM)); - } - else { - unsigned clause_id = Sets.size(); - for (unsigned i = 0; i < sz; ++i) { - use_list[S[i]].push_back(clause_id); - } - j = justification(clause_id, !sign); - watch[S[0]].push_back(clause_id); - watch[S[1]].push_back(clause_id); - Sets.push_back(set::mk(m_alloc, sz, S)); - if (!sign) { - pop(scope_lvl()); - inc_score(clause_id); - } - TRACE("opt", display(tout, j);); - IF_VERBOSE(2, if (!sign) display(verbose_stream(), j);); - if (!sign && m_enable_simplex) { - add_simplex_row(!sign, sz, S); - } - } - return j; - } - - lbool compute_lower() { - m_lower.reset(); - rational w1 = L1(); - rational w2 = L2(); - rational w3 = L3(); - if (w1 > m_lower) m_lower = w1; - if (w2 > m_lower) m_lower = w2; - if (w3 > m_lower) m_lower = w3; - return l_true; - } - - lbool compute_upper() { - m_upper = m_max_weight; - unsigned fsz = m_F.size(); - lbool r = search(); - pop(scope_lvl()); - - - IF_VERBOSE(1, verbose_stream() << "(hsmax.negated-size: " << fsz << ")\n";); -#if 0 - // garbage collect agressively on exit. - // all learned clases for negative branches are - // pruned. - for (unsigned i = fsz; i < m_F.size(); ++i) { - m_alloc.deallocate(m_F[i]->alloc_size(), m_F[i]); - } - m_F.resize(fsz); - for (unsigned i = 0; i < m_fuse_list.size(); ++i) { - unsigned_vector & uses = m_fuse_list[i]; - while (!uses.empty() && uses.back() >= fsz) uses.pop_back(); - unsigned_vector & watch = m_fwatch[i]; - unsigned j = 0, k = 0; - for (; j < watch.size(); ++j) { - if (watch[j] < fsz) { - watch[k] = watch[j]; - ++k; - } - } - watch.resize(k); - } -#endif - return r; - } - - rational get_lower() { - return m_lower/m_denominator; - } - - rational get_upper() { - return m_upper/m_denominator; - } - - void set_upper(rational const& r) { - m_max_weight = r*m_denominator; - } - - bool get_value(unsigned idx) { - return - idx < m_model.size() && - m_model[idx] == l_true; - } - - void collect_statistics(::statistics& st) const { - m_simplex.collect_statistics(st); - } - - void reset() { - m_lower.reset(); - m_upper = m_max_weight; - } - - void init_weights() { - if (m_weights_var != 0) { - return; - } - m_weights_var = m_weights.size(); - unsigned_vector vars; - scoped_mpz_vector coeffs(m); - - // normalize weights to integral. - rational d(1); - for (unsigned i = 0; i < m_weights.size(); ++i) { - d = lcm(d, denominator(m_weights[i])); - } - m_denominator = d; - if (!d.is_one()) { - for (unsigned i = 0; i < m_weights.size(); ++i) { - m_weights[i] *= d; - } - } - rational lc(1); - for (unsigned i = 0; i < m_weights.size(); ++i) { - lc = lcm(lc, m_weights[i]); - } - for (unsigned i = 0; i < m_weights.size(); ++i) { - m_weights_inv[i] = lc/m_weights[i]; - } - - m_heap.set_bounds(m_weights.size()); - for (unsigned i = 0; i < m_weights.size(); ++i) { - m_heap.insert(i); - } - update_heap(); - - // set up Simplex objective function. - for (unsigned i = 0; i < m_weights.size(); ++i) { - vars.push_back(i); - coeffs.push_back(m_weights[i].to_mpq().numerator()); - } - m_simplex.ensure_var(m_weights_var); - vars.push_back(m_weights_var); - coeffs.push_back(mpz(-1)); - m_simplex.add_row(m_weights_var, coeffs.size(), vars.c_ptr(), coeffs.c_ptr()); - - } - - void display(std::ostream& out) const { - out << "inconsistent: " << m_inconsistent << "\n"; - out << "weight: " << m_weight << "\n"; - for (unsigned i = 0; i < m_weights.size(); ++i) { - out << i << ": " << value(i) << " w: " << m_weights[i] << " s: " << m_scores[i] << "\n"; - } - for (unsigned i = 0; i < m_T.size(); ++i) { - display(out << "+" << i << ": ", *m_T[i]); - } - for (unsigned i = 0; i < m_F.size(); ++i) { - display(out << "-" << i << ": ", *m_F[i]); - } - out << "watch lists:\n"; - for (unsigned i = 0; i < m_fwatch.size(); ++i) { - out << i << ": "; - for (unsigned j = 0; j < m_twatch[i].size(); ++j) { - out << "+" << m_twatch[i][j] << " "; - } - for (unsigned j = 0; j < m_fwatch[i].size(); ++j) { - out << "-" << m_fwatch[i][j] << " "; - } - out << "\n"; - } - out << "trail\n"; - for (unsigned i = 0; i < m_trail.size(); ++i) { - unsigned idx = m_trail[i]; - out << (m_justification[idx].is_decision()?"d":"") << idx << " "; - } - out << "\n"; - } - - void display(std::ostream& out, set const& S) const { - for (unsigned i = 0; i < S.size(); ++i) { - out << S[i] << " "; - } - out << "\n"; - } - - void display(std::ostream& out, justification const& j) const { - switch(j.kind()) { - case justification::AXIOM: - out << "axiom\n"; - break; - case justification::DECISION: - out << "decision\n"; - break; - case justification::CLAUSE: { - out << "clause: "; - set const& S = j.pos()?(*m_T[j.clause()]):(*m_F[j.clause()]); - for (unsigned i = 0; i < S.size(); ++i) { - out << S[i] << " "; - } - out << "\n"; - } - } - } - - void display_lemma(std::ostream& out) { - out << "lemma: "; - for (unsigned i = 0; i < m_lemma.size(); ++i) { - out << m_lemma[i] << " "; - } - out << "\n"; - } - - struct scoped_push { - imp& s; - scoped_push(imp& s):s(s) { s.push(); } - ~scoped_push() { s.pop(1); } - }; - - struct value_lt { - vector const& weights; - value_lt(vector const& weights): - weights(weights) {} - bool operator()(int v1, int v2) const { - return weights[v1] > weights[v2]; - } - }; - - void inc_score(unsigned clause_id) { - set const& S = *m_T[clause_id]; - if (!has_selected(S)) { - for (unsigned j = 0; j < S.size(); ++j) { - ++m_scores[S[j]]; - m_score_updated[S[j]] = true; - } - } - } - - void dec_score(unsigned clause_id) { - set const& S = *m_T[clause_id]; - if (!has_selected(S)) { - for (unsigned j = 0; j < S.size(); ++j) { - SASSERT(m_scores[S[j]] > 0); - --m_scores[S[j]]; - m_score_updated[S[j]] = true; - } - } - } - - void update_score(unsigned idx, bool inc) { - unsigned_vector const& uses = m_tuse_list[idx]; - for (unsigned i = 0; i < uses.size(); ++i) { - if (inc) { - inc_score(uses[i]); - } - else { - dec_score(uses[i]); - } - } - } - - rational L1() { - rational w(m_weight); - scoped_push _sc(*this); - for (unsigned i = 0; !canceled() && i < m_T.size(); ++i) { - set const& S = *m_T[i]; - SASSERT(!S.empty()); - if (!has_selected(S)) { - w += m_weights[select_min(S)]; - for (unsigned j = 0; j < S.size(); ++j) { - assign(S[j], l_true, justification(justification::DECISION)); - } - } - } - return w; - } - - void update_heap() { - for (unsigned i = 0; i < m_scored_weights.size(); ++i) { - if (m_score_updated[i]) { - rational const& old_w = m_scored_weights[i]; - rational new_w = rational(m_scores[i])*m_weights_inv[i]; - if (new_w > old_w) { - m_scored_weights[i] = new_w; - //m_heap.decreased(i); - } - else if (new_w < old_w) { - m_scored_weights[i] = new_w; - //m_heap.increased(i); - } - m_score_updated[i] = false; - } - } - } - - rational L2() { - rational w(m_weight); - scoped_push _sc(*this); - int n = 0; - for (unsigned i = 0; i < m_T.size(); ++i) { - if (!has_selected(*m_T[i])) ++n; - } - - update_heap(); - value_lt lt(m_scored_weights); - std::sort(m_indices.begin(), m_indices.end(), lt); - for(unsigned i = 0; i < m_indices.size() && n > 0; ++i) { - // deg(c) = score(c) - // wt(c) = m_weights[c] - - unsigned idx = m_indices[i]; - if (m_scores[idx] == 0) { - break; - } - if (m_scores[idx] < static_cast(n) || m_weights[idx].is_one()) { - w += m_weights[idx]; - } - else { - w += div((rational(n)*m_weights[idx]), rational(m_scores[idx])); - } - n -= m_scores[idx]; - } - return w; - } - - rational L3() { - TRACE("simplex", m_simplex.display(tout);); - VERIFY(l_true == m_simplex.make_feasible()); - TRACE("simplex", m_simplex.display(tout);); - VERIFY(l_true == m_simplex.minimize(m_weights_var)); - mpq_inf const& val = m_simplex.get_value(m_weights_var); - unsynch_mpq_inf_manager mg; - unsynch_mpq_manager& mq = mg.get_mpq_manager(); - scoped_mpq c(mq); - mg.ceil(val, c); - rational w(c); - CTRACE("simplex", - w >= m_weight, tout << w << " " << m_weight << " !!!!\n"; - display(tout);); - SASSERT(w >= m_weight); - return w; - } - - void add_simplex_row(bool is_some_true, unsigned sz, unsigned const* S) { - unsigned_vector vars; - scoped_mpz_vector coeffs(m); - for (unsigned i = 0; i < sz; ++i) { - vars.push_back(S[i]); - coeffs.push_back(mpz(1)); - } - unsigned base_var = m_F.size() + m_T.size() + m_weights.size(); - m_simplex.ensure_var(base_var); - vars.push_back(base_var); - coeffs.push_back(mpz(-1)); - // S - base_var = 0 - if (is_some_true) { - // base_var >= 1 - m_simplex.set_lower(base_var, mpq_inf(mpq(1),mpq(0))); - } - else { - // base_var <= sz-1 - m_simplex.set_upper(base_var, mpq_inf(mpq(sz-1),mpq(0))); - } - m_simplex.add_row(base_var, coeffs.size(), vars.c_ptr(), coeffs.c_ptr()); - } - - unsigned select_min(set const& S) { - unsigned result = S[0]; - for (unsigned i = 1; i < S.size(); ++i) { - if (m_weights[result] > m_weights[S[i]]) { - result = S[i]; - } - } - return result; - } - - bool have_selected(lbool val, ptr_vector const& Sets, unsigned& i) { - for (i = 0; i < Sets.size(); ++i) { - if (!has_selected(val, *Sets[i])) return false; - } - return true; - } - - void set_undef_to_false() { - for (unsigned i = 0; i < m_model.size(); ++i) { - if (m_model[i] == l_undef) { - m_model[i] = l_false; - } - } - } - - bool values_satisfy_Fs(unsigned& i) { - unsigned j = 0; - for (i = 0; i < m_F.size(); ++i) { - set const& F = *m_F[i]; - for (j = 0; j < F.size(); ++j) { - if (m_model[F[j]] == l_false) { - break; - } - } - if (F.size() == j) { - break; - } - } - return i == m_F.size(); - } - - bool has_selected(set const& S) { - return has_selected(l_true, S); - } - - bool has_unselected(set const& S) { - return has_selected(l_false, S); - } - - bool has_unset(set const& S) { - return has_selected(l_undef, S); - } - - bool has_selected(lbool val, set const& S) { - for (unsigned i = 0; i < S.size(); ++i) { - if (val == value(S[i])) { - return true; - } - } - return false; - } - - // (greedy) CDCL learner for hitting sets. - - inline unsigned scope_lvl() const { return m_scope_lvl; } - inline bool inconsistent() const { return m_inconsistent; } - inline bool canceled() const { return !m_limit.inc(); } - inline unsigned lvl(unsigned idx) const { return m_level[idx]; } - inline lbool value(unsigned idx) const { return m_value[idx]; } - - inline bool is_marked(unsigned v) const { return m_mark[v] != 0; } - inline void mark(unsigned v) { SASSERT(!is_marked(v)); m_mark[v] = true; } - inline void reset_mark(unsigned v) { SASSERT(is_marked(v)); m_mark[v] = false; } - - void push() { - SASSERT(!inconsistent()); - ++m_scope_lvl; - m_scopes.push_back(scope()); - scope& s = m_scopes.back(); - s.m_trail_lim = m_trail.size(); - } - - void pop(unsigned n) { - if (n > 0) { - m_inconsistent = false; - m_scope_lvl = scope_lvl() - n; - unassign(m_scopes[scope_lvl()].m_trail_lim); - m_scopes.shrink(scope_lvl()); - } - } - - void assign(unsigned idx, lbool val, justification const& justification) { - if (val == l_true) { - m_weight += m_weights[idx]; - update_score(idx, false); - if (m_enable_simplex) { - m_simplex.set_lower(idx, mpq_inf(mpq(1),mpq(0))); - } - } - SASSERT(val != l_true || m_scores[idx] == 0); - m_value[idx] = val; - m_justification[idx] = justification; - m_trail.push_back(idx); - m_level[idx] = scope_lvl(); - TRACE("opt", tout << idx << " := " << val << " scope: " << scope_lvl() << " w: " << m_weight << "\n";); - } - - - svector m_replay_idx; - svector m_replay_val; - void unassign(unsigned sz) { - for (unsigned j = sz; j < m_trail.size(); ++j) { - unsigned idx = m_trail[j]; - lbool val = value(idx); - m_value[idx] = l_undef; - if (val == l_true) { - m_weight -= m_weights[idx]; - update_score(idx, true); - if (m_enable_simplex) { - m_simplex.set_lower(idx, mpq_inf(mpq(0),mpq(0))); - } - } - if (m_justification[idx].is_axiom()) { - m_replay_idx.push_back(idx); - m_replay_val.push_back(val); - } - } - TRACE("opt", tout << m_weight << "\n";); - m_trail.shrink(sz); - m_qhead = sz; - for (unsigned i = m_replay_idx.size(); i > 0; ) { - --i; - unsigned idx = m_replay_idx[i]; - lbool val = m_replay_val[i]; - assign(idx, val, justification(justification::AXIOM)); - } - m_replay_idx.reset(); - m_replay_val.reset(); - } - - - lbool search() { - TRACE("opt", display(tout);); - pop(scope_lvl()); - while (true) { - while (true) { - propagate(); - if (canceled()) return l_undef; - if (!inconsistent()) break; - if (!resolve_conflict()) return l_false; - SASSERT(!inconsistent()); - } - if (!decide()) { - SASSERT(validate_model()); - m_model.reset(); - m_model.append(m_value); - m_upper = m_weight; - // SASSERT(m_weight < m_max_weight); - return l_true; - } - } - } - - bool validate_model() { - for (unsigned i = 0; i < m_T.size(); ++i) { - set const& S = *m_T[i]; - bool found = false; - for (unsigned j = 0; !found && j < S.size(); ++j) { - found = value(S[j]) == l_true; - } - CTRACE("opt", !found, - display(tout << "not found: " << i << "\n", S); - display(tout);); - SASSERT(found); - } - for (unsigned i = 0; i < m_F.size(); ++i) { - set const& S = *m_F[i]; - bool found = false; - for (unsigned j = 0; !found && j < S.size(); ++j) { - found = value(S[j]) != l_true; - } - CTRACE("opt", !found, - display(tout << "not found: " << i << "\n", S); - display(tout);); - SASSERT(found); - } - - return true; - } - - 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]]; - SASSERT(S[0] == i || S[1] == i); - } - } - for (unsigned i = 0; i < m_twatch.size(); ++i) { - for (unsigned j = 0; j < m_twatch[i].size(); ++j) { - set const& S = *m_T[m_twatch[i][j]]; - SASSERT(S[0] == i || S[1] == i); - } - }); - return true; - } - - bool resolve_conflict() { - while (true) { - if (!resolve_conflict_core()) return false; - if (!inconsistent()) return true; - } - } - - unsigned get_max_lvl(unsigned conflict_l, justification const& conflict_j) { - if (scope_lvl() == 0) return 0; - unsigned r = lvl(conflict_l); - if (conflict_j.is_clause()) { - unsigned clause = conflict_j.clause(); - ptr_vector const& S = conflict_j.pos()?m_T:m_F; - r = std::max(r, lvl((*S[clause])[0])); - r = std::max(r, lvl((*S[clause])[1])); - } - return r; - } - - bool resolve_conflict_core() { - SASSERT(inconsistent()); - TRACE("opt", display(tout);); - unsigned conflict_l = m_conflict_l; - justification conflict_j(m_conflict_j); - if (conflict_j.is_axiom()) { - return false; - } - m_conflict_lvl = get_max_lvl(conflict_l, conflict_j); - if (m_conflict_lvl == 0) { - return false; - } - unsigned idx = skip_above_conflict_level(); - unsigned num_marks = 0; - m_lemma.reset(); - m_lemma.push_back(0); - process_antecedent(conflict_l, num_marks); - do { - TRACE("opt", tout << "conflict literal: " << conflict_l << "\n"; - display(tout, conflict_j);); - if (conflict_j.is_clause()) { - unsigned cl = conflict_j.clause(); - unsigned i = 0; - SASSERT(value(conflict_l) != l_undef); - set const& T = conflict_j.pos()?(*m_T[cl]):(*m_F[cl]); - if (T[0] == conflict_l) { - i = 1; - } - else { - SASSERT(T[1] == conflict_l); - process_antecedent(T[0], num_marks); - i = 2; - } - unsigned sz = T.size(); - for (; i < sz; ++i) { - process_antecedent(T[i], num_marks); - } - } - else if (conflict_j.is_decision()) { - --num_marks; - SASSERT(num_marks == 0); - break; - } - else if (conflict_j.is_axiom()) { - IF_VERBOSE(0, verbose_stream() << "axiom " << conflict_l << " " << value(conflict_l) << " " << num_marks << "\n";); - --num_marks; - SASSERT(num_marks == 0); - break; - } - while (true) { - unsigned l = m_trail[idx]; - if (is_marked(l)) break; - SASSERT(idx > 0); - --idx; - } - conflict_l = m_trail[idx]; - conflict_j = m_justification[conflict_l]; - --idx; - --num_marks; - if (num_marks == 0 && value(conflict_l) == l_false) { - ++num_marks; - } - reset_mark(conflict_l); - } - while (num_marks > 0); - m_lemma[0] = conflict_l; - TRACE("opt", display_lemma(tout);); - SASSERT(value(conflict_l) == l_true); - unsigned new_scope_lvl = 0; - for (unsigned i = 1; i < m_lemma.size(); ++i) { - SASSERT(l_true == value(m_lemma[i])); - new_scope_lvl = std::max(new_scope_lvl, lvl(m_lemma[i])); - reset_mark(m_lemma[i]); - } - pop(scope_lvl() - new_scope_lvl); - SASSERT(l_undef == value(conflict_l)); - justification j = add_exists_false(m_lemma.size(), m_lemma.c_ptr()); - if (!j.is_axiom()) assign(conflict_l, l_false, j); - return true; - } - - - void process_antecedent(unsigned antecedent, unsigned& num_marks) { - unsigned alvl = lvl(antecedent); - SASSERT(alvl <= m_conflict_lvl); - if (!is_marked(antecedent) && alvl > 0 && !m_justification[antecedent].is_axiom()) { - mark(antecedent); - if (alvl == m_conflict_lvl || value(antecedent) == l_false) { - ++num_marks; - } - else { - m_lemma.push_back(antecedent); - } - } - } - - unsigned skip_above_conflict_level() { - unsigned idx = m_trail.size(); - if (idx == 0) { - return idx; - } - idx--; - // skip literals from levels above the conflict level - while (lvl(m_trail[idx]) > m_conflict_lvl) { - SASSERT(idx > 0); - idx--; - } - return idx; - } - - void set_conflict(unsigned idx, justification const& justification) { - if (!inconsistent()) { - TRACE("opt", tout << "conflict: " << idx << "\n";); - m_inconsistent = true; - m_conflict_j = justification; - m_conflict_l = idx; - } - } - - unsigned next_var() { - update_heap(); - - value_lt lt(m_scored_weights); - std::sort(m_indices.begin(), m_indices.end(), lt); - unsigned idx = m_indices[0]; - if (m_scores[idx] == 0) return UINT_MAX; - return idx; -#if 0 - int min_val = m_heap.min_value(); - if (min_val == -1) { - return UINT_MAX; - } - SASSERT(0 <= min_val && static_cast(min_val) < m_weights.size()); - if (m_scores[min_val] == 0) { - return UINT_MAX; - } - return static_cast(min_val); -#endif - } - - bool decide() { - unsigned idx = next_var(); - if (idx == UINT_MAX) { - return false; - } - else { - push(); - TRACE("opt", tout << "decide " << idx << "\n";); - assign(idx, l_true, justification(justification::DECISION)); - return true; - } - } - - void propagate() { - TRACE("opt", display(tout);); - SASSERT(invariant()); - while (m_qhead < m_trail.size() && !inconsistent() && !canceled()) { - unsigned idx = m_trail[m_qhead]; - ++m_qhead; - switch (value(idx)) { - case l_undef: - UNREACHABLE(); - break; - case l_true: - propagate(idx, l_false, m_fwatch, m_F); - break; - case l_false: - propagate(idx, l_true, m_twatch, m_T); - break; - } - } - prune_branch(); - } - - void propagate(unsigned idx, lbool good_val, vector& watch, ptr_vector& Fs) - { - TRACE("opt", tout << idx << " " << value(idx) << "\n";); - unsigned_vector& w = watch[idx]; - unsigned sz = w.size(); - lbool bad_val = ~good_val; - SASSERT(value(idx) == bad_val); - unsigned l = 0; - for (unsigned i = 0; i < sz && !canceled(); ++i, ++l) { - unsigned clause_id = w[i]; - set& F = *Fs[clause_id]; - SASSERT(F.size() >= 2); - bool k1 = (F[0] != idx); - bool k2 = !k1; - SASSERT(F[k1] == idx); - SASSERT(value(F[k1]) == bad_val); - if (value(F[k2]) == good_val) { - w[l] = w[i]; - continue; - } - bool found = false; - unsigned sz2 = F.size(); - for (unsigned j = 2; !found && j < sz2; ++j) { - unsigned idx2 = F[j]; - if (value(idx2) != bad_val) { - found = true; - std::swap(F[k1], F[j]); - --l; - watch[idx2].push_back(clause_id); - } - } - if (!found) { - if (value(F[k2]) == bad_val) { - set_conflict(F[k2], justification(clause_id, good_val == l_true)); - if (i == l) { - l = sz; - } - else { - for (; i < sz; ++i, ++l) { - w[l] = w[i]; - } - } - break; - } - else { - SASSERT(value(F[k2]) == l_undef); - assign(F[k2], good_val, justification(clause_id, good_val == l_true)); - w[l] = w[i]; - } - } - } - watch[idx].shrink(l); - SASSERT(invariant()); - TRACE("opt", tout << idx << " " << value(idx) << "\n";); - SASSERT(value(idx) == bad_val); - } - - bool infeasible_lookahead() { - if (m_enable_simplex && L3() >= m_max_weight) { - return true; - } - return - (L1() >= m_max_weight) || - (L2() >= m_max_weight); - } - - void prune_branch() { - if (inconsistent() || !infeasible_lookahead()) { - return; - } - - IF_VERBOSE(4, verbose_stream() << "(hs.prune-branch " << m_weight << ")\n";); - m_lemma.reset(); - unsigned i = 0; - rational w(0); - for (; i < m_trail.size() && w < m_max_weight; ++i) { - unsigned idx = m_trail[i]; - if (m_justification[idx].is_decision()) { - SASSERT(value(idx) == l_true); - m_lemma.push_back(idx); - w += m_weights[idx]; - } - } - // undo the lower bounds. - TRACE("opt", - tout << "prune branch: " << m_weight << " "; - display_lemma(tout); - display(tout); - ); - justification j = add_exists_false(m_lemma.size(), m_lemma.c_ptr()); - unsigned idx = m_lemma.empty()?0:m_lemma[0]; - set_conflict(idx, j); - } - - // TBD: derive strong inequalities and add them to Simplex. - // x_i1 + .. + x_ik >= k-1 for each subset k from set n: x_1 + .. + x_n >= k - }; - - - hitting_sets::hitting_sets(reslimit& lim) { m_imp = alloc(imp, lim); } - hitting_sets::~hitting_sets() { dealloc(m_imp); } - void hitting_sets::add_weight(rational const& w) { m_imp->add_weight(w); } - void hitting_sets::add_exists_true(unsigned sz, unsigned const* elems) { m_imp->add_exists_true(sz, elems); } - void hitting_sets::add_exists_false(unsigned sz, unsigned const* elems) { m_imp->add_exists_false(sz, elems); } - lbool hitting_sets::compute_lower() { return m_imp->compute_lower(); } - lbool hitting_sets::compute_upper() { return m_imp->compute_upper(); } - rational hitting_sets::get_lower() { return m_imp->get_lower(); } - rational hitting_sets::get_upper() { return m_imp->get_upper(); } - void hitting_sets::set_upper(rational const& r) { return m_imp->set_upper(r); } - bool hitting_sets::get_value(unsigned idx) { return m_imp->get_value(idx); } - void hitting_sets::collect_statistics(::statistics& st) const { m_imp->collect_statistics(st); } - void hitting_sets::reset() { m_imp->reset(); } - - -}; diff --git a/src/opt/hitting_sets.h b/src/opt/hitting_sets.h deleted file mode 100644 index c9708710f..000000000 --- a/src/opt/hitting_sets.h +++ /dev/null @@ -1,52 +0,0 @@ -/*++ -Copyright (c) 2014 Microsoft Corporation - -Module Name: - - hitting_sets.h - -Abstract: - - Hitting set approximations. - -Author: - - Nikolaj Bjorner (nbjorner) 2014-06-06 - -Notes: - ---*/ -#ifndef HITTING_SETS_H_ -#define HITTING_SETS_H_ - -#include "rational.h" -#include "statistics.h" -#include "lbool.h" -#include "rlimit.h" - -namespace opt { - - class hitting_sets { - struct imp; - imp* m_imp; - public: - hitting_sets(reslimit& lim); - ~hitting_sets(); - void add_weight(rational const& w); - void add_exists_true(unsigned sz, unsigned const* elems); - void add_exists_false(unsigned sz, unsigned const* elems); - lbool compute_lower(); - lbool compute_upper(); - void set_upper(rational const& r); - rational get_lower(); - rational get_upper(); - bool get_value(unsigned idx); - void set_cancel(bool f); - void collect_statistics(::statistics& st) const; - void reset(); - }; - - -}; - -#endif diff --git a/src/opt/maxhs.cpp b/src/opt/maxhs.cpp deleted file mode 100644 index 2297bdc20..000000000 --- a/src/opt/maxhs.cpp +++ /dev/null @@ -1,556 +0,0 @@ -/*++ -Copyright (c) 2014 Microsoft Corporation - -Module Name: - - maxhs.cpp - -Abstract: - - maxhs based MaxSAT. - -Author: - - Nikolaj Bjorner (nbjorner) 2014-4-17 - -Notes: - ---*/ -#include "optsmt.h" -#include "hitting_sets.h" -#include "stopwatch.h" -#include "ast_pp.h" -#include "model_smt2_pp.h" -#include "uint_set.h" -#include "maxhs.h" -#include "opt_context.h" - -namespace opt { - - class scoped_stopwatch { - double& m_time; - stopwatch m_watch; - public: - scoped_stopwatch(double& time): m_time(time) { - m_watch.start(); - } - ~scoped_stopwatch() { - m_watch.stop(); - m_time += m_watch.get_seconds(); - } - }; - - - // ---------------------------------- - // MaxSatHS+MSS - // variant of MaxSAT-HS (Algorithm 9) - // that also refines upper bound during progressive calls - // to the underlying optimization solver for the soft constraints. - // - - class maxhs : public maxsmt_solver_base { - struct stats { - stats() { reset(); } - void reset() { memset(this, 0, sizeof(*this)); } - unsigned m_num_iterations; - unsigned m_num_core_reductions_success; - unsigned m_num_core_reductions_failure; - unsigned m_num_model_expansions_success; - unsigned m_num_model_expansions_failure; - double m_core_reduction_time; - double m_model_expansion_time; - double m_aux_sat_time; - double m_disjoint_cores_time; - }; - - hitting_sets m_hs; - expr_ref_vector m_aux; // auxiliary (indicator) variables. - obj_map m_aux2index; // expr |-> index - unsigned_vector m_core_activity; // number of times soft constraint is used in a core. - svector m_seed; // clause selected in current model. - svector m_aux_active; // active soft clauses. - ptr_vector m_asms; // assumptions (over aux) - stats m_stats; - bool m_at_lower_bound; - - - public: - maxhs(maxsat_context& c, weights_t& ws, expr_ref_vector const& soft): - maxsmt_solver_base(c, ws, soft), - m_hs(m.limit()), - m_aux(m), - m_at_lower_bound(false) { - } - virtual ~maxhs() {} - - virtual void collect_statistics(statistics& st) const { - maxsmt_solver_base::collect_statistics(st); - m_hs.collect_statistics(st); - st.update("maxhs-num-iterations", m_stats.m_num_iterations); - st.update("maxhs-num-core-reductions-n", m_stats.m_num_core_reductions_failure); - st.update("maxhs-num-core-reductions-y", m_stats.m_num_core_reductions_success); - st.update("maxhs-num-model-expansions-n", m_stats.m_num_model_expansions_failure); - st.update("maxhs-num-model-expansions-y", m_stats.m_num_model_expansions_success); - st.update("maxhs-core-reduction-time", m_stats.m_core_reduction_time); - st.update("maxhs-model-expansion-time", m_stats.m_model_expansion_time); - st.update("maxhs-aux-sat-time", m_stats.m_aux_sat_time); - st.update("maxhs-disj-core-time", m_stats.m_disjoint_cores_time); - } - - lbool operator()() { - ptr_vector hs; - init(); - init_local(); - if (!disjoint_cores(hs)) { - return l_undef; - } - seed2assumptions(); - while (m_lower < m_upper) { - ++m_stats.m_num_iterations; - trace_bounds("maxhs"); - TRACE("opt", tout << "(maxhs [" << m_lower << ":" << m_upper << "])\n";); - if (m.canceled()) { - return l_undef; - } - - lbool core_found = generate_cores(hs); - switch(core_found) { - case l_undef: - return l_undef; - case l_true: { - lbool is_sat = next_seed(); - switch(is_sat) { - case l_true: - seed2hs(false, hs); - break; - case l_false: - TRACE("opt", tout << "no more seeds\n";); - IF_VERBOSE(1, verbose_stream() << "(opt.maxhs.no-more-seeds)\n";); - m_lower = m_upper; - return l_true; - case l_undef: - return l_undef; - } - break; - } - case l_false: - IF_VERBOSE(1, verbose_stream() << "(opt.maxhs.no-more-cores)\n";); - TRACE("opt", tout << "no more cores\n";); - m_lower = m_upper; - return l_true; - } - } - return l_true; - } - - private: - - unsigned num_soft() const { return m_soft.size(); } - - void init_local() { - unsigned sz = num_soft(); - app_ref fml(m), obj(m); - expr_ref_vector sum(m); - m_asms.reset(); - m_seed.reset(); - m_aux.reset(); - m_aux_active.reset(); - m_aux2index.reset(); - m_core_activity.reset(); - for (unsigned i = 0; i < sz; ++i) { - bool tt = is_true(m_model, m_soft[i]); - m_seed.push_back(tt); - m_aux. push_back(mk_fresh(m.mk_bool_sort())); - m_aux_active.push_back(false); - m_core_activity.push_back(0); - m_aux2index.insert(m_aux.back(), i); - if (tt) { - m_asms.push_back(m_aux.back()); - ensure_active(i); - } - } - - for (unsigned i = 0; i < m_weights.size(); ++i) { - m_hs.add_weight(m_weights[i]); - } - TRACE("opt", print_seed(tout);); - } - - - void hs2seed(ptr_vector const& hs) { - for (unsigned i = 0; i < num_soft(); ++i) { - m_seed[i] = true; - } - for (unsigned i = 0; i < hs.size(); ++i) { - m_seed[m_aux2index.find(hs[i])] = false; - } - TRACE("opt", - print_asms(tout << "hitting set: ", hs); - print_seed(tout);); - } - - void seed2hs(bool pos, ptr_vector& hs) { - hs.reset(); - for (unsigned i = 0; i < num_soft(); ++i) { - if (pos == m_seed[i]) { - hs.push_back(m_aux[i].get()); - } - } - TRACE("opt", - print_asms(tout << "hitting set: ", hs); - print_seed(tout);); - - } - - void seed2assumptions() { - seed2hs(true, m_asms); - } - - - // - // Find disjoint cores for soft constraints. - // - bool disjoint_cores(ptr_vector& hs) { - scoped_stopwatch _sw(m_stats.m_disjoint_cores_time); - m_asms.reset(); - svector active(num_soft(), true); - rational lower(0); - update_assumptions(active, lower, hs); - SASSERT(lower.is_zero()); - while (true) { - lbool is_sat = s().check_sat(m_asms.size(), m_asms.c_ptr()); - switch (is_sat) { - case l_true: - if (lower > m_lower) { - m_lower = lower; - } - return true; - case l_false: - if (!shrink()) return false; - block_up(); - update_assumptions(active, lower, hs); - break; - case l_undef: - return false; - } - } - } - - void update_assumptions(svector& active, rational& lower, ptr_vector& hs) { - rational arg_min(0); - expr* e = 0; - for (unsigned i = 0; i < m_asms.size(); ++i) { - unsigned index = m_aux2index.find(m_asms[i]); - active[index] = false; - if (arg_min.is_zero() || arg_min > m_weights[index]) { - arg_min = m_weights[index]; - e = m_asms[i]; - } - } - if (e) { - hs.push_back(e); - lower += arg_min; - } - m_asms.reset(); - for (unsigned i = 0; i < num_soft(); ++i) { - if (active[i]) { - m_asms.push_back(m_aux[i].get()); - ensure_active(i); - } - } - } - - // - // Auxiliary Algorithm 10 for producing cores. - // - lbool generate_cores(ptr_vector& hs) { - bool core = !m_at_lower_bound; - while (true) { - hs2seed(hs); - lbool is_sat = check_subset(); - switch(is_sat) { - case l_undef: - return l_undef; - case l_true: - if (!grow()) return l_undef; - block_down(); - return core?l_true:l_false; - case l_false: - core = true; - if (!shrink()) return l_undef; - block_up(); - find_non_optimal_hitting_set(hs); - break; - } - } - } - - struct lt_activity { - maxhs& hs; - lt_activity(maxhs& hs):hs(hs) {} - bool operator()(expr* a, expr* b) const { - unsigned w1 = hs.m_core_activity[hs.m_aux2index.find(a)]; - unsigned w2 = hs.m_core_activity[hs.m_aux2index.find(b)]; - return w1 < w2; - } - }; - - // - // produce the non-optimal hitting set by using the 10% heuristic. - // of most active cores constraints. - // m_asms contains the current core. - // - void find_non_optimal_hitting_set(ptr_vector& hs) { - std::sort(m_asms.begin(), m_asms.end(), lt_activity(*this)); - for (unsigned i = m_asms.size(); i > 9*m_asms.size()/10;) { - --i; - hs.push_back(m_asms[i]); - } - } - - // - // retrieve the next seed that satisfies state of hs. - // state of hs must be satisfiable before optimization is called. - // - lbool next_seed() { - scoped_stopwatch _sw(m_stats.m_aux_sat_time); - TRACE("opt", tout << "\n";); - - // min c_i*(not x_i) for x_i are soft clauses. - // max c_i*x_i for x_i are soft clauses - - m_at_lower_bound = false; - - lbool is_sat = m_hs.compute_upper(); - - if (is_sat == l_true) { - is_sat = m_hs.compute_lower(); - } - if (is_sat == l_true) { - m_at_lower_bound = m_hs.get_upper() == m_hs.get_lower(); - if (m_hs.get_lower() > m_lower) { - m_lower = m_hs.get_lower(); - } - for (unsigned i = 0; i < num_soft(); ++i) { - m_seed[i] = is_active(i) && !m_hs.get_value(i); - } - TRACE("opt", print_seed(tout);); - } - return is_sat; - } - - // - // check assignment returned by HS with the original - // hard constraints. - // - lbool check_subset() { - TRACE("opt", tout << "\n";); - m_asms.reset(); - for (unsigned i = 0; i < num_soft(); ++i) { - if (m_seed[i]) { - m_asms.push_back(m_aux[i].get()); - ensure_active(i); - } - } - return s().check_sat(m_asms.size(), m_asms.c_ptr()); - } - - // - // extend the current assignment to one that - // satisfies as many soft constraints as possible. - // update the upper bound based on this assignment - // - bool grow() { - scoped_stopwatch _sw(m_stats.m_model_expansion_time); - model_ref mdl; - s().get_model(mdl); - for (unsigned i = 0; i < num_soft(); ++i) { - ensure_active(i); - m_seed[i] = false; - } - for (unsigned i = 0; i < m_asms.size(); ++i) { - m_seed[m_aux2index.find(m_asms[i])] = true; - } - - for (unsigned i = 0; i < num_soft(); ++i) { - if (m_seed[i]) { - // already an assumption - } - else if (is_true(mdl, m_soft[i])) { - m_seed[i] = true; - m_asms.push_back(m_aux[i].get()); - } - else { - m_asms.push_back(m_aux[i].get()); - lbool is_sat = s().check_sat(m_asms.size(), m_asms.c_ptr()); - switch(is_sat) { - case l_undef: - return false; - case l_false: - ++m_stats.m_num_model_expansions_failure; - m_asms.pop_back(); - break; - case l_true: - ++m_stats.m_num_model_expansions_success; - s().get_model(mdl); - m_seed[i] = true; - break; - } - } - } - rational upper(0); - for (unsigned i = 0; i < num_soft(); ++i) { - if (!m_seed[i]) { - upper += m_weights[i]; - } - } - if (upper < m_upper) { - m_upper = upper; - m_hs.set_upper(upper); - m_model = mdl; - m_assignment.reset(); - m_assignment.append(m_seed); - TRACE("opt", - tout << "new upper: " << m_upper << "\n"; - model_smt2_pp(tout, m, *(mdl.get()), 0);); - } - DEBUG_CODE( - for (unsigned i = 0; i < num_soft(); ++i) { - SASSERT(is_true(mdl, m_soft[i]) == m_seed[i]); - }); - - return true; - } - - // - // remove soft constraints from the current core. - // - bool shrink() { - scoped_stopwatch _sw(m_stats.m_core_reduction_time); - m_asms.reset(); - s().get_unsat_core(m_asms); - TRACE("opt", print_asms(tout, m_asms);); - obj_map asm2index; - for (unsigned i = 0; i < m_asms.size(); ++i) { - asm2index.insert(m_asms[i], i); - } - obj_map::iterator it = asm2index.begin(), end = asm2index.end(); - for (; it != end; ++it) { - unsigned i = it->m_value; - if (i < m_asms.size()) { - expr* tmp = m_asms[i]; - expr* back = m_asms.back(); - m_asms[i] = back; - m_asms.pop_back(); - lbool is_sat = s().check_sat(m_asms.size(), m_asms.c_ptr()); - TRACE("opt", tout << "checking: " << mk_pp(tmp, m) << ": " << is_sat << "\n";); - switch(is_sat) { - case l_true: - ++m_stats.m_num_core_reductions_failure; - // put back literal into core - m_asms.push_back(back); - m_asms[i] = tmp; - break; - case l_false: - // update the core - m_asms.reset(); - ++m_stats.m_num_core_reductions_success; - s().get_unsat_core(m_asms); - TRACE("opt", print_asms(tout, m_asms);); - update_index(asm2index); - break; - case l_undef: - return false; - } - } - } - return true; - } - - void print_asms(std::ostream& out, ptr_vector const& asms) { - for (unsigned j = 0; j < asms.size(); ++j) { - out << mk_pp(asms[j], m) << " "; - } - out << "\n"; - } - - void print_seed(std::ostream& out) { - out << "seed: "; - for (unsigned i = 0; i < num_soft(); ++i) { - out << (m_seed[i]?"1":"0"); - } - out << "\n"; - } - - // - // must include some literal not from asms. - // (furthermore, update upper bound constraint in HS) - // - void block_down() { - uint_set indices; - unsigned_vector c_indices; - for (unsigned i = 0; i < m_asms.size(); ++i) { - indices.insert(m_aux2index.find(m_asms[i])); - } - for (unsigned i = 0; i < num_soft(); ++i) { - if (!indices.contains(i)) { - c_indices.push_back(i); - } - } - m_hs.add_exists_false(c_indices.size(), c_indices.c_ptr()); - } - - // should exclude some literal from core. - void block_up() { - unsigned_vector indices; - for (unsigned i = 0; i < m_asms.size(); ++i) { - unsigned index = m_aux2index.find(m_asms[i]); - m_core_activity[index]++; - indices.push_back(index); - } - m_hs.add_exists_true(indices.size(), indices.c_ptr()); - } - - void update_index(obj_map& asm2index) { - obj_map::iterator it = asm2index.begin(), end = asm2index.end(); - for (; it != end; ++it) { - it->m_value = UINT_MAX; - } - for (unsigned i = 0; i < m_asms.size(); ++i) { - asm2index.find(m_asms[i]) = i; - } - } - - app_ref mk_fresh(sort* s) { - app_ref r(m); - r = m.mk_fresh_const("r", s); - m_c.fm().insert(r->get_decl()); - return r; - } - - bool is_true(model_ref& mdl, expr* e) { - expr_ref val(m); - return mdl->eval(e, val) && m.is_true(val); - } - - bool is_active(unsigned i) const { - return m_aux_active[i]; - } - - void ensure_active(unsigned i) { - if (!is_active(i)) { - expr_ref fml(m); - fml = m.mk_implies(m_aux[i].get(), m_soft[i]); - s().assert_expr(fml); - m_aux_active[i] = true; - } - } - - }; - - maxsmt_solver_base* mk_maxhs( - maxsat_context& c, weights_t& ws, expr_ref_vector const& soft) { - return alloc(maxhs, c, ws, soft); - } - -} diff --git a/src/opt/maxhs.h b/src/opt/maxhs.h deleted file mode 100644 index 903354c0e..000000000 --- a/src/opt/maxhs.h +++ /dev/null @@ -1,29 +0,0 @@ -/*++ -Copyright (c) 2014 Microsoft Corporation - -Module Name: - - maxhs.h - -Abstract: - - HS-max based MaxSAT. - -Author: - - Nikolaj Bjorner (nbjorner) 2014-4-17 - -Notes: - ---*/ - -#ifndef HS_MAX_H_ -#define HS_MAX_H_ - -#include "maxsmt.h" - -namespace opt { - maxsmt_solver_base* mk_maxhs(maxsat_context& c, - weights_t& ws, expr_ref_vector const& soft); -} -#endif diff --git a/src/opt/maxsmt.cpp b/src/opt/maxsmt.cpp index 5229fafab..992e13fe4 100644 --- a/src/opt/maxsmt.cpp +++ b/src/opt/maxsmt.cpp @@ -19,10 +19,7 @@ Notes: #include #include "maxsmt.h" -#include "fu_malik.h" #include "maxres.h" -#include "maxhs.h" -#include "bcd2.h" #include "wmax.h" #include "maxsls.h" #include "ast_pp.h" @@ -166,19 +163,10 @@ namespace opt { else if (maxsat_engine == symbol("pd-maxres")) { m_msolver = mk_primal_dual_maxres(m_c, m_index, m_weights, m_soft_constraints); } - else if (maxsat_engine == symbol("bcd2")) { - m_msolver = mk_bcd2(m_c, m_weights, m_soft_constraints); - } - else if (maxsat_engine == symbol("maxhs")) { - m_msolver = mk_maxhs(m_c, m_weights, m_soft_constraints); - } else if (maxsat_engine == symbol("sls")) { // NB: this is experimental one-round version of SLS m_msolver = mk_sls(m_c, m_weights, m_soft_constraints); } - else if (is_maxsat_problem(m_weights) && maxsat_engine == symbol("fu_malik")) { - m_msolver = mk_fu_malik(m_c, m_weights, m_soft_constraints); - } else { if (maxsat_engine != symbol::null && maxsat_engine != symbol("wmax")) { warning_msg("solver %s is not recognized, using default 'wmax'", diff --git a/src/opt/opt_params.pyg b/src/opt/opt_params.pyg index 629b3aa53..eb8d61423 100644 --- a/src/opt/opt_params.pyg +++ b/src/opt/opt_params.pyg @@ -2,7 +2,7 @@ def_module_params('opt', description='optimization parameters', export=True, params=(('optsmt_engine', SYMBOL, 'basic', "select optimization engine: 'basic', 'farkas', 'symba'"), - ('maxsat_engine', SYMBOL, 'maxres', "select engine for maxsat: 'fu_malik', 'core_maxsat', 'wmax', 'pbmax', 'maxres', 'pd-maxres', 'bcd2', 'wpm2', 'sls', 'maxhs'"), + ('maxsat_engine', SYMBOL, 'maxres', "select engine for maxsat: 'core_maxsat', 'wmax', 'maxres', 'pd-maxres', 'sls'"), ('priority', SYMBOL, 'lex', "select how to priortize objectives: 'lex' (lexicographic), 'pareto', or 'box'"), ('dump_benchmarks', BOOL, False, 'dump benchmarks for profiling'), ('print_model', BOOL, False, 'display model for satisfiable constraints'), From 1073e161c764886c656bce5585f0bac495d0652b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 20 Jul 2016 19:08:23 -0700 Subject: [PATCH 102/536] remove deprecated max-sat solvers Signed-off-by: Nikolaj Bjorner --- contrib/cmake/examples/tptp/CMakeLists.txt | 4 ++++ contrib/cmake/src/opt/CMakeLists.txt | 4 ---- 2 files changed, 4 insertions(+), 4 deletions(-) create mode 100644 contrib/cmake/examples/tptp/CMakeLists.txt diff --git a/contrib/cmake/examples/tptp/CMakeLists.txt b/contrib/cmake/examples/tptp/CMakeLists.txt new file mode 100644 index 000000000..447307cd7 --- /dev/null +++ b/contrib/cmake/examples/tptp/CMakeLists.txt @@ -0,0 +1,4 @@ +add_executable(tptp5 EXCLUDE_FROM_ALL tptp5.cpp) +target_link_libraries(tptp5 PRIVATE libz3) +target_include_directories(tptp5 PRIVATE "${CMAKE_SOURCE_DIR}/src/api") +target_include_directories(tptp5 PRIVATE "${CMAKE_SOURCE_DIR}/src/api/c++") diff --git a/contrib/cmake/src/opt/CMakeLists.txt b/contrib/cmake/src/opt/CMakeLists.txt index e4166e3d4..778edc2de 100644 --- a/contrib/cmake/src/opt/CMakeLists.txt +++ b/contrib/cmake/src/opt/CMakeLists.txt @@ -1,9 +1,5 @@ z3_add_component(opt SOURCES - bcd2.cpp - fu_malik.cpp - hitting_sets.cpp - maxhs.cpp maxres.cpp maxsls.cpp maxsmt.cpp From 16e3a91bdfed56ad8c46561a83de6aab874e1a09 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 21 Jul 2016 07:56:21 -0700 Subject: [PATCH 103/536] fix issues reported by Geoff Signed-off-by: Nikolaj Bjorner --- contrib/cmake/examples/tptp/CMakeLists.txt | 8 ++-- examples/tptp/tptp5.cpp | 48 +++++++++++----------- 2 files changed, 28 insertions(+), 28 deletions(-) diff --git a/contrib/cmake/examples/tptp/CMakeLists.txt b/contrib/cmake/examples/tptp/CMakeLists.txt index 447307cd7..41fa9cc65 100644 --- a/contrib/cmake/examples/tptp/CMakeLists.txt +++ b/contrib/cmake/examples/tptp/CMakeLists.txt @@ -1,4 +1,4 @@ -add_executable(tptp5 EXCLUDE_FROM_ALL tptp5.cpp) -target_link_libraries(tptp5 PRIVATE libz3) -target_include_directories(tptp5 PRIVATE "${CMAKE_SOURCE_DIR}/src/api") -target_include_directories(tptp5 PRIVATE "${CMAKE_SOURCE_DIR}/src/api/c++") +add_executable(z3_tptp5 EXCLUDE_FROM_ALL tptp5.cpp tptp5.lex.cpp) +target_link_libraries(z3_tptp5 PRIVATE libz3) +target_include_directories(z3_tptp5 PRIVATE "${CMAKE_SOURCE_DIR}/src/api") +target_include_directories(z3_tptp5 PRIVATE "${CMAKE_SOURCE_DIR}/src/api/c++") diff --git a/examples/tptp/tptp5.cpp b/examples/tptp/tptp5.cpp index a180d4ca9..8f28111ac 100644 --- a/examples/tptp/tptp5.cpp +++ b/examples/tptp/tptp5.cpp @@ -1232,16 +1232,9 @@ public: } void display(std::ostream& out, z3::expr e) { - if (e.is_numeral()) { - __int64 num, den; - if (Z3_get_numeral_small(ctx, e, &num, &den)) { - if (num < 0 && den == 1 && num != std::numeric_limits<__int64>::min()) { - out << "-" << (-num); - return; - } - } - // potential incompatibility: prints negative numbers with a space. - out << e; + std::string s; + if (e.is_numeral(s)) { + out << s; } else if (e.is_var()) { unsigned idx = Z3_get_index_value(ctx, e); @@ -2372,7 +2365,7 @@ static void prove_tptp() { } catch (failure_ex& ex) { std::cerr << ex.msg << "\n"; - std::cout << "SZS status GaveUp\n"; + std::cout << "% SZS status GaveUp\n"; return; } @@ -2404,16 +2397,16 @@ static void prove_tptp() { std::cout << result << "\n"; } else if (fmls.has_conjecture()) { - std::cout << "SZS status Theorem\n"; + std::cout << "% SZS status Theorem\n"; } else { - std::cout << "SZS status Unsatisfiable\n"; + std::cout << "% SZS status Unsatisfiable\n"; } if (g_generate_proof) { try { - std::cout << "SZS output start Proof\n"; + std::cout << "% SZS output start Proof\n"; display_proof(ctx, fmls, solver); - std::cout << "SZS output end Proof\n"; + std::cout << "% SZS output end Proof\n"; } catch (failure_ex& ex) { std::cerr << "Proof display could not be completed: " << ex.msg << "\n"; @@ -2421,7 +2414,7 @@ static void prove_tptp() { } if (g_generate_core) { z3::expr_vector core = solver.unsat_core(); - std::cout << "SZS core "; + std::cout << "% SZS core "; for (unsigned i = 0; i < core.size(); ++i) { std::cout << core[i] << " "; } @@ -2433,15 +2426,15 @@ static void prove_tptp() { std::cout << result << "\n"; } else if (fmls.has_conjecture()) { - std::cout << "SZS status CounterSatisfiable\n"; + std::cout << "% SZS status CounterSatisfiable\n"; } else { - std::cout << "SZS status Satisfiable\n"; + std::cout << "% SZS status Satisfiable\n"; } if (g_generate_model) { - std::cout << "SZS output start Model\n"; + std::cout << "% SZS output start Model\n"; display_model(ctx, solver.get_model()); - std::cout << "SZS output end Model\n"; + std::cout << "% SZS output end Model\n"; } break; case z3::unknown: @@ -2449,12 +2442,12 @@ static void prove_tptp() { std::cout << result << "\n"; } else if (!g_first_interrupt) { - std::cout << "SZS status Interrupted\n"; + std::cout << "% SZS status Interrupted\n"; } else { - std::cout << "SZS status GaveUp\n"; + std::cout << "% SZS status GaveUp\n"; std::string reason = solver.reason_unknown(); - std::cout << "SZS reason " << reason << "\n"; + std::cout << "% SZS reason " << reason << "\n"; } break; } @@ -2487,7 +2480,14 @@ int main(int argc, char** argv) { display_smt2(*g_out); } else { - prove_tptp(); + try { + prove_tptp(); + } + catch (z3::exception& ex) { + std::cerr << "Proof display could not be completed: " << ex.msg() << "\n"; + } + + } return 0; } From 3581f6de429e592bd60c252ed5b8bd00b836138b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 21 Jul 2016 18:18:42 -0700 Subject: [PATCH 104/536] remove stale SLS option Signed-off-by: Nikolaj Bjorner --- contrib/cmake/src/opt/CMakeLists.txt | 1 - src/opt/maxsls.cpp | 73 --------------------------- src/opt/maxsls.h | 35 ------------- src/opt/maxsmt.cpp | 6 +-- src/opt/opt_context.cpp | 2 +- src/opt/opt_params.pyg | 2 +- src/opt/opt_sls_solver.h | 5 +- src/sat/sat_solver/inc_sat_solver.cpp | 3 ++ 8 files changed, 10 insertions(+), 117 deletions(-) delete mode 100644 src/opt/maxsls.cpp delete mode 100644 src/opt/maxsls.h diff --git a/contrib/cmake/src/opt/CMakeLists.txt b/contrib/cmake/src/opt/CMakeLists.txt index 778edc2de..b8d17ec89 100644 --- a/contrib/cmake/src/opt/CMakeLists.txt +++ b/contrib/cmake/src/opt/CMakeLists.txt @@ -1,7 +1,6 @@ z3_add_component(opt SOURCES maxres.cpp - maxsls.cpp maxsmt.cpp mss.cpp opt_cmds.cpp diff --git a/src/opt/maxsls.cpp b/src/opt/maxsls.cpp deleted file mode 100644 index 4e59cfdfd..000000000 --- a/src/opt/maxsls.cpp +++ /dev/null @@ -1,73 +0,0 @@ -/*++ -Copyright (c) 2013 Microsoft Corporation - -Module Name: - - maxsls.cpp - -Abstract: - - Weighted SLS MAXSAT module - -Author: - - Nikolaj Bjorner (nbjorner) 2014-4-17 - -Notes: - ---*/ - -#include "maxsls.h" -#include "ast_pp.h" -#include "model_smt2_pp.h" -#include "opt_context.h" -#include "inc_sat_solver.h" - - -namespace opt { - - class sls : public maxsmt_solver_base { - public: - sls(maxsat_context& c, weights_t& ws, expr_ref_vector const& soft): - maxsmt_solver_base(c, ws, soft) { - } - virtual ~sls() {} - lbool operator()() { - IF_VERBOSE(1, verbose_stream() << "(opt.sls)\n";); - init(); - enable_sls(true); - lbool is_sat = check(); - if (is_sat == l_true) { - s().get_model(m_model); - m_upper.reset(); - for (unsigned i = 0; i < m_soft.size(); ++i) { - expr_ref tmp(m); - m_model->eval(m_soft[i], tmp, true); - m_assignment[i] = m.is_true(tmp); - if (!m_assignment[i]) { - m_upper += m_weights[i]; - } - } - } - return is_sat; - } - - lbool check() { - if (m_c.sat_enabled()) { - return inc_sat_check_sat( - s(), m_soft.size(), m_soft.c_ptr(), m_weights.c_ptr(), m_upper); - } - else { - return s().check_sat(0, 0); - } - } - - }; - - maxsmt_solver_base* mk_sls( - maxsat_context& c, weights_t& ws, expr_ref_vector const& soft) { - return alloc(sls, c, ws, soft); - } - - -}; diff --git a/src/opt/maxsls.h b/src/opt/maxsls.h deleted file mode 100644 index b23512df4..000000000 --- a/src/opt/maxsls.h +++ /dev/null @@ -1,35 +0,0 @@ -/*++ -Copyright (c) 2013 Microsoft Corporation - -Module Name: - - maxsls.h - -Abstract: - - Weighted SLS MAXSAT module - -Author: - - Nikolaj Bjorner (nbjorner) 2014-4-17 - -Notes: - - Partial, one-round SLS optimizer. Finds the first - local maximum given a resource bound and returns. - ---*/ -#ifndef OPT_SLS_MAX_SAT_H_ -#define OPT_SLS_MAX_SAT_H_ - -#include "maxsmt.h" - -namespace opt { - - - maxsmt_solver_base* mk_sls(maxsat_context& c, weights_t& ws, expr_ref_vector const& soft); - - -}; - -#endif diff --git a/src/opt/maxsmt.cpp b/src/opt/maxsmt.cpp index 992e13fe4..a0dd2aed1 100644 --- a/src/opt/maxsmt.cpp +++ b/src/opt/maxsmt.cpp @@ -21,7 +21,6 @@ Notes: #include "maxsmt.h" #include "maxres.h" #include "wmax.h" -#include "maxsls.h" #include "ast_pp.h" #include "uint_set.h" #include "opt_context.h" @@ -163,15 +162,12 @@ namespace opt { else if (maxsat_engine == symbol("pd-maxres")) { m_msolver = mk_primal_dual_maxres(m_c, m_index, m_weights, m_soft_constraints); } - else if (maxsat_engine == symbol("sls")) { - // NB: this is experimental one-round version of SLS - m_msolver = mk_sls(m_c, m_weights, m_soft_constraints); - } else { if (maxsat_engine != symbol::null && maxsat_engine != symbol("wmax")) { warning_msg("solver %s is not recognized, using default 'wmax'", maxsat_engine.str().c_str()); } + std::cout << "wmax\n"; m_msolver = mk_wmax(m_c, m_weights, m_soft_constraints); } diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 4de602ec4..4eafb93f2 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -561,7 +561,7 @@ namespace opt { if (opt_params(m_params).priority() == symbol("pareto")) { return; } - m_params.set_bool("minimize_core_partial", true); // false); + m_params.set_bool("minimize_core_partial", true); m_params.set_bool("minimize_core", true); m_sat_solver = mk_inc_sat_solver(m, m_params); expr_ref_vector fmls(m); diff --git a/src/opt/opt_params.pyg b/src/opt/opt_params.pyg index eb8d61423..a7c9e0011 100644 --- a/src/opt/opt_params.pyg +++ b/src/opt/opt_params.pyg @@ -2,7 +2,7 @@ def_module_params('opt', description='optimization parameters', export=True, params=(('optsmt_engine', SYMBOL, 'basic', "select optimization engine: 'basic', 'farkas', 'symba'"), - ('maxsat_engine', SYMBOL, 'maxres', "select engine for maxsat: 'core_maxsat', 'wmax', 'maxres', 'pd-maxres', 'sls'"), + ('maxsat_engine', SYMBOL, 'maxres', "select engine for maxsat: 'core_maxsat', 'wmax', 'maxres', 'pd-maxres'"), ('priority', SYMBOL, 'lex', "select how to priortize objectives: 'lex' (lexicographic), 'pareto', or 'box'"), ('dump_benchmarks', BOOL, False, 'dump benchmarks for profiling'), ('print_model', BOOL, False, 'display model for satisfiable constraints'), diff --git a/src/opt/opt_sls_solver.h b/src/opt/opt_sls_solver.h index 5071563f7..17c5a51bf 100644 --- a/src/opt/opt_sls_solver.h +++ b/src/opt/opt_sls_solver.h @@ -184,9 +184,10 @@ namespace opt { expr_ref tmp(m); goal_ref g(alloc(goal, m, true, false)); for (unsigned i = 0; i < m_solver->get_num_assertions(); ++i) { - m_pb2bv(m_solver->get_assertion(i), tmp); + m_pb2bv(m_solver->get_assertion(i), tmp); g->assert_expr(tmp); } + TRACE("opt", g->display(tout);); tactic_ref simplify = mk_nnf_tactic(m); proof_converter_ref pc; expr_dependency_ref core(m); @@ -198,6 +199,7 @@ namespace opt { for (unsigned i = 0; i < r->size(); ++i) { m_bvsls->assert_expr(r->form(i)); } + TRACE("opt", m_bvsls->display(tout);); } void pbsls_opt(model_ref& mdl) { @@ -230,6 +232,7 @@ namespace opt { } assertions2sls(); expr_ref objective = soft2bv(m_soft, m_weights); + TRACE("opt", tout << objective << "\n";); opt_result res(m); res.is_sat = l_undef; try { diff --git a/src/sat/sat_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp index 766ed52be..badb0a67a 100644 --- a/src/sat/sat_solver/inc_sat_solver.cpp +++ b/src/sat/sat_solver/inc_sat_solver.cpp @@ -474,6 +474,9 @@ lbool inc_sat_check_sat(solver& _s, unsigned sz, expr*const* soft, rational cons for (unsigned i = 0; _weights && i < sz; ++i) { weights.push_back(_weights[i].get_double()); } + params_ref p; + p.set_bool("minimize_core", false); + s.updt_params(p); return s.check_sat(sz, soft, weights.c_ptr(), max_weight.get_double()); } From f325b512138163daba0b27deb7b1c54969594cdf Mon Sep 17 00:00:00 2001 From: Philipp Wendler Date: Fri, 22 Jul 2016 16:49:50 +0200 Subject: [PATCH 105/536] Java API: In fromInt() methods of enums fail on invalid value. The existing code just returns one of the enum values if an unknown int value is passed, silently hiding bugs. --- scripts/mk_genfile_common.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/mk_genfile_common.py b/scripts/mk_genfile_common.py index b8d6ac5e1..51d68f56c 100644 --- a/scripts/mk_genfile_common.py +++ b/scripts/mk_genfile_common.py @@ -345,7 +345,7 @@ def mk_z3consts_java_internal(api_files, package_name, output_dir): efile.write(' public static final %s fromInt(int v) {\n' % name) efile.write(' for (%s k: values()) \n' % name) efile.write(' if (k.intValue == v) return k;\n') - efile.write(' return values()[0];\n') + efile.write(' throw new IllegalArgumentException("Illegal value " + v + " for %s");\n' % name) efile.write(' }\n\n') efile.write(' public final int toInt() { return this.intValue; }\n') # efile.write(';\n %s(int v) {}\n' % name) From c3b8c15f35d1b2996517e8c2097d71996ab8e667 Mon Sep 17 00:00:00 2001 From: Philipp Wendler Date: Fri, 22 Jul 2016 17:28:40 +0200 Subject: [PATCH 106/536] Java API: Make enum lookup more efficient. The existing code causes an allocation of an array with all enum values on every method call (inside the values() method), and loops over all enum entries. --- scripts/mk_genfile_common.py | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/scripts/mk_genfile_common.py b/scripts/mk_genfile_common.py index 51d68f56c..cbeb8a82d 100644 --- a/scripts/mk_genfile_common.py +++ b/scripts/mk_genfile_common.py @@ -323,6 +323,9 @@ def mk_z3consts_java_internal(api_files, package_name, output_dir): generated_enumeration_files.append(efile.name) efile.write('/**\n * Automatically generated file\n **/\n\n') efile.write('package %s.enumerations;\n\n' % package_name) + efile.write('import java.util.HashMap;\n') + efile.write('import java.util.Map;\n') + efile.write('\n') efile.write('/**\n') efile.write(' * %s\n' % name) @@ -342,9 +345,18 @@ def mk_z3consts_java_internal(api_files, package_name, output_dir): efile.write(' %s(int v) {\n' % name) efile.write(' this.intValue = v;\n') efile.write(' }\n\n') + efile.write(' // Cannot initialize map in constructor, so need to do it lazily.\n') + efile.write(' // Easiest thread-safe way is the initialization-on-demand holder pattern.\n') + efile.write(' private static class %s_MappingHolder {\n' % name) + efile.write(' private static final Map intMapping = new HashMap<>();\n' % name) + efile.write(' static {\n') + efile.write(' for (%s k : %s.values())\n' % (name, name)) + efile.write(' intMapping.put(k.toInt(), k);\n') + efile.write(' }\n') + efile.write(' }\n\n') efile.write(' public static final %s fromInt(int v) {\n' % name) - efile.write(' for (%s k: values()) \n' % name) - efile.write(' if (k.intValue == v) return k;\n') + efile.write(' %s k = %s_MappingHolder.intMapping.get(v);\n' % (name, name)) + efile.write(' if (k != null) return k;\n') efile.write(' throw new IllegalArgumentException("Illegal value " + v + " for %s");\n' % name) efile.write(' }\n\n') efile.write(' public final int toInt() { return this.intValue; }\n') From 083939ab0e245f0fe89a9de8d789cff1fa642918 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 23 Jul 2016 14:11:21 -0700 Subject: [PATCH 107/536] add tactic to eliminate enumeration sorts in favor of bit-vectors Signed-off-by: Nikolaj Bjorner --- contrib/cmake/src/tactic/bv/CMakeLists.txt | 1 + src/ast/datatype_decl_plugin.cpp | 20 ++ src/ast/datatype_decl_plugin.h | 3 + src/tactic/bv/dt2bv_tactic.cpp | 304 +++++++++++++++++++++ src/tactic/bv/dt2bv_tactic.h | 32 +++ src/tactic/bv/elim_small_bv_tactic.cpp | 5 +- 6 files changed, 362 insertions(+), 3 deletions(-) create mode 100644 src/tactic/bv/dt2bv_tactic.cpp create mode 100644 src/tactic/bv/dt2bv_tactic.h diff --git a/contrib/cmake/src/tactic/bv/CMakeLists.txt b/contrib/cmake/src/tactic/bv/CMakeLists.txt index 42cff2bfc..b39d77a0a 100644 --- a/contrib/cmake/src/tactic/bv/CMakeLists.txt +++ b/contrib/cmake/src/tactic/bv/CMakeLists.txt @@ -7,6 +7,7 @@ z3_add_component(bv_tactics bvarray2uf_tactic.cpp bv_bounds_tactic.cpp bv_size_reduction_tactic.cpp + dt2bv_tactic.cpp elim_small_bv_tactic.cpp max_bv_sharing_tactic.cpp COMPONENT_DEPENDENCIES diff --git a/src/ast/datatype_decl_plugin.cpp b/src/ast/datatype_decl_plugin.cpp index eb15910bc..8bfd9b36d 100644 --- a/src/ast/datatype_decl_plugin.cpp +++ b/src/ast/datatype_decl_plugin.cpp @@ -933,6 +933,25 @@ bool datatype_util::is_recursive(sort * ty) { return r; } + +bool datatype_util::is_enum_sort(sort* s) { + if (!is_datatype(s)) { + return false; + } + bool r = false; + if (m_is_enum.find(s, r)) + return r; + ptr_vector const& cnstrs = *get_datatype_constructors(s); + r = true; + for (unsigned i = 0; r && i < cnstrs.size(); ++i) { + r = cnstrs[i]->get_arity() == 0; + } + m_is_enum.insert(s, r); + m_asts.push_back(s); + return r; +} + + void datatype_util::reset() { m_datatype2constructors.reset(); m_datatype2nonrec_constructor.reset(); @@ -941,6 +960,7 @@ void datatype_util::reset() { m_recognizer2constructor.reset(); m_accessor2constructor.reset(); m_is_recursive.reset(); + m_is_enum.reset(); std::for_each(m_vectors.begin(), m_vectors.end(), delete_proc >()); m_vectors.reset(); m_asts.reset(); diff --git a/src/ast/datatype_decl_plugin.h b/src/ast/datatype_decl_plugin.h index 8ef6fb557..019dd339e 100644 --- a/src/ast/datatype_decl_plugin.h +++ b/src/ast/datatype_decl_plugin.h @@ -173,6 +173,7 @@ class datatype_util { obj_map m_recognizer2constructor; obj_map m_accessor2constructor; obj_map m_is_recursive; + obj_map m_is_enum; ast_ref_vector m_asts; ptr_vector > m_vectors; @@ -184,6 +185,8 @@ public: ~datatype_util(); ast_manager & get_manager() const { return m_manager; } bool is_datatype(sort * s) const { return is_sort_of(s, m_family_id, DATATYPE_SORT); } + bool is_enum_sort(sort* s); + bool is_recursive(sort * ty); bool is_constructor(func_decl * f) const { return is_decl_of(f, m_family_id, OP_DT_CONSTRUCTOR); } bool is_recognizer(func_decl * f) const { return is_decl_of(f, m_family_id, OP_DT_RECOGNISER); } diff --git a/src/tactic/bv/dt2bv_tactic.cpp b/src/tactic/bv/dt2bv_tactic.cpp new file mode 100644 index 000000000..022617c6d --- /dev/null +++ b/src/tactic/bv/dt2bv_tactic.cpp @@ -0,0 +1,304 @@ +/*++ +Copyright (c) 2016 Microsoft Corporation + +Module Name: + + dt2bv_tactic.cpp + +Abstract: + + Tactic that eliminates finite domain data-types. + +Author: + + nbjorner 2016-07-22 + +Revision History: + +--*/ + +#include "dt2bv_tactic.h" +#include "tactical.h" +#include "filter_model_converter.h" +#include "datatype_decl_plugin.h" +#include "bv_decl_plugin.h" +#include "rewriter_def.h" +#include "filter_model_converter.h" +#include "extension_model_converter.h" +#include "var_subst.h" +#include "ast_util.h" + +#if 0 + +enumeration types: + +a = x: + x = y + +forall x . phi + + f(x,y) = z -> + +#endif + + +class dt2bv_tactic : public tactic { + + ast_manager& m; + params_ref m_params; + datatype_util m_dt; + bv_util m_bv; + obj_hashtable m_fd_sorts; + obj_hashtable m_non_fd_sorts; + expr_ref_vector m_bounds; + ref m_ext; + ref m_filter; + unsigned m_num_transformed; + + struct rw_cfg : public default_rewriter_cfg { + dt2bv_tactic& m_t; + ast_manager& m; + params_ref m_params; + obj_map m_cache; + expr_ref_vector m_trail; + + rw_cfg(dt2bv_tactic& t, ast_manager & m, params_ref const & p) : + m_t(t), + m(m), + m_params(p), + m_trail(m) + {} + + br_status reduce_app(func_decl * f, unsigned num, expr * const * args, expr_ref & result, proof_ref & result_pr) { + expr_ref a0(m), a1(m); + if (m.is_eq(f) && reduce_arg(args[0], a0) && reduce_arg(args[1], a1)) { + result = m.mk_eq(a0, a1); + return BR_DONE; + } + else { + return BR_FAILED; + } + } + + bool reduce_arg(expr* a, expr_ref& result) { + expr* b; + if (m_cache.find(a, b)) { + result = b; + return true; + } + + sort* s = get_sort(a); + if (!m_t.m_fd_sorts.contains(s)) { + return false; + } + unsigned bv_size = get_bv_size(s); + + if (is_var(a)) { + result = m.mk_var(to_var(a)->get_idx(), m_t.m_bv.mk_sort(bv_size)); + return true; + } + SASSERT(is_app(a)); + func_decl* f = to_app(a)->get_decl(); + if (m_t.m_dt.is_constructor(f)) { + unsigned idx = m_t.m_dt.get_constructor_idx(f); + result = m_t.m_bv.mk_numeral(idx, bv_size); + } + else { + // create a fresh variable, add bounds constraints for it. + unsigned nc = m_t.m_dt.get_datatype_num_constructors(s); + result = m.mk_fresh_const(f->get_name().str().c_str(), m_t.m_bv.mk_sort(bv_size)); + if (!is_power_of_two(nc)) { + m_t.m_bounds.push_back(m_t.m_bv.mk_ule(result, m_t.m_bv.mk_numeral(nc, bv_size))); + } + expr_ref f_def(m); + ptr_vector const& cs = *m_t.m_dt.get_datatype_constructors(s); + f_def = m.mk_const(cs[nc-1]); + for (unsigned i = nc - 1; i > 0; ) { + --i; + f_def = m.mk_ite(m.mk_eq(result, m_t.m_bv.mk_numeral(i,bv_size)), m.mk_const(cs[i]), f_def); + } + // update model converters. + m_t.m_ext->insert(f, f_def); + m_t.m_filter->insert(to_app(result)->get_decl()); + } + m_cache.insert(a, result); + ++m_t.m_num_transformed; + return true; + } + + ptr_buffer m_sorts; + + bool reduce_quantifier( + quantifier * q, + expr * old_body, + expr * const * new_patterns, + expr * const * new_no_patterns, + expr_ref & result, + proof_ref & result_pr) { + m_sorts.reset(); + expr_ref_vector bounds(m); + bool found = false; + for (unsigned i = 0; i < q->get_num_decls(); ++i) { + sort* s = q->get_decl_sort(i); + if (m_t.m_fd_sorts.contains(s)) { + unsigned bv_size = get_bv_size(s); + m_sorts.push_back(m_t.m_bv.mk_sort(bv_size)); + unsigned nc = m_t.m_dt.get_datatype_num_constructors(s); + if (!is_power_of_two(nc)) { + bounds.push_back(m_t.m_bv.mk_ule(m.mk_var(q->get_num_decls()-i-1, m_sorts[i]), m_t.m_bv.mk_numeral(nc, bv_size))); + } + found = true; + } + else { + m_sorts.push_back(s); + } + } + if (!found) { + return false; + } + expr_ref new_body_ref(old_body, m), tmp(m); + if (!bounds.empty()) { + if (q->is_forall()) { + new_body_ref = m.mk_implies(mk_and(bounds), new_body_ref); + } + else { + bounds.push_back(new_body_ref); + new_body_ref = mk_and(bounds); + } + } + result = m.mk_quantifier(q->is_forall(), q->get_num_decls(), m_sorts.c_ptr(), q->get_decl_names(), new_body_ref, + q->get_weight(), q->get_qid(), q->get_skid(), + q->get_num_patterns(), new_patterns, + q->get_num_no_patterns(), new_no_patterns); + result_pr = 0; + return true; + } + + unsigned get_bv_size(sort* s) { + unsigned nc = m_t.m_dt.get_datatype_num_constructors(s); + unsigned bv_size = 1; + while ((unsigned)(1 << bv_size) < nc) { + ++bv_size; + } + return bv_size; + } + }; + + struct rw : public rewriter_tpl { + rw_cfg m_cfg; + + rw(dt2bv_tactic& t, ast_manager & m, params_ref const & p) : + rewriter_tpl(m, m.proofs_enabled(), m_cfg), + m_cfg(t, m, p) { + } + }; + + + + bool is_fd(expr* a) { return is_fd(get_sort(a)); } + bool is_fd(sort* a) { return m_dt.is_enum_sort(a); } + + struct check_fd { + dt2bv_tactic& m_t; + ast_manager& m; + + check_fd(dt2bv_tactic& t): m_t(t), m(t.m) {} + + void operator()(app* a) { + if (m.is_eq(a)) { + return; + } + if (m_t.is_fd(a)) { + m_t.m_fd_sorts.insert(get_sort(a)); + } + else { + unsigned sz = a->get_num_args(); + for (unsigned i = 0; i < sz; ++i) { + if (m_t.is_fd(a->get_arg(i))) { + m_t.m_non_fd_sorts.insert(get_sort(a->get_arg(i))); + } + } + } + } + + void operator()(var * v) { + if (m_t.is_fd(v)) { + m_t.m_fd_sorts.insert(get_sort(v)); + } + } + + void operator()(quantifier* q) {} + }; + +public: + + dt2bv_tactic(ast_manager& m, params_ref const& p): + m(m), m_params(p), m_dt(m), m_bv(m), m_bounds(m) {} + + virtual tactic * translate(ast_manager & m) { + return alloc(dt2bv_tactic, m, m_params); + } + + virtual void updt_params(params_ref const & p) { + } + + virtual void collect_param_descrs(param_descrs & r) { + } + + virtual void operator()(goal_ref const & g, + goal_ref_buffer & result, + model_converter_ref & mc, + proof_converter_ref & pc, + expr_dependency_ref & core) { + mc = 0; pc = 0; core = 0; + bool produce_proofs = g->proofs_enabled(); + tactic_report report("dt2bv", *g); + unsigned size = g->size(); + expr_fast_mark1 visited; + check_fd proc(*this); + for (unsigned i = 0; i < size; ++i) { + quick_for_each_expr(proc, visited, g->form(i)); + } + obj_hashtable::iterator it = m_non_fd_sorts.begin(), end = m_non_fd_sorts.end(); + for (; it != end; ++it) { + m_fd_sorts.remove(*it); + } + if (!m_fd_sorts.empty()) { + m_bounds.reset(); + m_num_transformed = 0; + m_ext = alloc(extension_model_converter, m); + m_filter = alloc(filter_model_converter, m); + scoped_ptr r = alloc(rw, *this, m, m_params); + expr_ref new_curr(m); + proof_ref new_pr(m); + for (unsigned idx = 0; idx < size; idx++) { + (*r)(g->form(idx), new_curr, new_pr); + if (produce_proofs) { + proof * pr = g->pr(idx); + new_pr = m.mk_modus_ponens(pr, new_pr); + } + g->update(idx, new_curr, new_pr, g->dep(idx)); + } + for (unsigned i = 0; i < m_bounds.size(); ++i) { + g->assert_expr(m_bounds[i].get()); + } + mc = concat(m_ext.get(), m_filter.get()); + report_tactic_progress(":fd-num-translated", m_num_transformed); + } + g->inc_depth(); + result.push_back(g.get()); + TRACE("dt2bv", g->display(tout);); + SASSERT(g->is_well_sorted()); + } + + virtual void cleanup() { + m_fd_sorts.reset(); + m_non_fd_sorts.reset(); + m_bounds.reset(); + } + +}; + +tactic * mk_dt2bv_tactic(ast_manager & m, params_ref const & p) { + return alloc(dt2bv_tactic, m, p); +} diff --git a/src/tactic/bv/dt2bv_tactic.h b/src/tactic/bv/dt2bv_tactic.h new file mode 100644 index 000000000..64d1d5497 --- /dev/null +++ b/src/tactic/bv/dt2bv_tactic.h @@ -0,0 +1,32 @@ +/*++ +Copyright (c) 2016 Microsoft Corporation + +Module Name: + + dt2bv_tactic.h + +Abstract: + + Tactic that eliminates finite domain data-types. + +Author: + + nbjorner 2016-07-22 + +Revision History: + +--*/ +#ifndef DT2BV_TACTIC_H_ +#define DT2BV_TACTIC_H_ + +#include"params.h" +class ast_manager; +class tactic; + +tactic * mk_dt2bv_tactic(ast_manager & m, params_ref const & p = params_ref()); + +/* + ADD_TACTIC("dt2bv", "eliminate finite domain data-types. Replace by bit-vectors.", "mk_dt2bv_tactic(m, p)") +*/ + +#endif diff --git a/src/tactic/bv/elim_small_bv_tactic.cpp b/src/tactic/bv/elim_small_bv_tactic.cpp index 7db3a15ca..e395433f5 100644 --- a/src/tactic/bv/elim_small_bv_tactic.cpp +++ b/src/tactic/bv/elim_small_bv_tactic.cpp @@ -119,9 +119,8 @@ class elim_small_bv_tactic : public tactic { return res; } - br_status reduce_app(func_decl * f, unsigned num, expr * const * args, expr_ref & result, proof_ref & result_pr) { - result = m.mk_app(f, num, args); - TRACE("elim_small_bv_app", tout << "reduce " << mk_ismt2_pp(result, m) << std::endl; ); + br_status reduce_app(func_decl * f, unsigned num, expr * const * args, expr_ref & result, proof_ref & result_pr) { + TRACE("elim_small_bv_app", expr_ref tmp(m.mk_app(f, num, args), m); tout << "reduce " << tmp << std::endl; ); return BR_FAILED; } From 6bf446dfc24090beccb20574230cbf22d9e660ed Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 23 Jul 2016 14:13:40 -0700 Subject: [PATCH 108/536] add tactic to eliminate enumeration sorts in favor of bit-vectors Signed-off-by: Nikolaj Bjorner --- src/tactic/bv/dt2bv_tactic.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tactic/bv/dt2bv_tactic.cpp b/src/tactic/bv/dt2bv_tactic.cpp index 022617c6d..5a6c4e5fd 100644 --- a/src/tactic/bv/dt2bv_tactic.cpp +++ b/src/tactic/bv/dt2bv_tactic.cpp @@ -282,7 +282,7 @@ public: for (unsigned i = 0; i < m_bounds.size(); ++i) { g->assert_expr(m_bounds[i].get()); } - mc = concat(m_ext.get(), m_filter.get()); + mc = concat(m_filter.get(), m_ext.get()); report_tactic_progress(":fd-num-translated", m_num_transformed); } g->inc_depth(); From a85c5f0faca721532c00afc3539e67d6dad5b289 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 24 Jul 2016 17:29:17 -0700 Subject: [PATCH 109/536] add handling of recognizers to enumeration types Signed-off-by: Nikolaj Bjorner --- src/tactic/bv/dt2bv_tactic.cpp | 35 +++++++++++++++++----------------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/src/tactic/bv/dt2bv_tactic.cpp b/src/tactic/bv/dt2bv_tactic.cpp index 5a6c4e5fd..6f20fc609 100644 --- a/src/tactic/bv/dt2bv_tactic.cpp +++ b/src/tactic/bv/dt2bv_tactic.cpp @@ -15,6 +15,8 @@ Author: Revision History: + Possible extension is to handle tuple types over finite domains. + --*/ #include "dt2bv_tactic.h" @@ -28,19 +30,6 @@ Revision History: #include "var_subst.h" #include "ast_util.h" -#if 0 - -enumeration types: - -a = x: - x = y - -forall x . phi - - f(x,y) = z -> - -#endif - class dt2bv_tactic : public tactic { @@ -53,7 +42,7 @@ class dt2bv_tactic : public tactic { expr_ref_vector m_bounds; ref m_ext; ref m_filter; - unsigned m_num_transformed; + unsigned m_num_translated; struct rw_cfg : public default_rewriter_cfg { dt2bv_tactic& m_t; @@ -75,6 +64,12 @@ class dt2bv_tactic : public tactic { result = m.mk_eq(a0, a1); return BR_DONE; } + else if (m_t.m_dt.is_recognizer(f) && reduce_arg(args[0], a0)) { + unsigned idx = m_t.m_dt.get_recognizer_constructor_idx(f); + a1 = m_t.m_bv.mk_numeral(rational(idx), get_sort(a0)); + result = m.mk_eq(a0, a1); + return BR_DONE; + } else { return BR_FAILED; } @@ -122,7 +117,7 @@ class dt2bv_tactic : public tactic { m_t.m_filter->insert(to_app(result)->get_decl()); } m_cache.insert(a, result); - ++m_t.m_num_transformed; + ++m_t.m_num_translated; return true; } @@ -208,6 +203,12 @@ class dt2bv_tactic : public tactic { if (m.is_eq(a)) { return; } + if (m_t.m_dt.is_recognizer(a->get_decl()) && + m_t.is_fd(a->get_arg(0))) { + m_t.m_fd_sorts.insert(get_sort(a->get_arg(0))); + return; + } + if (m_t.is_fd(a)) { m_t.m_fd_sorts.insert(get_sort(a)); } @@ -265,7 +266,7 @@ public: } if (!m_fd_sorts.empty()) { m_bounds.reset(); - m_num_transformed = 0; + m_num_translated = 0; m_ext = alloc(extension_model_converter, m); m_filter = alloc(filter_model_converter, m); scoped_ptr r = alloc(rw, *this, m, m_params); @@ -283,7 +284,7 @@ public: g->assert_expr(m_bounds[i].get()); } mc = concat(m_filter.get(), m_ext.get()); - report_tactic_progress(":fd-num-translated", m_num_transformed); + report_tactic_progress(":fd-num-translated", m_num_translated); } g->inc_depth(); result.push_back(g.get()); From 56c78753f0ef0b73c18d200368337df78f9d1637 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 24 Jul 2016 18:16:32 -0700 Subject: [PATCH 110/536] updating default solver selection. Add dt2bv transformation Signed-off-by: Nikolaj Bjorner --- src/opt/maxsmt.cpp | 13 ++++++------- src/opt/opt_context.cpp | 11 +++++------ src/smt/theory_wmaxsat.cpp | 3 ++- 3 files changed, 13 insertions(+), 14 deletions(-) diff --git a/src/opt/maxsmt.cpp b/src/opt/maxsmt.cpp index a0dd2aed1..1ad2a09be 100644 --- a/src/opt/maxsmt.cpp +++ b/src/opt/maxsmt.cpp @@ -156,20 +156,19 @@ namespace opt { symbol const& maxsat_engine = m_c.maxsat_engine(); IF_VERBOSE(1, verbose_stream() << "(maxsmt)\n";); TRACE("opt", tout << "maxsmt\n";); - if (m_soft_constraints.empty() || maxsat_engine == symbol("maxres")) { + if (m_soft_constraints.empty() || maxsat_engine == symbol("maxres") || maxsat_engine == symbol::null) { m_msolver = mk_maxres(m_c, m_index, m_weights, m_soft_constraints); } else if (maxsat_engine == symbol("pd-maxres")) { m_msolver = mk_primal_dual_maxres(m_c, m_index, m_weights, m_soft_constraints); } - else { - if (maxsat_engine != symbol::null && maxsat_engine != symbol("wmax")) { - warning_msg("solver %s is not recognized, using default 'wmax'", - maxsat_engine.str().c_str()); - } - std::cout << "wmax\n"; + else if (maxsat_engine == symbol("wmax")) { m_msolver = mk_wmax(m_c, m_weights, m_soft_constraints); } + else { + warning_msg("solver %s is not recognized, using default 'maxres'", maxsat_engine.str().c_str()); + m_msolver = mk_maxres(m_c, m_index, m_weights, m_soft_constraints); + } if (m_msolver) { m_msolver->updt_params(m_params); diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 4eafb93f2..aad034130 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -35,6 +35,7 @@ Notes: #include "model_smt2_pp.h" #include "card2bv_tactic.h" #include "eq2bv_tactic.h" +#include "dt2bv_tactic.h" #include "inc_sat_solver.h" #include "bv_decl_plugin.h" #include "pb_decl_plugin.h" @@ -688,21 +689,19 @@ namespace opt { // NB: mk_elim_uncstr_tactic(m) is not sound with soft constraints mk_simplify_tactic(m)); opt_params optp(m_params); - tactic_ref tac2, tac3, tac4; + tactic_ref tac1, tac2, tac3, tac4; if (optp.elim_01()) { + tac1 = mk_dt2bv_tactic(m); tac2 = mk_elim01_tactic(m); tac3 = mk_lia2card_tactic(m); tac4 = mk_eq2bv_tactic(m); params_ref lia_p; lia_p.set_bool("compile_equality", optp.pb_compile_equality()); tac3->updt_params(lia_p); - set_simplify(and_then(tac0.get(), tac2.get(), tac3.get(), tac4.get(), mk_simplify_tactic(m))); + set_simplify(and_then(tac0.get(), tac1.get(), tac2.get(), tac3.get(), tac4.get(), mk_simplify_tactic(m))); } else { - tactic_ref tac1 = - and_then(tac0.get(), - mk_simplify_tactic(m)); - set_simplify(tac1.get()); + set_simplify(tac0.get()); } proof_converter_ref pc; expr_dependency_ref core(m); diff --git a/src/smt/theory_wmaxsat.cpp b/src/smt/theory_wmaxsat.cpp index e52475d06..b572d8e69 100644 --- a/src/smt/theory_wmaxsat.cpp +++ b/src/smt/theory_wmaxsat.cpp @@ -35,7 +35,8 @@ theory_wmaxsat::theory_wmaxsat(ast_manager& m, filter_model_converter& mc): m_zmin_cost(m_mpz), m_found_optimal(false), m_propagate(false), - m_normalize(false) + m_normalize(false), + m_den(1) {} theory_wmaxsat::~theory_wmaxsat() { From 67c6f9be91d4645f7e734e9faac7390de8738ce6 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 26 Jul 2016 10:32:54 -0700 Subject: [PATCH 111/536] have the classifier revert to full arithmetic on non-difference logic, reported on http://stackoverflow.com/questions/38594208/changing-order-of-z3-fixepoint-queries-changes-the-result/38596187#3 Signed-off-by: Nikolaj Bjorner --- examples/tptp/tptp5.cpp | 56 +++++++++++++-------------- src/math/automata/symbolic_automata.h | 4 +- src/muz/pdr/pdr_context.cpp | 6 ++- 3 files changed, 34 insertions(+), 32 deletions(-) diff --git a/examples/tptp/tptp5.cpp b/examples/tptp/tptp5.cpp index 8f28111ac..b2736df4c 100644 --- a/examples/tptp/tptp5.cpp +++ b/examples/tptp/tptp5.cpp @@ -1227,11 +1227,11 @@ public: void display_axiom(std::ostream& out, z3::expr e) { out << "tff(formula" << (++m_formula_id) << ", axiom,\n "; - display(out, e); + display(out, e, true); out << ").\n"; } - void display(std::ostream& out, z3::expr e) { + void display(std::ostream& out, z3::expr e, bool in_paren) { std::string s; if (e.is_numeral(s)) { out << s; @@ -1249,32 +1249,33 @@ public: out << "$false"; break; case Z3_OP_AND: - display_infix(out, "&", e); + display_infix(out, "&", e, in_paren); break; case Z3_OP_OR: - display_infix(out, "|", e); + display_infix(out, "|", e, in_paren); break; case Z3_OP_IMPLIES: - display_infix(out, "=>", e); + display_infix(out, "=>", e, in_paren); break; case Z3_OP_NOT: - out << "(~"; - display(out, e.arg(0)); - out << ")"; + if (!in_paren) out << "("; + out << "~"; + display(out, e.arg(0), false); + if (!in_paren) out << ")"; break; case Z3_OP_EQ: if (e.arg(0).is_bool()) { - display_infix(out, "<=>", e); + display_infix(out, "<=>", e, in_paren); } else { - display_infix(out, "=", e); + display_infix(out, "=", e, in_paren); } break; case Z3_OP_IFF: - display_infix(out, "<=>", e); + display_infix(out, "<=>", e, in_paren); break; case Z3_OP_XOR: - display_infix(out, "<~>", e); + display_infix(out, "<~>", e, in_paren); break; case Z3_OP_MUL: display_binary(out, "$product", e); @@ -1351,7 +1352,7 @@ public: } } out << "] : "; - display(out, e.body()); + display(out, e.body(), false); for (unsigned i = 0; i < nb; ++i) { names.pop_back(); } @@ -1366,7 +1367,7 @@ public: out << lower_case_fun(e.decl().name()) << "("; unsigned n = e.num_args(); for(unsigned i = 0; i < n; ++i) { - display(out, e.arg(i)); + display(out, e.arg(i), n == 1); if (i + 1 < n) { out << ", "; } @@ -1389,23 +1390,23 @@ public: } } - void display_infix(std::ostream& out, char const* conn, z3::expr& e) { - out << "("; + void display_infix(std::ostream& out, char const* conn, z3::expr& e, bool in_paren) { + if (!in_paren) out << "("; unsigned sz = e.num_args(); for (unsigned i = 0; i < sz; ++i) { - display(out, e.arg(i)); + display(out, e.arg(i), false); if (i + 1 < sz) { out << " " << conn << " "; } } - out << ")"; + if (!in_paren) out << ")"; } void display_prefix(std::ostream& out, char const* conn, z3::expr& e) { out << conn << "("; unsigned sz = e.num_args(); for (unsigned i = 0; i < sz; ++i) { - display(out, e.arg(i)); + display(out, e.arg(i), sz == 1); if (i + 1 < sz) { out << ", "; } @@ -1418,7 +1419,7 @@ public: unsigned sz = e.num_args(); unsigned np = 1; for (unsigned i = 0; i < sz; ++i) { - display(out, e.arg(i)); + display(out, e.arg(i), false); if (i + 1 < sz) { out << ", "; } @@ -1562,7 +1563,7 @@ public: formula_file = "unknown"; } out << "tff(" << m_node_number << ",axiom,("; - display(out, get_proof_formula(p)); + display(out, get_proof_formula(p), true); out << "), file('" << formula_file << "','"; out << formula_name << "')).\n"; break; @@ -1625,12 +1626,12 @@ public: break; case Z3_OP_PR_HYPOTHESIS: out << "tff(" << m_node_number << ",assumption,("; - display(out, get_proof_formula(p)); + display(out, get_proof_formula(p), true); out << "), introduced(assumption)).\n"; break; case Z3_OP_PR_LEMMA: { out << "tff(" << m_node_number << ",plain,("; - display(out, get_proof_formula(p)); + display(out, get_proof_formula(p), true); out << "), inference(lemma,lemma(discharge,"; unsigned parent_id = Z3_get_ast_id(ctx, p.arg(0)); std::set const& hyps = m_proof_hypotheses.find(parent_id)->second; @@ -1747,7 +1748,7 @@ public: unsigned id = Z3_get_ast_id(ctx, p); std::set const& hyps = m_proof_hypotheses.find(id)->second; out << "tff(" << m_node_number << ",plain,\n ("; - display(out, get_proof_formula(p)); + display(out, get_proof_formula(p), true); out << "),\n inference(" << name << ",[status(" << status << ")"; if (!hyps.empty()) { out << ", assumptions("; @@ -1776,7 +1777,7 @@ public: unsigned display_hyp_inference(std::ostream& out, char const* name, char const* status, z3::expr conclusion, unsigned hyp1, unsigned hyp2 = 0) { ++m_node_number; out << "tff(" << m_node_number << ",plain,(\n "; - display(out, conclusion); + display(out, conclusion, true); out << "),\n inference(" << name << ",[status(" << status << ")],"; out << "[" << hyp1; if (hyp2) { @@ -2467,7 +2468,6 @@ static void prove_tptp() { int main(int argc, char** argv) { - //std::ostream* out = &std::cout; g_start_time = static_cast(clock()); signal(SIGINT, on_ctrl_c); @@ -2484,10 +2484,8 @@ int main(int argc, char** argv) { prove_tptp(); } catch (z3::exception& ex) { - std::cerr << "Proof display could not be completed: " << ex.msg() << "\n"; + std::cerr << "Exception during proof: " << ex.msg() << "\n"; } - - } return 0; } diff --git a/src/math/automata/symbolic_automata.h b/src/math/automata/symbolic_automata.h index cc3a0f5a8..c358bcac8 100644 --- a/src/math/automata/symbolic_automata.h +++ b/src/math/automata/symbolic_automata.h @@ -96,8 +96,8 @@ class symbolic_automata { public: symbolic_automata(M& m, ba_t& ba): m(m), m_ba(ba) {} - automaton_t* mk_determinstic(automaton_t& a); - automaton_t* mk_complement(automaton_t& a); + //automaton_t* mk_determinstic(automaton_t& a); + //automaton_t* mk_complement(automaton_t& a); automaton_t* remove_epsilons(automaton_t& a); automaton_t* mk_total(automaton_t& a); automaton_t* mk_minimize(automaton_t& a); diff --git a/src/muz/pdr/pdr_context.cpp b/src/muz/pdr/pdr_context.cpp index 6dc93048a..b6a889756 100644 --- a/src/muz/pdr/pdr_context.cpp +++ b/src/muz/pdr/pdr_context.cpp @@ -895,7 +895,7 @@ namespace pdr { SASSERT(m_prev); SASSERT(children().empty()); if (this == m_next) { - SASSERT(root == this); + // SASSERT(root == this); root = 0; } else { @@ -1818,6 +1818,10 @@ namespace pdr { m_fparams.m_arith_mode = AS_UTVPI; m_fparams.m_arith_expand_eqs = true; } + else { + m_fparams.m_arith_mode = AS_ARITH; + m_fparams.m_arith_expand_eqs = false; + } } } if (m_params.pdr_use_convex_closure_generalizer()) { From eec68cfa2d2cb86faaad8790461ad56d720f9841 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Tue, 26 Jul 2016 19:21:50 +0100 Subject: [PATCH 112/536] Added 32/64 bit indication and githash to output of -version. --- src/shell/main.cpp | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/shell/main.cpp b/src/shell/main.cpp index d1a9d21c6..fddce4f69 100644 --- a/src/shell/main.cpp +++ b/src/shell/main.cpp @@ -154,7 +154,18 @@ void parse_cmd_line_args(int argc, char ** argv) { exit(0); } if (strcmp(opt_name, "version") == 0) { - std::cout << "Z3 version " << Z3_MAJOR_VERSION << "." << Z3_MINOR_VERSION << "." << Z3_BUILD_NUMBER << "\n"; + std::cout << "Z3 version " << Z3_MAJOR_VERSION << "." << Z3_MINOR_VERSION << "." << Z3_BUILD_NUMBER; + std::cout << " - "; +#ifdef _AMD64_ + std::cout << "64"; +#else + std::cout << "32"; +#endif + std::cout << " bit"; +#ifdef Z3GITHASH + std::cout << " - build hashcode " << STRINGIZE_VALUE_OF(Z3GITHASH); +#endif + std::cout << "\n"; exit(0); } else if (strcmp(opt_name, "smt") == 0) { From 9cab896632b9cc21374c540af0b2734c54e6bf9b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 26 Jul 2016 14:31:29 -0700 Subject: [PATCH 113/536] adding sign option if keyfile is present Signed-off-by: Nikolaj Bjorner --- scripts/mk_util.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/scripts/mk_util.py b/scripts/mk_util.py index 8fafd1caa..591f748ec 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -1554,11 +1554,17 @@ class DotNetDLLComponent(Component): '/linkresource:{}.dll'.format(get_component(Z3_DLL_COMPONENT).dll_name), ] ) + pathToSnk = os.path.join(self.to_src_dir, 'z3.snk') + snkFile = os.path.join(self.src_dir, 'z3.snk') else: # We need to give the assembly a strong name so that it # can be installed into the GAC with ``make install`` pathToSnk = os.path.join(self.to_src_dir, 'Microsoft.Z3.mono.snk') + snkFile = os.path.join(self.src_dir, 'Microsoft.Z3.mono.snk') + if os.path.isfile(snkFile): cscCmdLine.append('/keyfile:{}'.format(pathToSnk)) + else: + print("Keyfile is not configured: %s" % snkFile) cscCmdLine.extend( ['/unsafe+', '/nowarn:1701,1702', From 5f5ef8b38d5a5010dba3c014da8ab7546244aa9d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 27 Jul 2016 09:02:56 -0700 Subject: [PATCH 114/536] adding support for distinct for dt2bv, re-entry harness for ~Context Signed-off-by: Nikolaj Bjorner --- src/api/dotnet/Context.cs | 5 +++-- src/tactic/bv/dt2bv_tactic.cpp | 17 +++++++++++++++++ 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/src/api/dotnet/Context.cs b/src/api/dotnet/Context.cs index 5bff8960a..cf235b4af 100644 --- a/src/api/dotnet/Context.cs +++ b/src/api/dotnet/Context.cs @@ -4940,11 +4940,12 @@ namespace Microsoft.Z3 // Console.WriteLine("Context Finalizer from " + System.Threading.Thread.CurrentThread.ManagedThreadId); Dispose(); - if (refCount == 0) + if (refCount == 0 && m_ctx != IntPtr.Zero) { m_n_err_handler = null; - Native.Z3_del_context(m_ctx); + IntPtr ctx = m_ctx; m_ctx = IntPtr.Zero; + Native.Z3_del_context(ctx); } else GC.ReRegisterForFinalize(this); diff --git a/src/tactic/bv/dt2bv_tactic.cpp b/src/tactic/bv/dt2bv_tactic.cpp index 6f20fc609..86717c807 100644 --- a/src/tactic/bv/dt2bv_tactic.cpp +++ b/src/tactic/bv/dt2bv_tactic.cpp @@ -60,10 +60,15 @@ class dt2bv_tactic : public tactic { br_status reduce_app(func_decl * f, unsigned num, expr * const * args, expr_ref & result, proof_ref & result_pr) { expr_ref a0(m), a1(m); + expr_ref_vector _args(m); if (m.is_eq(f) && reduce_arg(args[0], a0) && reduce_arg(args[1], a1)) { result = m.mk_eq(a0, a1); return BR_DONE; } + else if (m.is_distinct(f) && reduce_args(num, args, _args)) { + result = m.mk_distinct(_args.size(), _args.c_ptr()); + return BR_DONE; + } else if (m_t.m_dt.is_recognizer(f) && reduce_arg(args[0], a0)) { unsigned idx = m_t.m_dt.get_recognizer_constructor_idx(f); a1 = m_t.m_bv.mk_numeral(rational(idx), get_sort(a0)); @@ -75,6 +80,15 @@ class dt2bv_tactic : public tactic { } } + bool reduce_args(unsigned sz, expr*const* as, expr_ref_vector& result) { + expr_ref tmp(m); + for (unsigned i = 0; i < sz; ++i) { + if (!reduce_arg(as[i], tmp)) return false; + result.push_back(tmp); + } + return true; + } + bool reduce_arg(expr* a, expr_ref& result) { expr* b; if (m_cache.find(a, b)) { @@ -203,6 +217,9 @@ class dt2bv_tactic : public tactic { if (m.is_eq(a)) { return; } + if (m.is_distinct(a)) { + return; + } if (m_t.m_dt.is_recognizer(a->get_decl()) && m_t.is_fd(a->get_arg(0))) { m_t.m_fd_sorts.insert(get_sort(a->get_arg(0))); From 1239c8f8e885f82a89e965f229c65c67f731e631 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 27 Jul 2016 11:20:31 -0700 Subject: [PATCH 115/536] update MSF example Signed-off-by: Nikolaj Bjorner --- .../Properties/AssemblyInfo.cs | 36 +++++++++++++++++++ .../Z3BaseSolver.cs | 8 ++--- 2 files changed, 40 insertions(+), 4 deletions(-) create mode 100644 examples/msf/SolverFoundation.Plugin.Z3/Properties/AssemblyInfo.cs diff --git a/examples/msf/SolverFoundation.Plugin.Z3/Properties/AssemblyInfo.cs b/examples/msf/SolverFoundation.Plugin.Z3/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..6d495a895 --- /dev/null +++ b/examples/msf/SolverFoundation.Plugin.Z3/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("SolverFoundation.Plugin.Z3")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Microsoft")] +[assembly: AssemblyProduct("SolverFoundation.Plugin.Z3")] +[assembly: AssemblyCopyright("Copyright © Microsoft 2010")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("ed1476c0-96de-4d2c-983d-3888b140c3ad")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/examples/msf/SolverFoundation.Plugin.Z3/Z3BaseSolver.cs b/examples/msf/SolverFoundation.Plugin.Z3/Z3BaseSolver.cs index af8bc92a2..1c82406be 100644 --- a/examples/msf/SolverFoundation.Plugin.Z3/Z3BaseSolver.cs +++ b/examples/msf/SolverFoundation.Plugin.Z3/Z3BaseSolver.cs @@ -47,7 +47,7 @@ namespace Microsoft.SolverFoundation.Plugin.Z3 private Dictionary _variables = new Dictionary(); ///

A map from MSF variable ids to Z3 goal ids - private Dictionary _goals = new Dictionary(); + private Dictionary _goals = new Dictionary(); internal Z3BaseSolver(IRowVariableModel model) { @@ -64,7 +64,7 @@ namespace Microsoft.SolverFoundation.Plugin.Z3 get { return _variables; } } - internal Dictionary Goals + internal Dictionary Goals { get { return _goals; } } @@ -332,7 +332,7 @@ namespace Microsoft.SolverFoundation.Plugin.Z3 // Remember all objective values foreach (var pair in _goals) { - var optimalValue = Utils.ToRational(_optSolver.GetUpper(pair.Value)); + var optimalValue = Utils.ToRational(pair.Value.Upper); _model.SetValue(pair.Key.Index, optimalValue); } model.Dispose(); @@ -356,7 +356,7 @@ namespace Microsoft.SolverFoundation.Plugin.Z3 // Remember all objective values foreach (var pair in _goals) { - var optimalValue = Utils.ToRational(_optSolver.GetUpper(pair.Value)); + var optimalValue = Utils.ToRational(pair.Value.Upper); _model.SetValue(pair.Key.Index, optimalValue); } subOptimalModel.Dispose(); From 0997eba700b3a2b5b7c989aea47a7e50d55bb470 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 27 Jul 2016 13:41:41 -0700 Subject: [PATCH 116/536] adding hash/eq to uint_set Signed-off-by: Nikolaj Bjorner --- src/test/uint_set.cpp | 27 +++++++++++++++++++++++++++ src/util/uint_set.h | 12 ++++++++++++ 2 files changed, 39 insertions(+) diff --git a/src/test/uint_set.cpp b/src/test/uint_set.cpp index 582a1d42f..fcbbd5c48 100644 --- a/src/test/uint_set.cpp +++ b/src/test/uint_set.cpp @@ -131,6 +131,32 @@ static void tst4() { SASSERT(!s.contains(0)); } +#include "map.h" + +template +struct uint_map : public map {}; + +static void tst5() { + uint_set s; + std::cout << s.get_hash() << "\n"; + s.insert(1); + std::cout << s.get_hash() << "\n"; + s.insert(2); + std::cout << s.get_hash() << "\n"; + s.insert(44); + std::cout << s.get_hash() << "\n"; + + uint_map m; + m.insert(s, 1); + s.insert(4); + m.insert(s, 3); + uint_map::iterator it = m.begin(), end = m.end(); + for (; it != end; ++it) { + std::cout << it->m_key << " : " << it->m_value << "\n"; + } + +} + void tst_uint_set() { for (unsigned i = 0; i < 100; i++) { tst1(1 + rand()%31); @@ -146,5 +172,6 @@ void tst_uint_set() { tst3(12); tst3(100); tst4(); + tst5(); } diff --git a/src/util/uint_set.h b/src/util/uint_set.h index aca73a5c5..525638f4f 100644 --- a/src/util/uint_set.h +++ b/src/util/uint_set.h @@ -218,6 +218,18 @@ public: iterator const begin() const { return iterator(*this, false); } iterator const end() const { return iterator(*this, true); } + + unsigned get_hash() const { + unsigned h = 0; + for (unsigned i = 0; i < size(); ++i) { + h += (i+1)*((*this)[i]); + } + return h; + } + + struct eq { bool operator()(uint_set const& s1, uint_set const& s2) const { return s1 == s2; } }; + struct hash { unsigned operator()(uint_set const& s) const { return s.get_hash(); } }; + }; inline std::ostream & operator<<(std::ostream & target, const uint_set & s) { From b7de813c6386a5625c5570c99d8daf0b00e245f8 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 27 Jul 2016 15:35:44 -0700 Subject: [PATCH 117/536] set solver on simplify command Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/seq_rewriter.h | 3 +++ src/ast/rewriter/th_rewriter.cpp | 9 +++++++++ src/ast/rewriter/th_rewriter.h | 5 +++++ src/cmd_context/simplify_cmd.cpp | 25 ++++++++++++++++++++++++- src/solver/solver.h | 9 +++++++-- 5 files changed, 48 insertions(+), 3 deletions(-) diff --git a/src/ast/rewriter/seq_rewriter.h b/src/ast/rewriter/seq_rewriter.h index 82579d53a..2b434f475 100644 --- a/src/ast/rewriter/seq_rewriter.h +++ b/src/ast/rewriter/seq_rewriter.h @@ -149,6 +149,9 @@ public: void updt_params(params_ref const & p) {} static void get_param_descrs(param_descrs & r) {} + void set_solver(expr_solver* solver) { m_re2aut.set_solver(solver); } + + br_status mk_app_core(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result); br_status mk_eq_core(expr * lhs, expr * rhs, expr_ref & result); diff --git a/src/ast/rewriter/th_rewriter.cpp b/src/ast/rewriter/th_rewriter.cpp index 6f6daf8df..ff6a10274 100644 --- a/src/ast/rewriter/th_rewriter.cpp +++ b/src/ast/rewriter/th_rewriter.cpp @@ -692,6 +692,7 @@ struct th_rewriter_cfg : public default_rewriter_cfg { return false; } + }; template class rewriter_tpl; @@ -705,6 +706,10 @@ struct th_rewriter::imp : public rewriter_tpl { expr_ref mk_app(func_decl* f, unsigned sz, expr* const* args) { return m_cfg.mk_app(f, sz, args); } + + void set_solver(expr_solver* solver) { + m_cfg.m_seq_rw.set_solver(solver); + } }; th_rewriter::th_rewriter(ast_manager & m, params_ref const & p): @@ -790,3 +795,7 @@ void th_rewriter::reset_used_dependencies() { expr_ref th_rewriter::mk_app(func_decl* f, unsigned num_args, expr* const* args) { return m_imp->mk_app(f, num_args, args); } + +void th_rewriter::set_solver(expr_solver* solver) { + m_imp->set_solver(solver); +} diff --git a/src/ast/rewriter/th_rewriter.h b/src/ast/rewriter/th_rewriter.h index bd5ce9c66..6aa4bb3da 100644 --- a/src/ast/rewriter/th_rewriter.h +++ b/src/ast/rewriter/th_rewriter.h @@ -25,6 +25,8 @@ Notes: class expr_substitution; +class expr_solver; + class th_rewriter { struct imp; imp * m_imp; @@ -58,6 +60,9 @@ public: // Remark: reset_used_dependecies will reset the internal cache if get_used_dependencies() != 0 expr_dependency * get_used_dependencies(); void reset_used_dependencies(); + + void set_solver(expr_solver* solver); + }; #endif diff --git a/src/cmd_context/simplify_cmd.cpp b/src/cmd_context/simplify_cmd.cpp index 1c249ce1f..8b354c8b7 100644 --- a/src/cmd_context/simplify_cmd.cpp +++ b/src/cmd_context/simplify_cmd.cpp @@ -24,9 +24,30 @@ Notes: #include"scoped_timer.h" #include"scoped_ctrl_c.h" #include"cancel_eh.h" +#include"seq_rewriter.h" #include class simplify_cmd : public parametric_cmd { + + class th_solver : public expr_solver { + cmd_context& m_ctx; + params_ref m_params; + ref m_solver; + public: + th_solver(cmd_context& ctx): m_ctx(ctx) {} + + virtual lbool check_sat(expr* e) { + if (!m_solver) { + m_solver = m_ctx.get_solver_factory()(m_ctx.m(), m_params, false, true, false, symbol::null); + } + m_solver->push(); + m_solver->assert_expr(e); + lbool r = m_solver->check_sat(0,0); + m_solver->pop(1); + return r; + } + }; + expr * m_target; public: simplify_cmd(char const * name = "simplify"):parametric_cmd(name) {} @@ -70,10 +91,12 @@ public: if (m_params.get_bool("som", false)) m_params.set_bool("flat", true); th_rewriter s(ctx.m(), m_params); + th_solver solver(ctx); + s.set_solver(alloc(th_solver, ctx)); unsigned cache_sz; unsigned num_steps = 0; unsigned timeout = m_params.get_uint("timeout", UINT_MAX); - unsigned rlimit = m_params.get_uint("rlimit", UINT_MAX); + unsigned rlimit = m_params.get_uint("rlimit", UINT_MAX); bool failed = false; cancel_eh eh(ctx.m().limit()); { diff --git a/src/solver/solver.h b/src/solver/solver.h index f320bec7c..e4e4942d3 100644 --- a/src/solver/solver.h +++ b/src/solver/solver.h @@ -149,8 +149,13 @@ public: */ virtual expr * get_assumption(unsigned idx) const = 0; - - + /** + \brief under assumptions, asms, retrieve set of consequences that fix values for expressions that can be + built from fns. For functions that take 0 arguments, we require that the function returns all consequences + that mention these functions. The consequences are clauses whose first literal constrain one of the + functions from fns and the other literals are negations of literals from asms. + */ + //virtual lbool get_consequences(expr_ref_vector const& asms, func_ref_vector const& fns, expr_ref_vector& consequences); /** \brief Display the content of this solver. From 3587baaf24e001e3d88d49395357a826f743a189 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Thu, 28 Jul 2016 18:06:02 +0100 Subject: [PATCH 118/536] Added full version strings and associated API functions. --- examples/dotnet/Program.cs | 2 ++ examples/java/JavaExample.java | 2 ++ examples/ml/ml_example.ml | 1 + scripts/mk_util.py | 20 +++++++++++++++++++- src/api/api_context.cpp | 5 +++++ src/api/dotnet/Version.cs | 11 +++++++++++ src/api/java/Version.java | 8 ++++++++ src/api/ml/z3.ml | 2 ++ src/api/ml/z3.mli | 3 +++ src/api/python/z3.py | 3 +++ src/api/z3_api.h | 7 +++++++ src/util/version.h.in | 2 ++ 12 files changed, 65 insertions(+), 1 deletion(-) diff --git a/examples/dotnet/Program.cs b/examples/dotnet/Program.cs index 26c081ee2..5b10dadd0 100644 --- a/examples/dotnet/Program.cs +++ b/examples/dotnet/Program.cs @@ -2159,6 +2159,8 @@ namespace test_mapi Console.WriteLine(Microsoft.Z3.Version.Major.ToString()); Console.Write("Z3 Full Version: "); Console.WriteLine(Microsoft.Z3.Version.ToString()); + Console.Write("Z3 Full Version String: "); + Console.WriteLine(Microsoft.Z3.Version.FullVersion); SimpleExample(); diff --git a/examples/java/JavaExample.java b/examples/java/JavaExample.java index 5c8a7508f..5810dab37 100644 --- a/examples/java/JavaExample.java +++ b/examples/java/JavaExample.java @@ -2291,6 +2291,8 @@ class JavaExample System.out.println(Version.getMajor()); System.out.print("Z3 Full Version: "); System.out.println(Version.getString()); + System.out.print("Z3 Full Version String: "); + System.out.println(Version.getFullVersion()); p.simpleExample(); diff --git a/examples/ml/ml_example.ml b/examples/ml/ml_example.ml index bab0ba2fc..eb64f8ee8 100644 --- a/examples/ml/ml_example.ml +++ b/examples/ml/ml_example.ml @@ -323,6 +323,7 @@ let _ = else ( Printf.printf "Running Z3 version %s\n" Version.to_string ; + Printf.printf "Z3 full version string: %s\n" Version.full_version ; let cfg = [("model", "true"); ("proof", "false")] in let ctx = (mk_context cfg) in let is = (Symbol.mk_int ctx 42) in diff --git a/scripts/mk_util.py b/scripts/mk_util.py index 591f748ec..4b5383b76 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -99,6 +99,7 @@ VS_PAR=False VS_PAR_NUM=8 GPROF=False GIT_HASH=False +GIT_DESCRIBE=False SLOW_OPTIMIZE=False USE_OMP=True @@ -534,11 +535,14 @@ def find_c_compiler(): raise MKException('C compiler was not found. Try to set the environment variable CC with the C compiler available in your system.') def set_version(major, minor, build, revision): - global VER_MAJOR, VER_MINOR, VER_BUILD, VER_REVISION + global VER_MAJOR, VER_MINOR, VER_BUILD, VER_REVISION, GIT_DESCRIBE VER_MAJOR = major VER_MINOR = minor VER_BUILD = build VER_REVISION = revision + if GIT_DESCRIBE: + branch = check_output(['git', 'rev-parse', '--abbrev-ref', 'HEAD']) + VER_REVISION = int(check_output(['git', 'rev-list', '--count', 'HEAD'])) def get_version(): return (VER_MAJOR, VER_MINOR, VER_BUILD, VER_REVISION) @@ -621,6 +625,7 @@ def display_help(exit_code): print(" --pypkgdir= Force a particular Python package directory (default %s)" % PYTHON_PACKAGE_DIR) print(" -b , --build= subdirectory where Z3 will be built (default: %s)." % BUILD_DIR) print(" --githash=hash include the given hash in the binaries.") + print(" --git-describe include the output of 'git describe' in the version information.") print(" -d, --debug compile Z3 in debug mode.") print(" -t, --trace enable tracing in release mode.") if IS_WINDOWS: @@ -732,6 +737,8 @@ def parse_options(): GPROF = True elif opt == '--githash': GIT_HASH=arg + elif opt == '--git-describe': + GIT_DESCRIBE = True elif opt in ('', '--ml'): ML_ENABLED = True elif opt in ('', '--noomp'): @@ -2593,6 +2600,16 @@ def update_version(): mk_all_assembly_infos(major, minor, build, revision) mk_def_files() +def get_full_version_string(major, minor, build, revision): + global GIT_HASH, GIT_DESCRIBE + res = "Z3 %s.%s.%s.%s" % (major, minor, build, revision) + if GIT_HASH: + res += " " + GIT_HASH + if GIT_DESCRIBE: + branch = check_output(['git', 'rev-parse', '--abbrev-ref', 'HEAD', '--long']) + res += " master " + check_output(['git', 'describe']) + return '"' + res + '"' + # Update files with the version number def mk_version_dot_h(major, minor, build, revision): c = get_component(UTIL_COMPONENT) @@ -2606,6 +2623,7 @@ def mk_version_dot_h(major, minor, build, revision): 'Z3_VERSION_MINOR': str(minor), 'Z3_VERSION_PATCH': str(build), 'Z3_VERSION_TWEAK': str(revision), + 'Z3_FULL_VERSION': get_full_version_string(major, minor, build, revision) } ) if VERBOSE: diff --git a/src/api/api_context.cpp b/src/api/api_context.cpp index a5804bd45..418ccc58c 100644 --- a/src/api/api_context.cpp +++ b/src/api/api_context.cpp @@ -430,6 +430,11 @@ extern "C" { *revision_number = Z3_REVISION_NUMBER; } + Z3_string Z3_API Z3_get_full_version(void) { + LOG_Z3_get_full_version(); + return Z3_FULL_VERSION; + } + void Z3_API Z3_enable_trace(Z3_string tag) { memory::initialize(UINT_MAX); LOG_Z3_enable_trace(tag); diff --git a/src/api/dotnet/Version.cs b/src/api/dotnet/Version.cs index 6c22ce7fe..364ada781 100644 --- a/src/api/dotnet/Version.cs +++ b/src/api/dotnet/Version.cs @@ -83,6 +83,17 @@ namespace Microsoft.Z3 } } + /// + /// A full version string + /// + public static string FullVersion + { + get + { + return Native.Z3_get_full_version(); + } + } + /// /// A string representation of the version information. /// diff --git a/src/api/java/Version.java b/src/api/java/Version.java index 939a3ca5c..0579e2b05 100644 --- a/src/api/java/Version.java +++ b/src/api/java/Version.java @@ -63,6 +63,14 @@ public class Version return revision.value; } + /** + * A full version string + **/ + public static String getFullVersion() + { + return Native.getFullVersion(); + } + /** * A string representation of the version information. **/ diff --git a/src/api/ml/z3.ml b/src/api/ml/z3.ml index bbbb9e74b..b7016c4c8 100644 --- a/src/api/ml/z3.ml +++ b/src/api/ml/z3.ml @@ -25,6 +25,8 @@ module Version = struct let (major, minor, build, revision) = Z3native.get_version () + let full_version : string = Z3native.get_full_version() + let to_string = string_of_int major ^ "." ^ string_of_int minor ^ "." ^ diff --git a/src/api/ml/z3.mli b/src/api/ml/z3.mli index 9104b3080..1c91b28aa 100644 --- a/src/api/ml/z3.mli +++ b/src/api/ml/z3.mli @@ -80,6 +80,9 @@ sig (** The revision. *) val revision : int + (** A full version string. *) + val full_version : string + (** A string representation of the version information. *) val to_string : string end diff --git a/src/api/python/z3.py b/src/api/python/z3.py index ca02975f1..62a2e2467 100644 --- a/src/api/python/z3.py +++ b/src/api/python/z3.py @@ -79,6 +79,9 @@ def get_version(): Z3_get_version(major, minor, build, rev) return (major.value, minor.value, build.value, rev.value) +def get_full_version(): + return Z3_get_full_version() + # We use _z3_assert instead of the assert command because we want to # produce nice error messages in Z3Py at rise4fun.com def _z3_assert(cond, msg): diff --git a/src/api/z3_api.h b/src/api/z3_api.h index 41ca923bb..59c424be8 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -5139,6 +5139,13 @@ extern "C" { */ void Z3_API Z3_get_version(unsigned * major, unsigned * minor, unsigned * build_number, unsigned * revision_number); + /** + \brief Return a string that fully describes the version of Z3 in use. + + def_API('Z3_get_full_version', STRING, ()) + */ + Z3_string Z3_API Z3_get_full_version(void); + /** \brief Enable tracing messages tagged as \c tag when Z3 is compiled in debug mode. It is a NOOP otherwise diff --git a/src/util/version.h.in b/src/util/version.h.in index 05b619f2d..daf568a29 100644 --- a/src/util/version.h.in +++ b/src/util/version.h.in @@ -3,3 +3,5 @@ #define Z3_MINOR_VERSION @Z3_VERSION_MINOR@ #define Z3_BUILD_NUMBER @Z3_VERSION_PATCH@ #define Z3_REVISION_NUMBER @Z3_VERSION_TWEAK@ + +#define Z3_FULL_VERSION @Z3_FULL_VERSION@ From 0d83f99d8df7f30306bbec37b403fdfc513d1aa4 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Thu, 28 Jul 2016 18:06:26 +0100 Subject: [PATCH 119/536] Fixed comment --- src/api/dotnet/InterpolationContext.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/dotnet/InterpolationContext.cs b/src/api/dotnet/InterpolationContext.cs index 17e92a40e..3f2feb5a6 100644 --- a/src/api/dotnet/InterpolationContext.cs +++ b/src/api/dotnet/InterpolationContext.cs @@ -30,7 +30,7 @@ namespace Microsoft.Z3 /// /// Constructor. /// - /// + /// public InterpolationContext(Dictionary settings) : base(settings) { } #region Terms From 7fefe40f210300dc073c93b2889be274bd92da62 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Thu, 28 Jul 2016 18:07:34 +0100 Subject: [PATCH 120/536] Added/improved facilities for strong name signing of the .NET assembly. --- scripts/mk_project.py | 2 +- scripts/mk_util.py | 49 ++++++++++++------ ...Microsoft.Z3.mono.snk => Microsoft.Z3.snk} | Bin 3 files changed, 33 insertions(+), 18 deletions(-) rename src/api/dotnet/{Microsoft.Z3.mono.snk => Microsoft.Z3.snk} (100%) diff --git a/scripts/mk_project.py b/scripts/mk_project.py index f7b832bb9..78bc290f8 100644 --- a/scripts/mk_project.py +++ b/scripts/mk_project.py @@ -88,7 +88,7 @@ def init_project_def(): dll_name='libz3', static=build_static_lib(), export_files=API_files) - add_dot_net_dll('dotnet', ['api_dll'], 'api/dotnet', dll_name='Microsoft.Z3', assembly_info_dir='Properties') + add_dot_net_dll('dotnet', ['api_dll'], 'api/dotnet', dll_name='Microsoft.Z3', assembly_info_dir='Properties', default_key_file='src/api/dotnet/Microsoft.Z3.snk') add_java_dll('java', ['api_dll'], 'api/java', dll_name='libz3java', package_name="com.microsoft.z3", manifest_file='manifest') add_ml_lib('ml', ['api_dll'], 'api/ml', lib_name='libz3ml') add_hlib('cpp', 'api/c++', includes2install=['z3++.h']) diff --git a/scripts/mk_util.py b/scripts/mk_util.py index 4b5383b76..66191e160 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -82,6 +82,7 @@ Z3PY_SRC_DIR=None VS_PROJ = False TRACE = False DOTNET_ENABLED=False +DOTNET_KEY_FILE=None JAVA_ENABLED=False ML_ENABLED=False PYTHON_INSTALL_ENABLED=False @@ -638,6 +639,7 @@ def display_help(exit_code): if IS_WINDOWS: print(" --optimize generate optimized code during linking.") print(" --dotnet generate .NET bindings.") + print(" --dotnet-key= sign the .NET assembly using the private key in .") print(" --java generate Java bindings.") print(" --ml generate OCaml bindings.") print(" --python generate Python bindings.") @@ -673,14 +675,14 @@ def display_help(exit_code): # Parse configuration option for mk_make script def parse_options(): global VERBOSE, DEBUG_MODE, IS_WINDOWS, VS_X64, ONLY_MAKEFILES, SHOW_CPPS, VS_PROJ, TRACE, VS_PAR, VS_PAR_NUM - global DOTNET_ENABLED, JAVA_ENABLED, ML_ENABLED, STATIC_LIB, STATIC_BIN, PREFIX, GMP, FOCI2, FOCI2LIB, PYTHON_PACKAGE_DIR, GPROF, GIT_HASH, PYTHON_INSTALL_ENABLED + global DOTNET_ENABLED, DOTNET_KEY_FILE, JAVA_ENABLED, ML_ENABLED, STATIC_LIB, STATIC_BIN, PREFIX, GMP, FOCI2, FOCI2LIB, PYTHON_PACKAGE_DIR, GPROF, GIT_HASH, GIT_DESCRIBE, PYTHON_INSTALL_ENABLED global LINUX_X64, SLOW_OPTIMIZE, USE_OMP try: options, remainder = getopt.gnu_getopt(sys.argv[1:], 'b:df:sxhmcvtnp:gj', ['build=', 'debug', 'silent', 'x64', 'help', 'makefiles', 'showcpp', 'vsproj', - 'trace', 'dotnet', 'staticlib', 'prefix=', 'gmp', 'foci2=', 'java', 'parallel=', 'gprof', - 'githash=', 'x86', 'ml', 'optimize', 'noomp', 'pypkgdir=', 'python', 'staticbin']) + 'trace', 'dotnet', 'dotnet-key=', 'staticlib', 'prefix=', 'gmp', 'foci2=', 'java', 'parallel=', 'gprof', + 'githash=', 'git-describe', 'x86', 'ml', 'optimize', 'noomp', 'pypkgdir=', 'python', 'staticbin']) except: print("ERROR: Invalid command line option") display_help(1) @@ -713,6 +715,8 @@ def parse_options(): TRACE = True elif opt in ('-.net', '--dotnet'): DOTNET_ENABLED = True + elif opt in ('--dotnet-key'): + DOTNET_KEY_FILE = arg elif opt in ('--staticlib'): STATIC_LIB = True elif opt in ('--staticbin'): @@ -1498,7 +1502,7 @@ class PythonInstallComponent(Component): return class DotNetDLLComponent(Component): - def __init__(self, name, dll_name, path, deps, assembly_info_dir): + def __init__(self, name, dll_name, path, deps, assembly_info_dir, default_key_file): Component.__init__(self, name, path, deps) if dll_name is None: dll_name = name @@ -1506,6 +1510,7 @@ class DotNetDLLComponent(Component): assembly_info_dir = "." self.dll_name = dll_name self.assembly_info_dir = assembly_info_dir + self.key_file = default_key_file def mk_pkg_config_file(self): """ @@ -1531,6 +1536,8 @@ class DotNetDLLComponent(Component): configure_file(pkg_config_template, pkg_config_output, substitutions) def mk_makefile(self, out): + global DOTNET_KEY_FILE + if not is_dotnet_enabled(): return cs_fp_files = [] @@ -1561,17 +1568,24 @@ class DotNetDLLComponent(Component): '/linkresource:{}.dll'.format(get_component(Z3_DLL_COMPONENT).dll_name), ] ) - pathToSnk = os.path.join(self.to_src_dir, 'z3.snk') - snkFile = os.path.join(self.src_dir, 'z3.snk') - else: - # We need to give the assembly a strong name so that it - # can be installed into the GAC with ``make install`` - pathToSnk = os.path.join(self.to_src_dir, 'Microsoft.Z3.mono.snk') - snkFile = os.path.join(self.src_dir, 'Microsoft.Z3.mono.snk') - if os.path.isfile(snkFile): - cscCmdLine.append('/keyfile:{}'.format(pathToSnk)) - else: - print("Keyfile is not configured: %s" % snkFile) + + # We need to give the assembly a strong name so that it + # can be installed into the GAC with ``make install`` + if not DOTNET_KEY_FILE is None: + self.key_file = DOTNET_KEY_FILE + + if not self.key_file is None: + if os.path.isfile(self.key_file): + self.key_file = os.path.abspath(self.key_file) + elif os.path.isfile(os.path.join(self.src_dir, self.key_file)): + self.key_file = os.path.abspath(os.path.join(self.src_dir, self.key_file)) + else: + print("Keyfile '%s' could not be found; %s.dll will be unsigned." % (self.dll_name, self.key_file)) + self.key_file = None + + if not self.key_file is None: + print("%s.dll will be signed using key '%s'." % (self.dll_name, self.key_file)) + cscCmdLine.append('/keyfile:{}'.format(self.key_file)) cscCmdLine.extend( ['/unsafe+', '/nowarn:1701,1702', @@ -1595,6 +1609,7 @@ class DotNetDLLComponent(Component): ) else: cscCmdLine.extend(['/optimize+']) + if IS_WINDOWS: if VS_X64: cscCmdLine.extend(['/platform:x64']) @@ -2179,8 +2194,8 @@ def add_dll(name, deps=[], path=None, dll_name=None, export_files=[], reexports= reg_component(name, c) return c -def add_dot_net_dll(name, deps=[], path=None, dll_name=None, assembly_info_dir=None): - c = DotNetDLLComponent(name, dll_name, path, deps, assembly_info_dir) +def add_dot_net_dll(name, deps=[], path=None, dll_name=None, assembly_info_dir=None, default_key_file=None): + c = DotNetDLLComponent(name, dll_name, path, deps, assembly_info_dir, default_key_file) reg_component(name, c) def add_java_dll(name, deps=[], path=None, dll_name=None, package_name=None, manifest_file=None): diff --git a/src/api/dotnet/Microsoft.Z3.mono.snk b/src/api/dotnet/Microsoft.Z3.snk similarity index 100% rename from src/api/dotnet/Microsoft.Z3.mono.snk rename to src/api/dotnet/Microsoft.Z3.snk From d5954e829b17cce03a12da43b96b006b55bed724 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Thu, 28 Jul 2016 18:49:57 +0100 Subject: [PATCH 121/536] Enabled donet key file in dist scripts --- scripts/mk_unix_dist.py | 15 ++++++++++++--- scripts/mk_win_dist.py | 11 ++++++++++- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/scripts/mk_unix_dist.py b/scripts/mk_unix_dist.py index 0c28058ed..ee1294a8b 100644 --- a/scripts/mk_unix_dist.py +++ b/scripts/mk_unix_dist.py @@ -23,6 +23,7 @@ VERBOSE=True DIST_DIR='dist' FORCE_MK=False DOTNET_ENABLED=True +DOTNET_KEY_FILE=None JAVA_ENABLED=True GIT_HASH=False @@ -52,13 +53,14 @@ def display_help(): print(" -b , --build= subdirectory where x86 and x64 Z3 versions will be built (default: build-dist).") print(" -f, --force force script to regenerate Makefiles.") print(" --nodotnet do not include .NET bindings in the binary distribution files.") + print(" --dotnet-key= sign the .NET assembly with the private key in .") print(" --nojava do not include Java bindings in the binary distribution files.") print(" --githash include git hash in the Zip file.") exit(0) # Parse configuration option for mk_make script def parse_options(): - global FORCE_MK, JAVA_ENABLED, GIT_HASH, DOTNET_ENABLED + global FORCE_MK, JAVA_ENABLED, GIT_HASH, DOTNET_ENABLED, DOTNET_KEY_FILE path = BUILD_DIR options, remainder = getopt.gnu_getopt(sys.argv[1:], 'b:hsf', ['build=', 'help', @@ -66,6 +68,7 @@ def parse_options(): 'force', 'nojava', 'nodotnet', + 'dotnet-key=', 'githash' ]) for opt, arg in options: @@ -80,7 +83,9 @@ def parse_options(): elif opt in ('-f', '--force'): FORCE_MK = True elif opt == '--nodotnet': - DOTNET_ENABLED = False + DOTNET_ENABLED = False + elif opt == '--dotnet-key': + DOTNET_KEY_FILE = arg elif opt == '--nojava': JAVA_ENABLED = False elif opt == '--githash': @@ -98,11 +103,14 @@ def mk_build_dir(path): if not check_build_dir(path) or FORCE_MK: opts = ["python", os.path.join('scripts', 'mk_make.py'), "-b", path, "--staticlib"] if DOTNET_ENABLED: - opts.append('--dotnet') + opts.append('--dotnet') + if not DOTNET_KEY_FILE is None: + opts.append('--dotnet-key=' + DOTNET_KEY_FILE) if JAVA_ENABLED: opts.append('--java') if GIT_HASH: opts.append('--githash=%s' % mk_util.git_hash()) + opts.append('--git-describe')) if subprocess.call(opts) != 0: raise MKException("Failed to generate build directory at '%s'" % path) @@ -171,6 +179,7 @@ def mk_dist_dir(): dist_path = os.path.join(DIST_DIR, get_z3_name()) mk_dir(dist_path) mk_util.DOTNET_ENABLED = DOTNET_ENABLED + mk_util.DOTNET_KEY_FILE = DOTNET_KEY_FILE mk_util.JAVA_ENABLED = JAVA_ENABLED mk_unix_dist(build_path, dist_path) if is_verbose(): diff --git a/scripts/mk_win_dist.py b/scripts/mk_win_dist.py index cee8c0460..145e356fb 100644 --- a/scripts/mk_win_dist.py +++ b/scripts/mk_win_dist.py @@ -25,6 +25,7 @@ VERBOSE=True DIST_DIR='dist' FORCE_MK=False DOTNET_ENABLED=True +DOTNET_KEY_FILE=None JAVA_ENABLED=True GIT_HASH=False @@ -57,13 +58,14 @@ def display_help(): print(" -b , --build= subdirectory where x86 and x64 Z3 versions will be built (default: build-dist).") print(" -f, --force force script to regenerate Makefiles.") print(" --nodotnet do not include .NET bindings in the binary distribution files.") + print(" --dotnet-key= sign the .NET assembly with the private key in .") print(" --nojava do not include Java bindings in the binary distribution files.") print(" --githash include git hash in the Zip file.") exit(0) # Parse configuration option for mk_make script def parse_options(): - global FORCE_MK, JAVA_ENABLED, GIT_HASH, DOTNET_ENABLED + global FORCE_MK, JAVA_ENABLED, GIT_HASH, DOTNET_ENABLED, DOTNET_KEY_FILE path = BUILD_DIR options, remainder = getopt.gnu_getopt(sys.argv[1:], 'b:hsf', ['build=', 'help', @@ -71,6 +73,7 @@ def parse_options(): 'force', 'nojava', 'nodotnet', + 'dotnet-key=', 'githash' ]) for opt, arg in options: @@ -86,6 +89,8 @@ def parse_options(): FORCE_MK = True elif opt == '--nodotnet': DOTNET_ENABLED = False + elif opt == '--dotnet-key': + DOTNET_KEY_FILE = arg elif opt == '--nojava': JAVA_ENABLED = False elif opt == '--githash': @@ -104,12 +109,15 @@ def mk_build_dir(path, x64): opts = ["python", os.path.join('scripts', 'mk_make.py'), "--parallel=24", "-b", path] if DOTNET_ENABLED: opts.append('--dotnet') + if not DOTNET_KEY_FILE is None: + opts.append('--dotnet-key=' + DOTNET_KEY_FILE) if JAVA_ENABLED: opts.append('--java') if x64: opts.append('-x') if GIT_HASH: opts.append('--githash=%s' % mk_util.git_hash()) + opts.append('--git-describe') if subprocess.call(opts) != 0: raise MKException("Failed to generate build directory at '%s'" % path) @@ -182,6 +190,7 @@ def mk_dist_dir_core(x64): dist_path = os.path.join(DIST_DIR, get_z3_name(x64)) mk_dir(dist_path) mk_util.DOTNET_ENABLED = DOTNET_ENABLED + mk_util.DOTNET_KEY_FILE = DOTNET_KEY_FILE mk_util.JAVA_ENABLED = JAVA_ENABLED mk_win_dist(build_path, dist_path) if is_verbose(): From 14f29e72653124e75c48227dc7c3a8adbf2a4057 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 28 Jul 2016 11:20:17 -0700 Subject: [PATCH 122/536] add basic built-in consequence finding Signed-off-by: Nikolaj Bjorner --- src/api/api_solver.cpp | 38 +++++++++++++++++++ src/api/dotnet/Solver.cs | 48 ++++++++++++++++++++---- src/api/python/z3.py | 22 +++++++++++ src/api/z3_api.h | 11 ++++++ src/solver/solver.cpp | 81 ++++++++++++++++++++++++++++++++++++++++ src/solver/solver.h | 13 ++++--- 6 files changed, 200 insertions(+), 13 deletions(-) diff --git a/src/api/api_solver.cpp b/src/api/api_solver.cpp index 518fa5384..799a2b56b 100644 --- a/src/api/api_solver.cpp +++ b/src/api/api_solver.cpp @@ -413,4 +413,42 @@ extern "C" { Z3_CATCH_RETURN(Z3_L_UNDEF); } + Z3_lbool Z3_API Z3_solver_get_consequences(Z3_context c, + Z3_solver s, + Z3_ast_vector assumptions, + Z3_ast_vector variables, + Z3_ast_vector consequences) { + Z3_TRY; + LOG_Z3_solver_get_consequences(c, s, assumptions, variables, consequences); + ast_manager& m = mk_c(c)->m(); + RESET_ERROR_CODE(); + CHECK_SEARCHING(c); + init_solver(c, s); + expr_ref_vector _assumptions(m), _consequences(m), _variables(m); + ast_ref_vector const& __assumptions = to_ast_vector_ref(assumptions); + unsigned sz = __assumptions.size(); + for (unsigned i = 0; i < sz; ++i) { + if (!is_expr(__assumptions[i])) { + SET_ERROR_CODE(Z3_INVALID_USAGE); + return Z3_L_UNDEF; + } + _assumptions.push_back(to_expr(__assumptions[i])); + } + ast_ref_vector const& __variables = to_ast_vector_ref(variables); + sz = __variables.size(); + for (unsigned i = 0; i < sz; ++i) { + if (!is_expr(__variables[i])) { + SET_ERROR_CODE(Z3_INVALID_USAGE); + return Z3_L_UNDEF; + } + _variables.push_back(to_expr(__variables[i])); + } + lbool result = to_solver_ref(s)->get_consequences(_assumptions, _variables, _consequences); + for (unsigned i = 0; i < _consequences.size(); ++i) { + to_ast_vector_ref(consequences).push_back(_consequences[i].get()); + } + return static_cast(result); + Z3_CATCH_RETURN(Z3_L_UNDEF); + } + }; diff --git a/src/api/dotnet/Solver.cs b/src/api/dotnet/Solver.cs index c9e76e68e..f8f340373 100644 --- a/src/api/dotnet/Solver.cs +++ b/src/api/dotnet/Solver.cs @@ -18,6 +18,7 @@ Notes: --*/ using System; +using System.Collections.Generic; using System.Diagnostics.Contracts; namespace Microsoft.Z3 @@ -212,12 +213,34 @@ namespace Microsoft.Z3 r = (Z3_lbool)Native.Z3_solver_check(Context.nCtx, NativeObject); else r = (Z3_lbool)Native.Z3_solver_check_assumptions(Context.nCtx, NativeObject, (uint)assumptions.Length, AST.ArrayToNative(assumptions)); - switch (r) - { - case Z3_lbool.Z3_L_TRUE: return Status.SATISFIABLE; - case Z3_lbool.Z3_L_FALSE: return Status.UNSATISFIABLE; - default: return Status.UNKNOWN; - } + return lboolToStatus(r); + } + + /// + /// Retrieve fixed assignments to the set of variables in the form of consequences. + /// Each consequence is an implication of the form + /// + /// relevant-assumptions Implies variable = value + /// + /// where the relevant assumptions is a subset of the assumptions that are passed in + /// and the equality on the right side of the implication indicates how a variable + /// is fixed. + /// + /// + /// + /// + /// + /// + public Status Consequences(IEnumerable assumptions, IEnumerable variables, out BoolExpr[] consequences) + { + ASTVector result = new ASTVector(Context); + ASTVector asms = new ASTVector(Context); + ASTVector vars = new ASTVector(Context); + foreach (var asm in assumptions) asms.Push(asm); + foreach (var v in variables) vars.Push(v); + Z3_lbool r = (Z3_lbool)Native.Z3_solver_get_consequences(Context.nCtx, NativeObject, asms.NativeObject, vars.NativeObject, result.NativeObject); + consequences = result.ToBoolExprArray(); + return lboolToStatus(r); } /// @@ -295,7 +318,7 @@ namespace Microsoft.Z3 /// public Solver Translate(Context ctx) { - Contract.Requires(ctx != null); + Contract.Requires(ctx != null); Contract.Ensures(Contract.Result() != null); return new Solver(ctx, Native.Z3_solver_translate(Context.nCtx, NativeObject, ctx.nCtx)); } @@ -355,6 +378,17 @@ namespace Microsoft.Z3 Context.Solver_DRQ.Add(o); base.DecRef(o); } + + private Status lboolToStatus(Z3_lbool r) + { + switch (r) + { + case Z3_lbool.Z3_L_TRUE: return Status.SATISFIABLE; + case Z3_lbool.Z3_L_FALSE: return Status.UNSATISFIABLE; + default: return Status.UNKNOWN; + } + } + #endregion } } diff --git a/src/api/python/z3.py b/src/api/python/z3.py index ca02975f1..7dfb95318 100644 --- a/src/api/python/z3.py +++ b/src/api/python/z3.py @@ -6123,6 +6123,28 @@ class Solver(Z3PPObject): """ return AstVector(Z3_solver_get_unsat_core(self.ctx.ref(), self.solver), self.ctx) + def consequences(self, assumptions, variables): + """Determine fixed values for the variables based on the solver state and assumptions. + documentation TBD + """ + if isinstance(assumptions, list): + _asms = AstVector(None, self.ctx) + for a in assumptions: + _asms.push(a) + assumptions = _asms + if isinstance(variables, list): + _vars = AstVector(None, self.ctx) + for a in variables: + _vars.push(a) + variables = _vars + _z3_assert(isinstance(assumptions, AstVector), "ast vector expected") + _z3_assert(isinstance(variables, AstVector), "ast vector expected") + consequences = AstVector(None, self.ctx) + r = Z3_solver_get_consequences(self.ctx.ref(), self.solver, assumptions.vector, variables.vector, consequences.vector) + sz = len(consequences) + consequences = [ consequences[i] for i in range(sz) ] + return CheckSatResult(r), consequences + def proof(self): """Return a proof for the last `check()`. Proof construction must be enabled.""" return _to_expr_ref(Z3_solver_get_proof(self.ctx.ref(), self.solver), self.ctx) diff --git a/src/api/z3_api.h b/src/api/z3_api.h index 41ca923bb..3334d1617 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -5887,6 +5887,17 @@ extern "C" { Z3_ast const terms[], unsigned class_ids[]); + /** + \brief retrieve consequences from solver that determine values of the supplied function symbols. + + def_API('Z3_solver_get_consequences', INT, (_in(CONTEXT), _in(SOLVER), _in(AST_VECTOR), _in(AST_VECTOR), _in(AST_VECTOR))) + */ + + Z3_lbool Z3_API Z3_solver_get_consequences(Z3_context c, + Z3_solver s, + Z3_ast_vector assumptions, + Z3_ast_vector variables, + Z3_ast_vector consequences); /** \brief Retrieve the model for the last #Z3_solver_check or #Z3_solver_check_assumptions diff --git a/src/solver/solver.cpp b/src/solver/solver.cpp index 3bbe1c3fd..c587a1722 100644 --- a/src/solver/solver.cpp +++ b/src/solver/solver.cpp @@ -17,6 +17,8 @@ Notes: --*/ #include"solver.h" +#include"model_evaluator.h" +#include"ast_util.h" unsigned solver::get_num_assertions() const { NOT_IMPLEMENTED_YET(); @@ -38,3 +40,82 @@ void solver::get_assertions(expr_ref_vector& fmls) const { fmls.push_back(get_assertion(i)); } } + +struct scoped_assumption_push { + expr_ref_vector& m_vec; + scoped_assumption_push(expr_ref_vector& v, expr* e): m_vec(v) { v.push_back(e); } + ~scoped_assumption_push() { m_vec.pop_back(); } +}; + +lbool solver::get_consequences(expr_ref_vector const& asms, expr_ref_vector const& vars, expr_ref_vector& consequences) { + ast_manager& m = asms.get_manager(); + lbool is_sat = check_sat(asms); + if (is_sat != l_true) { + return is_sat; + } + model_ref model; + get_model(model); + expr_ref tmp(m), nlit(m), lit(m), val(m); + expr_ref_vector asms1(asms); + model_evaluator eval(*model.get()); + unsigned k = 0; + for (unsigned i = 0; i < vars.size(); ++i) { + expr_ref_vector core(m); + tmp = vars[i]; + val = eval(tmp); + if (!m.is_value(val)) { + continue; + } + if (m.is_bool(tmp) && is_uninterp_const(tmp)) { + if (m.is_true(val)) { + nlit = m.mk_not(tmp); + lit = tmp; + } + else if (m.is_false(val)) { + nlit = tmp; + lit = m.mk_not(tmp); + } + else { + continue; + } + scoped_assumption_push _scoped_push(asms1, nlit); + is_sat = check_sat(asms1); + switch (is_sat) { + case l_undef: + return is_sat; + case l_true: + break; + case l_false: + get_unsat_core(core); + k = 0; + for (unsigned j = 0; j < core.size(); ++j) { + if (core[j].get() != nlit) { + core[k] = core[j].get(); + ++k; + } + } + core.resize(k); + consequences.push_back(m.mk_implies(mk_and(core), lit)); + break; + } + } + else { + lit = m.mk_eq(tmp, val); + nlit = m.mk_not(lit); + scoped_push _scoped_push(*this); + assert_expr(nlit); + is_sat = check_sat(asms); + switch (is_sat) { + case l_undef: + return is_sat; + case l_true: + break; + case l_false: + get_unsat_core(core); + consequences.push_back(m.mk_implies(mk_and(core), lit)); + break; + } + } + } + return l_true; +} diff --git a/src/solver/solver.h b/src/solver/solver.h index e4e4942d3..d55db9821 100644 --- a/src/solver/solver.h +++ b/src/solver/solver.h @@ -150,12 +150,13 @@ public: virtual expr * get_assumption(unsigned idx) const = 0; /** - \brief under assumptions, asms, retrieve set of consequences that fix values for expressions that can be - built from fns. For functions that take 0 arguments, we require that the function returns all consequences - that mention these functions. The consequences are clauses whose first literal constrain one of the - functions from fns and the other literals are negations of literals from asms. - */ - //virtual lbool get_consequences(expr_ref_vector const& asms, func_ref_vector const& fns, expr_ref_vector& consequences); + \brief under assumptions, asms, retrieve set of consequences that + fix values for expressions that can be built from vars. + The consequences are clauses whose first literal constrain one of the + functions from vars and the other literals are negations of literals from asms. + */ + + virtual lbool get_consequences(expr_ref_vector const& asms, expr_ref_vector const& vars, expr_ref_vector& consequences); /** \brief Display the content of this solver. From ceb3f0c869000359b925d96b2361f0c438d37908 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 28 Jul 2016 11:30:39 -0700 Subject: [PATCH 123/536] patch full version for cmake to re-enable build Signed-off-by: Nikolaj Bjorner --- CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 869ca4992..6a2ed0ebd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -35,6 +35,7 @@ set(Z3_VERSION_MAJOR 4) set(Z3_VERSION_MINOR 4) set(Z3_VERSION_PATCH 2) set(Z3_VERSION_TWEAK 1) +set(Z3_FULL_VERSION 0) set(Z3_VERSION "${Z3_VERSION_MAJOR}.${Z3_VERSION_MINOR}.${Z3_VERSION_PATCH}.${Z3_VERSION_TWEAK}") message(STATUS "Z3 version ${Z3_VERSION}") From 73bd4acfc580afc2a92b41574cd3a1a4efb75742 Mon Sep 17 00:00:00 2001 From: Loris D'Antoni Date: Thu, 28 Jul 2016 13:50:05 -0700 Subject: [PATCH 124/536] added symbolic automata complement for sequences --- src/ast/rewriter/seq_rewriter.cpp | 82 +++------ src/math/automata/automaton.h | 16 +- src/math/automata/boolean_algebra.h | 2 +- src/math/automata/symbolic_automata.h | 42 ++++- src/math/automata/symbolic_automata_def.h | 212 ++++++++++------------ 5 files changed, 174 insertions(+), 180 deletions(-) diff --git a/src/ast/rewriter/seq_rewriter.cpp b/src/ast/rewriter/seq_rewriter.cpp index 3a447d0f5..814b2168f 100644 --- a/src/ast/rewriter/seq_rewriter.cpp +++ b/src/ast/rewriter/seq_rewriter.cpp @@ -86,20 +86,25 @@ public: expr_ref fml(m.mk_true(), m); return sym_expr::mk_pred(fml, m.mk_bool_sort()); } - virtual T mk_and(T x, T y) { - if (x->is_char() && y->is_char()) { - if (x->get_char() == y->get_char()) { - return x; - } - if (m.are_distinct(x->get_char(), y->get_char())) { - expr_ref fml(m.mk_false(), m); - return sym_expr::mk_pred(fml, x->get_sort()); - } - } - var_ref v(m.mk_var(0, x->get_sort()), m); - expr_ref fml1 = x->accept(v); - expr_ref fml2 = y->accept(v); - if (m.is_true(fml1)) return y; + virtual T mk_and(T x, T y) { + if (x->is_char() && y->is_char()) { + if (x->get_char() == y->get_char()) { + return x; + } + if (m.are_distinct(x->get_char(), y->get_char())) { + expr_ref fml(m.mk_false(), m); + return sym_expr::mk_pred(fml, x->get_sort()); + } + } + + sort* s = x->get_sort(); + if (m.is_bool(s)) s = y->get_sort(); + var_ref v(m.mk_var(0, s), m); + expr_ref fml1 = x->accept(v); + expr_ref fml2 = y->accept(v); + if (m.is_true(fml1)) { + return y; + } if (m.is_true(fml2)) return x; expr_ref fml(m.mk_and(fml1, fml2), m); return sym_expr::mk_pred(fml, x->get_sort()); @@ -166,6 +171,11 @@ public: expr_ref fml(m.mk_not(x->accept(v)), m); return sym_expr::mk_pred(fml, x->get_sort()); } + + /*virtual vector, T>> generate_min_terms(vector constraints){ + + return 0; + }*/ }; re2automaton::re2automaton(ast_manager& m): m(m), u(m), bv(m), m_ba(0), m_sa(0) {} @@ -233,47 +243,9 @@ eautomaton* re2automaton::re2aut(expr* e) { TRACE("seq", tout << "Range expression is not handled: " << mk_pp(e, m) << "\n";); } } - else if (u.re.is_complement(e, e0)) { - // TBD non-standard semantics of complementation. - if (u.re.is_range(e0, e1, e2) && u.str.is_string(e1, s1) && u.str.is_string(e2, s2) && - s1.length() == 1 && s2.length() == 1) { - unsigned start = s1[0]; - unsigned stop = s2[0]; - unsigned nb = s1.num_bits(); - sort_ref s(bv.mk_sort(nb), m); - expr_ref v(m.mk_var(0, s), m); - expr_ref _start(bv.mk_numeral(start, nb), m); - expr_ref _stop(bv.mk_numeral(stop, nb), m); - expr_ref _pred(m.mk_not(m.mk_and(bv.mk_ule(_start, v), bv.mk_ule(v, _stop))), m); - a = alloc(eautomaton, sm, sym_expr::mk_pred(_pred, s)); - display_expr1 disp(m); - TRACE("seq", tout << mk_pp(e, m) << "\n"; a->display(tout, disp);); - return a.detach(); - } - else if (u.re.is_to_re(e0, e1) && u.str.is_string(e1, s1) && s1.length() == 1) { - unsigned nb = s1.num_bits(); - sort_ref s(bv.mk_sort(nb), m); - expr_ref v(m.mk_var(0, s), m); - expr_ref _ch(bv.mk_numeral(s1[0], nb), m); - expr_ref _pred(m.mk_not(m.mk_eq(v, _ch)), m); - a = alloc(eautomaton, sm, sym_expr::mk_pred(_pred, s)); - display_expr1 disp(m); - TRACE("seq", tout << mk_pp(e, m) << "\n"; a->display(tout, disp);); - return a.detach(); - } - else if (u.re.is_to_re(e0, e1) && u.str.is_unit(e1, e2)) { - sort* s = m.get_sort(e2); - expr_ref v(m.mk_var(0, s), m); - expr_ref _pred(m.mk_not(m.mk_eq(v, e2)), m); - a = alloc(eautomaton, sm, sym_expr::mk_pred(_pred, s)); - display_expr1 disp(m); - TRACE("seq", tout << mk_pp(e, m) << "\n"; a->display(tout, disp);); - return a.detach(); - } - else { - TRACE("seq", tout << "Complement expression is not handled: " << mk_pp(e, m) << "\n";); - } - } + else if (u.re.is_complement(e, e0) && (a = re2aut(e0)) && m_sa) { + return m_sa->mk_complement(*a); + } else if (u.re.is_loop(e, e1, lo, hi) && (a = re2aut(e1))) { scoped_ptr eps = eautomaton::mk_epsilon(sm); b = eautomaton::mk_epsilon(sm); diff --git a/src/math/automata/automaton.h b/src/math/automata/automaton.h index dd1ff87f5..2a68cba08 100644 --- a/src/math/automata/automaton.h +++ b/src/math/automata/automaton.h @@ -467,10 +467,17 @@ public: unsigned out_degree(unsigned state) const { return m_delta[state].size(); } move const& get_move_from(unsigned state) const { SASSERT(m_delta[state].size() == 1); return m_delta[state][0]; } move const& get_move_to(unsigned state) const { SASSERT(m_delta_inv[state].size() == 1); return m_delta_inv[state][0]; } - moves const& get_moves_from(unsigned state) const { return m_delta[state]; } + moves const& get_moves_from(unsigned state) const { return m_delta[state]; } moves const& get_moves_to(unsigned state) const { return m_delta_inv[state]; } bool initial_state_is_source() const { return m_delta_inv[m_init].empty(); } bool is_final_state(unsigned s) const { return m_final_set.contains(s); } + bool is_final_configuration(uint_set s) const { + for (uint_set::iterator it = s.begin(), end = s.end(); it != end; ++it) { + if (is_final_state(*it)) + return true; + } + return false; + } bool is_epsilon_free() const { for (unsigned i = 0; i < m_delta.size(); ++i) { moves const& mvs = m_delta[i]; @@ -517,6 +524,13 @@ public: void get_moves_from(unsigned state, moves& mvs, bool epsilon_closure = true) const { get_moves(state, m_delta, mvs, epsilon_closure); } + void get_moves_from_states(uint_set states, moves& mvs, bool epsilon_closure = true) const { + for (uint_set::iterator it = states.begin(), end = states.end(); it != end; ++it) { + moves curr; + get_moves(*it, m_delta, curr, epsilon_closure); + mvs.append(curr); + } + } void get_moves_to(unsigned state, moves& mvs, bool epsilon_closure = true) { get_moves(state, m_delta_inv, mvs, epsilon_closure); } diff --git a/src/math/automata/boolean_algebra.h b/src/math/automata/boolean_algebra.h index 503878ef3..e3977b4cd 100644 --- a/src/math/automata/boolean_algebra.h +++ b/src/math/automata/boolean_algebra.h @@ -38,7 +38,7 @@ public: template class boolean_algebra : public positive_boolean_algebra { public: - virtual T mk_not(T x) = 0; + virtual T mk_not(T x) = 0; //virtual lbool are_equivalent(T x, T y) = 0; //virtual T simplify(T x) = 0; }; diff --git a/src/math/automata/symbolic_automata.h b/src/math/automata/symbolic_automata.h index c358bcac8..7589a931b 100644 --- a/src/math/automata/symbolic_automata.h +++ b/src/math/automata/symbolic_automata.h @@ -96,16 +96,54 @@ class symbolic_automata { public: symbolic_automata(M& m, ba_t& ba): m(m), m_ba(ba) {} - //automaton_t* mk_determinstic(automaton_t& a); - //automaton_t* mk_complement(automaton_t& a); + automaton_t* mk_determinstic(automaton_t& a); + automaton_t* mk_complement(automaton_t& a); automaton_t* remove_epsilons(automaton_t& a); automaton_t* mk_total(automaton_t& a); automaton_t* mk_minimize(automaton_t& a); automaton_t* mk_minimize_total(automaton_t& a); automaton_t* mk_difference(automaton_t& a, automaton_t& b); automaton_t* mk_product(automaton_t& a, automaton_t& b); + +private: + automaton_t* mk_determinstic_param(automaton_t& a, bool flip_acceptance); + + vector, ref_t>> generate_min_terms(vector &constraints) { + vector, ref_t>> min_terms; + + ref_t curr_pred(m_ba.mk_true(), m); + vector curr_bv; + + generate_min_terms_rec(constraints, min_terms, 0, curr_bv, curr_pred); + + return min_terms; + } + void generate_min_terms_rec(vector &constraints, vector, ref_t>> &min_terms, unsigned i, vector &curr_bv, ref_t &curr_pred) { + lbool is_sat = m_ba.is_sat(curr_pred); + if (is_sat != l_true) { + return; + } + + if (i == constraints.size()) { + min_terms.push_back(std::pair, ref_t>(curr_bv, curr_pred)); + } + else { + //true case + curr_bv.push_back(true); + ref_t new_pred_pos(m_ba.mk_and(curr_pred, constraints[i]), m); + generate_min_terms_rec(constraints, min_terms, i + 1, curr_bv, new_pred_pos); + curr_bv.pop_back(); + + //false case + curr_bv.push_back(false); + ref_t new_pred_neg(m_ba.mk_and(curr_pred, m_ba.mk_not(constraints[i])), m); + generate_min_terms_rec(constraints, min_terms, i + 1, curr_bv, new_pred_neg); + curr_bv.pop_back(); + } + } }; + #endif diff --git a/src/math/automata/symbolic_automata_def.h b/src/math/automata/symbolic_automata_def.h index 2df5275c2..ad03492eb 100644 --- a/src/math/automata/symbolic_automata_def.h +++ b/src/math/automata/symbolic_automata_def.h @@ -273,6 +273,95 @@ typename symbolic_automata::automaton_t* symbolic_automata::mk_minim return alloc(automaton_t, m, new_init, new_final, new_moves); } +template +typename symbolic_automata::automaton_t* symbolic_automata::mk_determinstic(automaton_t& a) { + return mk_determinstic_param(a); +} + +template +typename symbolic_automata::automaton_t* symbolic_automata::mk_complement(automaton_t& a) { + return mk_determinstic_param(a, true); +} + +template +typename symbolic_automata::automaton_t* symbolic_automata::mk_determinstic_param(automaton_t& a, bool flip_acceptance = false) { + vector, ref_t>> min_terms; + vector predicates; + + map s2id; // set of states to unique id + vector id2s; // unique id to set of b-states + uint_set set; + unsigned_vector vector; + moves_t new_mvs; // moves in the resulting automaton + unsigned_vector new_final_states; // new final states + unsigned p_state_id = 0; // next state identifier + + // adds non-final states of a to final if flipping and and final otherwise + if (a.is_final_configuration(set) != flip_acceptance) { + new_final_states.push_back(p_state_id); + } + + set.insert(a.init()); // initial state as aset + s2id.insert(set, p_state_id++); // the index to the initial state is 0 + id2s.push_back(set); + + svector todo; //States to visit + todo.push_back(set); + + uint_set state; + moves_t mvsA; + + new_mvs.reset(); + + // or just make todo a vector whose indices coincide with state_id. + while (!todo.empty()) { + uint_set state = todo.back(); + + unsigned state_id = s2id[state]; + todo.pop_back(); + mvsA.reset(); + + min_terms.reset(); + predicates.reset(); + + a.get_moves_from_states(state, mvsA); + + for (unsigned j = 0; j < mvsA.size(); ++j) { + ref_t mv_guard(mvsA[j].t(),m); + predicates.push_back(mv_guard); + } + + min_terms = generate_min_terms(predicates); + for (unsigned j = 0; j < min_terms.size(); ++j) { + set = uint_set(); + for (unsigned i = 0; i < mvsA.size(); ++i) { + if (min_terms[j].first[i]) + set.insert(mvsA[i].dst()); + } + + bool is_new = !s2id.contains(set); + if (is_new) { + if (a.is_final_configuration(set) != flip_acceptance) { + new_final_states.push_back(p_state_id); + } + + s2id.insert(set, p_state_id++); + id2s.push_back(set); + todo.push_back(set); + } + new_mvs.push_back(move_t(m, state_id, s2id[set], min_terms[j].second)); + } + } + + if (new_final_states.empty()) { + return alloc(automaton_t, m); + } + + return alloc(automaton_t, m, 0, new_final_states, new_mvs); +} + + + template typename symbolic_automata::automaton_t* symbolic_automata::mk_product(automaton_t& a, automaton_t& b) { u2_map pair2id; @@ -362,130 +451,11 @@ typename symbolic_automata::automaton_t* symbolic_automata::mk_produ } } -#if 0 -template -unsigned symbolic_automata::get_product_state_id(u2_map& pair2id, unsigned_pair const& p, unsigned& id) { - unsigned result = 0; - if (!pair2id.find(p, result)) { - result = id++; - pair2id.insert(p, result); - } - return result; -} -#endif + template typename symbolic_automata::automaton_t* symbolic_automata::mk_difference(automaton_t& a, automaton_t& b) { -#if 0 - map bs2id; // set of b-states to unique id - vector id2bs; // unique id to set of b-states - u2_map pair2id; // pair of states to new state id - unsigned sink_state = UINT_MAX; - uint_set bset; - moves_t new_moves; // moves in the resulting automaton - unsigned_vector new_final_states; // new final states - unsigned p_state_id = 0; // next state identifier - bs2id.insert(uint_set(), sink_state); // the sink state has no b-states - bset.insert(b.init()); // the initial state has a single initial b state - bs2id.insert(bset, 0); // the index to the initial b state is 0 - id2bs.push_back(bset); - if (!b.is_final_state(b.init()) && a.is_final_state(a.init())) { - new_final_states.push_back(p_state_id); - } - - svector todo; - unsigned_pair state(a.init(), 0); - todo.push_back(state); - pair2id.insert(state, p_state_id++); - - // or just make todo a vector whose indices coincide with state_id. - while (!todo.empty()) { - state = todo.back(); - unsigned state_id = pair2id[state]; - todo.pop_back(); - mvsA.reset(); - a.get_moves_from(state.first, mvsA, true); - if (state.second == sink_state) { - for (unsigned i = 0; i < mvsA.size(); ++i) { - unsigned_pair dst(mvsA[i].dst(), sink_state); - bool is_new = !pair2id.contains(dst); - unsigned dst_id = get_product_state_id(pair2id, dst, p_state_id); - new_moves.push_back(move_t(m, state_id, dst_id, mvsA[i].t())); - if (is_new && a.is_final_state(mvsA[i].dst())) { - new_final_states.push_back(dst_id); - todo.push_back(dst); - } - } - } - else { - get_moves_from(b, id2bs[state.second], mvsB); - generate_min_terms(mvsB, min_terms); - for (unsigned j = 0; j < min_terms.size(); ++j) { - for (unsigned i = 0; i < mvsA.size(); ++i) { - ref_t cond(m_ba.mk_and(mvsA[i].t(), min_terms[j].second), m); - switch (m_ba.is_sat(cond)) { - case l_false: - break; - case l_true: - ab_combinations.push_back(ab_comb(i, min_terms[j].first, cond)); - break; - case l_undef: - return 0; - } - } - } - - for (unsigned i = 0; i < ab_combinations.size(); ++i) { - move_t const& mvA = mvsA[ab_combinations[i].A]; - bset.reset(); - bool is_final = a.is_final_state(mvA.dst()); - for (unsigned j = 0; j < mvsB.size(); ++j) { - if (ab_combinations[i].B[j]) { - bset.insert(mvsB[j].dst()); - is_final &= !b.is_final_state(mvsB[j].dst()); - } - } - unsigned new_b; - if (bset.empty()) { - new_b = sink_state; - } - else if (!bs2id.find(bset, new_b)) { - new_b = id2bs.size(); - id2bs.push_back(bset); - bs2id.insert(bset, new_b); - } - unsigned_pair dst(mvA.dst(), new_b); - bool is_new = !pair2id.contains(dst); - dst_id = get_product_state_id(pair2id, dst, p_state_id); - move_t new_move(m, state_id, dst_id, ab_combinations[i].cond); - new_moves.push_back(new_move); - if (is_new) { - if (is_final) { - new_final_states.push_back(dst_id); - } - todo.push_back(dst); - } - } - } - } - - - if (new_final_states.empty()) { - return alloc(automaton_t, m); - } - - automaton_t* result = alloc(automaton_t, m, 0, new_final_states, new_moves); - -#if 0 - result->isEpsilonFree = true; - if (A.IsDeterministic) - result->isDeterministic = true; - result->EliminateDeadStates(); -#endif - return result; - -#endif - return 0; + return mk_product(a,mk_complement(b)); } #endif From 8221a09659ea878f29d4aa413122f9e4a73b88d9 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 28 Jul 2016 16:49:19 -0700 Subject: [PATCH 125/536] fast path for antecedent extraction in smt_context Signed-off-by: Nikolaj Bjorner --- contrib/cmake/src/smt/CMakeLists.txt | 1 + src/smt/smt_consequences.cpp | 189 +++++++++++++++++++++++++++ src/smt/smt_context.cpp | 7 + src/smt/smt_context.h | 8 ++ src/smt/smt_kernel.cpp | 8 ++ src/smt/smt_kernel.h | 5 + src/smt/smt_solver.cpp | 4 + src/solver/solver.cpp | 4 + src/solver/solver.h | 5 + src/solver/solver_na2as.cpp | 5 + src/solver/solver_na2as.h | 1 + 11 files changed, 237 insertions(+) create mode 100644 src/smt/smt_consequences.cpp diff --git a/contrib/cmake/src/smt/CMakeLists.txt b/contrib/cmake/src/smt/CMakeLists.txt index e9306b2d6..035ac07c9 100644 --- a/contrib/cmake/src/smt/CMakeLists.txt +++ b/contrib/cmake/src/smt/CMakeLists.txt @@ -18,6 +18,7 @@ z3_add_component(smt smt_checker.cpp smt_clause.cpp smt_conflict_resolution.cpp + smt_consequences.cpp smt_context.cpp smt_context_inv.cpp smt_context_pp.cpp diff --git a/src/smt/smt_consequences.cpp b/src/smt/smt_consequences.cpp new file mode 100644 index 000000000..083fd6e0c --- /dev/null +++ b/src/smt/smt_consequences.cpp @@ -0,0 +1,189 @@ +/*++ +Copyright (c) 2006 Microsoft Corporation + +Module Name: + + smt_consequences.cpp + +Abstract: + + Tuned consequence finding for smt_context. + +Author: + + nbjorner 2016-07-28. + +Revision History: + +--*/ +#include "smt_context.h" +#include "ast_util.h" + +namespace smt { + + expr_ref context::antecedent2fml(uint_set const& vars) { + expr_ref_vector premises(m_manager); + uint_set::iterator it = vars.begin(), end = vars.end(); + for (; it != end; ++it) { + premises.push_back(bool_var2expr(*it)); + } + return mk_and(premises); + } + + void context::extract_fixed_consequences(unsigned start, obj_map& vars, obj_hashtable const& assumptions, expr_ref_vector& conseq) { + ast_manager& m = m_manager; + pop_to_search_lvl(); + literal_vector const& lits = assigned_literals(); + unsigned sz = lits.size(); + expr* e1, *e2; + expr_ref fml(m); + for (unsigned i = start; i < sz; ++i) { + literal lit = lits[i]; + if (lit == true_literal) continue; + expr* e = bool_var2expr(lit.var()); + uint_set s; + if (assumptions.contains(e)) { + s.insert(get_literal(e).var()); + } + else { + b_justification js = get_justification(lit.var()); + switch (js.get_kind()) { + case b_justification::CLAUSE: { + clause * cls = js.get_clause(); + unsigned num_lits = cls->get_num_literals(); + for (unsigned j = 0; j < num_lits; ++j) { + literal lit2 = cls->get_literal(j); + if (lit2.var() != lit.var()) { + s |= m_antecedents.find(lit2.var()); + } + } + break; + } + case b_justification::BIN_CLAUSE: { + s |= m_antecedents.find(js.get_literal().var()); + break; + } + case b_justification::AXIOM: { + break; + } + case b_justification::JUSTIFICATION: + justification* j = js.get_justification(); + // warning_msg("TODO: extract antecedents from theory justification"); + // std::cout << "TODO: justification\n"; + break; + } + } + m_antecedents.insert(lit.var(), s); + bool found = false; + if (vars.contains(e)) { + found = true; + fml = lit.sign()?m.mk_not(e):e; + vars.erase(e); + } + else if (!lit.sign() && m.is_eq(e, e1, e2)) { + if (vars.contains(e2)) { + std::swap(e1, e2); + } + if (vars.contains(e1) && m.is_value(e2)) { + found = true; + fml = e; + vars.erase(e1); + } + } + if (found) { + fml = m.mk_implies(antecedent2fml(s), fml); + conseq.push_back(fml); + } + } + } + + lbool context::get_consequences(expr_ref_vector const& assumptions, + expr_ref_vector const& vars, expr_ref_vector& conseq) { + + lbool is_sat = check(assumptions.size(), assumptions.c_ptr()); + if (is_sat != l_true) { + return is_sat; + } + obj_map var2val; + obj_hashtable _assumptions; + for (unsigned i = 0; i < assumptions.size(); ++i) { + _assumptions.insert(assumptions[i]); + } + model_ref mdl; + get_model(mdl); + expr_ref_vector trail(m_manager); + model_evaluator eval(*mdl.get()); + expr_ref val(m_manager); + for (unsigned i = 0; i < vars.size(); ++i) { + eval(vars[i], val); + if (m_manager.is_value(val)) { + trail.push_back(val); + var2val.insert(vars[i], val); + } + } + extract_fixed_consequences(0, var2val, _assumptions, conseq); + unsigned num_units = assigned_literals().size(); + app_ref eq(m_manager); + TRACE("context", + tout << "pop: " << num_levels << "\n"; + tout << "vars: " << vars.size() << "\n"; + tout << "lits: " << num_units << "\n";); + m_case_split_queue->init_search_eh(); + while (!var2val.empty()) { + obj_map::iterator it = var2val.begin(); + expr* e = it->m_key; + expr* val = it->m_value; + push_scope(); + unsigned current_level = m_scope_lvl; + + literal lit; + if (m_manager.is_bool(e)) { + lit = literal(get_bool_var(e), m_manager.is_true(val)); + } + else { + eq = mk_eq_atom(e, val); + internalize_formula(eq, false); + lit = literal(get_bool_var(eq), true); + } + assign(lit, b_justification::mk_axiom(), true); + flet l(m_searching, true); + while (true) { + is_sat = bounded_search(); + TRACE("context", tout << "search result: " << is_sat << "\n";); + if (is_sat != l_true && m_last_search_failure != OK) { + return is_sat; + } + if (is_sat == l_undef) { + TRACE("context", tout << "restart\n";); + inc_limits(); + continue; + } + break; + } + if (get_assignment(lit) == l_true) { + var2val.erase(e); + } + else if (get_assign_level(lit) > get_search_level()) { + TRACE("context", tout << "Retry fixing: " << mk_pp(e, m_manager) << "\n";); + pop_to_search_lvl(); + continue; + } + else { + TRACE("context", tout << "Fixed: " << mk_pp(e, m_manager) << "\n";); + } + extract_fixed_consequences(num_units, var2val, _assumptions, conseq); + num_units = assigned_literals().size(); + if (var2val.contains(e)) { + TRACE("context", tout << "TBD: Fixed value to " << mk_pp(e, m_manager) << " was not retrieved\n";); + var2val.erase(e); + SASSERT(get_assignment(lit) == l_false); + } + + // repeat until we either have a model with negated literal or + // the literal is implied at base. + TRACE("context", tout << "Unfixed variables: " << var2val.size() << "\n";); + } + return l_true; + } + +} diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index 5b60b6893..3aeb623f9 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -2460,6 +2460,13 @@ namespace smt { SASSERT(m_scope_lvl == m_base_lvl); } + void context::pop_to_search_lvl() { + unsigned num_levels = m_scope_lvl - get_search_level(); + if (num_levels > 0) { + pop_scope(num_levels); + } + } + /** \brief Simplify the given clause using the assignment. Return true if the clause was already satisfied, and false otherwise. diff --git a/src/smt/smt_context.h b/src/smt/smt_context.h index 3c260abbe..b5e143d9d 100644 --- a/src/smt/smt_context.h +++ b/src/smt/smt_context.h @@ -1322,6 +1322,7 @@ namespace smt { virtual void setup_context(bool use_static_features); void setup_components(void); void pop_to_base_lvl(); + void pop_to_search_lvl(); #ifdef Z3DEBUG bool already_internalized_theory(theory * th) const; bool already_internalized_theory_core(theory * th, expr_ref_vector const & s) const; @@ -1343,6 +1344,11 @@ namespace smt { literal lit, context& src_ctx, context& dst_ctx, vector b2v, ast_translation& tr); + u_map m_antecedents; + void extract_fixed_consequences(unsigned idx, obj_map& vars, obj_hashtable const& assumptions, expr_ref_vector& conseq); + + expr_ref antecedent2fml(uint_set const& ante); + public: context(ast_manager & m, smt_params & fp, params_ref const & p = params_ref()); @@ -1382,6 +1388,8 @@ namespace smt { void pop(unsigned num_scopes); lbool check(unsigned num_assumptions = 0, expr * const * assumptions = 0, bool reset_cancel = true); + + lbool get_consequences(expr_ref_vector const& assumptions, expr_ref_vector const& vars, expr_ref_vector& conseq); lbool setup_and_check(bool reset_cancel = true); diff --git a/src/smt/smt_kernel.cpp b/src/smt/smt_kernel.cpp index 418dfdb04..8f18b7311 100644 --- a/src/smt/smt_kernel.cpp +++ b/src/smt/smt_kernel.cpp @@ -98,6 +98,10 @@ namespace smt { lbool check(unsigned num_assumptions, expr * const * assumptions) { return m_kernel.check(num_assumptions, assumptions); } + + lbool get_consequences(expr_ref_vector const& assumptions, expr_ref_vector const& vars, expr_ref_vector& conseq) { + return m_kernel.get_consequences(assumptions, vars, conseq); + } void get_model(model_ref & m) const { m_kernel.get_model(m); @@ -264,6 +268,10 @@ namespace smt { return r; } + lbool kernel::get_consequences(expr_ref_vector const& assumptions, expr_ref_vector const& vars, expr_ref_vector& conseq) { + return m_imp->get_consequences(assumptions, vars, conseq); + } + void kernel::get_model(model_ref & m) const { m_imp->get_model(m); } diff --git a/src/smt/smt_kernel.h b/src/smt/smt_kernel.h index bf559a775..4cf170681 100644 --- a/src/smt/smt_kernel.h +++ b/src/smt/smt_kernel.h @@ -126,6 +126,11 @@ namespace smt { lbool check(app_ref_vector const& asms) { return check(asms.size(), (expr* const*)asms.c_ptr()); } + /** + \brief extract consequences among variables. + */ + lbool get_consequences(expr_ref_vector const& assumptions, expr_ref_vector const& vars, expr_ref_vector& conseq); + /** \brief Return the model associated with the last check command. */ diff --git a/src/smt/smt_solver.cpp b/src/smt/smt_solver.cpp index 6ae7f107c..ec874ed8f 100644 --- a/src/smt/smt_solver.cpp +++ b/src/smt/smt_solver.cpp @@ -67,6 +67,10 @@ namespace smt { m_context.collect_statistics(st); } + virtual lbool get_consequences_core(expr_ref_vector const& assumptions, expr_ref_vector const& vars, expr_ref_vector& conseq) { + return m_context.get_consequences(assumptions, vars, conseq); + } + virtual void assert_expr(expr * t) { m_context.assert_expr(t); } diff --git a/src/solver/solver.cpp b/src/solver/solver.cpp index c587a1722..7b11317d1 100644 --- a/src/solver/solver.cpp +++ b/src/solver/solver.cpp @@ -48,6 +48,10 @@ struct scoped_assumption_push { }; lbool solver::get_consequences(expr_ref_vector const& asms, expr_ref_vector const& vars, expr_ref_vector& consequences) { + return get_consequences_core(asms, vars, consequences); +} + +lbool solver::get_consequences_core(expr_ref_vector const& asms, expr_ref_vector const& vars, expr_ref_vector& consequences) { ast_manager& m = asms.get_manager(); lbool is_sat = check_sat(asms); if (is_sat != l_true) { diff --git a/src/solver/solver.h b/src/solver/solver.h index d55db9821..7f36e2ad7 100644 --- a/src/solver/solver.h +++ b/src/solver/solver.h @@ -171,6 +171,11 @@ public: ~scoped_push() { if (!m_nopop) s.pop(1); } void disable_pop() { m_nopop = true; } }; + +protected: + + virtual lbool get_consequences_core(expr_ref_vector const& asms, expr_ref_vector const& vars, expr_ref_vector& consequences); + }; #endif diff --git a/src/solver/solver_na2as.cpp b/src/solver/solver_na2as.cpp index 2ca6e187c..99917fff8 100644 --- a/src/solver/solver_na2as.cpp +++ b/src/solver/solver_na2as.cpp @@ -65,6 +65,11 @@ lbool solver_na2as::check_sat(unsigned num_assumptions, expr * const * assumptio return check_sat_core(m_assumptions.size(), m_assumptions.c_ptr()); } +lbool solver_na2as::get_consequences(expr_ref_vector const& asms, expr_ref_vector const& vars, expr_ref_vector& consequences) { + append_assumptions app(m_assumptions, asms.size(), asms.c_ptr()); + return get_consequences_core(m_assumptions, vars, consequences); +} + void solver_na2as::push() { m_scopes.push_back(m_assumptions.size()); push_core(); diff --git a/src/solver/solver_na2as.h b/src/solver/solver_na2as.h index 9aeb56fb1..45253e950 100644 --- a/src/solver/solver_na2as.h +++ b/src/solver/solver_na2as.h @@ -45,6 +45,7 @@ public: virtual unsigned get_num_assumptions() const { return m_assumptions.size(); } virtual expr * get_assumption(unsigned idx) const { return m_assumptions[idx]; } + virtual lbool get_consequences(expr_ref_vector const& asms, expr_ref_vector const& vars, expr_ref_vector& consequences); protected: virtual lbool check_sat_core(unsigned num_assumptions, expr * const * assumptions) = 0; virtual void push_core() = 0; From 7fd931d480e8fd8f7fd011b344be3c92145bf2cd Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Fri, 29 Jul 2016 00:55:05 +0100 Subject: [PATCH 126/536] build fix --- scripts/mk_unix_dist.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/mk_unix_dist.py b/scripts/mk_unix_dist.py index ee1294a8b..4905a7141 100644 --- a/scripts/mk_unix_dist.py +++ b/scripts/mk_unix_dist.py @@ -110,7 +110,7 @@ def mk_build_dir(path): opts.append('--java') if GIT_HASH: opts.append('--githash=%s' % mk_util.git_hash()) - opts.append('--git-describe')) + opts.append('--git-describe') if subprocess.call(opts) != 0: raise MKException("Failed to generate build directory at '%s'" % path) From 2e362aa6c049ca451c38e787f7108c26033a661f Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Fri, 29 Jul 2016 01:02:48 +0100 Subject: [PATCH 127/536] build fix --- src/math/automata/symbolic_automata.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/math/automata/symbolic_automata.h b/src/math/automata/symbolic_automata.h index 7589a931b..6fbcead3a 100644 --- a/src/math/automata/symbolic_automata.h +++ b/src/math/automata/symbolic_automata.h @@ -108,8 +108,8 @@ public: private: automaton_t* mk_determinstic_param(automaton_t& a, bool flip_acceptance); - vector, ref_t>> generate_min_terms(vector &constraints) { - vector, ref_t>> min_terms; + vector, ref_t> > generate_min_terms(vector &constraints) { + vector, ref_t> > min_terms; ref_t curr_pred(m_ba.mk_true(), m); vector curr_bv; @@ -118,7 +118,7 @@ private: return min_terms; } - void generate_min_terms_rec(vector &constraints, vector, ref_t>> &min_terms, unsigned i, vector &curr_bv, ref_t &curr_pred) { + void generate_min_terms_rec(vector &constraints, vector, ref_t> > &min_terms, unsigned i, vector &curr_bv, ref_t &curr_pred) { lbool is_sat = m_ba.is_sat(curr_pred); if (is_sat != l_true) { return; From 0055254f4cfa35fbe292644f2e954e01a37f70af Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 28 Jul 2016 17:04:06 -0700 Subject: [PATCH 128/536] fix build for non C++11 Signed-off-by: Nikolaj Bjorner --- src/math/automata/symbolic_automata.h | 70 +++++++++++------------ src/math/automata/symbolic_automata_def.h | 2 +- 2 files changed, 36 insertions(+), 36 deletions(-) diff --git a/src/math/automata/symbolic_automata.h b/src/math/automata/symbolic_automata.h index 7589a931b..6d7bc8290 100644 --- a/src/math/automata/symbolic_automata.h +++ b/src/math/automata/symbolic_automata.h @@ -106,41 +106,41 @@ public: automaton_t* mk_product(automaton_t& a, automaton_t& b); private: - automaton_t* mk_determinstic_param(automaton_t& a, bool flip_acceptance); - - vector, ref_t>> generate_min_terms(vector &constraints) { - vector, ref_t>> min_terms; - - ref_t curr_pred(m_ba.mk_true(), m); - vector curr_bv; - - generate_min_terms_rec(constraints, min_terms, 0, curr_bv, curr_pred); - - return min_terms; - } - void generate_min_terms_rec(vector &constraints, vector, ref_t>> &min_terms, unsigned i, vector &curr_bv, ref_t &curr_pred) { - lbool is_sat = m_ba.is_sat(curr_pred); - if (is_sat != l_true) { - return; - } - - if (i == constraints.size()) { - min_terms.push_back(std::pair, ref_t>(curr_bv, curr_pred)); - } - else { - //true case - curr_bv.push_back(true); - ref_t new_pred_pos(m_ba.mk_and(curr_pred, constraints[i]), m); - generate_min_terms_rec(constraints, min_terms, i + 1, curr_bv, new_pred_pos); - curr_bv.pop_back(); - - //false case - curr_bv.push_back(false); - ref_t new_pred_neg(m_ba.mk_and(curr_pred, m_ba.mk_not(constraints[i])), m); - generate_min_terms_rec(constraints, min_terms, i + 1, curr_bv, new_pred_neg); - curr_bv.pop_back(); - } - } + automaton_t* mk_determinstic_param(automaton_t& a, bool flip_acceptance); + + vector, ref_t> > generate_min_terms(vector &constraints) { + vector, ref_t> > min_terms; + + ref_t curr_pred(m_ba.mk_true(), m); + vector curr_bv; + + generate_min_terms_rec(constraints, min_terms, 0, curr_bv, curr_pred); + + return min_terms; + } + void generate_min_terms_rec(vector &constraints, vector, ref_t> > &min_terms, unsigned i, vector &curr_bv, ref_t &curr_pred) { + lbool is_sat = m_ba.is_sat(curr_pred); + if (is_sat != l_true) { + return; + } + + if (i == constraints.size()) { + min_terms.push_back(std::pair, ref_t>(curr_bv, curr_pred)); + } + else { + //true case + curr_bv.push_back(true); + ref_t new_pred_pos(m_ba.mk_and(curr_pred, constraints[i]), m); + generate_min_terms_rec(constraints, min_terms, i + 1, curr_bv, new_pred_pos); + curr_bv.pop_back(); + + //false case + curr_bv.push_back(false); + ref_t new_pred_neg(m_ba.mk_and(curr_pred, m_ba.mk_not(constraints[i])), m); + generate_min_terms_rec(constraints, min_terms, i + 1, curr_bv, new_pred_neg); + curr_bv.pop_back(); + } + } }; diff --git a/src/math/automata/symbolic_automata_def.h b/src/math/automata/symbolic_automata_def.h index ad03492eb..737dc9e19 100644 --- a/src/math/automata/symbolic_automata_def.h +++ b/src/math/automata/symbolic_automata_def.h @@ -285,7 +285,7 @@ typename symbolic_automata::automaton_t* symbolic_automata::mk_compl template typename symbolic_automata::automaton_t* symbolic_automata::mk_determinstic_param(automaton_t& a, bool flip_acceptance = false) { - vector, ref_t>> min_terms; + vector, ref_t> > min_terms; vector predicates; map s2id; // set of states to unique id From 4958edeb42511f81ec6d5dc9c0fc0f61f51653d3 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 28 Jul 2016 19:40:49 -0700 Subject: [PATCH 129/536] fix build Signed-off-by: Nikolaj Bjorner --- src/ast/arith_decl_plugin.h | 6 +++++ src/ast/rewriter/arith_rewriter.cpp | 35 ++++++++++++++++------------- src/smt/smt_consequences.cpp | 1 - 3 files changed, 25 insertions(+), 17 deletions(-) diff --git a/src/ast/arith_decl_plugin.h b/src/ast/arith_decl_plugin.h index 9ccf02d0d..4f0379674 100644 --- a/src/ast/arith_decl_plugin.h +++ b/src/ast/arith_decl_plugin.h @@ -290,6 +290,9 @@ public: bool is_asin(expr const* n) const { return is_app_of(n, m_afid, OP_ASIN); } bool is_acos(expr const* n) const { return is_app_of(n, m_afid, OP_ACOS); } bool is_atan(expr const* n) const { return is_app_of(n, m_afid, OP_ATAN); } + bool is_asinh(expr const* n) const { return is_app_of(n, m_afid, OP_ASINH); } + bool is_acosh(expr const* n) const { return is_app_of(n, m_afid, OP_ACOSH); } + bool is_atanh(expr const* n) const { return is_app_of(n, m_afid, OP_ATANH); } bool is_pi(expr * arg) { return is_app_of(arg, m_afid, OP_PI); } bool is_e(expr * arg) { return is_app_of(arg, m_afid, OP_E); } @@ -311,10 +314,13 @@ public: MATCH_UNARY(is_sin); MATCH_UNARY(is_asin); + MATCH_UNARY(is_asinh); MATCH_UNARY(is_cos); MATCH_UNARY(is_acos); + MATCH_UNARY(is_acosh); MATCH_UNARY(is_tan); MATCH_UNARY(is_atan); + MATCH_UNARY(is_atanh); }; diff --git a/src/ast/rewriter/arith_rewriter.cpp b/src/ast/rewriter/arith_rewriter.cpp index 8f8c9a2bc..368476b8e 100644 --- a/src/ast/rewriter/arith_rewriter.cpp +++ b/src/ast/rewriter/arith_rewriter.cpp @@ -946,12 +946,13 @@ br_status arith_rewriter::mk_power_core(expr * arg1, expr * arg2, expr_ref & res br_status arith_rewriter::mk_to_int_core(expr * arg, expr_ref & result) { numeral a; + expr* x; if (m_util.is_numeral(arg, a)) { result = m_util.mk_numeral(floor(a), true); return BR_DONE; } - else if (m_util.is_to_real(arg)) { - result = to_app(arg)->get_arg(0); + else if (m_util.is_to_real(arg, x)) { + result = x; return BR_DONE; } else { @@ -982,8 +983,8 @@ br_status arith_rewriter::mk_to_int_core(expr * arg, expr_ref & result) { new_args.push_back(m_util.mk_numeral(a, true)); } else { - SASSERT(m_util.is_to_real(c)); - new_args.push_back(to_app(c)->get_arg(0)); + VERIFY (m_util.is_to_real(c, x)); + new_args.push_back(x); } } SASSERT(num_args == new_args.size()); @@ -1315,9 +1316,10 @@ br_status arith_rewriter::mk_cos_core(expr * arg, expr_ref & result) { } br_status arith_rewriter::mk_tan_core(expr * arg, expr_ref & result) { - if (is_app_of(arg, get_fid(), OP_ATAN)) { + expr* x; + if (m_util.is_atan(arg, x)) { // tan(atan(x)) == x - result = to_app(arg)->get_arg(0); + result = x; return BR_DONE; } @@ -1497,9 +1499,10 @@ br_status arith_rewriter::mk_atan_core(expr * arg, expr_ref & result) { } br_status arith_rewriter::mk_sinh_core(expr * arg, expr_ref & result) { - if (is_app_of(arg, get_fid(), OP_ASINH)) { + expr* x; + if (m_util.is_asinh(arg, x)) { // sinh(asinh(x)) == x - result = to_app(arg)->get_arg(0); + result = x; return BR_DONE; } expr * t; @@ -1512,12 +1515,12 @@ br_status arith_rewriter::mk_sinh_core(expr * arg, expr_ref & result) { } br_status arith_rewriter::mk_cosh_core(expr * arg, expr_ref & result) { - if (is_app_of(arg, get_fid(), OP_ACOSH)) { - // cosh(acosh(x)) == x - result = to_app(arg)->get_arg(0); + expr* t; + if (m_util.is_acosh(arg, t)) { + // cosh(acosh(t)) == t + result = t; return BR_DONE; } - expr * t; if (m_util.is_times_minus_one(arg, t)) { // cosh(-t) == cosh result = m_util.mk_cosh(t); @@ -1527,12 +1530,12 @@ br_status arith_rewriter::mk_cosh_core(expr * arg, expr_ref & result) { } br_status arith_rewriter::mk_tanh_core(expr * arg, expr_ref & result) { - if (is_app_of(arg, get_fid(), OP_ATANH)) { - // tanh(atanh(x)) == x - result = to_app(arg)->get_arg(0); + expr * t; + if (m_util.is_atanh(arg, t)) { + // tanh(atanh(t)) == t + result = t; return BR_DONE; } - expr * t; if (m_util.is_times_minus_one(arg, t)) { // tanh(-t) == -tanh(t) result = m_util.mk_uminus(m_util.mk_tanh(t)); diff --git a/src/smt/smt_consequences.cpp b/src/smt/smt_consequences.cpp index 083fd6e0c..109eb0deb 100644 --- a/src/smt/smt_consequences.cpp +++ b/src/smt/smt_consequences.cpp @@ -125,7 +125,6 @@ namespace smt { unsigned num_units = assigned_literals().size(); app_ref eq(m_manager); TRACE("context", - tout << "pop: " << num_levels << "\n"; tout << "vars: " << vars.size() << "\n"; tout << "lits: " << num_units << "\n";); m_case_split_queue->init_search_eh(); From 5c99405db3da8ebe13419701a57deae1fa78a192 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 28 Jul 2016 20:15:47 -0700 Subject: [PATCH 130/536] finish consequence fast path code Signed-off-by: Nikolaj Bjorner --- src/api/python/z3.py | 10 ++++++++-- src/smt/smt_consequences.cpp | 35 ++++++++++++++++++++++------------- 2 files changed, 30 insertions(+), 15 deletions(-) diff --git a/src/api/python/z3.py b/src/api/python/z3.py index 345b33d94..e10d8aa50 100644 --- a/src/api/python/z3.py +++ b/src/api/python/z3.py @@ -6127,8 +6127,14 @@ class Solver(Z3PPObject): return AstVector(Z3_solver_get_unsat_core(self.ctx.ref(), self.solver), self.ctx) def consequences(self, assumptions, variables): - """Determine fixed values for the variables based on the solver state and assumptions. - documentation TBD + """Determine fixed values for the variables based on the solver state and assumptions. + >>> s = Solver() + >>> a, b, c, d = Bools('a b c d') + >>> s.add(Implies(a,b), Implies(b, c)) + >>> s.consequences([a],[b,c,d]) + (sat, [Implies(a, b), Implies(a, c)]) + >>> s.consequences([Not(c),d],[a,b,c,d]) + (sat, [Implies(Not(c), Not(a)), Implies(Not(c), Not(b)), Implies(True, Not(c)), Implies(True, d)]) """ if isinstance(assumptions, list): _asms = AstVector(None, self.ctx) diff --git a/src/smt/smt_consequences.cpp b/src/smt/smt_consequences.cpp index 109eb0deb..65204c2fc 100644 --- a/src/smt/smt_consequences.cpp +++ b/src/smt/smt_consequences.cpp @@ -66,11 +66,14 @@ namespace smt { case b_justification::AXIOM: { break; } - case b_justification::JUSTIFICATION: - justification* j = js.get_justification(); - // warning_msg("TODO: extract antecedents from theory justification"); - // std::cout << "TODO: justification\n"; + case b_justification::JUSTIFICATION: { + literal_vector literals; + m_conflict_resolution->justification2literals(js.get_justification(), literals); + for (unsigned j = 0; j < literals.size(); ++j) { + s |= m_antecedents.find(literals[j].var()); + } break; + } } } m_antecedents.insert(lit.var(), s); @@ -100,6 +103,7 @@ namespace smt { lbool context::get_consequences(expr_ref_vector const& assumptions, expr_ref_vector const& vars, expr_ref_vector& conseq) { + m_antecedents.reset(); lbool is_sat = check(assumptions.size(), assumptions.c_ptr()); if (is_sat != l_true) { return is_sat; @@ -111,19 +115,20 @@ namespace smt { } model_ref mdl; get_model(mdl); - expr_ref_vector trail(m_manager); + ast_manager& m = m_manager; + expr_ref_vector trail(m); model_evaluator eval(*mdl.get()); - expr_ref val(m_manager); + expr_ref val(m); for (unsigned i = 0; i < vars.size(); ++i) { eval(vars[i], val); - if (m_manager.is_value(val)) { + if (m.is_value(val)) { trail.push_back(val); var2val.insert(vars[i], val); } } extract_fixed_consequences(0, var2val, _assumptions, conseq); unsigned num_units = assigned_literals().size(); - app_ref eq(m_manager); + app_ref eq(m); TRACE("context", tout << "vars: " << vars.size() << "\n"; tout << "lits: " << num_units << "\n";); @@ -136,8 +141,8 @@ namespace smt { unsigned current_level = m_scope_lvl; literal lit; - if (m_manager.is_bool(e)) { - lit = literal(get_bool_var(e), m_manager.is_true(val)); + if (m.is_bool(e)) { + lit = literal(get_bool_var(e), m.is_true(val)); } else { eq = mk_eq_atom(e, val); @@ -163,17 +168,21 @@ namespace smt { var2val.erase(e); } else if (get_assign_level(lit) > get_search_level()) { - TRACE("context", tout << "Retry fixing: " << mk_pp(e, m_manager) << "\n";); + TRACE("context", tout << "Retry fixing: " << mk_pp(e, m) << "\n";); pop_to_search_lvl(); continue; } else { - TRACE("context", tout << "Fixed: " << mk_pp(e, m_manager) << "\n";); + TRACE("context", tout << "Fixed: " << mk_pp(e, m) << "\n";); } extract_fixed_consequences(num_units, var2val, _assumptions, conseq); num_units = assigned_literals().size(); if (var2val.contains(e)) { - TRACE("context", tout << "TBD: Fixed value to " << mk_pp(e, m_manager) << " was not retrieved\n";); + TRACE("context", tout << "Fixed value to " << mk_pp(e, m) << " was not processed\n";); + expr_ref fml(m); + fml = m.mk_eq(e, var2val.find(e)); + fml = m.mk_implies(antecedent2fml(m_antecedents[lit.var()]), fml); + conseq.push_back(fml); var2val.erase(e); SASSERT(get_assignment(lit) == l_false); } From 82d0310d94537c18bacdc80e00fb5ae71aeba409 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 28 Jul 2016 21:13:12 -0700 Subject: [PATCH 131/536] remove repeated default argument, remove tabs Signed-off-by: Nikolaj Bjorner --- src/math/automata/symbolic_automata_def.h | 155 +++++++++++----------- 1 file changed, 78 insertions(+), 77 deletions(-) diff --git a/src/math/automata/symbolic_automata_def.h b/src/math/automata/symbolic_automata_def.h index 737dc9e19..01476eb53 100644 --- a/src/math/automata/symbolic_automata_def.h +++ b/src/math/automata/symbolic_automata_def.h @@ -275,89 +275,90 @@ typename symbolic_automata::automaton_t* symbolic_automata::mk_minim template typename symbolic_automata::automaton_t* symbolic_automata::mk_determinstic(automaton_t& a) { - return mk_determinstic_param(a); + return mk_determinstic_param(a); } template typename symbolic_automata::automaton_t* symbolic_automata::mk_complement(automaton_t& a) { - return mk_determinstic_param(a, true); + return mk_determinstic_param(a, true); } template -typename symbolic_automata::automaton_t* symbolic_automata::mk_determinstic_param(automaton_t& a, bool flip_acceptance = false) { - vector, ref_t> > min_terms; - vector predicates; - - map s2id; // set of states to unique id - vector id2s; // unique id to set of b-states - uint_set set; - unsigned_vector vector; - moves_t new_mvs; // moves in the resulting automaton - unsigned_vector new_final_states; // new final states - unsigned p_state_id = 0; // next state identifier - - // adds non-final states of a to final if flipping and and final otherwise - if (a.is_final_configuration(set) != flip_acceptance) { - new_final_states.push_back(p_state_id); - } - - set.insert(a.init()); // initial state as aset - s2id.insert(set, p_state_id++); // the index to the initial state is 0 - id2s.push_back(set); - - svector todo; //States to visit - todo.push_back(set); - - uint_set state; - moves_t mvsA; - - new_mvs.reset(); - - // or just make todo a vector whose indices coincide with state_id. - while (!todo.empty()) { - uint_set state = todo.back(); - - unsigned state_id = s2id[state]; - todo.pop_back(); - mvsA.reset(); - - min_terms.reset(); - predicates.reset(); - - a.get_moves_from_states(state, mvsA); - - for (unsigned j = 0; j < mvsA.size(); ++j) { - ref_t mv_guard(mvsA[j].t(),m); - predicates.push_back(mv_guard); - } - - min_terms = generate_min_terms(predicates); - for (unsigned j = 0; j < min_terms.size(); ++j) { - set = uint_set(); - for (unsigned i = 0; i < mvsA.size(); ++i) { - if (min_terms[j].first[i]) - set.insert(mvsA[i].dst()); - } - - bool is_new = !s2id.contains(set); - if (is_new) { - if (a.is_final_configuration(set) != flip_acceptance) { - new_final_states.push_back(p_state_id); - } - - s2id.insert(set, p_state_id++); - id2s.push_back(set); - todo.push_back(set); - } - new_mvs.push_back(move_t(m, state_id, s2id[set], min_terms[j].second)); - } - } - - if (new_final_states.empty()) { - return alloc(automaton_t, m); - } - - return alloc(automaton_t, m, 0, new_final_states, new_mvs); +typename symbolic_automata::automaton_t* +symbolic_automata::mk_determinstic_param(automaton_t& a, bool flip_acceptance) { + vector, ref_t> > min_terms; + vector predicates; + + map s2id; // set of states to unique id + vector id2s; // unique id to set of b-states + uint_set set; + unsigned_vector vector; + moves_t new_mvs; // moves in the resulting automaton + unsigned_vector new_final_states; // new final states + unsigned p_state_id = 0; // next state identifier + + // adds non-final states of a to final if flipping and and final otherwise + if (a.is_final_configuration(set) != flip_acceptance) { + new_final_states.push_back(p_state_id); + } + + set.insert(a.init()); // Initial state as aset + s2id.insert(set, p_state_id++); // the index to the initial state is 0 + id2s.push_back(set); + + svector todo; //States to visit + todo.push_back(set); + + uint_set state; + moves_t mvsA; + + new_mvs.reset(); + + // or just make todo a vector whose indices coincide with state_id. + while (!todo.empty()) { + uint_set state = todo.back(); + + unsigned state_id = s2id[state]; + todo.pop_back(); + mvsA.reset(); + + min_terms.reset(); + predicates.reset(); + + a.get_moves_from_states(state, mvsA); + + for (unsigned j = 0; j < mvsA.size(); ++j) { + ref_t mv_guard(mvsA[j].t(),m); + predicates.push_back(mv_guard); + } + + min_terms = generate_min_terms(predicates); + for (unsigned j = 0; j < min_terms.size(); ++j) { + set = uint_set(); + for (unsigned i = 0; i < mvsA.size(); ++i) { + if (min_terms[j].first[i]) + set.insert(mvsA[i].dst()); + } + + bool is_new = !s2id.contains(set); + if (is_new) { + if (a.is_final_configuration(set) != flip_acceptance) { + new_final_states.push_back(p_state_id); + } + + s2id.insert(set, p_state_id++); + id2s.push_back(set); + todo.push_back(set); + } + new_mvs.push_back(move_t(m, state_id, s2id[set], min_terms[j].second)); + } + } + + if (new_final_states.empty()) { + return alloc(automaton_t, m); + } + + return alloc(automaton_t, m, 0, new_final_states, new_mvs); } @@ -455,7 +456,7 @@ typename symbolic_automata::automaton_t* symbolic_automata::mk_produ template typename symbolic_automata::automaton_t* symbolic_automata::mk_difference(automaton_t& a, automaton_t& b) { - return mk_product(a,mk_complement(b)); + return mk_product(a,mk_complement(b)); } #endif From 2263be1b4dbeace9b9e8e452f3e45ffa2d237bea Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 29 Jul 2016 17:24:14 -0700 Subject: [PATCH 132/536] adding consequence examples Signed-off-by: Nikolaj Bjorner --- examples/c++/example.cpp | 19 +++++++++++++++++++ src/api/c++/z3++.h | 5 +++++ src/smt/smt_consequences.cpp | 3 ++- 3 files changed, 26 insertions(+), 1 deletion(-) diff --git a/examples/c++/example.cpp b/examples/c++/example.cpp index 2753e1475..a1240543f 100644 --- a/examples/c++/example.cpp +++ b/examples/c++/example.cpp @@ -1111,6 +1111,24 @@ void param_descrs_example() { } } +void consequence_example() { + std::cout << "consequence example\n"; + context c; + expr A = c.bool_const("a"); + expr B = c.bool_const("b"); + expr C = c.bool_const("c"); + solver s(c); + s.add(implies(A, B)); + s.add(implies(B, C)); + expr_vector assumptions(c), vars(c), consequences(c); + assumptions.push_back(!C); + vars.push_back(A); + vars.push_back(B); + vars.push_back(C); + std::cout << s.consequences(assumptions, vars, consequences) << "\n"; + std::cout << consequences << "\n"; +} + int main() { try { @@ -1154,6 +1172,7 @@ int main() { extract_example(); std::cout << "\n"; param_descrs_example(); std::cout << "\n"; sudoku_example(); std::cout << "\n"; + consequence_example(); std::cout << "\n"; std::cout << "done\n"; } catch (exception & ex) { diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index e0c520f5b..5d01ef5c2 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -1723,6 +1723,11 @@ namespace z3 { return to_check_result(r); } model get_model() const { Z3_model m = Z3_solver_get_model(ctx(), m_solver); check_error(); return model(ctx(), m); } + check_result consequences(expr_vector& assumptions, expr_vector& vars, expr_vector& conseq) { + Z3_lbool r = Z3_solver_get_consequences(ctx(), m_solver, assumptions, vars, conseq); + check_error(); + return to_check_result(r); + } std::string reason_unknown() const { Z3_string r = Z3_solver_get_reason_unknown(ctx(), m_solver); check_error(); return r; } stats statistics() const { Z3_stats r = Z3_solver_get_statistics(ctx(), m_solver); check_error(); return stats(ctx(), r); } expr_vector unsat_core() const { Z3_ast_vector r = Z3_solver_get_unsat_core(ctx(), m_solver); check_error(); return expr_vector(ctx(), r); } diff --git a/src/smt/smt_consequences.cpp b/src/smt/smt_consequences.cpp index 65204c2fc..1f528aaff 100644 --- a/src/smt/smt_consequences.cpp +++ b/src/smt/smt_consequences.cpp @@ -25,7 +25,8 @@ namespace smt { expr_ref_vector premises(m_manager); uint_set::iterator it = vars.begin(), end = vars.end(); for (; it != end; ++it) { - premises.push_back(bool_var2expr(*it)); + expr* e = bool_var2expr(*it); + premises.push_back(get_assignment(*it) != l_false ? e : m_manager.mk_not(e)); } return mk_and(premises); } From 7d545d902df1cace6e09694132e54daaa9c3cf40 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 29 Jul 2016 17:36:11 -0700 Subject: [PATCH 133/536] switch to specialized consequence generator in combined_solver Signed-off-by: Nikolaj Bjorner --- src/solver/combined_solver.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/solver/combined_solver.cpp b/src/solver/combined_solver.cpp index 7db056396..30b387b98 100644 --- a/src/solver/combined_solver.cpp +++ b/src/solver/combined_solver.cpp @@ -194,6 +194,11 @@ public: return m_solver1->get_scope_level(); } + virtual lbool get_consequences(expr_ref_vector const& asms, expr_ref_vector const& vars, expr_ref_vector& consequences) { + switch_inc_mode(); + return m_solver2->get_consequences(asms, vars, consequences); + } + virtual lbool check_sat(unsigned num_assumptions, expr * const * assumptions) { m_check_sat_executed = true; m_use_solver1_results = false; From d32019f4c95244525a4a2b15146f9866d8974ef8 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 30 Jul 2016 10:49:06 -0700 Subject: [PATCH 134/536] fix consequence tracking for negated assumptions Signed-off-by: Nikolaj Bjorner --- src/api/python/z3.py | 2 +- src/smt/smt_consequences.cpp | 11 ++++++----- src/smt/smt_context.h | 2 +- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/api/python/z3.py b/src/api/python/z3.py index e10d8aa50..6e3ef26ac 100644 --- a/src/api/python/z3.py +++ b/src/api/python/z3.py @@ -6134,7 +6134,7 @@ class Solver(Z3PPObject): >>> s.consequences([a],[b,c,d]) (sat, [Implies(a, b), Implies(a, c)]) >>> s.consequences([Not(c),d],[a,b,c,d]) - (sat, [Implies(Not(c), Not(a)), Implies(Not(c), Not(b)), Implies(True, Not(c)), Implies(True, d)]) + (sat, [Implies(Not(c), Not(c)), Implies(d, d), Implies(Not(c), Not(b)), Implies(Not(c), Not(a))]) """ if isinstance(assumptions, list): _asms = AstVector(None, self.ctx) diff --git a/src/smt/smt_consequences.cpp b/src/smt/smt_consequences.cpp index 1f528aaff..87a50e82f 100644 --- a/src/smt/smt_consequences.cpp +++ b/src/smt/smt_consequences.cpp @@ -31,7 +31,7 @@ namespace smt { return mk_and(premises); } - void context::extract_fixed_consequences(unsigned start, obj_map& vars, obj_hashtable const& assumptions, expr_ref_vector& conseq) { + void context::extract_fixed_consequences(unsigned start, obj_map& vars, uint_set const& assumptions, expr_ref_vector& conseq) { ast_manager& m = m_manager; pop_to_search_lvl(); literal_vector const& lits = assigned_literals(); @@ -43,8 +43,8 @@ namespace smt { if (lit == true_literal) continue; expr* e = bool_var2expr(lit.var()); uint_set s; - if (assumptions.contains(e)) { - s.insert(get_literal(e).var()); + if (assumptions.contains(lit.var())) { + s.insert(lit.var()); } else { b_justification js = get_justification(lit.var()); @@ -78,6 +78,7 @@ namespace smt { } } m_antecedents.insert(lit.var(), s); + TRACE("context", display_literal_verbose(tout, lit); tout << " " << s << "\n";); bool found = false; if (vars.contains(e)) { found = true; @@ -110,9 +111,9 @@ namespace smt { return is_sat; } obj_map var2val; - obj_hashtable _assumptions; + uint_set _assumptions; for (unsigned i = 0; i < assumptions.size(); ++i) { - _assumptions.insert(assumptions[i]); + _assumptions.insert(get_literal(assumptions[i]).var()); } model_ref mdl; get_model(mdl); diff --git a/src/smt/smt_context.h b/src/smt/smt_context.h index b5e143d9d..e6ca16290 100644 --- a/src/smt/smt_context.h +++ b/src/smt/smt_context.h @@ -1345,7 +1345,7 @@ namespace smt { vector b2v, ast_translation& tr); u_map m_antecedents; - void extract_fixed_consequences(unsigned idx, obj_map& vars, obj_hashtable const& assumptions, expr_ref_vector& conseq); + void extract_fixed_consequences(unsigned idx, obj_map& vars, uint_set const& assumptions, expr_ref_vector& conseq); expr_ref antecedent2fml(uint_set const& ante); From 734609889552e733c141bacff2e5d8f3b4f567df Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 30 Jul 2016 11:22:34 -0700 Subject: [PATCH 135/536] fix unsat core extraction code in smt_context Signed-off-by: Nikolaj Bjorner --- src/smt/smt_conflict_resolution.cpp | 23 ++++++++++++++--------- src/smt/smt_context.cpp | 9 ++++----- src/solver/solver.cpp | 1 + 3 files changed, 19 insertions(+), 14 deletions(-) diff --git a/src/smt/smt_conflict_resolution.cpp b/src/smt/smt_conflict_resolution.cpp index e3c2be123..6c7c71602 100644 --- a/src/smt/smt_conflict_resolution.cpp +++ b/src/smt/smt_conflict_resolution.cpp @@ -1334,8 +1334,9 @@ namespace smt { if (!m_ctx.is_marked(var)) { m_ctx.set_mark(var); m_unmark.push_back(var); - if (m_ctx.is_assumption(var)) - m_assumptions.push_back(antecedent); + } + if (m_ctx.is_assumption(var)) { + m_assumptions.push_back(antecedent); } } @@ -1373,7 +1374,7 @@ namespace smt { } while (true) { - TRACE("unsat_core_bug", tout << "js.get_kind(): " << js.get_kind() << ", idx: " << idx << "\n";); + TRACE("unsat_core_bug", tout << consequent << " js.get_kind(): " << js.get_kind() << ", idx: " << idx << "\n";); switch (js.get_kind()) { case b_justification::CLAUSE: { clause * cls = js.get_clause(); @@ -1410,18 +1411,22 @@ namespace smt { default: UNREACHABLE(); } - - while (true) { - if (idx < 0) - goto end_unsat_core; + + if (m_ctx.is_assumption(consequent.var())) { + m_assumptions.push_back(consequent); + } + while (idx >= 0) { literal l = m_assigned_literals[idx]; TRACE("unsat_core_bug", tout << "l: " << l << ", get_assign_level(l): " << m_ctx.get_assign_level(l) << ", is_marked(l): " << m_ctx.is_marked(l.var()) << "\n";); - if (m_ctx.get_assign_level(l) < search_lvl || idx == 0) - goto end_unsat_core; + if (m_ctx.get_assign_level(l) < search_lvl) + goto end_unsat_core; if (m_ctx.is_marked(l.var())) break; idx--; } + if (idx < 0) { + goto end_unsat_core; + } SASSERT(idx >= 0); consequent = m_assigned_literals[idx]; diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index 3aeb623f9..88d0c8aff 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -3044,7 +3044,7 @@ namespace smt { SASSERT(m_assumptions.empty()); return; } - obj_hashtable already_found_assumptions; + uint_set already_found_assumptions; literal_vector::const_iterator it = m_conflict_resolution->begin_unsat_core(); literal_vector::const_iterator end = m_conflict_resolution->end_unsat_core(); for (; it != end; ++it) { @@ -3053,10 +3053,9 @@ namespace smt { SASSERT(get_bdata(l.var()).m_assumption); if (!m_literal2assumption.contains(l.index())) l.neg(); SASSERT(m_literal2assumption.contains(l.index())); - expr * a = m_literal2assumption[l.index()]; - if (!already_found_assumptions.contains(a)) { - already_found_assumptions.insert(a); - m_unsat_core.push_back(a); + if (!already_found_assumptions.contains(l.index())) { + already_found_assumptions.insert(l.index()); + m_unsat_core.push_back(m_literal2assumption[l.index()]); } } reset_assumptions(); diff --git a/src/solver/solver.cpp b/src/solver/solver.cpp index 7b11317d1..b0ae6a540 100644 --- a/src/solver/solver.cpp +++ b/src/solver/solver.cpp @@ -19,6 +19,7 @@ Notes: #include"solver.h" #include"model_evaluator.h" #include"ast_util.h" +#include"ast_pp.h" unsigned solver::get_num_assertions() const { NOT_IMPLEMENTED_YET(); From 7562efbe846f36c5cc3a07e47d98b8c666146c2d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 30 Jul 2016 12:59:29 -0700 Subject: [PATCH 136/536] add consequence command Signed-off-by: Nikolaj Bjorner --- src/cmd_context/basic_cmds.cpp | 37 +++++++++++++++++++++++++++++++++ src/cmd_context/cmd_context.cpp | 25 ++++++++++++++++++++++ src/cmd_context/cmd_context.h | 1 + 3 files changed, 63 insertions(+) diff --git a/src/cmd_context/basic_cmds.cpp b/src/cmd_context/basic_cmds.cpp index f5e92fe57..84a0d9af8 100644 --- a/src/cmd_context/basic_cmds.cpp +++ b/src/cmd_context/basic_cmds.cpp @@ -753,6 +753,42 @@ public: } }; +class get_consequences_cmd : public cmd { + ptr_vector m_assumptions; + ptr_vector m_variables; + unsigned m_count; +public: + get_consequences_cmd(): cmd("get-consequences"), m_count(0) {} + virtual char const * get_usage() const { return "(*) (*)"; } + virtual char const * get_descr(cmd_context & ctx) const { return "retrieve consequences that fix values for supplied variables"; } + virtual unsigned get_arity() const { return 2; } + virtual cmd_arg_kind next_arg_kind(cmd_context & ctx) const { return CPK_EXPR_LIST; } + virtual void set_next_arg(cmd_context & ctx, unsigned num, expr * const * tlist) { + if (m_count == 0) { + m_assumptions.append(num, tlist); + ++m_count; + } + else { + m_variables.append(num, tlist); + } + } + virtual void failure_cleanup(cmd_context & ctx) {} + virtual void execute(cmd_context & ctx) { + ast_manager& m = ctx.m(); + expr_ref_vector assumptions(m), variables(m), consequences(m); + assumptions.append(m_assumptions.size(), m_assumptions.c_ptr()); + variables.append(m_variables.size(), m_variables.c_ptr()); + ctx.get_consequences(assumptions, variables, consequences); + ctx.regular_stream() << consequences << "\n"; + } + virtual void prepare(cmd_context & ctx) { reset(ctx); } + + virtual void reset(cmd_context& ctx) { + m_assumptions.reset(); m_variables.reset(); m_count = 0; + } + virtual void finalize(cmd_context & ctx) {} +}; + // provides "help" for builtin cmds class builtin_cmd : public cmd { char const * m_usage; @@ -776,6 +812,7 @@ void install_basic_cmds(cmd_context & ctx) { ctx.insert(alloc(get_option_cmd)); ctx.insert(alloc(get_info_cmd)); ctx.insert(alloc(set_info_cmd)); + ctx.insert(alloc(get_consequences_cmd)); ctx.insert(alloc(builtin_cmd, "assert", "", "assert term.")); ctx.insert(alloc(builtin_cmd, "check-sat", "*", "check if the current context is satisfiable. If a list of boolean constants B is provided, then check if the current context is consistent with assigning every constant in B to true.")); ctx.insert(alloc(builtin_cmd, "push", "?", "push 1 (or ) scopes.")); diff --git a/src/cmd_context/cmd_context.cpp b/src/cmd_context/cmd_context.cpp index 153d02e42..f6c3582d4 100644 --- a/src/cmd_context/cmd_context.cpp +++ b/src/cmd_context/cmd_context.cpp @@ -1505,6 +1505,31 @@ void cmd_context::check_sat(unsigned num_assumptions, expr * const * assumptions } } +void cmd_context::get_consequences(expr_ref_vector const& assumptions, expr_ref_vector const& vars, expr_ref_vector & conseq) { + unsigned timeout = m_params.m_timeout; + unsigned rlimit = m_params.m_rlimit; + lbool r; + m_check_sat_result = m_solver.get(); // solver itself stores the result. + m_solver->set_progress_callback(this); + cancel_eh eh(m().limit()); + scoped_ctrl_c ctrlc(eh); + scoped_timer timer(timeout, &eh); + scoped_rlimit _rlimit(m().limit(), rlimit); + try { + r = m_solver->get_consequences(assumptions, vars, conseq); + } + catch (z3_error & ex) { + throw ex; + } + catch (z3_exception & ex) { + m_solver->set_reason_unknown(ex.msg()); + r = l_undef; + } + m_solver->set_status(r); + display_sat_result(r); +} + + void cmd_context::reset_assertions() { if (!m_global_decls) { reset(false); diff --git a/src/cmd_context/cmd_context.h b/src/cmd_context/cmd_context.h index 976fe946a..097a9aff2 100644 --- a/src/cmd_context/cmd_context.h +++ b/src/cmd_context/cmd_context.h @@ -392,6 +392,7 @@ public: void push(unsigned n); void pop(unsigned n); void check_sat(unsigned num_assumptions, expr * const * assumptions); + void get_consequences(expr_ref_vector const& assumptions, expr_ref_vector const& vars, expr_ref_vector & conseq); void reset_assertions(); // display the result produced by a check-sat or check-sat-using commands in the regular stream void display_sat_result(lbool r); From cb2d8d21071b9e895158adc4b0a3e8dd052e41a4 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 30 Jul 2016 19:12:41 -0700 Subject: [PATCH 137/536] add detection of non-fixed variables to consequence finding Signed-off-by: Nikolaj Bjorner --- src/api/api_opt.cpp | 50 +++++++++++++++++++++++++++++- src/api/c++/z3++.h | 2 ++ src/api/dotnet/Optimize.cs | 19 ++++++++++++ src/api/python/z3.py | 8 +++++ src/api/z3_optimization.h | 30 +++++++++++++++++- src/muz/fp/dl_cmds.cpp | 7 +---- src/opt/opt_cmds.cpp | 31 +++++++++++-------- src/opt/opt_cmds.h | 3 +- src/smt/smt_consequences.cpp | 59 ++++++++++++++++++++++++++++++++++-- src/smt/smt_context.h | 4 ++- 10 files changed, 188 insertions(+), 25 deletions(-) diff --git a/src/api/api_opt.cpp b/src/api/api_opt.cpp index c0a311929..58d8902c3 100644 --- a/src/api/api_opt.cpp +++ b/src/api/api_opt.cpp @@ -23,9 +23,10 @@ Revision History: #include"api_util.h" #include"api_model.h" #include"opt_context.h" +#include"opt_cmds.h" #include"cancel_eh.h" #include"scoped_timer.h" - +#include"smt2parser.h" extern "C" { @@ -248,6 +249,53 @@ extern "C" { Z3_CATCH_RETURN(0); } + static void Z3_optimize_from_stream( + Z3_context c, + Z3_optimize opt, + std::istream& s) { + ast_manager& m = mk_c(c)->m(); + cmd_context ctx(false, &m); + install_opt_cmds(ctx, to_optimize_ptr(opt)); + ctx.set_ignore_check(true); + if (!parse_smt2_commands(ctx, s)) { + SET_ERROR_CODE(Z3_PARSER_ERROR); + return; + } + ptr_vector::const_iterator it = ctx.begin_assertions(); + ptr_vector::const_iterator end = ctx.end_assertions(); + for (; it != end; ++it) { + to_optimize_ptr(opt)->add_hard_constraint(*it); + } + } + + void Z3_API Z3_optimize_from_string( + Z3_context c, + Z3_optimize d, + Z3_string s) { + Z3_TRY; + //LOG_Z3_optimize_from_string(c, d, s); + std::string str(s); + std::istringstream is(str); + Z3_optimize_from_stream(c, d, is); + Z3_CATCH; + } + + void Z3_API Z3_optimize_from_file( + Z3_context c, + Z3_optimize d, + Z3_string s) { + Z3_TRY; + //LOG_Z3_optimize_from_file(c, d, s); + std::ifstream is(s); + if (!is) { + SET_ERROR_CODE(Z3_PARSER_ERROR); + return; + } + Z3_optimize_from_stream(c, d, is); + Z3_CATCH; + } + + }; diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index 5d01ef5c2..3271d4b0f 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -2035,6 +2035,8 @@ namespace z3 { } stats statistics() const { Z3_stats r = Z3_optimize_get_statistics(ctx(), m_opt); check_error(); return stats(ctx(), r); } friend std::ostream & operator<<(std::ostream & out, optimize const & s); + void from_file(char const* filename) { Z3_optimize_from_file(ctx(), m_opt, filename); check_error(); } + void from_string(char const* constraints) { Z3_optimize_from_string(ctx(), m_opt, constraints); check_error(); } std::string help() const { char const * r = Z3_optimize_get_help(ctx(), m_opt); check_error(); return r; } }; inline std::ostream & operator<<(std::ostream & out, optimize const & s) { out << Z3_optimize_to_string(s.ctx(), s.m_opt); return out; } diff --git a/src/api/dotnet/Optimize.cs b/src/api/dotnet/Optimize.cs index 304e3e86f..e5982e4fc 100644 --- a/src/api/dotnet/Optimize.cs +++ b/src/api/dotnet/Optimize.cs @@ -273,6 +273,25 @@ namespace Microsoft.Z3 return Native.Z3_optimize_to_string(Context.nCtx, NativeObject); } + /// + /// Parse an SMT-LIB2 file with optimization objectives and constraints. + /// The parsed constraints and objectives are added to the optimization context. + /// + public void FromFile(string file) + { + Native.Z3_optimize_from_file(Context.nCtx, NativeObject, file); + } + + /// + /// Similar to FromFile. Instead it takes as argument a string. + /// + public void FromString(string s) + { + Native.Z3_optimize_from_string(Context.nCtx, NativeObject, s); + } + + + /// /// Optimize statistics. /// diff --git a/src/api/python/z3.py b/src/api/python/z3.py index 6e3ef26ac..6c4ac13a4 100644 --- a/src/api/python/z3.py +++ b/src/api/python/z3.py @@ -6755,6 +6755,14 @@ class Optimize(Z3PPObject): raise Z3Exception("Expecting objective handle returned by maximize/minimize") return obj.upper() + def from_file(self, filename): + """Parse assertions and objectives from a file""" + Z3_optimize_from_file(self.ctx.ref(), self.optimize, filename) + + def from_string(self, s): + """Parse assertions and objectives from a string""" + Z3_optimize_from_string(self.ctx.ref(), self.optimize, s) + def __repr__(self): """Return a formatted string with all added rules and constraints.""" return self.sexpr() diff --git a/src/api/z3_optimization.h b/src/api/z3_optimization.h index c59428d9e..15a6dff16 100644 --- a/src/api/z3_optimization.h +++ b/src/api/z3_optimization.h @@ -197,6 +197,34 @@ extern "C" { */ Z3_string Z3_API Z3_optimize_to_string(Z3_context c, Z3_optimize o); + /** + \brief Parse an SMT-LIB2 string with assertions, + soft constraints and optimization objectives. + Add the parsed constraints and objectives to the optimization context. + + \param c - context. + \param o - optimize context. + \param s - string containing SMT2 specification. + + def_API('Z3_optimize_from_string', VOID, (_in(CONTEXT), _in(OPTIMIZE), _in(STRING))) + */ + void Z3_API Z3_optimize_from_string(Z3_context c, Z3_optimize o, Z3_string s); + + + /** + \brief Parse an SMT-LIB2 file with assertions, + soft constraints and optimization objectives. + Add the parsed constraints and objectives to the optimization context. + + + \param c - context. + \param o - optimize context. + \param s - string containing SMT2 specification. + + def_API('Z3_optimize_from_file', VOID, (_in(CONTEXT), _in(OPTIMIZE), _in(STRING))) + */ + void Z3_API Z3_optimize_from_file(Z3_context c, Z3_optimize o, Z3_string s); + /** \brief Return a string containing a description of parameters accepted by optimize. @@ -218,4 +246,4 @@ extern "C" { } #endif // __cplusplus -#endif \ No newline at end of file +#endif diff --git a/src/muz/fp/dl_cmds.cpp b/src/muz/fp/dl_cmds.cpp index 049c34343..49632b39c 100644 --- a/src/muz/fp/dl_cmds.cpp +++ b/src/muz/fp/dl_cmds.cpp @@ -527,13 +527,8 @@ static void install_dl_cmds_aux(cmd_context& ctx, dl_collected_cmds* collected_c ctx.insert(alloc(dl_query_cmd, dl_ctx)); ctx.insert(alloc(dl_declare_rel_cmd, dl_ctx)); ctx.insert(alloc(dl_declare_var_cmd, dl_ctx)); - // #ifndef _EXTERNAL_RELEASE - // TODO: we need these! -#if 1 - ctx.insert(alloc(dl_push_cmd, dl_ctx)); // not exposed to keep command-extensions simple. + ctx.insert(alloc(dl_push_cmd, dl_ctx)); ctx.insert(alloc(dl_pop_cmd, dl_ctx)); -#endif - // #endif } void install_dl_cmds(cmd_context & ctx) { diff --git a/src/opt/opt_cmds.cpp b/src/opt/opt_cmds.cpp index 8822f4e77..5406eaca3 100644 --- a/src/opt/opt_cmds.cpp +++ b/src/opt/opt_cmds.cpp @@ -32,7 +32,10 @@ Notes: #include "opt_params.hpp" #include "model_smt2_pp.h" -static opt::context& get_opt(cmd_context& cmd) { +static opt::context& get_opt(cmd_context& cmd, opt::context* opt) { + if (opt) { + return *opt; + } if (!cmd.get_opt()) { cmd.set_opt(alloc(opt::context, cmd.m())); } @@ -43,12 +46,14 @@ static opt::context& get_opt(cmd_context& cmd) { class assert_soft_cmd : public parametric_cmd { unsigned m_idx; expr* m_formula; + opt::context* m_opt; public: - assert_soft_cmd(): + assert_soft_cmd(opt::context* opt): parametric_cmd("assert-soft"), m_idx(0), - m_formula(0) + m_formula(0), + m_opt(opt) {} virtual ~assert_soft_cmd() { @@ -96,8 +101,8 @@ public: if (weight.is_zero()) { weight = rational::one(); } - symbol id = ps().get_sym(symbol("id"), symbol::null); - get_opt(ctx).add_soft_constraint(m_formula, weight, id); + symbol id = ps().get_sym(symbol("id"), symbol::null); + get_opt(ctx, m_opt).add_soft_constraint(m_formula, weight, id); reset(ctx); } @@ -108,11 +113,13 @@ public: class min_maximize_cmd : public cmd { bool m_is_max; + opt::context* m_opt; public: - min_maximize_cmd(bool is_max): + min_maximize_cmd(bool is_max, opt::context* opt): cmd(is_max?"maximize":"minimize"), - m_is_max(is_max) + m_is_max(is_max), + m_opt(opt) {} virtual void reset(cmd_context & ctx) { } @@ -126,7 +133,7 @@ public: if (!is_app(t)) { throw cmd_exception("malformed objective term: it cannot be a quantifier or bound variable"); } - get_opt(ctx).add_objective(to_app(t), m_is_max); + get_opt(ctx, m_opt).add_objective(to_app(t), m_is_max); } virtual void failure_cleanup(cmd_context & ctx) { @@ -139,10 +146,10 @@ public: -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)); +void install_opt_cmds(cmd_context & ctx, opt::context* opt) { + ctx.insert(alloc(assert_soft_cmd, opt)); + ctx.insert(alloc(min_maximize_cmd, true, opt)); + ctx.insert(alloc(min_maximize_cmd, false, opt)); } diff --git a/src/opt/opt_cmds.h b/src/opt/opt_cmds.h index d8dd0dbfa..f0da778df 100644 --- a/src/opt/opt_cmds.h +++ b/src/opt/opt_cmds.h @@ -19,10 +19,11 @@ Notes: #define OPT_CMDS_H_ #include "ast.h" +#include "opt_context.h" class cmd_context; -void install_opt_cmds(cmd_context & ctx); +void install_opt_cmds(cmd_context & ctx, opt::context* opt = 0); #endif diff --git a/src/smt/smt_consequences.cpp b/src/smt/smt_consequences.cpp index 87a50e82f..49236be1b 100644 --- a/src/smt/smt_consequences.cpp +++ b/src/smt/smt_consequences.cpp @@ -102,6 +102,47 @@ namespace smt { } } + void context::delete_unfixed(obj_map& var2val) { + ast_manager& m = m_manager; + ptr_vector to_delete; + obj_map::iterator it = var2val.begin(), end = var2val.end(); + for (; it != end; ++it) { + expr* k = it->m_key; + expr* v = it->m_value; + if (m.is_bool(k)) { + literal lit = get_literal(k); + switch (get_assignment(lit)) { + case l_true: + if (m.is_false(v)) { + to_delete.push_back(k); + } + else { + force_phase(lit.var(), false); + } + break; + case l_false: + if (m.is_true(v)) { + to_delete.push_back(k); + } + else { + force_phase(lit.var(), true); + } + break; + default: + to_delete.push_back(k); + break; + } + } + else if (e_internalized(k) && m.are_distinct(v, get_enode(k)->get_root()->get_owner())) { + to_delete.push_back(k); + } + } + IF_VERBOSE(1, verbose_stream() << "(get-consequences deleting: " << to_delete.size() << " num-values: " << var2val.size() << ")\n";); + for (unsigned i = 0; i < to_delete.size(); ++i) { + var2val.remove(to_delete[i]); + } + } + lbool context::get_consequences(expr_ref_vector const& assumptions, expr_ref_vector const& vars, expr_ref_vector& conseq) { @@ -135,7 +176,10 @@ namespace smt { tout << "vars: " << vars.size() << "\n"; tout << "lits: " << num_units << "\n";); m_case_split_queue->init_search_eh(); + unsigned num_iterations = 0; + unsigned model_threshold = 2; while (!var2val.empty()) { + ++num_iterations; obj_map::iterator it = var2val.begin(); expr* e = it->m_key; expr* val = it->m_value; @@ -177,6 +221,17 @@ namespace smt { else { TRACE("context", tout << "Fixed: " << mk_pp(e, m) << "\n";); } + + TRACE("context", tout << "Unfixed variables: " << var2val.size() << "\n";); + if (model_threshold <= num_iterations) { + delete_unfixed(var2val); + // The next time we check the model is after 1.5 additional iterations. + model_threshold *= 3; + model_threshold /= 2; + } + // repeat until we either have a model with negated literal or + // the literal is implied at base. + extract_fixed_consequences(num_units, var2val, _assumptions, conseq); num_units = assigned_literals().size(); if (var2val.contains(e)) { @@ -189,10 +244,8 @@ namespace smt { SASSERT(get_assignment(lit) == l_false); } - // repeat until we either have a model with negated literal or - // the literal is implied at base. - TRACE("context", tout << "Unfixed variables: " << var2val.size() << "\n";); } + end_search(); return l_true; } diff --git a/src/smt/smt_context.h b/src/smt/smt_context.h index e6ca16290..30a262285 100644 --- a/src/smt/smt_context.h +++ b/src/smt/smt_context.h @@ -1345,7 +1345,9 @@ namespace smt { vector b2v, ast_translation& tr); u_map m_antecedents; - void extract_fixed_consequences(unsigned idx, obj_map& vars, uint_set const& assumptions, expr_ref_vector& conseq); + void extract_fixed_consequences(unsigned idx, obj_map& var2val, uint_set const& assumptions, expr_ref_vector& conseq); + + void delete_unfixed(obj_map& var2val); expr_ref antecedent2fml(uint_set const& ante); From 491b3b34aa25ee5c48fdf86db4f4256e39600de3 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 3 Aug 2016 11:14:29 -0700 Subject: [PATCH 138/536] tune consequence finding. Factor solver pretty-printing as SMT-LIB into top-level Signed-off-by: Nikolaj Bjorner --- src/opt/opt_context.h | 4 +- src/opt/opt_solver.h | 2 +- src/sat/sat_solver/inc_sat_solver.cpp | 2 +- src/smt/smt_conflict_resolution.cpp | 15 +++++ src/smt/smt_conflict_resolution.h | 3 + src/smt/smt_consequences.cpp | 91 ++++++++++++++++++++++++--- src/smt/smt_context.cpp | 1 - src/smt/smt_context.h | 6 +- src/smt/smt_kernel.cpp | 32 +++++----- src/smt/smt_kernel.h | 3 +- src/smt/smt_solver.cpp | 16 ++--- src/solver/check_sat_result.h | 4 +- src/solver/combined_solver.cpp | 2 +- src/solver/solver.cpp | 15 ++++- src/solver/tactic2solver.cpp | 22 +------ 15 files changed, 149 insertions(+), 69 deletions(-) diff --git a/src/opt/opt_context.h b/src/opt/opt_context.h index 07fe53268..ac1fe8e7a 100644 --- a/src/opt/opt_context.h +++ b/src/opt/opt_context.h @@ -48,7 +48,7 @@ namespace opt { virtual filter_model_converter& fm() = 0; // converter that removes fresh names introduced by simplification. virtual bool sat_enabled() const = 0; // is using th SAT solver core enabled? virtual solver& get_solver() = 0; // retrieve solver object (SAT or SMT solver) - virtual ast_manager& get_manager() = 0; + virtual ast_manager& get_manager() const = 0; virtual params_ref& params() = 0; virtual void enable_sls(bool force) = 0; // stochastic local search virtual symbol const& maxsat_engine() const = 0; // retrieve maxsat engine configuration parameter. @@ -217,7 +217,7 @@ namespace opt { virtual filter_model_converter& fm() { return m_fm; } virtual bool sat_enabled() const { return 0 != m_sat_solver.get(); } virtual solver& get_solver(); - virtual ast_manager& get_manager() { return this->m; } + virtual ast_manager& get_manager() const { return this->m; } virtual params_ref& params() { return m_params; } virtual void enable_sls(bool force); virtual symbol const& maxsat_engine() const { return m_maxsat_engine; } diff --git a/src/opt/opt_solver.h b/src/opt/opt_solver.h index e5ee5afcf..b2fa18ad8 100644 --- a/src/opt/opt_solver.h +++ b/src/opt/opt_solver.h @@ -105,7 +105,7 @@ namespace opt { virtual unsigned get_num_assertions() const; virtual expr * get_assertion(unsigned idx) const; virtual std::ostream& display(std::ostream & out) const; - virtual ast_manager& get_manager() { return m; } + virtual ast_manager& get_manager() const { return m; } void set_logic(symbol const& logic); smt::theory_var add_objective(app* term); diff --git a/src/sat/sat_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp index badb0a67a..ce6b199d6 100644 --- a/src/sat/sat_solver/inc_sat_solver.cpp +++ b/src/sat/sat_solver/inc_sat_solver.cpp @@ -196,7 +196,7 @@ public: assert_expr(t); } } - virtual ast_manager& get_manager() { return m; } + virtual ast_manager& get_manager() const { return m; } virtual void assert_expr(expr * t) { TRACE("sat", tout << mk_pp(t, m) << "\n";); m_fmls.push_back(t); diff --git a/src/smt/smt_conflict_resolution.cpp b/src/smt/smt_conflict_resolution.cpp index 6c7c71602..6907d6f37 100644 --- a/src/smt/smt_conflict_resolution.cpp +++ b/src/smt/smt_conflict_resolution.cpp @@ -187,6 +187,10 @@ namespace smt { SASSERT(m_todo_js_qhead <= m_todo_js.size()); m_antecedents = &result; mark_justification(js); + process_justifications(); + } + + void conflict_resolution::process_justifications() { while (true) { unsigned sz = m_todo_js.size(); while (m_todo_js_qhead < sz) { @@ -234,6 +238,17 @@ namespace smt { SASSERT(m_todo_eqs.empty()); } + void conflict_resolution::eq2literals(enode* n1, enode* n2, literal_vector & result) { + SASSERT(m_todo_js.empty()); + SASSERT(m_todo_js_qhead == 0); + SASSERT(m_todo_eqs.empty()); + m_antecedents = &result; + m_todo_eqs.push_back(enode_pair(n1, n2)); + process_justifications(); + unmark_justifications(0); + SASSERT(m_todo_eqs.empty()); + } + /** \brief Return maximum scope level of an antecedent literal of js. */ diff --git a/src/smt/smt_conflict_resolution.h b/src/smt/smt_conflict_resolution.h index daccadbb7..fad3ab50d 100644 --- a/src/smt/smt_conflict_resolution.h +++ b/src/smt/smt_conflict_resolution.h @@ -168,6 +168,7 @@ namespace smt { void eq_branch2literals(enode * n1, enode * n2); void eq2literals(enode * n1, enode * n2); void justification2literals_core(justification * js, literal_vector & result) ; + void process_justifications(); void unmark_justifications(unsigned old_js_qhead); literal_vector m_tmp_literal_vector; @@ -257,6 +258,8 @@ namespace smt { void justification2literals(justification * js, literal_vector & result); + void eq2literals(enode * n1, enode * n2, literal_vector & result); + }; inline void mark_literals(conflict_resolution & cr, unsigned sz, literal const * ls) { diff --git a/src/smt/smt_consequences.cpp b/src/smt/smt_consequences.cpp index 49236be1b..1ae9f28e7 100644 --- a/src/smt/smt_consequences.cpp +++ b/src/smt/smt_consequences.cpp @@ -102,7 +102,7 @@ namespace smt { } } - void context::delete_unfixed(obj_map& var2val) { + unsigned context::delete_unfixed(obj_map& var2val, expr_ref_vector& unfixed) { ast_manager& m = m_manager; ptr_vector to_delete; obj_map::iterator it = var2val.begin(), end = var2val.end(); @@ -137,14 +137,59 @@ namespace smt { to_delete.push_back(k); } } - IF_VERBOSE(1, verbose_stream() << "(get-consequences deleting: " << to_delete.size() << " num-values: " << var2val.size() << ")\n";); + for (unsigned i = 0; i < to_delete.size(); ++i) { + var2val.remove(to_delete[i]); + unfixed.push_back(to_delete[i]); + } + return to_delete.size(); + } + + // + // Extract equalities that are congruent at the search level. + // + unsigned context::extract_fixed_eqs(obj_map& var2val, expr_ref_vector& conseq) { + ast_manager& m = m_manager; + ptr_vector to_delete; + expr_ref fml(m), eq(m); + obj_map::iterator it = var2val.begin(), end = var2val.end(); + for (; it != end; ++it) { + expr* k = it->m_key; + expr* v = it->m_value; + if (!m.is_bool(k) && e_internalized(k) && e_internalized(v) && + get_enode(k)->get_root() == get_enode(v)->get_root()) { + literal_vector literals; + m_conflict_resolution->eq2literals(get_enode(v), get_enode(k), literals); + uint_set s; + for (unsigned i = 0; i < literals.size(); ++i) { + SASSERT(get_assign_level(literals[i]) <= get_search_level()); + s |= m_antecedents.find(literals[i].var()); + } + + fml = m.mk_eq(k, v); + fml = m.mk_implies(antecedent2fml(s), fml); + conseq.push_back(fml); + to_delete.push_back(k); + + for (unsigned i = 0; i < literals.size(); ++i) { + literals[i].neg(); + } + eq = mk_eq_atom(k, v); + internalize_formula(eq, false); + literal lit(get_bool_var(eq), true); + literals.push_back(lit); + mk_clause(literals.size(), literals.c_ptr(), 0); + } + } for (unsigned i = 0; i < to_delete.size(); ++i) { var2val.remove(to_delete[i]); } + return to_delete.size(); } lbool context::get_consequences(expr_ref_vector const& assumptions, - expr_ref_vector const& vars, expr_ref_vector& conseq) { + expr_ref_vector const& vars, + expr_ref_vector& conseq, + expr_ref_vector& unfixed) { m_antecedents.reset(); lbool is_sat = check(assumptions.size(), assumptions.c_ptr()); @@ -168,6 +213,9 @@ namespace smt { trail.push_back(val); var2val.insert(vars[i], val); } + else { + unfixed.push_back(vars[i]); + } } extract_fixed_consequences(0, var2val, _assumptions, conseq); unsigned num_units = assigned_literals().size(); @@ -178,8 +226,10 @@ namespace smt { m_case_split_queue->init_search_eh(); unsigned num_iterations = 0; unsigned model_threshold = 2; + unsigned num_unfixed = 0; + unsigned num_fixed_eqs = 0; + unsigned num_reiterations = 0; while (!var2val.empty()) { - ++num_iterations; obj_map::iterator it = var2val.begin(); expr* e = it->m_key; expr* val = it->m_value; @@ -212,28 +262,50 @@ namespace smt { } if (get_assignment(lit) == l_true) { var2val.erase(e); + unfixed.push_back(e); } else if (get_assign_level(lit) > get_search_level()) { TRACE("context", tout << "Retry fixing: " << mk_pp(e, m) << "\n";); pop_to_search_lvl(); + ++num_reiterations; continue; } else { TRACE("context", tout << "Fixed: " << mk_pp(e, m) << "\n";); } + ++num_iterations; - TRACE("context", tout << "Unfixed variables: " << var2val.size() << "\n";); - if (model_threshold <= num_iterations) { - delete_unfixed(var2val); + bool apply_slow_pass = model_threshold <= num_iterations || num_iterations <= 2; + if (apply_slow_pass) { + num_unfixed += delete_unfixed(var2val, unfixed); // The next time we check the model is after 1.5 additional iterations. model_threshold *= 3; - model_threshold /= 2; + model_threshold /= 2; } // repeat until we either have a model with negated literal or // the literal is implied at base. extract_fixed_consequences(num_units, var2val, _assumptions, conseq); num_units = assigned_literals().size(); + if (apply_slow_pass) { + num_fixed_eqs += extract_fixed_eqs(var2val, conseq); + IF_VERBOSE(1, verbose_stream() << "(get-consequences" + << " iterations: " << num_iterations + << " variables: " << var2val.size() + << " fixed: " << conseq.size() + << " unfixed: " << unfixed.size() + << " fixed-eqs: " << num_fixed_eqs + << " unfixed-deleted: " << num_unfixed + << ")\n";); + TRACE("context", tout << "(get-consequences" + << " iterations: " << num_iterations + << " variables: " << var2val.size() + << " fixed: " << conseq.size() + << " unfixed: " << unfixed.size() + << " fixed-eqs: " << num_fixed_eqs + << " unfixed-deleted: " << num_unfixed + << ")\n";); + } if (var2val.contains(e)) { TRACE("context", tout << "Fixed value to " << mk_pp(e, m) << " was not processed\n";); expr_ref fml(m); @@ -242,8 +314,7 @@ namespace smt { conseq.push_back(fml); var2val.erase(e); SASSERT(get_assignment(lit) == l_false); - } - + } } end_search(); return l_true; diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index 88d0c8aff..c692173e6 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -3422,7 +3422,6 @@ namespace smt { } lbool context::bounded_search() { - SASSERT(!inconsistent()); unsigned counter = 0; TRACE("bounded_search", tout << "starting bounded search...\n";); diff --git a/src/smt/smt_context.h b/src/smt/smt_context.h index 30a262285..48f6004e9 100644 --- a/src/smt/smt_context.h +++ b/src/smt/smt_context.h @@ -1347,7 +1347,9 @@ namespace smt { u_map m_antecedents; void extract_fixed_consequences(unsigned idx, obj_map& var2val, uint_set const& assumptions, expr_ref_vector& conseq); - void delete_unfixed(obj_map& var2val); + unsigned delete_unfixed(obj_map& var2val, expr_ref_vector& unfixed); + + unsigned extract_fixed_eqs(obj_map& var2val, expr_ref_vector& conseq); expr_ref antecedent2fml(uint_set const& ante); @@ -1391,7 +1393,7 @@ namespace smt { lbool check(unsigned num_assumptions = 0, expr * const * assumptions = 0, bool reset_cancel = true); - lbool get_consequences(expr_ref_vector const& assumptions, expr_ref_vector const& vars, expr_ref_vector& conseq); + lbool get_consequences(expr_ref_vector const& assumptions, expr_ref_vector const& vars, expr_ref_vector& conseq, expr_ref_vector& unfixed); lbool setup_and_check(bool reset_cancel = true); diff --git a/src/smt/smt_kernel.cpp b/src/smt/smt_kernel.cpp index 8f18b7311..6b65d0426 100644 --- a/src/smt/smt_kernel.cpp +++ b/src/smt/smt_kernel.cpp @@ -55,6 +55,18 @@ namespace smt { void set_progress_callback(progress_callback * callback) { return m_kernel.set_progress_callback(callback); } + + void display(std::ostream & out) const { + // m_kernel.display(out); <<< for external users it is just junk + // TODO: it will be replaced with assertion_stack.display + unsigned num = m_kernel.get_num_asserted_formulas(); + expr * const * fms = m_kernel.get_asserted_formulas(); + out << "(kernel"; + for (unsigned i = 0; i < num; i++) { + out << "\n " << mk_ismt2_pp(fms[i], m(), 2); + } + out << ")"; + } void assert_expr(expr * e) { TRACE("smt_kernel", tout << "assert:\n" << mk_ismt2_pp(e, m()) << "\n";); @@ -99,8 +111,8 @@ namespace smt { return m_kernel.check(num_assumptions, assumptions); } - lbool get_consequences(expr_ref_vector const& assumptions, expr_ref_vector const& vars, expr_ref_vector& conseq) { - return m_kernel.get_consequences(assumptions, vars, conseq); + lbool get_consequences(expr_ref_vector const& assumptions, expr_ref_vector const& vars, expr_ref_vector& conseq, expr_ref_vector& unfixed) { + return m_kernel.get_consequences(assumptions, vars, conseq, unfixed); } void get_model(model_ref & m) const { @@ -150,18 +162,6 @@ namespace smt { void get_guessed_literals(expr_ref_vector & result) { m_kernel.get_guessed_literals(result); } - - void display(std::ostream & out) const { - // m_kernel.display(out); <<< for external users it is just junk - // TODO: it will be replaced with assertion_stack.display - unsigned num = m_kernel.get_num_asserted_formulas(); - expr * const * fms = m_kernel.get_asserted_formulas(); - out << "(kernel"; - for (unsigned i = 0; i < num; i++) { - out << "\n " << mk_ismt2_pp(fms[i], m(), 2); - } - out << ")"; - } void collect_statistics(::statistics & st) const { m_kernel.collect_statistics(st); @@ -268,8 +268,8 @@ namespace smt { return r; } - lbool kernel::get_consequences(expr_ref_vector const& assumptions, expr_ref_vector const& vars, expr_ref_vector& conseq) { - return m_imp->get_consequences(assumptions, vars, conseq); + lbool kernel::get_consequences(expr_ref_vector const& assumptions, expr_ref_vector const& vars, expr_ref_vector& conseq, expr_ref_vector& unfixed) { + return m_imp->get_consequences(assumptions, vars, conseq, unfixed); } void kernel::get_model(model_ref & m) const { diff --git a/src/smt/smt_kernel.h b/src/smt/smt_kernel.h index 4cf170681..a10961207 100644 --- a/src/smt/smt_kernel.h +++ b/src/smt/smt_kernel.h @@ -129,7 +129,8 @@ namespace smt { /** \brief extract consequences among variables. */ - lbool get_consequences(expr_ref_vector const& assumptions, expr_ref_vector const& vars, expr_ref_vector& conseq); + lbool get_consequences(expr_ref_vector const& assumptions, expr_ref_vector const& vars, + expr_ref_vector& conseq, expr_ref_vector& unfixed); /** \brief Return the model associated with the last check command. diff --git a/src/smt/smt_solver.cpp b/src/smt/smt_solver.cpp index ec874ed8f..f9da1bf60 100644 --- a/src/smt/smt_solver.cpp +++ b/src/smt/smt_solver.cpp @@ -23,6 +23,7 @@ Notes: #include"smt_params_helper.hpp" #include"mus.h" + namespace smt { class solver : public solver_na2as { @@ -68,7 +69,8 @@ namespace smt { } virtual lbool get_consequences_core(expr_ref_vector const& assumptions, expr_ref_vector const& vars, expr_ref_vector& conseq) { - return m_context.get_consequences(assumptions, vars, conseq); + expr_ref_vector unfixed(m_context.m()); + return m_context.get_consequences(assumptions, vars, conseq, unfixed); } virtual void assert_expr(expr * t) { @@ -143,8 +145,7 @@ namespace smt { r.append(tmp.size(), tmp.c_ptr()); } - virtual ast_manager& get_manager() { return m_context.m(); } - + virtual ast_manager& get_manager() const { return m_context.m(); } virtual void set_progress_callback(progress_callback * callback) { m_callback = callback; @@ -158,15 +159,8 @@ namespace smt { virtual expr * get_assertion(unsigned idx) const { SASSERT(idx < get_num_assertions()); return m_context.get_formulas()[idx]; - } - - virtual std::ostream& display(std::ostream & out) const { - m_context.display(out); - return out; - } - + } }; - }; solver * mk_smt_solver(ast_manager & m, params_ref const & p, symbol const & logic) { diff --git a/src/solver/check_sat_result.h b/src/solver/check_sat_result.h index 3da6b72a7..36eadd97d 100644 --- a/src/solver/check_sat_result.h +++ b/src/solver/check_sat_result.h @@ -58,7 +58,7 @@ public: virtual std::string reason_unknown() const = 0; virtual void set_reason_unknown(char const* msg) = 0; virtual void get_labels(svector & r) = 0; - virtual ast_manager& get_manager() = 0; + virtual ast_manager& get_manager() const = 0; }; @@ -75,7 +75,7 @@ struct simple_check_sat_result : public check_sat_result { simple_check_sat_result(ast_manager & m); virtual ~simple_check_sat_result(); - virtual ast_manager& get_manager() { return m_proof.get_manager(); } + virtual ast_manager& get_manager() const { return m_proof.get_manager(); } virtual void collect_statistics(statistics & st) const; virtual void get_unsat_core(ptr_vector & r); virtual void get_model(model_ref & m); diff --git a/src/solver/combined_solver.cpp b/src/solver/combined_solver.cpp index 30b387b98..fc76f85c1 100644 --- a/src/solver/combined_solver.cpp +++ b/src/solver/combined_solver.cpp @@ -101,7 +101,7 @@ private: m_inc_unknown_behavior = static_cast(p.solver2_unknown()); } - virtual ast_manager& get_manager() { return m_solver1->get_manager(); } + virtual ast_manager& get_manager() const { return m_solver1->get_manager(); } bool has_quantifiers() const { unsigned sz = get_num_assertions(); diff --git a/src/solver/solver.cpp b/src/solver/solver.cpp index b0ae6a540..5e732075d 100644 --- a/src/solver/solver.cpp +++ b/src/solver/solver.cpp @@ -20,6 +20,7 @@ Notes: #include"model_evaluator.h" #include"ast_util.h" #include"ast_pp.h" +#include"ast_pp_util.h" unsigned solver::get_num_assertions() const { NOT_IMPLEMENTED_YET(); @@ -32,7 +33,13 @@ expr * solver::get_assertion(unsigned idx) const { } std::ostream& solver::display(std::ostream & out) const { - return out << "(solver)"; + expr_ref_vector fmls(get_manager()); + get_assertions(fmls); + ast_pp_util visitor(get_manager()); + visitor.collect(fmls); + visitor.display_decls(out); + visitor.display_asserts(out, fmls, true); + return out; } void solver::get_assertions(expr_ref_vector& fmls) const { @@ -69,6 +76,7 @@ lbool solver::get_consequences_core(expr_ref_vector const& asms, expr_ref_vector tmp = vars[i]; val = eval(tmp); if (!m.is_value(val)) { + // vars[i] is unfixed continue; } if (m.is_bool(tmp) && is_uninterp_const(tmp)) { @@ -81,6 +89,7 @@ lbool solver::get_consequences_core(expr_ref_vector const& asms, expr_ref_vector lit = m.mk_not(tmp); } else { + // vars[i] is unfixed continue; } scoped_assumption_push _scoped_push(asms1, nlit); @@ -89,6 +98,7 @@ lbool solver::get_consequences_core(expr_ref_vector const& asms, expr_ref_vector case l_undef: return is_sat; case l_true: + // vars[i] is unfixed break; case l_false: get_unsat_core(core); @@ -114,6 +124,7 @@ lbool solver::get_consequences_core(expr_ref_vector const& asms, expr_ref_vector case l_undef: return is_sat; case l_true: + // vars[i] is unfixed break; case l_false: get_unsat_core(core); @@ -124,3 +135,5 @@ lbool solver::get_consequences_core(expr_ref_vector const& asms, expr_ref_vector } return l_true; } + + diff --git a/src/solver/tactic2solver.cpp b/src/solver/tactic2solver.cpp index 2a00d7195..f53301948 100644 --- a/src/solver/tactic2solver.cpp +++ b/src/solver/tactic2solver.cpp @@ -21,7 +21,6 @@ Notes: --*/ #include"solver_na2as.h" #include"tactic.h" -#include"ast_pp_util.h" #include"ast_translation.h" #include"mus.h" @@ -75,11 +74,10 @@ public: virtual unsigned get_num_assertions() const; virtual expr * get_assertion(unsigned idx) const; - virtual std::ostream& display(std::ostream & out) const; - virtual ast_manager& get_manager(); + virtual ast_manager& get_manager() const; }; -ast_manager& tactic2solver::get_manager() { return m_assertions.get_manager(); } +ast_manager& tactic2solver::get_manager() const { return m_assertions.get_manager(); } tactic2solver::tactic2solver(ast_manager & m, tactic * t, params_ref const & p, bool produce_proofs, bool produce_models, bool produce_unsat_cores, symbol const & logic): solver_na2as(m), @@ -243,22 +241,6 @@ expr * tactic2solver::get_assertion(unsigned idx) const { return m_assertions.get(idx); } -std::ostream& tactic2solver::display(std::ostream & out) const { - ast_pp_util visitor(m_assertions.m()); - visitor.collect(m_assertions); - visitor.display_decls(out); - visitor.display_asserts(out, m_assertions, true); -#if 0 - ast_manager & m = m_assertions.m(); - unsigned num = m_assertions.size(); - out << "(solver"; - for (unsigned i = 0; i < num; i++) { - out << "\n " << mk_ismt2_pp(m_assertions.get(i), m, 2); - } - out << ")"; -#endif - return out; -} solver * mk_tactic2solver(ast_manager & m, tactic * t, From bbfe02b25ac47241bf1a5a6cc2368d4d7eaeaac2 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 3 Aug 2016 11:16:29 -0700 Subject: [PATCH 139/536] modulating data-type solver Signed-off-by: Nikolaj Bjorner --- src/ast/datatype_decl_plugin.cpp | 17 +++++++++-------- src/ast/datatype_decl_plugin.h | 3 ++- src/smt/smt_consequences.cpp | 26 ++++++++++++++++++-------- src/smt/smt_context.cpp | 1 - src/smt/smt_context.h | 4 ++-- src/smt/smt_kernel.cpp | 8 ++++---- src/smt/smt_kernel.h | 3 ++- src/smt/smt_solver.cpp | 3 ++- src/smt/theory_datatype.h | 1 + src/solver/solver.cpp | 4 ++++ 10 files changed, 44 insertions(+), 26 deletions(-) diff --git a/src/ast/datatype_decl_plugin.cpp b/src/ast/datatype_decl_plugin.cpp index 8bfd9b36d..8ad33d6fc 100644 --- a/src/ast/datatype_decl_plugin.cpp +++ b/src/ast/datatype_decl_plugin.cpp @@ -732,7 +732,8 @@ void datatype_decl_plugin::get_op_names(svector & op_names, symbol datatype_util::datatype_util(ast_manager & m): m_manager(m), m_family_id(m.mk_family_id("datatype")), - m_asts(m) { + m_asts(m), + m_start(0) { } datatype_util::~datatype_util() { @@ -807,11 +808,11 @@ func_decl * datatype_util::get_non_rec_constructor_core(sort * ty, ptr_vector const * constructors = get_datatype_constructors(ty); - ptr_vector::const_iterator it = constructors->begin(); - ptr_vector::const_iterator end = constructors->end(); // step 1) - for (; it != end; ++it) { - func_decl * c = *it; + unsigned sz = constructors->size(); + ++m_start; + for (unsigned j = 0; j < sz; ++j) { + func_decl * c = (*constructors)[(j + m_start) % sz]; unsigned num_args = c->get_arity(); unsigned i = 0; for (; i < num_args; i++) { @@ -823,9 +824,8 @@ func_decl * datatype_util::get_non_rec_constructor_core(sort * ty, ptr_vectorbegin(); - for (; it != end; ++it) { - func_decl * c = *it; + for (unsigned j = 0; j < sz; ++j) { + func_decl * c = (*constructors)[(j + m_start) % sz]; TRACE("datatype_util_bug", tout << "non_rec_constructor c: " << c->get_name() << "\n";); unsigned num_args = c->get_arity(); unsigned i = 0; @@ -964,6 +964,7 @@ void datatype_util::reset() { std::for_each(m_vectors.begin(), m_vectors.end(), delete_proc >()); m_vectors.reset(); m_asts.reset(); + ++m_start; } /** diff --git a/src/ast/datatype_decl_plugin.h b/src/ast/datatype_decl_plugin.h index 019dd339e..ba0bedd32 100644 --- a/src/ast/datatype_decl_plugin.h +++ b/src/ast/datatype_decl_plugin.h @@ -176,7 +176,8 @@ class datatype_util { obj_map m_is_enum; ast_ref_vector m_asts; ptr_vector > m_vectors; - + unsigned m_start; + func_decl * get_non_rec_constructor_core(sort * ty, ptr_vector & forbidden_set); func_decl * get_constructor(sort * ty, unsigned c_id); diff --git a/src/smt/smt_consequences.cpp b/src/smt/smt_consequences.cpp index 49236be1b..1cb943d9f 100644 --- a/src/smt/smt_consequences.cpp +++ b/src/smt/smt_consequences.cpp @@ -102,7 +102,7 @@ namespace smt { } } - void context::delete_unfixed(obj_map& var2val) { + void context::delete_unfixed(obj_map& var2val, expr_ref_vector& unfixed) { ast_manager& m = m_manager; ptr_vector to_delete; obj_map::iterator it = var2val.begin(), end = var2val.end(); @@ -137,14 +137,16 @@ namespace smt { to_delete.push_back(k); } } - IF_VERBOSE(1, verbose_stream() << "(get-consequences deleting: " << to_delete.size() << " num-values: " << var2val.size() << ")\n";); for (unsigned i = 0; i < to_delete.size(); ++i) { var2val.remove(to_delete[i]); + unfixed.push_back(to_delete[i]); } } lbool context::get_consequences(expr_ref_vector const& assumptions, - expr_ref_vector const& vars, expr_ref_vector& conseq) { + expr_ref_vector const& vars, + expr_ref_vector& conseq, + expr_ref_vector& unfixed) { m_antecedents.reset(); lbool is_sat = check(assumptions.size(), assumptions.c_ptr()); @@ -168,6 +170,9 @@ namespace smt { trail.push_back(val); var2val.insert(vars[i], val); } + else { + unfixed.push_back(vars[i]); + } } extract_fixed_consequences(0, var2val, _assumptions, conseq); unsigned num_units = assigned_literals().size(); @@ -179,7 +184,6 @@ namespace smt { unsigned num_iterations = 0; unsigned model_threshold = 2; while (!var2val.empty()) { - ++num_iterations; obj_map::iterator it = var2val.begin(); expr* e = it->m_key; expr* val = it->m_value; @@ -212,22 +216,29 @@ namespace smt { } if (get_assignment(lit) == l_true) { var2val.erase(e); + unfixed.push_back(e); } else if (get_assign_level(lit) > get_search_level()) { TRACE("context", tout << "Retry fixing: " << mk_pp(e, m) << "\n";); pop_to_search_lvl(); + IF_VERBOSE(1, verbose_stream() << "(get-consequences re-iterating)\n";); continue; } else { TRACE("context", tout << "Fixed: " << mk_pp(e, m) << "\n";); } + ++num_iterations; TRACE("context", tout << "Unfixed variables: " << var2val.size() << "\n";); - if (model_threshold <= num_iterations) { - delete_unfixed(var2val); + if (model_threshold <= num_iterations || num_iterations <= 2) { + unsigned num_deleted = unfixed.size(); + delete_unfixed(var2val, unfixed); + num_deleted = unfixed.size() - num_deleted; // The next time we check the model is after 1.5 additional iterations. model_threshold *= 3; model_threshold /= 2; + IF_VERBOSE(1, verbose_stream() << "(get-consequences deleting: " << num_deleted << " num-values: " << var2val.size() << " num-iterations: " << num_iterations << ")\n";); + } // repeat until we either have a model with negated literal or // the literal is implied at base. @@ -242,8 +253,7 @@ namespace smt { conseq.push_back(fml); var2val.erase(e); SASSERT(get_assignment(lit) == l_false); - } - + } } end_search(); return l_true; diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index 88d0c8aff..c692173e6 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -3422,7 +3422,6 @@ namespace smt { } lbool context::bounded_search() { - SASSERT(!inconsistent()); unsigned counter = 0; TRACE("bounded_search", tout << "starting bounded search...\n";); diff --git a/src/smt/smt_context.h b/src/smt/smt_context.h index 30a262285..b20ad6d5c 100644 --- a/src/smt/smt_context.h +++ b/src/smt/smt_context.h @@ -1347,7 +1347,7 @@ namespace smt { u_map m_antecedents; void extract_fixed_consequences(unsigned idx, obj_map& var2val, uint_set const& assumptions, expr_ref_vector& conseq); - void delete_unfixed(obj_map& var2val); + void delete_unfixed(obj_map& var2val, expr_ref_vector& unfixed); expr_ref antecedent2fml(uint_set const& ante); @@ -1391,7 +1391,7 @@ namespace smt { lbool check(unsigned num_assumptions = 0, expr * const * assumptions = 0, bool reset_cancel = true); - lbool get_consequences(expr_ref_vector const& assumptions, expr_ref_vector const& vars, expr_ref_vector& conseq); + lbool get_consequences(expr_ref_vector const& assumptions, expr_ref_vector const& vars, expr_ref_vector& conseq, expr_ref_vector& unfixed); lbool setup_and_check(bool reset_cancel = true); diff --git a/src/smt/smt_kernel.cpp b/src/smt/smt_kernel.cpp index 8f18b7311..f740a39da 100644 --- a/src/smt/smt_kernel.cpp +++ b/src/smt/smt_kernel.cpp @@ -99,8 +99,8 @@ namespace smt { return m_kernel.check(num_assumptions, assumptions); } - lbool get_consequences(expr_ref_vector const& assumptions, expr_ref_vector const& vars, expr_ref_vector& conseq) { - return m_kernel.get_consequences(assumptions, vars, conseq); + lbool get_consequences(expr_ref_vector const& assumptions, expr_ref_vector const& vars, expr_ref_vector& conseq, expr_ref_vector& unfixed) { + return m_kernel.get_consequences(assumptions, vars, conseq, unfixed); } void get_model(model_ref & m) const { @@ -268,8 +268,8 @@ namespace smt { return r; } - lbool kernel::get_consequences(expr_ref_vector const& assumptions, expr_ref_vector const& vars, expr_ref_vector& conseq) { - return m_imp->get_consequences(assumptions, vars, conseq); + lbool kernel::get_consequences(expr_ref_vector const& assumptions, expr_ref_vector const& vars, expr_ref_vector& conseq, expr_ref_vector& unfixed) { + return m_imp->get_consequences(assumptions, vars, conseq, unfixed); } void kernel::get_model(model_ref & m) const { diff --git a/src/smt/smt_kernel.h b/src/smt/smt_kernel.h index 4cf170681..a10961207 100644 --- a/src/smt/smt_kernel.h +++ b/src/smt/smt_kernel.h @@ -129,7 +129,8 @@ namespace smt { /** \brief extract consequences among variables. */ - lbool get_consequences(expr_ref_vector const& assumptions, expr_ref_vector const& vars, expr_ref_vector& conseq); + lbool get_consequences(expr_ref_vector const& assumptions, expr_ref_vector const& vars, + expr_ref_vector& conseq, expr_ref_vector& unfixed); /** \brief Return the model associated with the last check command. diff --git a/src/smt/smt_solver.cpp b/src/smt/smt_solver.cpp index ec874ed8f..3bd8ece51 100644 --- a/src/smt/smt_solver.cpp +++ b/src/smt/smt_solver.cpp @@ -68,7 +68,8 @@ namespace smt { } virtual lbool get_consequences_core(expr_ref_vector const& assumptions, expr_ref_vector const& vars, expr_ref_vector& conseq) { - return m_context.get_consequences(assumptions, vars, conseq); + expr_ref_vector unfixed(m_context.m()); + return m_context.get_consequences(assumptions, vars, conseq, unfixed); } virtual void assert_expr(expr * t) { diff --git a/src/smt/theory_datatype.h b/src/smt/theory_datatype.h index 95c729dc2..b97adacfe 100644 --- a/src/smt/theory_datatype.h +++ b/src/smt/theory_datatype.h @@ -97,6 +97,7 @@ namespace smt { virtual void pop_scope_eh(unsigned num_scopes); virtual final_check_status final_check_eh(); virtual void reset_eh(); + virtual void restart_eh() { m_util.reset(); } virtual bool is_shared(theory_var v) const; public: theory_datatype(ast_manager & m, theory_datatype_params & p); diff --git a/src/solver/solver.cpp b/src/solver/solver.cpp index b0ae6a540..79bede1da 100644 --- a/src/solver/solver.cpp +++ b/src/solver/solver.cpp @@ -69,6 +69,7 @@ lbool solver::get_consequences_core(expr_ref_vector const& asms, expr_ref_vector tmp = vars[i]; val = eval(tmp); if (!m.is_value(val)) { + // vars[i] is unfixed continue; } if (m.is_bool(tmp) && is_uninterp_const(tmp)) { @@ -81,6 +82,7 @@ lbool solver::get_consequences_core(expr_ref_vector const& asms, expr_ref_vector lit = m.mk_not(tmp); } else { + // vars[i] is unfixed continue; } scoped_assumption_push _scoped_push(asms1, nlit); @@ -89,6 +91,7 @@ lbool solver::get_consequences_core(expr_ref_vector const& asms, expr_ref_vector case l_undef: return is_sat; case l_true: + // vars[i] is unfixed break; case l_false: get_unsat_core(core); @@ -114,6 +117,7 @@ lbool solver::get_consequences_core(expr_ref_vector const& asms, expr_ref_vector case l_undef: return is_sat; case l_true: + // vars[i] is unfixed break; case l_false: get_unsat_core(core); From f3ef59b095f3ea73af70c888436d9733432faa6b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 4 Aug 2016 13:17:37 -0700 Subject: [PATCH 140/536] fix scanner bug at EOF Signed-off-by: Nikolaj Bjorner --- src/parsers/smt2/smt2scanner.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/parsers/smt2/smt2scanner.cpp b/src/parsers/smt2/smt2scanner.cpp index 911f449dc..fb2f9f34a 100644 --- a/src/parsers/smt2/smt2scanner.cpp +++ b/src/parsers/smt2/smt2scanner.cpp @@ -92,7 +92,7 @@ namespace smt2 { } scanner::token scanner::read_symbol_core() { - while (true) { + while (!m_at_eof) { char c = curr(); signed char n = m_normalized[static_cast(c)]; if (n == 'a' || n == '0' || n == '-') { @@ -106,6 +106,7 @@ namespace smt2 { return SYMBOL_TOKEN; } } + return EOF_TOKEN; } scanner::token scanner::read_symbol() { From 87b767424582b08b7df6814e12c5d96e29227164 Mon Sep 17 00:00:00 2001 From: "Douglas B. Staple" Date: Fri, 5 Aug 2016 14:11:51 -0300 Subject: [PATCH 141/536] Removed complete() from handling of y.is_zero() in process_power --- src/tactic/arith/purify_arith_tactic.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/tactic/arith/purify_arith_tactic.cpp b/src/tactic/arith/purify_arith_tactic.cpp index 6affe2fa0..463e1a9e8 100644 --- a/src/tactic/arith/purify_arith_tactic.cpp +++ b/src/tactic/arith/purify_arith_tactic.cpp @@ -410,14 +410,12 @@ struct purify_arith_proc { expr * x = args[0]; expr * zero = u().mk_numeral(rational(0), is_int); expr * one = u().mk_numeral(rational(1), is_int); - if (y.is_zero() && complete()) { + if (y.is_zero()) { // (^ x 0) --> k | x != 0 implies k = 1, x = 0 implies k = 0^0 push_cnstr(OR(EQ(x, zero), EQ(k, one))); push_cnstr_pr(result_pr); - if (complete()) { - push_cnstr(OR(NOT(EQ(x, zero)), EQ(k, is_int ? u().mk_0_pw_0_int() : u().mk_0_pw_0_real()))); - push_cnstr_pr(result_pr); - } + push_cnstr(OR(NOT(EQ(x, zero)), EQ(k, is_int ? u().mk_0_pw_0_int() : u().mk_0_pw_0_real()))); + push_cnstr_pr(result_pr); } else if (!is_int) { SASSERT(!y.is_int()); From 14e8126f1681fd7cb142594aeba90626d21895c4 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 5 Aug 2016 11:32:12 -0700 Subject: [PATCH 142/536] wrapping interruptable with solver consequence call Signed-off-by: Nikolaj Bjorner --- src/api/api_solver.cpp | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/api/api_solver.cpp b/src/api/api_solver.cpp index 799a2b56b..786a7c4ba 100644 --- a/src/api/api_solver.cpp +++ b/src/api/api_solver.cpp @@ -443,7 +443,24 @@ extern "C" { } _variables.push_back(to_expr(__variables[i])); } - lbool result = to_solver_ref(s)->get_consequences(_assumptions, _variables, _consequences); + lbool result = l_undef; + unsigned timeout = to_solver(s)->m_params.get_uint("timeout", mk_c(c)->get_timeout()); + unsigned rlimit = to_solver(s)->m_params.get_uint("rlimit", mk_c(c)->get_rlimit()); + bool use_ctrl_c = to_solver(s)->m_params.get_bool("ctrl_c", false); + cancel_eh eh(mk_c(c)->m().limit()); + api::context::set_interruptable si(*(mk_c(c)), eh); + { + scoped_ctrl_c ctrlc(eh, false, use_ctrl_c); + scoped_timer timer(timeout, &eh); + scoped_rlimit _rlimit(mk_c(c)->m().limit(), rlimit); + try { + result = to_solver_ref(s)->get_consequences(_assumptions, _variables, _consequences); + } + catch (z3_exception & ex) { + mk_c(c)->handle_exception(ex); + return Z3_L_UNDEF; + } + } for (unsigned i = 0; i < _consequences.size(); ++i) { to_ast_vector_ref(consequences).push_back(_consequences[i].get()); } From 03aa6914a38646d8b2c781a4a2053c5d0f785e3a Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Tue, 9 Aug 2016 13:20:45 +0100 Subject: [PATCH 143/536] Fixed sub-logic detection for the ALL logic. --- src/cmd_context/cmd_context.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/cmd_context/cmd_context.cpp b/src/cmd_context/cmd_context.cpp index f6c3582d4..7239e09e5 100644 --- a/src/cmd_context/cmd_context.cpp +++ b/src/cmd_context/cmd_context.cpp @@ -580,7 +580,7 @@ bool cmd_context::logic_has_bv() const { } bool cmd_context::logic_has_seq_core(symbol const& s) const { - return s == "QF_BVRE" || s == "QF_S"; + return s == "QF_BVRE" || s == "QF_S" || "ALL"; } bool cmd_context::logic_has_seq() const { @@ -588,7 +588,7 @@ bool cmd_context::logic_has_seq() const { } bool cmd_context::logic_has_fpa_core(symbol const& s) const { - return s == "QF_FP" || s == "QF_FPBV" || s == "QF_BVFP"; + return s == "QF_FP" || s == "QF_FPBV" || s == "QF_BVFP" || "ALL"; } bool cmd_context::logic_has_fpa() const { @@ -705,7 +705,7 @@ void cmd_context::init_external_manager() { } bool cmd_context::supported_logic(symbol const & s) const { - return s == "QF_UF" || s == "UF" || + return s == "QF_UF" || s == "UF" || "ALL" || logic_has_arith_core(s) || logic_has_bv_core(s) || logic_has_array_core(s) || logic_has_seq_core(s) || logic_has_horn(s) || logic_has_fpa_core(s); From ff3c630207886e32451d018f8970b1ff6c90c59f Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Tue, 9 Aug 2016 16:36:32 +0100 Subject: [PATCH 144/536] .NET API: Added MkMul from IEnumerable. --- src/api/dotnet/Context.cs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/api/dotnet/Context.cs b/src/api/dotnet/Context.cs index cf235b4af..b37dc12d7 100644 --- a/src/api/dotnet/Context.cs +++ b/src/api/dotnet/Context.cs @@ -1055,6 +1055,19 @@ namespace Microsoft.Z3 return (ArithExpr)Expr.Create(this, Native.Z3_mk_mul(nCtx, (uint)t.Length, AST.ArrayToNative(t))); } + /// + /// Create an expression representing t[0] * t[1] * .... + /// + public ArithExpr MkMul(IEnumerable t) + { + Contract.Requires(t != null); + Contract.Requires(Contract.ForAll(t, a => a != null)); + Contract.Ensures(Contract.Result() != null); + + CheckContextMatch(t); + return (ArithExpr)Expr.Create(this, Native.Z3_mk_mul(nCtx, (uint)t.Count(), AST.EnumToNative(t))); + } + /// /// Create an expression representing t[0] - t[1] - .... /// From f54a7db1086b8151d42315ae7e2d96efa8ebdbd0 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Tue, 9 Aug 2016 16:36:49 +0100 Subject: [PATCH 145/536] Added debug traces. --- src/smt/tactic/smt_tactic.cpp | 1 + src/solver/solver_na2as.cpp | 1 + 2 files changed, 2 insertions(+) diff --git a/src/smt/tactic/smt_tactic.cpp b/src/smt/tactic/smt_tactic.cpp index baaaf7bb0..f2fbcf6d9 100644 --- a/src/smt/tactic/smt_tactic.cpp +++ b/src/smt/tactic/smt_tactic.cpp @@ -199,6 +199,7 @@ public: tout << "fail-if-inconclusive: " << m_fail_if_inconclusive << "\n"; tout << "params_ref: " << m_params_ref << "\n"; tout << "nnf: " << fparams().m_nnf_cnf << "\n";); + TRACE("smt_tactic_params", m_params.display(tout);); TRACE("smt_tactic_detail", in->display(tout);); TRACE("smt_tactic_memory", tout << "wasted_size: " << m.get_allocator().get_wasted_size() << "\n";); scoped_init_ctx init(*this, m); diff --git a/src/solver/solver_na2as.cpp b/src/solver/solver_na2as.cpp index 99917fff8..29ce4864f 100644 --- a/src/solver/solver_na2as.cpp +++ b/src/solver/solver_na2as.cpp @@ -62,6 +62,7 @@ struct append_assumptions { lbool solver_na2as::check_sat(unsigned num_assumptions, expr * const * assumptions) { append_assumptions app(m_assumptions, num_assumptions, assumptions); + TRACE("solver_na2as", display(tout);); return check_sat_core(m_assumptions.size(), m_assumptions.c_ptr()); } From b74bff7fb79280b22856459bdecfaf7c458a900c Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Wed, 10 Aug 2016 11:39:47 +0100 Subject: [PATCH 146/536] logic detection fix --- src/cmd_context/cmd_context.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/cmd_context/cmd_context.cpp b/src/cmd_context/cmd_context.cpp index 7239e09e5..3260f02b0 100644 --- a/src/cmd_context/cmd_context.cpp +++ b/src/cmd_context/cmd_context.cpp @@ -580,7 +580,7 @@ bool cmd_context::logic_has_bv() const { } bool cmd_context::logic_has_seq_core(symbol const& s) const { - return s == "QF_BVRE" || s == "QF_S" || "ALL"; + return s == "QF_BVRE" || s == "QF_S" || s == "ALL"; } bool cmd_context::logic_has_seq() const { @@ -588,7 +588,7 @@ bool cmd_context::logic_has_seq() const { } bool cmd_context::logic_has_fpa_core(symbol const& s) const { - return s == "QF_FP" || s == "QF_FPBV" || s == "QF_BVFP" || "ALL"; + return s == "QF_FP" || s == "QF_FPBV" || s == "QF_BVFP" || s == "ALL"; } bool cmd_context::logic_has_fpa() const { @@ -705,7 +705,7 @@ void cmd_context::init_external_manager() { } bool cmd_context::supported_logic(symbol const & s) const { - return s == "QF_UF" || s == "UF" || "ALL" || + return s == "QF_UF" || s == "UF" || s == "ALL" || logic_has_arith_core(s) || logic_has_bv_core(s) || logic_has_array_core(s) || logic_has_seq_core(s) || logic_has_horn(s) || logic_has_fpa_core(s); From 244c641234e0df2b84a4ea575a708fbe74913b70 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Fri, 12 Aug 2016 13:19:12 +0100 Subject: [PATCH 147/536] debug check fix --- src/api/api_context.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/api_context.h b/src/api/api_context.h index 7cba15c44..d2c0b3ad4 100644 --- a/src/api/api_context.h +++ b/src/api/api_context.h @@ -245,7 +245,7 @@ inline api::context * mk_c(Z3_context c) { return reinterpret_castcheck_searching(); inline bool is_expr(Z3_ast a) { return is_expr(to_ast(a)); } -#define CHECK_IS_EXPR(_p_, _ret_) { if (!is_expr(_p_)) { SET_ERROR_CODE(Z3_INVALID_ARG); return _ret_; } } +#define CHECK_IS_EXPR(_p_, _ret_) { if (_p_ == 0 || !is_expr(_p_)) { SET_ERROR_CODE(Z3_INVALID_ARG); return _ret_; } } inline bool is_bool_expr(Z3_context c, Z3_ast a) { return is_expr(a) && mk_c(c)->m().is_bool(to_expr(a)); } #define CHECK_FORMULA(_a_, _ret_) { if (_a_ == 0 || !CHECK_REF_COUNT(_a_) || !is_bool_expr(c, _a_)) { SET_ERROR_CODE(Z3_INVALID_ARG); return _ret_; } } inline void check_sorts(Z3_context c, ast * n) { mk_c(c)->check_sorts(n); } From e8141aaa84bb47a927282ce0318686fd12c7b2f9 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Fri, 12 Aug 2016 19:52:59 +0100 Subject: [PATCH 148/536] debug fixes --- src/ast/macros/macro_util.cpp | 7 ++++--- src/ast/rewriter/rewriter_def.h | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/ast/macros/macro_util.cpp b/src/ast/macros/macro_util.cpp index ce8834cc7..bc2feafed 100644 --- a/src/ast/macros/macro_util.cpp +++ b/src/ast/macros/macro_util.cpp @@ -482,12 +482,13 @@ void macro_util::normalize_expr(app * head, expr * t, expr_ref & norm_t) const { } if (changed) { // REMARK: t may have nested quantifiers... So, I must use the std order for variable substitution. - var_subst subst(m_manager); + var_subst subst(m_manager, true); TRACE("macro_util_bug", tout << "head: " << mk_pp(head, m_manager) << "\n"; - tout << "applying substitution to:\n" << mk_ll_pp(t, m_manager) << "\nsubstitituion:\n"; + tout << "applying substitution to:\n" << mk_ll_pp(t, m_manager) << "\nsubstitution:\n"; for (unsigned i = 0; i < var_mapping.size(); i++) { - tout << "#" << i << " -> " << mk_pp(var_mapping[i], m_manager) << "\n"; + if (var_mapping[i] != 0) + tout << "#" << i << " -> " << mk_pp(var_mapping[i], m_manager) << "\n"; }); subst(t, var_mapping.size(), var_mapping.c_ptr(), norm_t); } diff --git a/src/ast/rewriter/rewriter_def.h b/src/ast/rewriter/rewriter_def.h index 9c200a3e2..cd6a63acc 100644 --- a/src/ast/rewriter/rewriter_def.h +++ b/src/ast/rewriter/rewriter_def.h @@ -39,7 +39,7 @@ void rewriter_tpl::process_var(var * v) { unsigned idx = v->get_idx(); if (idx < m_bindings.size()) { unsigned index = m_bindings.size() - idx - 1; - expr * r = m_bindings[index]; + var * r = (var*)(m_bindings[index]); if (r != 0) { SASSERT(v->get_sort() == m().get_sort(r)); if (!is_ground(r) && m_shifts[index] != m_bindings.size()) { From 665fccf07aaedc94b1240b63b7dffcf95dc682ad Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 18 Aug 2016 18:01:29 -0700 Subject: [PATCH 149/536] addressing max-segment issue for AMD64 + Debug Signed-off-by: Nikolaj Bjorner --- src/api/python/z3.py | 5 ++++- src/sat/sat_clause.cpp | 45 ++++++++++++++++++++++++++++++------------ src/sat/sat_clause.h | 8 ++++++-- 3 files changed, 42 insertions(+), 16 deletions(-) diff --git a/src/api/python/z3.py b/src/api/python/z3.py index 6c4ac13a4..23704f44f 100644 --- a/src/api/python/z3.py +++ b/src/api/python/z3.py @@ -1547,6 +1547,9 @@ def And(*args): if isinstance(last_arg, Context): ctx = args[len(args)-1] args = args[:len(args)-1] + elif len(args) == 1 and isinstance(args[0], AstVector): + ctx = args[0].ctx + args = [a for a in args[0]] else: ctx = main_ctx() args = _get_args(args) @@ -6773,7 +6776,7 @@ class Optimize(Z3PPObject): return Z3_optimize_to_string(self.ctx.ref(), self.optimize) def statistics(self): - """Return statistics for the last `query()`. + """Return statistics for the last check`. """ return Statistics(Z3_optimize_get_statistics(self.ctx.ref(), self.optimize), self.ctx) diff --git a/src/sat/sat_clause.cpp b/src/sat/sat_clause.cpp index eabc4fdb1..70965ff9b 100644 --- a/src/sat/sat_clause.cpp +++ b/src/sat/sat_clause.cpp @@ -123,21 +123,28 @@ namespace sat { clause_allocator::clause_allocator(): m_allocator("clause-allocator") { -#ifdef _AMD64_ +#if defined(_AMD64_) m_num_segments = 0; + m_overflow_valid = false; #endif } clause * clause_allocator::get_clause(clause_offset cls_off) const { -#ifdef _AMD64_ +#if defined(_AMD64_) + clause const* result; + if (m_overflow_valid && m_cls_offset2ptr.find(cls_off, result)) { + return const_cast(result); + } return reinterpret_cast(m_segments[cls_off & c_aligment_mask] + (static_cast(cls_off) & ~c_aligment_mask)); #else return reinterpret_cast(cls_off); #endif } -#ifdef _AMD64_ - unsigned clause_allocator::get_segment(size_t ptr) { +#if defined(_AMD64_) + unsigned clause_allocator::get_segment(clause const* cls) { + size_t ptr = reinterpret_cast(cls); + SASSERT((ptr & c_aligment_mask) == 0); ptr &= ~0xFFFFFFFFull; // Keep only high part unsigned i = 0; @@ -145,18 +152,30 @@ namespace sat { if (m_segments[i] == ptr) return i; i = m_num_segments; - m_num_segments++; - SASSERT(m_num_segments <= c_max_segments); - if (i >= c_max_segments) - throw default_exception("segment out of range"); - m_segments[i] = ptr; + SASSERT(m_num_segments < c_max_segments); + if (i + 1 == c_max_segments) { + m_overflow_valid = true; + i += c_max_segments * m_cls_offset2ptr.size(); + m_ptr2cls_offset.insert(ptr, i); + m_cls_offset2ptr.insert(i, cls); + } + else { + m_num_segments++; + m_segments[i] = ptr; + } return i; } #endif clause_offset clause_allocator::get_offset(clause const * ptr) const { -#ifdef _AMD64_ - return static_cast(reinterpret_cast(ptr)) + const_cast(this)->get_segment(reinterpret_cast(ptr)); +#if defined(_AMD64_) + unsigned segment = const_cast(this)->get_segment(ptr); + if (segment >= c_max_segments) { + return m_ptr2cls_offset.find(reinterpret_cast(ptr)); + } + else { + return static_cast(reinterpret_cast(ptr)) + segment; + } #else return reinterpret_cast(ptr); #endif @@ -164,7 +183,7 @@ namespace sat { clause * clause_allocator::mk_clause(unsigned num_lits, literal const * lits, bool learned) { size_t size = clause::get_obj_size(num_lits); -#ifdef _AMD64_ +#if defined(_AMD64_) size_t slot = size >> c_cls_alignment; if ((size & c_aligment_mask) != 0) slot++; @@ -181,7 +200,7 @@ namespace sat { TRACE("sat", tout << "delete: " << cls->id() << " " << cls << " " << *cls << "\n";); m_id_gen.recycle(cls->id()); size_t size = clause::get_obj_size(cls->m_capacity); -#ifdef _AMD64_ +#if defined(_AMD64_) size_t slot = size >> c_cls_alignment; if ((size & c_aligment_mask) != 0) slot++; diff --git a/src/sat/sat_clause.h b/src/sat/sat_clause.h index 6a183c3df..f78f6b960 100644 --- a/src/sat/sat_clause.h +++ b/src/sat/sat_clause.h @@ -22,6 +22,7 @@ Revision History: #include"sat_types.h" #include"small_object_allocator.h" #include"id_gen.h" +#include"map.h" #ifdef _MSC_VER #pragma warning(disable : 4200) @@ -124,13 +125,16 @@ namespace sat { class clause_allocator { small_object_allocator m_allocator; id_gen m_id_gen; -#ifdef _AMD64_ - unsigned get_segment(size_t ptr); +#if defined(_AMD64_) + unsigned get_segment(clause const* cls); static const unsigned c_cls_alignment = 3; static const unsigned c_max_segments = 1 << c_cls_alignment; static const size_t c_aligment_mask = (1ull << c_cls_alignment) - 1ull; unsigned m_num_segments; size_t m_segments[c_max_segments]; + bool m_overflow_valid; + size_t_map m_ptr2cls_offset; + u_map m_cls_offset2ptr; #endif public: clause_allocator(); From e132c5eae890a125d0b241a1663574dedb9661e9 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 19 Aug 2016 08:42:40 -0700 Subject: [PATCH 150/536] safe sat clause_offset in debug mode Signed-off-by: Nikolaj Bjorner --- src/sat/sat_clause.cpp | 21 ++++++++++++++++----- src/sat/sat_clause.h | 2 ++ 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/src/sat/sat_clause.cpp b/src/sat/sat_clause.cpp index 70965ff9b..7b8abf6fb 100644 --- a/src/sat/sat_clause.cpp +++ b/src/sat/sat_clause.cpp @@ -131,10 +131,12 @@ namespace sat { clause * clause_allocator::get_clause(clause_offset cls_off) const { #if defined(_AMD64_) +#if defined (Z3DEBUG) clause const* result; if (m_overflow_valid && m_cls_offset2ptr.find(cls_off, result)) { return const_cast(result); } +#endif return reinterpret_cast(m_segments[cls_off & c_aligment_mask] + (static_cast(cls_off) & ~c_aligment_mask)); #else return reinterpret_cast(cls_off); @@ -152,7 +154,8 @@ namespace sat { if (m_segments[i] == ptr) return i; i = m_num_segments; - SASSERT(m_num_segments < c_max_segments); +#if defined(Z3DEBUG) + SASSERT(i < c_max_segments); if (i + 1 == c_max_segments) { m_overflow_valid = true; i += c_max_segments * m_cls_offset2ptr.size(); @@ -160,9 +163,17 @@ namespace sat { m_cls_offset2ptr.insert(i, cls); } else { - m_num_segments++; + ++m_num_segments; m_segments[i] = ptr; } +#else + SASSERT(i <= c_max_segments); + if (i == c_max_segments) { + throw default_exception("segment out of range"); + } + m_segments[i] = ptr; + ++m_num_segments; +#endif return i; } #endif @@ -170,12 +181,12 @@ namespace sat { clause_offset clause_allocator::get_offset(clause const * ptr) const { #if defined(_AMD64_) unsigned segment = const_cast(this)->get_segment(ptr); +#if defined(Z3DEBUG) if (segment >= c_max_segments) { return m_ptr2cls_offset.find(reinterpret_cast(ptr)); } - else { - return static_cast(reinterpret_cast(ptr)) + segment; - } +#endif + return static_cast(reinterpret_cast(ptr)) + segment; #else return reinterpret_cast(ptr); #endif diff --git a/src/sat/sat_clause.h b/src/sat/sat_clause.h index f78f6b960..be17cc7d9 100644 --- a/src/sat/sat_clause.h +++ b/src/sat/sat_clause.h @@ -132,9 +132,11 @@ namespace sat { static const size_t c_aligment_mask = (1ull << c_cls_alignment) - 1ull; unsigned m_num_segments; size_t m_segments[c_max_segments]; +#if defined(Z3DEBUG) bool m_overflow_valid; size_t_map m_ptr2cls_offset; u_map m_cls_offset2ptr; +#endif #endif public: clause_allocator(); From 5069da62a3a2338e0f13e6fde82c9a985e3082a5 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 19 Aug 2016 08:45:06 -0700 Subject: [PATCH 151/536] safe sat clause_offset in debug mode Signed-off-by: Nikolaj Bjorner --- src/sat/sat_clause.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/sat/sat_clause.cpp b/src/sat/sat_clause.cpp index 7b8abf6fb..eb51cb6ac 100644 --- a/src/sat/sat_clause.cpp +++ b/src/sat/sat_clause.cpp @@ -125,7 +125,9 @@ namespace sat { m_allocator("clause-allocator") { #if defined(_AMD64_) m_num_segments = 0; +#if defined(Z3DEBUG) m_overflow_valid = false; +#endif #endif } From f2b5c11d1c4435d98f75d5209c856f89f60b682b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 20 Aug 2016 03:52:45 -0700 Subject: [PATCH 152/536] add option for prettier proof printing, Issue #706 Signed-off-by: Nikolaj Bjorner --- examples/python/mus/mss.py | 52 +++++++++++++++++++--------- src/api/python/z3.py | 2 ++ src/ast/pp_params.pyg | 1 + src/cmd_context/basic_cmds.cpp | 22 +++++++----- src/cmd_context/interpolant_cmds.cpp | 1 - src/sat/sat_bceq.cpp | 4 +-- src/sat/sat_config.cpp | 4 +-- src/sat/sat_config.h | 4 +-- src/sat/sat_mus.cpp | 8 ++--- src/sat/sat_params.pyg | 4 +-- src/sat/sat_solver.cpp | 4 +-- src/smt/theory_arith_eq.h | 12 +++---- 12 files changed, 72 insertions(+), 46 deletions(-) diff --git a/examples/python/mus/mss.py b/examples/python/mus/mss.py index b31fd92a8..fd2d209da 100644 --- a/examples/python/mus/mss.py +++ b/examples/python/mus/mss.py @@ -73,6 +73,10 @@ class MSSSolver: self.varcache[i] = Not(v) return self.varcache[i] + # Retrieve the latest model + # Add formulas that are true in the model to + # the current mss + def update_unknown(self): self.model = self.s.model() new_unknown = set([]) @@ -83,23 +87,29 @@ class MSSSolver: new_unknown.add(x) self.unknown = new_unknown - def relax_core(self, core): - assert(core <= self.soft_vars) - prev = BoolVal(True) - core_list = [x for x in core] - self.soft_vars -= core - # replace x0, x1, x2, .. by - # Or(x1, x0), Or(x2, And(x1, x0)), Or(x3, And(x2, And(x1, x0))), ... - for i in range(len(core_list)-1): - x = core_list[i] - y = core_list[i+1] - prevf = And(x, prev) - prev = Bool("%s" % prevf) - self.s.add(prev == prevf) - zf = Or(prev, y) - z = Bool("%s" % zf) - self.s.add(z == zf) - self.soft_vars.add(z) + # Create a name, propositional atom, + # for formula 'fml' and return the name. + + def add_def(self, fml): + name = Bool("%s" % fml) + self.s.add(name == fml) + return name + + # replace Fs := f0, f1, f2, .. by + # Or(f1, f0), Or(f2, And(f1, f0)), Or(f3, And(f2, And(f1, f0))), ... + + def relax_core(self, Fs): + assert(Fs <= self.soft_vars) + prefix = BoolVal(True) + self.soft_vars -= Fs + Fs = [ f for f in Fs ] + for i in range(len(Fs)-1): + prefix = self.add_def(And(Fs[i], prefix)) + self.soft_vars.add(self.add_def(Or(prefix, Fs[i+1]))) + + # Resolve literals from the core that + # are 'explained', e.g., implied by + # other literals. def resolve_core(self, core): new_core = set([]) @@ -111,6 +121,14 @@ class MSSSolver: return new_core + # Given a current satisfiable state + # Extract an MSS, and ensure that currently + # encoutered cores are avoided in next iterations + # by weakening the set of literals that are + # examined in next iterations. + # Strengthen the solver state by enforcing that + # an element from the MCS is encoutered. + def grow(self): self.mss = [] self.mcs = [] diff --git a/src/api/python/z3.py b/src/api/python/z3.py index 6c4ac13a4..39c646c01 100644 --- a/src/api/python/z3.py +++ b/src/api/python/z3.py @@ -118,6 +118,8 @@ def _get_args(args): try: if len(args) == 1 and (isinstance(args[0], tuple) or isinstance(args[0], list)): return args[0] + elif len(args) == 1 and isinstance(args[0], set): + return [arg for arg in args[0]] else: return args except: # len is not necessarily defined when args is not a sequence (use reflection?) diff --git a/src/ast/pp_params.pyg b/src/ast/pp_params.pyg index 46273b140..6b43cbea3 100644 --- a/src/ast/pp_params.pyg +++ b/src/ast/pp_params.pyg @@ -16,4 +16,5 @@ def_module_params('pp', ('fixed_indent', BOOL, False, 'use a fixed indentation for applications'), ('single_line', BOOL, False, 'ignore line breaks when true'), ('bounded', BOOL, False, 'ignore characters exceeding max width'), + ('pretty_proof', BOOL, False, 'use slower, but prettier, printer for proofs'), ('simplify_implies', BOOL, True, 'simplify nested implications for pretty printing'))) diff --git a/src/cmd_context/basic_cmds.cpp b/src/cmd_context/basic_cmds.cpp index 84a0d9af8..87cbd2738 100644 --- a/src/cmd_context/basic_cmds.cpp +++ b/src/cmd_context/basic_cmds.cpp @@ -29,6 +29,7 @@ Notes: #include"gparams.h" #include"env_params.h" #include"well_sorted.h" +#include"pp_params.hpp" class help_cmd : public cmd { svector m_cmds; @@ -161,14 +162,19 @@ ATOMIC_CMD(get_proof_cmd, "get-proof", "retrieve proof", { throw cmd_exception("proof is not well sorted"); } - // TODO: reimplement a new SMT2 pretty printer - ast_smt_pp pp(ctx.m()); - cmd_is_declared isd(ctx); - pp.set_is_declared(&isd); - pp.set_logic(ctx.get_logic()); - // ctx.regular_stream() << mk_pp(pr, ctx.m()) << "\n"; - pp.display_smt2(ctx.regular_stream(), pr); - ctx.regular_stream() << std::endl; + pp_params params; + if (params.pretty_proof()) { + ctx.regular_stream() << mk_pp(pr, ctx.m()) << std::endl; + } + else { + // TODO: reimplement a new SMT2 pretty printer + ast_smt_pp pp(ctx.m()); + cmd_is_declared isd(ctx); + pp.set_is_declared(&isd); + pp.set_logic(ctx.get_logic()); + pp.display_smt2(ctx.regular_stream(), pr); + ctx.regular_stream() << std::endl; + } }); #define PRINT_CORE() \ diff --git a/src/cmd_context/interpolant_cmds.cpp b/src/cmd_context/interpolant_cmds.cpp index c482b4d09..53da91d1e 100644 --- a/src/cmd_context/interpolant_cmds.cpp +++ b/src/cmd_context/interpolant_cmds.cpp @@ -28,7 +28,6 @@ #include"mpq.h" #include"expr2var.h" #include"pp.h" -#include"pp_params.hpp" #include"iz3interp.h" #include"iz3checker.h" #include"iz3profiling.h" diff --git a/src/sat/sat_bceq.cpp b/src/sat/sat_bceq.cpp index 9ff286aaa..fa0309327 100644 --- a/src/sat/sat_bceq.cpp +++ b/src/sat/sat_bceq.cpp @@ -493,14 +493,14 @@ namespace sat { void bceq::operator()() { if (!m_solver.m_config.m_bcd) return; flet _disable_bcd(m_solver.m_config.m_bcd, false); - flet _disable_min(m_solver.m_config.m_minimize_core, false); + flet _disable_min(m_solver.m_config.m_core_minimize, false); flet _disable_opt(m_solver.m_config.m_optimize_model, false); flet _bound_maxc(m_solver.m_config.m_max_conflicts, 1500); use_list ul; solver s(m_solver.m_params, m_solver.rlimit(), 0); s.m_config.m_bcd = false; - s.m_config.m_minimize_core = false; + s.m_config.m_core_minimize = false; s.m_config.m_optimize_model = false; s.m_config.m_max_conflicts = 1500; m_use_list = &ul; diff --git a/src/sat/sat_config.cpp b/src/sat/sat_config.cpp index aff023b22..f976e1d71 100644 --- a/src/sat/sat_config.cpp +++ b/src/sat/sat_config.cpp @@ -107,8 +107,8 @@ namespace sat { m_gc_increment = p.gc_increment(); } m_minimize_lemmas = p.minimize_lemmas(); - m_minimize_core = p.minimize_core(); - m_minimize_core_partial = p.minimize_core_partial(); + m_core_minimize = p.core_minimize(); + m_core_minimize_partial = p.core_minimize_partial(); m_optimize_model = p.optimize_model(); m_bcd = p.bcd(); m_dyn_sub_res = p.dyn_sub_res(); diff --git a/src/sat/sat_config.h b/src/sat/sat_config.h index 2eff402ad..0234b5710 100644 --- a/src/sat/sat_config.h +++ b/src/sat/sat_config.h @@ -69,8 +69,8 @@ namespace sat { bool m_minimize_lemmas; bool m_dyn_sub_res; - bool m_minimize_core; - bool m_minimize_core_partial; + bool m_core_minimize; + bool m_core_minimize_partial; bool m_optimize_model; bool m_bcd; diff --git a/src/sat/sat_mus.cpp b/src/sat/sat_mus.cpp index 9c7c8c7bb..7b3277b6c 100644 --- a/src/sat/sat_mus.cpp +++ b/src/sat/sat_mus.cpp @@ -58,7 +58,7 @@ namespace sat { } lbool mus::operator()() { - flet _disable_min(s.m_config.m_minimize_core, false); + flet _disable_min(s.m_config.m_core_minimize, false); flet _disable_opt(s.m_config.m_optimize_model, false); flet _is_active(m_is_active, true); IF_VERBOSE(3, verbose_stream() << "(sat.mus " << s.get_core() << ")\n";); @@ -69,7 +69,7 @@ namespace sat { } lbool mus::mus1() { - bool minimize_partial = s.m_config.m_minimize_core_partial; + bool minimize_partial = s.m_config.m_core_minimize_partial; TRACE("sat", tout << "old core: " << s.get_core() << "\n";); literal_vector& core = get_core(); literal_vector& mus = m_mus; @@ -96,7 +96,7 @@ namespace sat { // IF_VERBOSE(0, verbose_stream() << "num literals: " << core << " " << mus << "\n";); break; } - if (s.m_config.m_minimize_core_partial && s.m_stats.m_restart - m_restart > m_max_restarts) { + if (s.m_config.m_core_minimize_partial && s.m_stats.m_restart - m_restart > m_max_restarts) { IF_VERBOSE(1, verbose_stream() << "(sat restart budget exceeded)\n";); set_core(); return l_true; @@ -172,7 +172,7 @@ namespace sat { lbool mus::qx(literal_set& assignment, literal_set& support, bool has_support) { lbool is_sat = l_true; - if (s.m_config.m_minimize_core_partial && s.m_stats.m_restart - m_restart > m_max_restarts) { + if (s.m_config.m_core_minimize_partial && s.m_stats.m_restart - m_restart > m_max_restarts) { IF_VERBOSE(1, verbose_stream() << "(sat restart budget exceeded)\n";); return l_true; } diff --git a/src/sat/sat_params.pyg b/src/sat/sat_params.pyg index c5ac97b4e..90e715a9d 100644 --- a/src/sat/sat_params.pyg +++ b/src/sat/sat_params.pyg @@ -19,8 +19,8 @@ def_module_params('sat', ('gc.k', UINT, 7, 'learned clauses that are inactive for k gc rounds are permanently deleted (only used in dyn_psm)'), ('minimize_lemmas', BOOL, True, 'minimize learned clauses'), ('dyn_sub_res', BOOL, True, 'dynamic subsumption resolution for minimizing learned clauses'), - ('minimize_core', BOOL, False, 'minimize computed core'), - ('minimize_core_partial', BOOL, False, 'apply partial (cheap) core minimization'), + ('core.minimize', BOOL, False, 'minimize computed core'), + ('core.minimize_partial', BOOL, False, 'apply partial (cheap) core minimization'), ('optimize_model', BOOL, False, 'enable optimization of soft constraints'), ('bcd', BOOL, False, 'enable blocked clause decomposition for equality extraction'), ('dimacs.core', BOOL, False, 'extract core from DIMACS benchmarks'))) diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 78067238a..d8d273f2b 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -937,7 +937,7 @@ namespace sat { bool solver::init_weighted_assumptions(unsigned num_lits, literal const* lits, double const* weights, double max_weight) { - flet _min1(m_config.m_minimize_core, false); + flet _min1(m_config.m_core_minimize, false); m_weight = 0; m_blocker.reset(); svector values; @@ -2015,7 +2015,7 @@ namespace sat { idx--; } reset_unmark(old_size); - if (m_config.m_minimize_core) { + if (m_config.m_core_minimize) { if (m_min_core_valid && m_min_core.size() < m_core.size()) { IF_VERBOSE(1, verbose_stream() << "(sat.updating core " << m_min_core.size() << " " << m_core.size() << ")\n";); m_core.reset(); diff --git a/src/smt/theory_arith_eq.h b/src/smt/theory_arith_eq.h index 8e1b52ee5..de76b6838 100644 --- a/src/smt/theory_arith_eq.h +++ b/src/smt/theory_arith_eq.h @@ -64,7 +64,7 @@ namespace smt { lower(v2)->push_justification(ante, numeral::zero(), proofs_enabled()); upper(v)->push_justification(ante, numeral::zero(), proofs_enabled()); - TRACE("arith_fixed_propagate_eq", tout << "propagate eq: v" << v << " = v" << v2 << "\n"; + TRACE("arith_eq", tout << "propagate eq: v" << v << " = v" << v2 << "\n"; display_var(tout, v); display_var(tout, v2);); m_stats.m_fixed_eqs++; @@ -175,7 +175,7 @@ namespace smt { timer.stop(); ok++; if (ok % 100000 == 0) { - TRACE("propagate_cheap_eq", + TRACE("arith_eq", tout << total << " " << ok << " " << static_cast(ok)/static_cast(total) << " " << timer.get_seconds() << "\n"; @@ -216,7 +216,7 @@ namespace smt { void theory_arith::propagate_cheap_eq(unsigned rid) { if (!propagate_eqs()) return; - TRACE("propagate_cheap_eq", tout << "checking if row " << rid << " can propagate equality.\n"; + TRACE("arith_eq", tout << "checking if row " << rid << " can propagate equality.\n"; display_row_info(tout, rid);); row const & r = m_rows[rid]; theory_var x; @@ -258,7 +258,7 @@ namespace smt { // found equality x = y antecedents ante(*this); collect_fixed_var_justifications(r, ante); - TRACE("propagate_cheap_eq", tout << "propagate eq using x-y=0 row:\n"; display_row_info(tout, r);); + TRACE("arith_eq", tout << "propagate eq using x-y=0 row:\n"; display_row_info(tout, r);); m_stats.m_offset_eqs++; propagate_eq_to_core(x, y, ante); } @@ -299,7 +299,7 @@ namespace smt { antecedents ante(*this); collect_fixed_var_justifications(r, ante); collect_fixed_var_justifications(r2, ante); - TRACE("propagate_cheap_eq", tout << "propagate eq two rows:\n"; + TRACE("arith_eq", tout << "propagate eq two rows:\n"; tout << "swapped: " << swapped << "\n"; tout << "x : v" << x << "\n"; tout << "x2 : v" << x2 << "\n"; @@ -343,7 +343,7 @@ namespace smt { antecedents.eqs().size(), antecedents.eqs().c_ptr(), _x, _y, antecedents.num_params(), antecedents.params("eq-propagate"))); - TRACE("propagate_eq_to_core", tout << "detected equality: #" << _x->get_owner_id() << " = #" << _y->get_owner_id() << "\n"; + TRACE("arith_eq", tout << "detected equality: #" << _x->get_owner_id() << " = #" << _y->get_owner_id() << "\n"; display_var(tout, x); display_var(tout, y);); ctx.assign_eq(_x, _y, eq_justification(js)); From 2d8325ed43444fb0d65abd5f14d4eb1511fdaad6 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 20 Aug 2016 06:05:13 -0700 Subject: [PATCH 153/536] fix axiomatization of str.replace. Fixes issue #703 Signed-off-by: Nikolaj Bjorner --- src/smt/theory_seq.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index 8b6c5baba..15122d7b6 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -2902,9 +2902,11 @@ void theory_seq::add_replace_axiom(expr* r) { expr_ref xty = mk_concat(x, t, y); expr_ref xsy = mk_concat(x, s, y); literal cnt = mk_literal(m_util.str.mk_contains(a ,s)); + literal a_emp = mk_eq_empty(a); + add_axiom(~a_emp, mk_seq_eq(r, a)); add_axiom(cnt, mk_seq_eq(r, a)); - add_axiom(~cnt, mk_seq_eq(a, xsy)); - add_axiom(~cnt, mk_seq_eq(r, xty)); + add_axiom(~cnt, a_emp, mk_seq_eq(a, xsy)); + add_axiom(~cnt, a_emp, mk_seq_eq(r, xty)); tightest_prefix(s, x); } From 879f792125ee295b95be7df59fc6fde6f3da614d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 20 Aug 2016 06:13:52 -0700 Subject: [PATCH 154/536] fix axiomatization of str.replace. Fixes issue #703 Signed-off-by: Nikolaj Bjorner --- src/ast/seq_decl_plugin.cpp | 3 +++ src/smt/theory_seq.cpp | 6 ++++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/ast/seq_decl_plugin.cpp b/src/ast/seq_decl_plugin.cpp index dc7307741..caf8bd5cb 100644 --- a/src/ast/seq_decl_plugin.cpp +++ b/src/ast/seq_decl_plugin.cpp @@ -144,6 +144,9 @@ zstring zstring::replace(zstring const& src, zstring const& dst) const { if (length() < src.length()) { return zstring(*this); } + if (src.length() == 0) { + return zstring(*this); + } bool found = false; for (unsigned i = 0; i < length(); ++i) { bool eq = !found && i + src.length() <= length(); diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index 15122d7b6..6a2208ad4 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -2903,10 +2903,12 @@ void theory_seq::add_replace_axiom(expr* r) { expr_ref xsy = mk_concat(x, s, y); literal cnt = mk_literal(m_util.str.mk_contains(a ,s)); literal a_emp = mk_eq_empty(a); + literal s_emp = mk_eq_empty(s); add_axiom(~a_emp, mk_seq_eq(r, a)); add_axiom(cnt, mk_seq_eq(r, a)); - add_axiom(~cnt, a_emp, mk_seq_eq(a, xsy)); - add_axiom(~cnt, a_emp, mk_seq_eq(r, xty)); + add_axiom(~s_emp, mk_seq_eq(r, a)); + add_axiom(~cnt, a_emp, s_emp, mk_seq_eq(a, xsy)); + add_axiom(~cnt, a_emp, s_emp, mk_seq_eq(r, xty)); tightest_prefix(s, x); } From 47e95f8676e9cf8db85de1a5127d614d19d92eab Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Sat, 20 Aug 2016 17:56:52 -0400 Subject: [PATCH 155/536] Fixed binding substitution in macro_util --- src/ast/macros/macro_util.cpp | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/src/ast/macros/macro_util.cpp b/src/ast/macros/macro_util.cpp index bc2feafed..166b9c4b0 100644 --- a/src/ast/macros/macro_util.cpp +++ b/src/ast/macros/macro_util.cpp @@ -458,28 +458,32 @@ void macro_util::normalize_expr(app * head, expr * t, expr_ref & norm_t) const { expr_ref_buffer var_mapping(m_manager); bool changed = false; unsigned num_args = head->get_num_args(); - unsigned max = num_args; + unsigned max_var_idx = 0; for (unsigned i = 0; i < num_args; i++) { - var * v = to_var(head->get_arg(i)); - if (v->get_idx() >= max) - max = v->get_idx() + 1; + var const * v = to_var(head->get_arg(i)); + if (v->get_idx() > max_var_idx) + max_var_idx = v->get_idx(); } TRACE("normalize_expr_bug", tout << "head: " << mk_pp(head, m_manager) << "\n"; tout << "applying substitution to:\n" << mk_bounded_pp(t, m_manager) << "\n";); for (unsigned i = 0; i < num_args; i++) { - var * v = to_var(head->get_arg(i)); + var * v = to_var(head->get_arg(i)); if (v->get_idx() != i) { changed = true; - var * new_var = m_manager.mk_var(i, v->get_sort()); - CTRACE("normalize_expr_bug", v->get_idx() >= num_args, tout << mk_pp(v, m_manager) << ", num_args: " << num_args << "\n";); - SASSERT(v->get_idx() < max); - var_mapping.setx(max - v->get_idx() - 1, new_var); - } - else { - var_mapping.setx(max - i - 1, v); + var_ref new_var(m_manager.mk_var(i, v->get_sort()), m_manager); + var_mapping.setx(max_var_idx - v->get_idx(), new_var); } + else + var_mapping.setx(max_var_idx - i, v); } + + for (unsigned i = num_args; i <= max_var_idx; i++) + // CMW: Won't be used, but dictates a larger binding size, + // so that the indexes between here and in the rewriter match. + // It's possible that we don't see the true max idx of all vars here. + var_mapping.setx(max_var_idx - i, 0); + if (changed) { // REMARK: t may have nested quantifiers... So, I must use the std order for variable substitution. var_subst subst(m_manager, true); @@ -488,7 +492,7 @@ void macro_util::normalize_expr(app * head, expr * t, expr_ref & norm_t) const { tout << "applying substitution to:\n" << mk_ll_pp(t, m_manager) << "\nsubstitution:\n"; for (unsigned i = 0; i < var_mapping.size(); i++) { if (var_mapping[i] != 0) - tout << "#" << i << " -> " << mk_pp(var_mapping[i], m_manager) << "\n"; + tout << "#" << i << " -> " << mk_ll_pp(var_mapping[i], m_manager); }); subst(t, var_mapping.size(), var_mapping.c_ptr(), norm_t); } From b03dc0af3b60237daf09137c6c9069a53b168ac3 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Sat, 20 Aug 2016 17:57:00 -0400 Subject: [PATCH 156/536] fixed memory leaks --- src/parsers/smt/smtparser.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/parsers/smt/smtparser.cpp b/src/parsers/smt/smtparser.cpp index f50e8b339..c9b20850c 100644 --- a/src/parsers/smt/smtparser.cpp +++ b/src/parsers/smt/smtparser.cpp @@ -1573,7 +1573,8 @@ private: return false; } } - expr * p = m_manager.mk_pattern(ts.size(), (app*const*)(ts.c_ptr())); + expr_ref p(m_manager); + p = m_manager.mk_pattern(ts.size(), (app*const*)(ts.c_ptr())); 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; @@ -1581,8 +1582,11 @@ private: patterns.push_back(p); } 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); + app_ref sk_hack(m_manager); + sk_hack = m_manager.mk_app(m_sk_hack, 1, ts.c_ptr()); + app * sk_hackp = sk_hack.get(); + expr_ref p(m_manager); + p = m_manager.mk_pattern(1, &sk_hackp); 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; From 0a09d5ff5285aa445634414d7bd99effdb9134fe Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 23 Aug 2016 11:33:40 -0300 Subject: [PATCH 157/536] check for non-nullness when handling optional info fields for marking. Fixes issue #719 Signed-off-by: Nikolaj Bjorner --- src/ast/ast.cpp | 16 ++++++++++++---- src/muz/transforms/dl_mk_coi_filter.cpp | 9 +++++++-- 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/src/ast/ast.cpp b/src/ast/ast.cpp index d138685ed..93769a3b4 100644 --- a/src/ast/ast.cpp +++ b/src/ast/ast.cpp @@ -1430,14 +1430,22 @@ ast_manager::~ast_manager() { for (; it_a != end_a; ++it_a) { ast* n = (*it_a); switch (n->get_kind()) { - case AST_SORT: - mark_array_ref(mark, to_sort(n)->get_info()->get_num_parameters(), to_sort(n)->get_info()->get_parameters()); + case AST_SORT: { + sort_info* info = to_sort(n)->get_info(); + if (info != 0) { + mark_array_ref(mark, info->get_num_parameters(), info->get_parameters()); + } break; - case AST_FUNC_DECL: - mark_array_ref(mark, to_func_decl(n)->get_info()->get_num_parameters(), to_func_decl(n)->get_info()->get_parameters()); + } + case AST_FUNC_DECL: { + func_decl_info* info = to_func_decl(n)->get_info(); + if (info != 0) { + mark_array_ref(mark, info->get_num_parameters(), info->get_parameters()); + } mark_array_ref(mark, to_func_decl(n)->get_arity(), to_func_decl(n)->get_domain()); mark.mark(to_func_decl(n)->get_range(), true); break; + } case AST_APP: mark.mark(to_app(n)->get_decl(), true); mark_array_ref(mark, to_app(n)->get_num_args(), to_app(n)->get_args()); diff --git a/src/muz/transforms/dl_mk_coi_filter.cpp b/src/muz/transforms/dl_mk_coi_filter.cpp index c452e2611..e3d01a537 100644 --- a/src/muz/transforms/dl_mk_coi_filter.cpp +++ b/src/muz/transforms/dl_mk_coi_filter.cpp @@ -44,6 +44,9 @@ namespace datalog { if (m_context.has_facts(r->get_decl(i))) { return 0; } + if (false && r->is_neg_tail(i)) { + return 0; + } if (r->is_neg_tail(i)) { if (!engine.get_fact(r->get_decl(i)).is_reachable()) { if (!new_tail) { @@ -53,11 +56,13 @@ namespace datalog { } new_tail = true; } - } else if (new_tail) { + } + else if (new_tail) { m_new_tail.push_back(r->get_tail(i)); m_new_tail_neg.push_back(true); } - } else { + } + else { SASSERT(!new_tail); if (!engine.get_fact(r->get_decl(i)).is_reachable()) { contained = false; From 510231df42f0d40a83121fa5363cd50cce6596ec Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 23 Aug 2016 12:26:38 -0300 Subject: [PATCH 158/536] fix to #717. The bottom-up COI filter can only use positive facts for filtering Signed-off-by: Nikolaj Bjorner --- src/muz/dataflow/dataflow.h | 6 +++--- src/muz/transforms/dl_mk_coi_filter.cpp | 5 ++--- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/muz/dataflow/dataflow.h b/src/muz/dataflow/dataflow.h index 1e52c5f93..d2be194eb 100644 --- a/src/muz/dataflow/dataflow.h +++ b/src/muz/dataflow/dataflow.h @@ -72,7 +72,7 @@ namespace datalog { } e->get_data().m_value->push_back(cur); } - if (cur->get_uninterpreted_tail_size() == 0) { + if (cur->get_positive_tail_size() == 0) { func_decl *sym = cur->get_head()->get_decl(); bool new_info = m_facts.insert_if_not_there2(sym, Fact())->get_data().m_value.init_up(m_context, cur); if (new_info) { @@ -97,7 +97,7 @@ namespace datalog { } void step_bottom_up() { - for(todo_set::iterator I = m_todo[m_todo_idx].begin(), + for(todo_set::iterator I = m_todo[m_todo_idx].begin(), E = m_todo[m_todo_idx].end(); I!=E; ++I) { ptr_vector * rules; if (!m_body2rules.find(*I, rules)) @@ -236,7 +236,7 @@ namespace datalog { return m_facts.get(m_rule->get_decl(idx), Fact::null_fact); } unsigned size() const { - return m_rule->get_uninterpreted_tail_size(); + return m_rule->get_positive_tail_size(); } }; diff --git a/src/muz/transforms/dl_mk_coi_filter.cpp b/src/muz/transforms/dl_mk_coi_filter.cpp index e3d01a537..0f155f65b 100644 --- a/src/muz/transforms/dl_mk_coi_filter.cpp +++ b/src/muz/transforms/dl_mk_coi_filter.cpp @@ -44,9 +44,7 @@ namespace datalog { if (m_context.has_facts(r->get_decl(i))) { return 0; } - if (false && r->is_neg_tail(i)) { - return 0; - } + if (r->is_neg_tail(i)) { if (!engine.get_fact(r->get_decl(i)).is_reachable()) { if (!new_tail) { @@ -62,6 +60,7 @@ namespace datalog { m_new_tail_neg.push_back(true); } } + else { SASSERT(!new_tail); if (!engine.get_fact(r->get_decl(i)).is_reachable()) { From 882c3bd0cdcfbaa0f8d0d7a04cee3009e151bb1e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 23 Aug 2016 18:18:11 -0300 Subject: [PATCH 159/536] fix unused variable warnings Signed-off-by: Nikolaj Bjorner --- src/ast/ast.cpp | 4 ++-- src/smt/smt_consequences.cpp | 1 - src/smt/smt_internalizer.cpp | 1 - 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/ast/ast.cpp b/src/ast/ast.cpp index 93769a3b4..050ada521 100644 --- a/src/ast/ast.cpp +++ b/src/ast/ast.cpp @@ -1865,8 +1865,8 @@ void ast_manager::delete_node(ast * n) { dec_array_ref(worklist, to_quantifier(n)->get_num_patterns(), to_quantifier(n)->get_patterns()); dec_array_ref(worklist, to_quantifier(n)->get_num_no_patterns(), to_quantifier(n)->get_no_patterns()); break; - default: - break; + default: + break; } if (m_debug_ref_count) { m_debug_free_indices.insert(n->m_id,0); diff --git a/src/smt/smt_consequences.cpp b/src/smt/smt_consequences.cpp index 1ae9f28e7..922156d46 100644 --- a/src/smt/smt_consequences.cpp +++ b/src/smt/smt_consequences.cpp @@ -234,7 +234,6 @@ namespace smt { expr* e = it->m_key; expr* val = it->m_value; push_scope(); - unsigned current_level = m_scope_lvl; literal lit; if (m.is_bool(e)) { diff --git a/src/smt/smt_internalizer.cpp b/src/smt/smt_internalizer.cpp index a17271e4e..d4880f7d7 100644 --- a/src/smt/smt_internalizer.cpp +++ b/src/smt/smt_internalizer.cpp @@ -1284,7 +1284,6 @@ namespace smt { TRACE("mk_clause", tout << "creating clause:\n"; display_literals(tout, num_lits, lits); tout << "\n";); switch (k) { case CLS_AUX: { - unsigned old_num_lits = num_lits; literal_buffer simp_lits; if (!simplify_aux_clause_literals(num_lits, lits, simp_lits)) return 0; // clause is equivalent to true; From d4539b8887306fb88add26efcc1fec36a90dbccb Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 30 Aug 2016 11:42:14 +0800 Subject: [PATCH 160/536] fix dt2bv transformation to only work with constants, issue #725 Signed-off-by: Nikolaj Bjorner --- src/tactic/bv/dt2bv_tactic.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/tactic/bv/dt2bv_tactic.cpp b/src/tactic/bv/dt2bv_tactic.cpp index 86717c807..e8763475b 100644 --- a/src/tactic/bv/dt2bv_tactic.cpp +++ b/src/tactic/bv/dt2bv_tactic.cpp @@ -112,7 +112,7 @@ class dt2bv_tactic : public tactic { unsigned idx = m_t.m_dt.get_constructor_idx(f); result = m_t.m_bv.mk_numeral(idx, bv_size); } - else { + else if (is_uninterp_const(a)) { // create a fresh variable, add bounds constraints for it. unsigned nc = m_t.m_dt.get_datatype_num_constructors(s); result = m.mk_fresh_const(f->get_name().str().c_str(), m_t.m_bv.mk_sort(bv_size)); @@ -130,6 +130,9 @@ class dt2bv_tactic : public tactic { m_t.m_ext->insert(f, f_def); m_t.m_filter->insert(to_app(result)->get_decl()); } + else { + return false; + } m_cache.insert(a, result); ++m_t.m_num_translated; return true; From 310c0f31a10ba2336897ab969f2f00abea61638c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 30 Aug 2016 12:07:06 +0800 Subject: [PATCH 161/536] use type constrsaints for co-variant subtying to enable .net 3.5 Signed-off-by: Nikolaj Bjorner --- src/api/dotnet/Context.cs | 60 ++++++++++++++++++------------------ src/api/dotnet/Expr.cs | 8 ++--- src/api/dotnet/Fixedpoint.cs | 4 +-- src/api/dotnet/FuncDecl.cs | 2 +- src/api/dotnet/Goal.cs | 2 +- src/api/dotnet/Quantifier.cs | 12 ++++---- src/api/dotnet/Solver.cs | 6 ++-- src/api/dotnet/Z3Object.cs | 2 +- 8 files changed, 48 insertions(+), 48 deletions(-) diff --git a/src/api/dotnet/Context.cs b/src/api/dotnet/Context.cs index b37dc12d7..6ca48fcb0 100644 --- a/src/api/dotnet/Context.cs +++ b/src/api/dotnet/Context.cs @@ -286,8 +286,8 @@ namespace Microsoft.Z3 Contract.Ensures(Contract.Result() != null); CheckContextMatch(name); - CheckContextMatch(fieldNames); - CheckContextMatch(fieldSorts); + CheckContextMatch(fieldNames); + CheckContextMatch(fieldSorts); return new TupleSort(this, name, (uint)fieldNames.Length, fieldNames, fieldSorts); } @@ -303,7 +303,7 @@ namespace Microsoft.Z3 Contract.Ensures(Contract.Result() != null); CheckContextMatch(name); - CheckContextMatch(enumNames); + CheckContextMatch(enumNames); return new EnumSort(this, name, enumNames); } @@ -423,7 +423,7 @@ namespace Microsoft.Z3 Contract.Ensures(Contract.Result() != null); CheckContextMatch(name); - CheckContextMatch(constructors); + CheckContextMatch(constructors); return new DatatypeSort(this, name, constructors); } @@ -436,7 +436,7 @@ namespace Microsoft.Z3 Contract.Requires(Contract.ForAll(constructors, c => c != null)); Contract.Ensures(Contract.Result() != null); - CheckContextMatch(constructors); + CheckContextMatch(constructors); return new DatatypeSort(this, MkSymbol(name), constructors); } @@ -454,7 +454,7 @@ namespace Microsoft.Z3 Contract.Requires(Contract.ForAll(names, name => name != null)); Contract.Ensures(Contract.Result() != null); - CheckContextMatch(names); + CheckContextMatch(names); uint n = (uint)names.Length; ConstructorList[] cla = new ConstructorList[n]; IntPtr[] n_constr = new IntPtr[n]; @@ -462,7 +462,7 @@ namespace Microsoft.Z3 { Constructor[] constructor = c[i]; Contract.Assume(Contract.ForAll(constructor, arr => arr != null), "Clousot does not support yet quantified formula on multidimensional arrays"); - CheckContextMatch(constructor); + CheckContextMatch(constructor); cla[i] = new ConstructorList(this, constructor); n_constr[i] = cla[i].NativeObject; } @@ -520,7 +520,7 @@ namespace Microsoft.Z3 Contract.Ensures(Contract.Result() != null); CheckContextMatch(name); - CheckContextMatch(domain); + CheckContextMatch(domain); CheckContextMatch(range); return new FuncDecl(this, name, domain, range); } @@ -551,7 +551,7 @@ namespace Microsoft.Z3 Contract.Requires(Contract.ForAll(domain, d => d != null)); Contract.Ensures(Contract.Result() != null); - CheckContextMatch(domain); + CheckContextMatch(domain); CheckContextMatch(range); return new FuncDecl(this, MkSymbol(name), domain, range); } @@ -582,7 +582,7 @@ namespace Microsoft.Z3 Contract.Requires(Contract.ForAll(domain, d => d != null)); Contract.Ensures(Contract.Result() != null); - CheckContextMatch(domain); + CheckContextMatch(domain); CheckContextMatch(range); return new FuncDecl(this, prefix, domain, range); } @@ -811,7 +811,7 @@ namespace Microsoft.Z3 Contract.Ensures(Contract.Result() != null); CheckContextMatch(f); - CheckContextMatch(args); + CheckContextMatch(args); return Expr.Create(this, f, args); } @@ -884,7 +884,7 @@ namespace Microsoft.Z3 Contract.Ensures(Contract.Result() != null); - CheckContextMatch(args); + CheckContextMatch(args); return new BoolExpr(this, Native.Z3_mk_distinct(nCtx, (uint)args.Length, AST.ArrayToNative(args))); } @@ -970,7 +970,7 @@ namespace Microsoft.Z3 Contract.Requires(Contract.ForAll(t, a => a != null)); Contract.Ensures(Contract.Result() != null); - CheckContextMatch(t); + CheckContextMatch(t); return new BoolExpr(this, Native.Z3_mk_and(nCtx, (uint)t.Length, AST.ArrayToNative(t))); } @@ -982,7 +982,7 @@ namespace Microsoft.Z3 Contract.Requires(t != null); Contract.Requires(Contract.ForAll(t, a => a != null)); Contract.Ensures(Contract.Result() != null); - CheckContextMatch(t); + CheckContextMatch(t); return new BoolExpr(this, Native.Z3_mk_and(nCtx, (uint)t.Count(), AST.EnumToNative(t))); } @@ -995,7 +995,7 @@ namespace Microsoft.Z3 Contract.Requires(Contract.ForAll(t, a => a != null)); Contract.Ensures(Contract.Result() != null); - CheckContextMatch(t); + CheckContextMatch(t); return new BoolExpr(this, Native.Z3_mk_or(nCtx, (uint)t.Length, AST.ArrayToNative(t))); } @@ -1025,7 +1025,7 @@ namespace Microsoft.Z3 Contract.Requires(Contract.ForAll(t, a => a != null)); Contract.Ensures(Contract.Result() != null); - CheckContextMatch(t); + CheckContextMatch(t); return (ArithExpr)Expr.Create(this, Native.Z3_mk_add(nCtx, (uint)t.Length, AST.ArrayToNative(t))); } @@ -1051,7 +1051,7 @@ namespace Microsoft.Z3 Contract.Requires(Contract.ForAll(t, a => a != null)); Contract.Ensures(Contract.Result() != null); - CheckContextMatch(t); + CheckContextMatch(t); return (ArithExpr)Expr.Create(this, Native.Z3_mk_mul(nCtx, (uint)t.Length, AST.ArrayToNative(t))); } @@ -1064,7 +1064,7 @@ namespace Microsoft.Z3 Contract.Requires(Contract.ForAll(t, a => a != null)); Contract.Ensures(Contract.Result() != null); - CheckContextMatch(t); + CheckContextMatch(t); return (ArithExpr)Expr.Create(this, Native.Z3_mk_mul(nCtx, (uint)t.Count(), AST.EnumToNative(t))); } @@ -1077,7 +1077,7 @@ namespace Microsoft.Z3 Contract.Requires(Contract.ForAll(t, a => a != null)); Contract.Ensures(Contract.Result() != null); - CheckContextMatch(t); + CheckContextMatch(t); return (ArithExpr)Expr.Create(this, Native.Z3_mk_sub(nCtx, (uint)t.Length, AST.ArrayToNative(t))); } @@ -2205,7 +2205,7 @@ namespace Microsoft.Z3 Contract.Ensures(Contract.Result() != null); CheckContextMatch(f); - CheckContextMatch(args); + CheckContextMatch(args); return (ArrayExpr)Expr.Create(this, Native.Z3_mk_map(nCtx, f.NativeObject, AST.ArrayLength(args), AST.ArrayToNative(args))); } @@ -2315,7 +2315,7 @@ namespace Microsoft.Z3 Contract.Requires(args != null); Contract.Requires(Contract.ForAll(args, a => a != null)); - CheckContextMatch(args); + CheckContextMatch(args); return (ArrayExpr)Expr.Create(this, Native.Z3_mk_set_union(nCtx, (uint)args.Length, AST.ArrayToNative(args))); } @@ -2328,7 +2328,7 @@ namespace Microsoft.Z3 Contract.Requires(Contract.ForAll(args, a => a != null)); Contract.Ensures(Contract.Result() != null); - CheckContextMatch(args); + CheckContextMatch(args); return (ArrayExpr)Expr.Create(this, Native.Z3_mk_set_intersect(nCtx, (uint)args.Length, AST.ArrayToNative(args))); } @@ -2429,7 +2429,7 @@ namespace Microsoft.Z3 Contract.Requires(Contract.ForAll(t, a => a != null)); Contract.Ensures(Contract.Result() != null); - CheckContextMatch(t); + CheckContextMatch(t); return new SeqExpr(this, Native.Z3_mk_seq_concat(nCtx, (uint)t.Length, AST.ArrayToNative(t))); } @@ -2593,7 +2593,7 @@ namespace Microsoft.Z3 Contract.Requires(Contract.ForAll(t, a => a != null)); Contract.Ensures(Contract.Result() != null); - CheckContextMatch(t); + CheckContextMatch(t); return new ReExpr(this, Native.Z3_mk_re_concat(nCtx, (uint)t.Length, AST.ArrayToNative(t))); } @@ -2606,7 +2606,7 @@ namespace Microsoft.Z3 Contract.Requires(Contract.ForAll(t, a => a != null)); Contract.Ensures(Contract.Result() != null); - CheckContextMatch(t); + CheckContextMatch(t); return new ReExpr(this, Native.Z3_mk_re_union(nCtx, (uint)t.Length, AST.ArrayToNative(t))); } @@ -2621,7 +2621,7 @@ namespace Microsoft.Z3 { Contract.Requires(args != null); Contract.Requires(Contract.Result() != null); - CheckContextMatch(args); + CheckContextMatch(args); return new BoolExpr(this, Native.Z3_mk_atmost(nCtx, (uint) args.Length, AST.ArrayToNative(args), k)); } @@ -2635,7 +2635,7 @@ namespace Microsoft.Z3 Contract.Requires(coeffs != null); Contract.Requires(args.Length == coeffs.Length); Contract.Requires(Contract.Result() != null); - CheckContextMatch(args); + CheckContextMatch(args); return new BoolExpr(this, Native.Z3_mk_pble(nCtx, (uint) args.Length, AST.ArrayToNative(args), coeffs, k)); @@ -3386,7 +3386,7 @@ namespace Microsoft.Z3 CheckContextMatch(t1); CheckContextMatch(t2); - CheckContextMatch(ts); + CheckContextMatch(ts); IntPtr last = IntPtr.Zero; if (ts != null && ts.Length > 0) @@ -3577,7 +3577,7 @@ namespace Microsoft.Z3 Contract.Requires(t == null || Contract.ForAll(t, tactic => tactic != null)); Contract.Ensures(Contract.Result() != null); - CheckContextMatch(t); + CheckContextMatch(t); return new Tactic(this, Native.Z3_tactic_par_or(nCtx, Tactic.ArrayLength(t), Tactic.ArrayToNative(t))); } @@ -4810,7 +4810,7 @@ namespace Microsoft.Z3 } [Pure] - internal void CheckContextMatch(IEnumerable arr) + internal void CheckContextMatch(IEnumerable arr) where T : Z3Object { Contract.Requires(arr == null || Contract.ForAll(arr, a => a != null)); diff --git a/src/api/dotnet/Expr.cs b/src/api/dotnet/Expr.cs index c995a12bd..cac62d2f0 100644 --- a/src/api/dotnet/Expr.cs +++ b/src/api/dotnet/Expr.cs @@ -98,7 +98,7 @@ namespace Microsoft.Z3 Contract.Requires(args != null); Contract.Requires(Contract.ForAll(args, a => a != null)); - Context.CheckContextMatch(args); + Context.CheckContextMatch(args); if (IsApp && args.Length != NumArgs) throw new Z3Exception("Number of arguments does not match"); NativeObject = Native.Z3_update_term(Context.nCtx, NativeObject, (uint)args.Length, Expr.ArrayToNative(args)); @@ -120,8 +120,8 @@ namespace Microsoft.Z3 Contract.Requires(Contract.ForAll(to, t => t != null)); Contract.Ensures(Contract.Result() != null); - Context.CheckContextMatch(from); - Context.CheckContextMatch(to); + Context.CheckContextMatch(from); + Context.CheckContextMatch(to); if (from.Length != to.Length) throw new Z3Exception("Argument sizes do not match"); return Expr.Create(Context, Native.Z3_substitute(Context.nCtx, NativeObject, (uint)from.Length, Expr.ArrayToNative(from), Expr.ArrayToNative(to))); @@ -152,7 +152,7 @@ namespace Microsoft.Z3 Contract.Requires(Contract.ForAll(to, t => t != null)); Contract.Ensures(Contract.Result() != null); - Context.CheckContextMatch(to); + Context.CheckContextMatch(to); return Expr.Create(Context, Native.Z3_substitute_vars(Context.nCtx, NativeObject, (uint)to.Length, Expr.ArrayToNative(to))); } diff --git a/src/api/dotnet/Fixedpoint.cs b/src/api/dotnet/Fixedpoint.cs index 66449ddbb..e2fb7fe5a 100644 --- a/src/api/dotnet/Fixedpoint.cs +++ b/src/api/dotnet/Fixedpoint.cs @@ -71,7 +71,7 @@ namespace Microsoft.Z3 Contract.Requires(constraints != null); Contract.Requires(Contract.ForAll(constraints, c => c != null)); - Context.CheckContextMatch(constraints); + Context.CheckContextMatch(constraints); foreach (BoolExpr a in constraints) { Native.Z3_fixedpoint_assert(Context.nCtx, NativeObject, a.NativeObject); @@ -151,7 +151,7 @@ namespace Microsoft.Z3 Contract.Requires(relations != null); Contract.Requires(Contract.ForAll(0, relations.Length, i => relations[i] != null)); - Context.CheckContextMatch(relations); + Context.CheckContextMatch(relations); Z3_lbool r = (Z3_lbool)Native.Z3_fixedpoint_query_relations(Context.nCtx, NativeObject, AST.ArrayLength(relations), AST.ArrayToNative(relations)); switch (r) diff --git a/src/api/dotnet/FuncDecl.cs b/src/api/dotnet/FuncDecl.cs index 15b6a59db..2f5cd0ce8 100644 --- a/src/api/dotnet/FuncDecl.cs +++ b/src/api/dotnet/FuncDecl.cs @@ -339,7 +339,7 @@ namespace Microsoft.Z3 { Contract.Requires(args == null || Contract.ForAll(args, a => a != null)); - Context.CheckContextMatch(args); + Context.CheckContextMatch(args); return Expr.Create(Context, this, args); } diff --git a/src/api/dotnet/Goal.cs b/src/api/dotnet/Goal.cs index 5ee44f34b..521b453f8 100644 --- a/src/api/dotnet/Goal.cs +++ b/src/api/dotnet/Goal.cs @@ -82,7 +82,7 @@ namespace Microsoft.Z3 Contract.Requires(constraints != null); Contract.Requires(Contract.ForAll(constraints, c => c != null)); - Context.CheckContextMatch(constraints); + Context.CheckContextMatch(constraints); foreach (BoolExpr c in constraints) { Contract.Assert(c != null); // It was an assume, now made an assert just to be sure we do not regress diff --git a/src/api/dotnet/Quantifier.cs b/src/api/dotnet/Quantifier.cs index 38e435309..eb21ed2b9 100644 --- a/src/api/dotnet/Quantifier.cs +++ b/src/api/dotnet/Quantifier.cs @@ -172,10 +172,10 @@ namespace Microsoft.Z3 Contract.Requires(patterns == null || Contract.ForAll(patterns, p => p != null)); Contract.Requires(noPatterns == null || Contract.ForAll(noPatterns, np => np != null)); - Context.CheckContextMatch(patterns); - Context.CheckContextMatch(noPatterns); - Context.CheckContextMatch(sorts); - Context.CheckContextMatch(names); + Context.CheckContextMatch(patterns); + Context.CheckContextMatch(noPatterns); + Context.CheckContextMatch(sorts); + Context.CheckContextMatch(names); Context.CheckContextMatch(body); if (sorts.Length != names.Length) @@ -212,8 +212,8 @@ namespace Microsoft.Z3 Contract.Requires(noPatterns == null || Contract.ForAll(noPatterns, np => np != null)); Contract.Requires(bound == null || Contract.ForAll(bound, n => n != null)); - Context.CheckContextMatch(noPatterns); - Context.CheckContextMatch(patterns); + Context.CheckContextMatch(noPatterns); + Context.CheckContextMatch(patterns); //Context.CheckContextMatch(bound); Context.CheckContextMatch(body); diff --git a/src/api/dotnet/Solver.cs b/src/api/dotnet/Solver.cs index f8f340373..8cb7670d7 100644 --- a/src/api/dotnet/Solver.cs +++ b/src/api/dotnet/Solver.cs @@ -111,7 +111,7 @@ namespace Microsoft.Z3 Contract.Requires(constraints != null); Contract.Requires(Contract.ForAll(constraints, c => c != null)); - Context.CheckContextMatch(constraints); + Context.CheckContextMatch(constraints); foreach (BoolExpr a in constraints) { Native.Z3_solver_assert(Context.nCtx, NativeObject, a.NativeObject); @@ -142,8 +142,8 @@ namespace Microsoft.Z3 Contract.Requires(constraints != null); Contract.Requires(Contract.ForAll(constraints, c => c != null)); Contract.Requires(Contract.ForAll(ps, c => c != null)); - Context.CheckContextMatch(constraints); - Context.CheckContextMatch(ps); + Context.CheckContextMatch(constraints); + Context.CheckContextMatch(ps); if (constraints.Length != ps.Length) throw new Z3Exception("Argument size mismatch"); diff --git a/src/api/dotnet/Z3Object.cs b/src/api/dotnet/Z3Object.cs index cd6803341..f32ba30af 100644 --- a/src/api/dotnet/Z3Object.cs +++ b/src/api/dotnet/Z3Object.cs @@ -138,7 +138,7 @@ namespace Microsoft.Z3 } [Pure] - internal static IntPtr[] EnumToNative(IEnumerable a) + internal static IntPtr[] EnumToNative(IEnumerable a) where T : Z3Object { Contract.Ensures(a == null || Contract.Result() != null); Contract.Ensures(a == null || Contract.Result().Length == a.Count()); From 237fde1f76e8d2c1b90dbc17cfdea6f7f7494922 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 31 Aug 2016 09:57:46 +0800 Subject: [PATCH 162/536] fix crash during shutdown. Issue #719 Signed-off-by: Nikolaj Bjorner --- src/ast/ast.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/ast/ast.cpp b/src/ast/ast.cpp index 050ada521..440179ba8 100644 --- a/src/ast/ast.cpp +++ b/src/ast/ast.cpp @@ -78,7 +78,10 @@ void parameter::del_eh(ast_manager & m, family_id fid) { } else if (is_external()) { SASSERT(fid != null_family_id); - m.get_plugin(fid)->del(*this); + decl_plugin * plugin = m.get_plugin(fid); + if (plugin) { + plugin->del(*this); + } } } @@ -1418,9 +1421,10 @@ ast_manager::~ast_manager() { } it = m_plugins.begin(); for (; it != end; ++it) { - if (*it) + if (*it) dealloc(*it); } + m_plugins.reset(); while (!m_ast_table.empty()) { DEBUG_CODE(std::cout << "ast_manager LEAKED: " << m_ast_table.size() << std::endl;); ptr_vector roots; From 4d9aadde351bb57c62db68e19f1d686a07260d0a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 31 Aug 2016 16:15:36 +0800 Subject: [PATCH 163/536] updated consequence finder to fix bug in processing enumeration types Signed-off-by: Nikolaj Bjorner --- src/api/api_context.cpp | 1 + src/smt/smt_consequences.cpp | 147 ++++++++++++++++++++--------------- src/smt/smt_context.h | 1 + src/smt/theory_seq.cpp | 26 ++++++- src/smt/theory_seq.h | 2 + 5 files changed, 112 insertions(+), 65 deletions(-) diff --git a/src/api/api_context.cpp b/src/api/api_context.cpp index 418ccc58c..b6c3384e7 100644 --- a/src/api/api_context.cpp +++ b/src/api/api_context.cpp @@ -415,6 +415,7 @@ extern "C" { return; } mk_c(c)->m().dec_ref(to_ast(a)); + Z3_CATCH; } diff --git a/src/smt/smt_consequences.cpp b/src/smt/smt_consequences.cpp index 922156d46..e71abf39d 100644 --- a/src/smt/smt_consequences.cpp +++ b/src/smt/smt_consequences.cpp @@ -18,6 +18,7 @@ Revision History: --*/ #include "smt_context.h" #include "ast_util.h" +#include "datatype_decl_plugin.h" namespace smt { @@ -31,74 +32,85 @@ namespace smt { return mk_and(premises); } - void context::extract_fixed_consequences(unsigned start, obj_map& vars, uint_set const& assumptions, expr_ref_vector& conseq) { + void context::extract_fixed_consequences(literal lit, obj_map& vars, uint_set const& assumptions, expr_ref_vector& conseq) { ast_manager& m = m_manager; + datatype_util dt(m); + expr* e1, *e2; + expr_ref fml(m); + if (lit == true_literal) return; + expr* e = bool_var2expr(lit.var()); + uint_set s; + if (assumptions.contains(lit.var())) { + s.insert(lit.var()); + } + else { + b_justification js = get_justification(lit.var()); + switch (js.get_kind()) { + case b_justification::CLAUSE: { + clause * cls = js.get_clause(); + unsigned num_lits = cls->get_num_literals(); + for (unsigned j = 0; j < num_lits; ++j) { + literal lit2 = cls->get_literal(j); + if (lit2.var() != lit.var()) { + s |= m_antecedents.find(lit2.var()); + } + } + break; + } + case b_justification::BIN_CLAUSE: { + s |= m_antecedents.find(js.get_literal().var()); + break; + } + case b_justification::AXIOM: { + break; + } + case b_justification::JUSTIFICATION: { + literal_vector literals; + m_conflict_resolution->justification2literals(js.get_justification(), literals); + for (unsigned j = 0; j < literals.size(); ++j) { + s |= m_antecedents.find(literals[j].var()); + } + break; + } + } + } + m_antecedents.insert(lit.var(), s); + TRACE("context", display_literal_verbose(tout, lit); tout << " " << s << "\n";); + bool found = false; + if (vars.contains(e)) { + found = true; + fml = lit.sign() ? m.mk_not(e) : e; + vars.erase(e); + } + else if (!lit.sign() && m.is_eq(e, e1, e2)) { + if (vars.contains(e2)) { + std::swap(e1, e2); + } + if (vars.contains(e1) && m.is_value(e2)) { + found = true; + fml = e; + vars.erase(e1); + } + } + else if (!lit.sign() && is_app(e) && dt.is_recognizer(to_app(e)->get_decl())) { + if (vars.contains(to_app(e)->get_arg(0))) { + found = true; + fml = m.mk_eq(to_app(e)->get_arg(0), m.mk_const(dt.get_recognizer_constructor(to_app(e)->get_decl()))); + vars.erase(to_app(e)->get_arg(0)); + } + } + if (found) { + fml = m.mk_implies(antecedent2fml(s), fml); + conseq.push_back(fml); + } + } + + void context::extract_fixed_consequences(unsigned start, obj_map& vars, uint_set const& assumptions, expr_ref_vector& conseq) { pop_to_search_lvl(); literal_vector const& lits = assigned_literals(); unsigned sz = lits.size(); - expr* e1, *e2; - expr_ref fml(m); for (unsigned i = start; i < sz; ++i) { - literal lit = lits[i]; - if (lit == true_literal) continue; - expr* e = bool_var2expr(lit.var()); - uint_set s; - if (assumptions.contains(lit.var())) { - s.insert(lit.var()); - } - else { - b_justification js = get_justification(lit.var()); - switch (js.get_kind()) { - case b_justification::CLAUSE: { - clause * cls = js.get_clause(); - unsigned num_lits = cls->get_num_literals(); - for (unsigned j = 0; j < num_lits; ++j) { - literal lit2 = cls->get_literal(j); - if (lit2.var() != lit.var()) { - s |= m_antecedents.find(lit2.var()); - } - } - break; - } - case b_justification::BIN_CLAUSE: { - s |= m_antecedents.find(js.get_literal().var()); - break; - } - case b_justification::AXIOM: { - break; - } - case b_justification::JUSTIFICATION: { - literal_vector literals; - m_conflict_resolution->justification2literals(js.get_justification(), literals); - for (unsigned j = 0; j < literals.size(); ++j) { - s |= m_antecedents.find(literals[j].var()); - } - break; - } - } - } - m_antecedents.insert(lit.var(), s); - TRACE("context", display_literal_verbose(tout, lit); tout << " " << s << "\n";); - bool found = false; - if (vars.contains(e)) { - found = true; - fml = lit.sign()?m.mk_not(e):e; - vars.erase(e); - } - else if (!lit.sign() && m.is_eq(e, e1, e2)) { - if (vars.contains(e2)) { - std::swap(e1, e2); - } - if (vars.contains(e1) && m.is_value(e2)) { - found = true; - fml = e; - vars.erase(e1); - } - } - if (found) { - fml = m.mk_implies(antecedent2fml(s), fml); - conseq.push_back(fml); - } + extract_fixed_consequences(lits[i], vars, assumptions, conseq); } } @@ -240,6 +252,7 @@ namespace smt { lit = literal(get_bool_var(e), m.is_true(val)); } else { + TRACE("context", tout << mk_pp(e, m) << " " << mk_pp(val, m) << "\n";); eq = mk_eq_atom(e, val); internalize_formula(eq, false); lit = literal(get_bool_var(eq), true); @@ -259,9 +272,10 @@ namespace smt { } break; } - if (get_assignment(lit) == l_true) { + if (is_sat == l_true && get_assignment(lit) == l_true) { var2val.erase(e); unfixed.push_back(e); + TRACE("context", tout << mk_pp(e, m) << " is unfixed\n";); } else if (get_assign_level(lit) > get_search_level()) { TRACE("context", tout << "Retry fixing: " << mk_pp(e, m) << "\n";); @@ -305,10 +319,15 @@ namespace smt { << " unfixed-deleted: " << num_unfixed << ")\n";); } + TRACE("context", tout << "finishing " << mk_pp(e, m) << "\n";); if (var2val.contains(e)) { TRACE("context", tout << "Fixed value to " << mk_pp(e, m) << " was not processed\n";); expr_ref fml(m); fml = m.mk_eq(e, var2val.find(e)); + if (!m_antecedents.contains(lit.var())) + { + extract_fixed_consequences(lit, var2val, _assumptions, conseq); + } fml = m.mk_implies(antecedent2fml(m_antecedents[lit.var()]), fml); conseq.push_back(fml); var2val.erase(e); diff --git a/src/smt/smt_context.h b/src/smt/smt_context.h index 48f6004e9..1a5952305 100644 --- a/src/smt/smt_context.h +++ b/src/smt/smt_context.h @@ -1345,6 +1345,7 @@ namespace smt { vector b2v, ast_translation& tr); u_map m_antecedents; + void extract_fixed_consequences(literal lit, obj_map& var2val, uint_set const& assumptions, expr_ref_vector& conseq); void extract_fixed_consequences(unsigned idx, obj_map& var2val, uint_set const& assumptions, expr_ref_vector& conseq); unsigned delete_unfixed(obj_map& var2val, expr_ref_vector& unfixed); diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index 6a2208ad4..5b862b2d1 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -249,6 +249,7 @@ final_check_status theory_seq::final_check_eh() { } m_new_propagation = false; TRACE("seq", display(tout << "level: " << get_context().get_scope_level() << "\n");); + TRACE("seq_verbose", get_context().display(tout);); if (simplify_and_solve_eqs()) { ++m_stats.m_solve_eqs; TRACE("seq", tout << ">>solve_eqs\n";); @@ -1009,6 +1010,17 @@ bool theory_seq::is_nth(expr* e) const { return is_skolem(m_nth, e); } +bool theory_seq::is_nth(expr* e, expr*& e1, expr*& e2) const { + if (is_nth(e)) { + e1 = to_app(e)->get_arg(0); + e2 = to_app(e)->get_arg(1); + return true; + } + else { + return false; + } +} + bool theory_seq::is_tail(expr* e, expr*& s, unsigned& idx) const { rational r; return @@ -1038,6 +1050,10 @@ expr_ref theory_seq::mk_nth(expr* s, expr* idx) { return mk_skolem(m_nth, s, idx, 0, char_sort); } +expr_ref theory_seq::mk_sk_ite(expr* c, expr* t, expr* e) { + return mk_skolem(symbol("seq.if"), c, t, e, m.get_sort(t)); +} + expr_ref theory_seq::mk_last(expr* s) { zstring str; if (m_util.str.is_string(s, str) && str.length() > 0) { @@ -1133,7 +1149,7 @@ bool theory_seq::check_extensionality() { continue; } TRACE("seq", tout << m_lhs << " = " << m_rhs << "\n";); - ctx.assume_eq(n1, n2); + ctx.assume_eq(n1, n2); return false; } } @@ -2668,6 +2684,13 @@ expr_ref theory_seq::expand(expr* e0, dependency*& eqs) { } else if (m.is_ite(e, e1, e2, e3)) { literal lit(mk_literal(e1)); +#if 0 + expr_ref sk_ite = mk_sk_ite(e1, e2, e3); + add_axiom(~lit, mk_eq(e2, sk_ite, false)); + add_axiom( lit, mk_eq(e3, sk_ite, false)); + result = sk_ite; + +#else switch (ctx.get_assignment(lit)) { case l_true: deps = m_dm.mk_join(deps, m_dm.mk_leaf(assumption(lit))); @@ -2684,6 +2707,7 @@ expr_ref theory_seq::expand(expr* e0, dependency*& eqs) { tout << lit << "@ level: " << ctx.get_scope_level() << "\n";); break; } +#endif } else if (m_util.str.is_itos(e, e1)) { rational val; diff --git a/src/smt/theory_seq.h b/src/smt/theory_seq.h index 187573623..21955bf30 100644 --- a/src/smt/theory_seq.h +++ b/src/smt/theory_seq.h @@ -449,10 +449,12 @@ namespace smt { bool is_var(expr* b); bool add_solution(expr* l, expr* r, dependency* dep); bool is_nth(expr* a) const; + bool is_nth(expr* a, expr*& e1, expr*& e2) const; bool is_tail(expr* a, expr*& s, unsigned& idx) const; bool is_eq(expr* e, expr*& a, expr*& b) const; bool is_pre(expr* e, expr*& s, expr*& i); bool is_post(expr* e, expr*& s, expr*& i); + expr_ref mk_sk_ite(expr* c, expr* t, expr* f); expr_ref mk_nth(expr* s, expr* idx); expr_ref mk_last(expr* e); expr_ref mk_first(expr* e); From c746d46d80ecf1ab6c383ab173be226528762539 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 1 Sep 2016 16:21:23 +0800 Subject: [PATCH 164/536] add validation code, fix bugs in consequence finder Signed-off-by: Nikolaj Bjorner --- src/smt/smt_conflict_resolution.cpp | 1 - src/smt/smt_consequences.cpp | 76 +++++++++++++++++++++++++---- src/smt/smt_context.h | 3 ++ 3 files changed, 70 insertions(+), 10 deletions(-) diff --git a/src/smt/smt_conflict_resolution.cpp b/src/smt/smt_conflict_resolution.cpp index 6907d6f37..8fb8f9f70 100644 --- a/src/smt/smt_conflict_resolution.cpp +++ b/src/smt/smt_conflict_resolution.cpp @@ -403,7 +403,6 @@ namespace smt { // the previous levels were already inconsistent, or the inconsistency was // triggered by an axiom or justification proof wrapper, this two kinds // of justification are considered level zero. - if (m_conflict_lvl <= m_ctx.get_search_level()) { TRACE("conflict", tout << "problem is unsat\n";); if (m_manager.proofs_enabled()) diff --git a/src/smt/smt_consequences.cpp b/src/smt/smt_consequences.cpp index e71abf39d..8aa83e407 100644 --- a/src/smt/smt_consequences.cpp +++ b/src/smt/smt_consequences.cpp @@ -107,11 +107,13 @@ namespace smt { void context::extract_fixed_consequences(unsigned start, obj_map& vars, uint_set const& assumptions, expr_ref_vector& conseq) { pop_to_search_lvl(); + SASSERT(!inconsistent()); literal_vector const& lits = assigned_literals(); unsigned sz = lits.size(); for (unsigned i = start; i < sz; ++i) { extract_fixed_consequences(lits[i], vars, assumptions, conseq); } + SASSERT(!inconsistent()); } unsigned context::delete_unfixed(obj_map& var2val, expr_ref_vector& unfixed) { @@ -160,6 +162,7 @@ namespace smt { // Extract equalities that are congruent at the search level. // unsigned context::extract_fixed_eqs(obj_map& var2val, expr_ref_vector& conseq) { + TRACE("context", tout << "extract fixed consequences\n";); ast_manager& m = m_manager; ptr_vector to_delete; expr_ref fml(m), eq(m); @@ -187,9 +190,10 @@ namespace smt { } eq = mk_eq_atom(k, v); internalize_formula(eq, false); - literal lit(get_bool_var(eq), true); + literal lit(get_bool_var(eq), false); literals.push_back(lit); mk_clause(literals.size(), literals.c_ptr(), 0); + TRACE("context", display_literals_verbose(tout, literals.size(), literals.c_ptr());); } } for (unsigned i = 0; i < to_delete.size(); ++i) { @@ -247,6 +251,9 @@ namespace smt { expr* val = it->m_value; push_scope(); + TRACE("context", tout << "scope level: " << get_scope_level() << "\n";); + SASSERT(!inconsistent()); + literal lit; if (m.is_bool(e)) { lit = literal(get_bool_var(e), m.is_true(val)); @@ -277,19 +284,29 @@ namespace smt { unfixed.push_back(e); TRACE("context", tout << mk_pp(e, m) << " is unfixed\n";); } - else if (get_assign_level(lit) > get_search_level()) { + else if (is_sat == l_true && get_assign_level(lit) > get_search_level()) { TRACE("context", tout << "Retry fixing: " << mk_pp(e, m) << "\n";); - pop_to_search_lvl(); + extract_fixed_consequences(num_units, var2val, _assumptions, conseq); ++num_reiterations; continue; } else { - TRACE("context", tout << "Fixed: " << mk_pp(e, m) << "\n";); + // The state can be labeled as inconsistent when the implied consequence does + // not depend on assumptions, then the conflict level sits at the search level + // which causes the conflict resolver to decide that the state is unsat. + if (l_false == is_sat) { + SASSERT(inconsistent()); + m_conflict = null_b_justification; + m_not_l = null_literal; + } + TRACE("context", tout << "Fixed: " << mk_pp(e, m) << " " << is_sat << "\n"; + if (is_sat == l_false) display(tout);); + } ++num_iterations; bool apply_slow_pass = model_threshold <= num_iterations || num_iterations <= 2; - if (apply_slow_pass) { + if (apply_slow_pass && is_sat == l_true) { num_unfixed += delete_unfixed(var2val, unfixed); // The next time we check the model is after 1.5 additional iterations. model_threshold *= 3; @@ -320,14 +337,14 @@ namespace smt { << ")\n";); } TRACE("context", tout << "finishing " << mk_pp(e, m) << "\n";); + SASSERT(!inconsistent()); if (var2val.contains(e)) { TRACE("context", tout << "Fixed value to " << mk_pp(e, m) << " was not processed\n";); expr_ref fml(m); fml = m.mk_eq(e, var2val.find(e)); - if (!m_antecedents.contains(lit.var())) - { - extract_fixed_consequences(lit, var2val, _assumptions, conseq); - } + if (!m_antecedents.contains(lit.var())) { + extract_fixed_consequences(lit, var2val, _assumptions, conseq); + } fml = m.mk_implies(antecedent2fml(m_antecedents[lit.var()]), fml); conseq.push_back(fml); var2val.erase(e); @@ -335,7 +352,48 @@ namespace smt { } } end_search(); + DEBUG_CODE(validate_consequences(assumptions, vars, conseq, unfixed);); return l_true; } + void context::validate_consequences(expr_ref_vector const& assumptions, expr_ref_vector const& vars, + expr_ref_vector const& conseq, expr_ref_vector const& unfixed) { + ast_manager& m = m_manager; + expr_ref tmp(m); + SASSERT(!inconsistent()); + for (unsigned i = 0; i < conseq.size(); ++i) { + push(); + for (unsigned j = 0; j < assumptions.size(); ++j) { + assert_expr(assumptions[j]); + } + TRACE("context", tout << "checking: " << mk_pp(conseq[i], m) << "\n";); + tmp = m.mk_not(conseq[i]); + assert_expr(tmp); + lbool is_sat = check(); + SASSERT(is_sat != l_true); + pop(1); + } + model_ref mdl; + for (unsigned i = 0; i < unfixed.size(); ++i) { + push(); + for (unsigned j = 0; j < assumptions.size(); ++j) { + assert_expr(assumptions[j]); + } + TRACE("context", tout << "checking unfixed: " << mk_pp(unfixed[i], m) << "\n";); + lbool is_sat = check(); + SASSERT(is_sat != l_false); + if (is_sat == l_true) { + get_model(mdl); + mdl->eval(unfixed[i], tmp); + if (m.is_value(tmp)) { + tmp = m.mk_not(m.mk_eq(unfixed[i], tmp)); + assert_expr(tmp); + is_sat = check(); + SASSERT(is_sat != l_false); + } + } + pop(1); + } + } + } diff --git a/src/smt/smt_context.h b/src/smt/smt_context.h index 1a5952305..69388e586 100644 --- a/src/smt/smt_context.h +++ b/src/smt/smt_context.h @@ -1354,6 +1354,9 @@ namespace smt { expr_ref antecedent2fml(uint_set const& ante); + void validate_consequences(expr_ref_vector const& assumptions, expr_ref_vector const& vars, + expr_ref_vector const& conseq, expr_ref_vector const& unfixed); + public: context(ast_manager & m, smt_params & fp, params_ref const & p = params_ref()); From dc48008d4654e0d1c966519c18f0d48f1761770b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 2 Sep 2016 11:00:40 +0800 Subject: [PATCH 165/536] fixestoconsequences Signed-off-by: Nikolaj Bjorner --- src/smt/smt_consequences.cpp | 106 +++++++++++++++++++++++++++++++---- src/smt/smt_context.cpp | 9 ++- src/smt/smt_context.h | 2 +- 3 files changed, 103 insertions(+), 14 deletions(-) diff --git a/src/smt/smt_consequences.cpp b/src/smt/smt_consequences.cpp index 8aa83e407..9e026760c 100644 --- a/src/smt/smt_consequences.cpp +++ b/src/smt/smt_consequences.cpp @@ -19,6 +19,7 @@ Revision History: #include "smt_context.h" #include "ast_util.h" #include "datatype_decl_plugin.h" +#include "model_pp.h" namespace smt { @@ -32,6 +33,15 @@ namespace smt { return mk_and(premises); } + // + // The literal lit is assigned at the search level, so it follows from the assumptions. + // We retrieve the set of assumptions it depends on in the set 's'. + // The map m_antecedents contains the association from these literals to the assumptions they depend on. + // We then examine the contents of the literal lit and augment the set of consequences in one of the following cases: + // - e is a propositional atom and it is one of the variables that is to be fixed. + // - e is an equality between a variable and value that is to be fixed. + // - e is a data-type recognizer of a variable that is to be fixed. + // void context::extract_fixed_consequences(literal lit, obj_map& vars, uint_set const& assumptions, expr_ref_vector& conseq) { ast_manager& m = m_manager; datatype_util dt(m); @@ -48,6 +58,7 @@ namespace smt { switch (js.get_kind()) { case b_justification::CLAUSE: { clause * cls = js.get_clause(); + if (!cls) break; unsigned num_lits = cls->get_num_literals(); for (unsigned j = 0; j < num_lits; ++j) { literal lit2 = cls->get_literal(j); @@ -115,6 +126,18 @@ namespace smt { } SASSERT(!inconsistent()); } + + + // + // The assignment stack is assumed consistent. + // For each Boolean variable, we check if there is a literal assigned to the + // opposite value of the reference model, and for non-Boolean variables we + // check if the current state forces the variable to be distinct from the reference value. + // + // For yet to be determined Boolean variables we furthermore force the phase to be opposite + // to the reference value in the attempt to let the sat engine emerge with a model that + // rules out as many non-fixed variables as possible. + // unsigned context::delete_unfixed(obj_map& var2val, expr_ref_vector& unfixed) { ast_manager& m = m_manager; @@ -158,8 +181,12 @@ namespace smt { return to_delete.size(); } +#define are_equal(v, k) (e_internalized(k) && e_internalized(v) && get_enode(k)->get_root() == get_enode(v)->get_root()) + // // Extract equalities that are congruent at the search level. + // Add a clause to short-circuit the congruence justifications for + // next rounds. // unsigned context::extract_fixed_eqs(obj_map& var2val, expr_ref_vector& conseq) { TRACE("context", tout << "extract fixed consequences\n";); @@ -170,8 +197,7 @@ namespace smt { for (; it != end; ++it) { expr* k = it->m_key; expr* v = it->m_value; - if (!m.is_bool(k) && e_internalized(k) && e_internalized(v) && - get_enode(k)->get_root() == get_enode(v)->get_root()) { + if (!m.is_bool(k) && are_equal(k, v)) { literal_vector literals; m_conflict_resolution->eq2literals(get_enode(v), get_enode(k), literals); uint_set s; @@ -208,6 +234,7 @@ namespace smt { expr_ref_vector& unfixed) { m_antecedents.reset(); + pop_to_base_lvl(); lbool is_sat = check(assumptions.size(), assumptions.c_ptr()); if (is_sat != l_true) { return is_sat; @@ -223,6 +250,7 @@ namespace smt { expr_ref_vector trail(m); model_evaluator eval(*mdl.get()); expr_ref val(m); + TRACE("context", model_pp(tout, *mdl);); for (unsigned i = 0; i < vars.size(); ++i) { eval(vars[i], val); if (m.is_value(val)) { @@ -249,23 +277,39 @@ namespace smt { obj_map::iterator it = var2val.begin(); expr* e = it->m_key; expr* val = it->m_value; - push_scope(); TRACE("context", tout << "scope level: " << get_scope_level() << "\n";); SASSERT(!inconsistent()); + // + // The current variable is checked to be a backbone + // We add the negation of the reference assignment to the variable. + // If the variable is a Boolean, it means adding literal that has + // the opposite value of the current reference model. + // If the variable is a non-Boolean, it means adding a disequality. + // literal lit; if (m.is_bool(e)) { lit = literal(get_bool_var(e), m.is_true(val)); } else { - TRACE("context", tout << mk_pp(e, m) << " " << mk_pp(val, m) << "\n";); eq = mk_eq_atom(e, val); internalize_formula(eq, false); lit = literal(get_bool_var(eq), true); + TRACE("context", tout << mk_pp(e, m) << " " << mk_pp(val, m) << "\n"; + display_literal_verbose(tout, lit); tout << "\n"; + tout << "Equal: " << are_equal(e, val) << "\n";); } + mark_as_relevant(lit); + push_scope(); assign(lit, b_justification::mk_axiom(), true); flet l(m_searching, true); + + // + // We check if the current assignment stack can be extended to a + // satisfying assignment. bounded search may decide to restart, + // in which case it returns l_undef and clears search failure. + // while (true) { is_sat = bounded_search(); TRACE("context", tout << "search result: " << is_sat << "\n";); @@ -279,21 +323,41 @@ namespace smt { } break; } - if (is_sat == l_true && get_assignment(lit) == l_true) { + // + // If the state is satisfiable with the current variable assigned to + // a different value from the reference model, it is unfixed. + // + // If it is assigned above the search level we can't conclude anything + // about its value. + // extract_fixed_consequences pops the assignment stack to the search level + // so this sets up the state to retry finding fixed values. + // + // Otherwise, the variable is fixed. + // - it is either assigned at the search level to l_false, or + // - the state is l_false, which means that the variable is fixed by + // the background constraints (and does not depend on assumptions). + // + if (is_sat == l_true && get_assignment(lit) == l_true && is_relevant(lit)) { var2val.erase(e); unfixed.push_back(e); - TRACE("context", tout << mk_pp(e, m) << " is unfixed\n";); + SASSERT(!are_equal(e, val)); + TRACE("context", tout << mk_pp(e, m) << " is unfixed\n"; + display_literal_verbose(tout, lit); tout << "\n"; + tout << "relevant: " << is_relevant(lit) << "\n"; + display(tout);); } - else if (is_sat == l_true && get_assign_level(lit) > get_search_level()) { + else if (is_sat == l_true && (get_assign_level(lit) > get_search_level() || !is_relevant(lit))) { TRACE("context", tout << "Retry fixing: " << mk_pp(e, m) << "\n";); extract_fixed_consequences(num_units, var2val, _assumptions, conseq); ++num_reiterations; continue; } else { + // // The state can be labeled as inconsistent when the implied consequence does // not depend on assumptions, then the conflict level sits at the search level // which causes the conflict resolver to decide that the state is unsat. + // if (l_false == is_sat) { SASSERT(inconsistent()); m_conflict = null_b_justification; @@ -305,6 +369,11 @@ namespace smt { } ++num_iterations; + // + // Check the slow pass: it retrieves an updated model and checks if the + // values in the updated model differ from the values in the reference + // model. + // bool apply_slow_pass = model_threshold <= num_iterations || num_iterations <= 2; if (apply_slow_pass && is_sat == l_true) { num_unfixed += delete_unfixed(var2val, unfixed); @@ -312,11 +381,20 @@ namespace smt { model_threshold *= 3; model_threshold /= 2; } - // repeat until we either have a model with negated literal or - // the literal is implied at base. + // + // Walk the assignment stack at level 1 for learned consequences. + // The current literal should be assigned at the search level unless + // the state is is_sat == l_true and the assignment to lit is l_true. + // This condition is checked above. + // extract_fixed_consequences(num_units, var2val, _assumptions, conseq); num_units = assigned_literals().size(); + + // + // Fixed equalities can be extracted by walking all variables and checking + // if the congruence roots are equal at the search level. + // if (apply_slow_pass) { num_fixed_eqs += extract_fixed_eqs(var2val, conseq); IF_VERBOSE(1, verbose_stream() << "(get-consequences" @@ -338,6 +416,11 @@ namespace smt { } TRACE("context", tout << "finishing " << mk_pp(e, m) << "\n";); SASSERT(!inconsistent()); + + // + // This becomes unnecessary when the fixed consequence are + // completely extracted. + // if (var2val.contains(e)) { TRACE("context", tout << "Fixed value to " << mk_pp(e, m) << " was not processed\n";); expr_ref fml(m); @@ -348,7 +431,6 @@ namespace smt { fml = m.mk_implies(antecedent2fml(m_antecedents[lit.var()]), fml); conseq.push_back(fml); var2val.erase(e); - SASSERT(get_assignment(lit) == l_false); } } end_search(); @@ -356,6 +438,10 @@ namespace smt { return l_true; } + // + // Validate, in a slow pass, that the current consequences are correctly + // extracted. + // void context::validate_consequences(expr_ref_vector const& assumptions, expr_ref_vector const& vars, expr_ref_vector const& conseq, expr_ref_vector const& unfixed) { ast_manager& m = m_manager; diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index c692173e6..0b3147d6b 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -1094,7 +1094,7 @@ namespace smt { \brief This method is invoked when a new disequality is asserted. The disequality is propagated to the theories. */ - void context::add_diseq(enode * n1, enode * n2) { + bool context::add_diseq(enode * n1, enode * n2) { enode * r1 = n1->get_root(); enode * r2 = n2->get_root(); TRACE("add_diseq", tout << "assigning: #" << n1->get_owner_id() << " != #" << n2->get_owner_id() << "\n"; @@ -1111,7 +1111,7 @@ namespace smt { if (r1 == r2) { TRACE("add_diseq_inconsistent", tout << "add_diseq #" << n1->get_owner_id() << " #" << n2->get_owner_id() << " inconsistency, scope_lvl: " << m_scope_lvl << "\n";); - return; // context is inconsistent + return false; // context is inconsistent } // Propagate disequalities to theories @@ -1145,6 +1145,7 @@ namespace smt { l1 = l1->get_next(); } } + return true; } /** @@ -1400,7 +1401,9 @@ namespace smt { } else { TRACE("add_diseq", display_eq_detail(tout, bool_var2enode(v));); - add_diseq(get_enode(lhs), get_enode(rhs)); + if (!add_diseq(get_enode(lhs), get_enode(rhs)) && !inconsistent()) { + set_conflict(b_justification(mk_justification(eq_propagation_justification(get_enode(lhs), get_enode(rhs)))), ~l); + } } } else if (d.is_theory_atom()) { diff --git a/src/smt/smt_context.h b/src/smt/smt_context.h index 69388e586..79b969118 100644 --- a/src/smt/smt_context.h +++ b/src/smt/smt_context.h @@ -942,7 +942,7 @@ namespace smt { push_eq(n1, n2, eq_justification::mk_cg(used_commutativity)); } - void add_diseq(enode * n1, enode * n2); + bool add_diseq(enode * n1, enode * n2); void assign_quantifier(quantifier * q); From c6b0fc444c6e36bc2c7696c24c724b33ac5e3586 Mon Sep 17 00:00:00 2001 From: AlexVonB Date: Mon, 5 Sep 2016 16:22:00 +0200 Subject: [PATCH 166/536] Fix VisualStudio 2010 compiler warning C4100 When compiling with Visual Studio 2010 the buildlog warns of the following: `z3++.h: warning C4100: 'e' : unreferenced formal parameter` and `z3++.h: warning C4100: 'c' : unreferenced formal parameter`. This merge request removes this warning. --- src/api/c++/z3++.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index 3271d4b0f..a9a4efd03 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -127,7 +127,7 @@ namespace z3 { */ class context { Z3_context m_ctx; - static void error_handler(Z3_context c, Z3_error_code e) { /* do nothing */ } + static void error_handler(Z3_context /*c*/, Z3_error_code /*e*/) { /* do nothing */ } void init(config & c) { m_ctx = Z3_mk_context_rc(c); Z3_set_error_handler(m_ctx, error_handler); From 3b70dd6678ecd307d1e13b89596ec1f57c0c5aff Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 6 Sep 2016 14:29:40 +0800 Subject: [PATCH 167/536] tuning by using get_consequences2 Signed-off-by: Nikolaj Bjorner --- src/smt/smt_consequences.cpp | 164 ++++++++++++++++++++++++++++++----- src/smt/smt_context.h | 7 +- src/smt/smt_kernel.cpp | 2 +- 3 files changed, 148 insertions(+), 25 deletions(-) diff --git a/src/smt/smt_consequences.cpp b/src/smt/smt_consequences.cpp index 9e026760c..df4f0f180 100644 --- a/src/smt/smt_consequences.cpp +++ b/src/smt/smt_consequences.cpp @@ -116,7 +116,7 @@ namespace smt { } } - void context::extract_fixed_consequences(unsigned start, obj_map& vars, uint_set const& assumptions, expr_ref_vector& conseq) { + void context::extract_fixed_consequences(unsigned& start, obj_map& vars, uint_set const& assumptions, expr_ref_vector& conseq) { pop_to_search_lvl(); SASSERT(!inconsistent()); literal_vector const& lits = assigned_literals(); @@ -124,6 +124,7 @@ namespace smt { for (unsigned i = start; i < sz; ++i) { extract_fixed_consequences(lits[i], vars, assumptions, conseq); } + start = sz; SASSERT(!inconsistent()); } @@ -261,8 +262,8 @@ namespace smt { unfixed.push_back(vars[i]); } } - extract_fixed_consequences(0, var2val, _assumptions, conseq); - unsigned num_units = assigned_literals().size(); + unsigned num_units = 0; + extract_fixed_consequences(num_units, var2val, _assumptions, conseq); app_ref eq(m); TRACE("context", tout << "vars: " << vars.size() << "\n"; @@ -270,7 +271,6 @@ namespace smt { m_case_split_queue->init_search_eh(); unsigned num_iterations = 0; unsigned model_threshold = 2; - unsigned num_unfixed = 0; unsigned num_fixed_eqs = 0; unsigned num_reiterations = 0; while (!var2val.empty()) { @@ -376,7 +376,7 @@ namespace smt { // bool apply_slow_pass = model_threshold <= num_iterations || num_iterations <= 2; if (apply_slow_pass && is_sat == l_true) { - num_unfixed += delete_unfixed(var2val, unfixed); + delete_unfixed(var2val, unfixed); // The next time we check the model is after 1.5 additional iterations. model_threshold *= 3; model_threshold /= 2; @@ -389,7 +389,6 @@ namespace smt { // This condition is checked above. // extract_fixed_consequences(num_units, var2val, _assumptions, conseq); - num_units = assigned_literals().size(); // // Fixed equalities can be extracted by walking all variables and checking @@ -397,22 +396,10 @@ namespace smt { // if (apply_slow_pass) { num_fixed_eqs += extract_fixed_eqs(var2val, conseq); - IF_VERBOSE(1, verbose_stream() << "(get-consequences" - << " iterations: " << num_iterations - << " variables: " << var2val.size() - << " fixed: " << conseq.size() - << " unfixed: " << unfixed.size() - << " fixed-eqs: " << num_fixed_eqs - << " unfixed-deleted: " << num_unfixed - << ")\n";); - TRACE("context", tout << "(get-consequences" - << " iterations: " << num_iterations - << " variables: " << var2val.size() - << " fixed: " << conseq.size() - << " unfixed: " << unfixed.size() - << " fixed-eqs: " << num_fixed_eqs - << " unfixed-deleted: " << num_unfixed - << ")\n";); + IF_VERBOSE(1, display_consequence_progress(verbose_stream(), num_iterations, var2val.size(), conseq.size(), + unfixed.size(), num_fixed_eqs);); + TRACE("context", display_consequence_progress(tout, num_iterations, var2val.size(), conseq.size(), + unfixed.size(), num_fixed_eqs);); } TRACE("context", tout << "finishing " << mk_pp(e, m) << "\n";); SASSERT(!inconsistent()); @@ -438,6 +425,139 @@ namespace smt { return l_true; } + lbool context::get_consequences2(expr_ref_vector const& assumptions, + expr_ref_vector const& vars, + expr_ref_vector& conseq, + expr_ref_vector& unfixed) { + + m_antecedents.reset(); + pop_to_base_lvl(); + lbool is_sat = check(assumptions.size(), assumptions.c_ptr()); + if (is_sat != l_true) { + return is_sat; + } + obj_map var2val; + uint_set _assumptions; + for (unsigned i = 0; i < assumptions.size(); ++i) { + _assumptions.insert(get_literal(assumptions[i]).var()); + } + model_ref mdl; + get_model(mdl); + ast_manager& m = m_manager; + expr_ref_vector trail(m); + model_evaluator eval(*mdl.get()); + expr_ref val(m); + TRACE("context", model_pp(tout, *mdl);); + for (unsigned i = 0; i < vars.size(); ++i) { + eval(vars[i], val); + if (m.is_value(val)) { + trail.push_back(val); + var2val.insert(vars[i], val); + } + else { + unfixed.push_back(vars[i]); + } + } + unsigned num_units = 0; + extract_fixed_consequences(num_units, var2val, _assumptions, conseq); + app_ref eq(m); + TRACE("context", + tout << "vars: " << vars.size() << "\n"; + tout << "lits: " << num_units << "\n";); + m_case_split_queue->init_search_eh(); + unsigned num_iterations = 0; + unsigned model_threshold = 2; + unsigned num_fixed_eqs = 0; + unsigned num_reiterations = 0; + unsigned chunk_size = 100; + + while (!var2val.empty()) { + obj_map::iterator it = var2val.begin(), end = var2val.end(); + unsigned num_vars = 0; + for (; it != end && num_vars < chunk_size; ++it) { + expr* e = it->m_key; + expr* val = it->m_value; + literal lit; + if (m.is_bool(e)) { + lit = literal(get_bool_var(e), m.is_true(val)); + } + else { + eq = mk_eq_atom(e, val); + internalize_formula(eq, false); + lit = literal(get_bool_var(eq), true); + TRACE("context", tout << mk_pp(e, m) << " " << mk_pp(val, m) << "\n"; + display_literal_verbose(tout, lit); tout << "\n"; + tout << "Equal: " << are_equal(e, val) << "\n";); + } + mark_as_relevant(lit); + if (get_assignment(lit) != l_undef) { + continue; + } + ++num_vars; + push_scope(); + assign(lit, b_justification::mk_axiom(), true); + if (!propagate()) { + if (!resolve_conflict() || inconsistent()) { + TRACE("context", tout << "inconsistent\n";); + SASSERT(inconsistent()); + m_conflict = null_b_justification; + m_not_l = null_literal; + SASSERT(m_search_lvl == get_search_level()); + } + if (get_cancel_flag()) { + return l_undef; + } + } + } + SASSERT(!inconsistent()); + ++num_iterations; + + lbool is_sat = l_undef; + while (true) { + is_sat = bounded_search(); + if (is_sat != l_true && m_last_search_failure != OK) { + return is_sat; + } + if (is_sat == l_undef) { + IF_VERBOSE(1, verbose_stream() << "(get-consequences inc-limits)\n";); + inc_limits(); + continue; + } + break; + } + if (is_sat == l_false) { + SASSERT(inconsistent()); + m_conflict = null_b_justification; + m_not_l = null_literal; + } + if (is_sat == l_true) { + delete_unfixed(var2val, unfixed); + } + extract_fixed_consequences(num_units, var2val, _assumptions, conseq); + num_fixed_eqs += extract_fixed_eqs(var2val, conseq); + IF_VERBOSE(1, display_consequence_progress(verbose_stream(), num_iterations, var2val.size(), conseq.size(), + unfixed.size(), num_fixed_eqs);); + TRACE("context", display_consequence_progress(tout, num_iterations, var2val.size(), conseq.size(), + unfixed.size(), num_fixed_eqs);); + } + + end_search(); + DEBUG_CODE(validate_consequences(assumptions, vars, conseq, unfixed);); + return l_true; + } + + + void context::display_consequence_progress(std::ostream& out, unsigned it, unsigned nv, unsigned fixed, unsigned unfixed, unsigned eq) { + out << "(get-consequences" + << " iterations: " << it + << " variables: " << nv + << " fixed: " << fixed + << " unfixed: " << unfixed + << " fixed-eqs: " << eq + << ")\n"; + } + + // // Validate, in a slow pass, that the current consequences are correctly // extracted. diff --git a/src/smt/smt_context.h b/src/smt/smt_context.h index 79b969118..dfb1389c2 100644 --- a/src/smt/smt_context.h +++ b/src/smt/smt_context.h @@ -1346,8 +1346,10 @@ namespace smt { u_map m_antecedents; void extract_fixed_consequences(literal lit, obj_map& var2val, uint_set const& assumptions, expr_ref_vector& conseq); - void extract_fixed_consequences(unsigned idx, obj_map& var2val, uint_set const& assumptions, expr_ref_vector& conseq); - + void extract_fixed_consequences(unsigned& idx, obj_map& var2val, uint_set const& assumptions, expr_ref_vector& conseq); + + void display_consequence_progress(std::ostream& out, unsigned it, unsigned nv, unsigned fixed, unsigned unfixed, unsigned eq); + unsigned delete_unfixed(obj_map& var2val, expr_ref_vector& unfixed); unsigned extract_fixed_eqs(obj_map& var2val, expr_ref_vector& conseq); @@ -1398,6 +1400,7 @@ namespace smt { lbool check(unsigned num_assumptions = 0, expr * const * assumptions = 0, bool reset_cancel = true); lbool get_consequences(expr_ref_vector const& assumptions, expr_ref_vector const& vars, expr_ref_vector& conseq, expr_ref_vector& unfixed); + lbool get_consequences2(expr_ref_vector const& assumptions, expr_ref_vector const& vars, expr_ref_vector& conseq, expr_ref_vector& unfixed); lbool setup_and_check(bool reset_cancel = true); diff --git a/src/smt/smt_kernel.cpp b/src/smt/smt_kernel.cpp index 6b65d0426..e5a8a639e 100644 --- a/src/smt/smt_kernel.cpp +++ b/src/smt/smt_kernel.cpp @@ -112,7 +112,7 @@ namespace smt { } lbool get_consequences(expr_ref_vector const& assumptions, expr_ref_vector const& vars, expr_ref_vector& conseq, expr_ref_vector& unfixed) { - return m_kernel.get_consequences(assumptions, vars, conseq, unfixed); + return m_kernel.get_consequences2(assumptions, vars, conseq, unfixed); } void get_model(model_ref & m) const { From 758266b952c379015daf56518f6cbbb054f0d968 Mon Sep 17 00:00:00 2001 From: cttghc Date: Tue, 6 Sep 2016 18:32:41 -0500 Subject: [PATCH 168/536] Fix omission of Z3_model_has_interp in z3++.h --- src/api/c++/z3++.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index a9a4efd03..b4643aa2b 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -1615,6 +1615,13 @@ namespace z3 { check_error(); return func_interp(ctx(), r); } + + // returns true iff the model contains an interpretation + // for function f. + bool has_interp(func_decl f) const { + check_context(*this, f); + return Z3_model_has_interp(ctx(), m_model, f); + } friend std::ostream & operator<<(std::ostream & out, model const & m); }; From 2d9dced1c72e27c8baa1c6c2959dd32e7ba11221 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 6 Sep 2016 20:18:31 -0700 Subject: [PATCH 169/536] fix spacing, cast to Bool Signed-off-by: Nikolaj Bjorner --- src/api/c++/z3++.h | 116 +++++++++++++++++++------------------- src/smt/theory_arith_eq.h | 2 +- 2 files changed, 60 insertions(+), 58 deletions(-) diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index b4643aa2b..4d832afd6 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -122,6 +122,13 @@ namespace z3 { unsat, sat, unknown }; + inline check_result to_check_result(Z3_lbool l) { + if (l == Z3_L_TRUE) return sat; + else if (l == Z3_L_FALSE) return unsat; + return unknown; + } + + /** \brief A Context manages all other Z3 objects, global configuration options, etc. */ @@ -146,7 +153,7 @@ namespace z3 { struct interpolation {}; context() { config c; init(c); } context(config & c) { init(c); } - context(config & c, interpolation) { init_interp(c); } + context(config & c, interpolation) { init_interp(c); } ~context() { Z3_del_context(m_ctx); } operator Z3_context() const { return m_ctx; } @@ -879,7 +886,7 @@ namespace z3 { unsigned lo() const { assert (is_app() && Z3_get_decl_num_parameters(ctx(), decl()) == 2); return static_cast(Z3_get_decl_int_parameter(ctx(), decl(), 1)); } unsigned hi() const { assert (is_app() && Z3_get_decl_num_parameters(ctx(), decl()) == 2); return static_cast(Z3_get_decl_int_parameter(ctx(), decl(), 0)); } - /** + /** \brief sequence and regular expression operations. + is overloaeded as sequence concatenation and regular expression union. concat is overloaded to handle sequences and regular expressions @@ -1279,51 +1286,51 @@ namespace z3 { inline expr udiv(expr const & a, int b) { return udiv(a, a.ctx().num_val(b, a.get_sort())); } inline expr udiv(int a, expr const & b) { return udiv(b.ctx().num_val(a, b.get_sort()), b); } - /** - \brief signed reminder operator for bitvectors - */ - inline expr srem(expr const & a, expr const & b) { return to_expr(a.ctx(), Z3_mk_bvsrem(a.ctx(), a, b)); } - inline expr srem(expr const & a, int b) { return srem(a, a.ctx().num_val(b, a.get_sort())); } - inline expr srem(int a, expr const & b) { return srem(b.ctx().num_val(a, b.get_sort()), b); } - - /** - \brief unsigned reminder operator for bitvectors - */ - inline expr urem(expr const & a, expr const & b) { return to_expr(a.ctx(), Z3_mk_bvurem(a.ctx(), a, b)); } - inline expr urem(expr const & a, int b) { return urem(a, a.ctx().num_val(b, a.get_sort())); } - inline expr urem(int a, expr const & b) { return urem(b.ctx().num_val(a, b.get_sort()), b); } - - /** - \brief shift left operator for bitvectors - */ - inline expr shl(expr const & a, expr const & b) { return to_expr(a.ctx(), Z3_mk_bvshl(a.ctx(), a, b)); } - inline expr shl(expr const & a, int b) { return shl(a, a.ctx().num_val(b, a.get_sort())); } - inline expr shl(int a, expr const & b) { return shl(b.ctx().num_val(a, b.get_sort()), b); } - - /** - \brief logic shift right operator for bitvectors - */ - inline expr lshr(expr const & a, expr const & b) { return to_expr(a.ctx(), Z3_mk_bvlshr(a.ctx(), a, b)); } - inline expr lshr(expr const & a, int b) { return lshr(a, a.ctx().num_val(b, a.get_sort())); } - inline expr lshr(int a, expr const & b) { return lshr(b.ctx().num_val(a, b.get_sort()), b); } - - /** - \brief arithmetic shift right operator for bitvectors - */ - inline expr ashr(expr const & a, expr const & b) { return to_expr(a.ctx(), Z3_mk_bvashr(a.ctx(), a, b)); } - inline expr ashr(expr const & a, int b) { return ashr(a, a.ctx().num_val(b, a.get_sort())); } - inline expr ashr(int a, expr const & b) { return ashr(b.ctx().num_val(a, b.get_sort()), b); } - - /** - \brief Extend the given bit-vector with zeros to the (unsigned) equivalent bitvector of size m+i, where m is the size of the given bit-vector. - */ - inline expr zext(expr const & a, unsigned i) { return to_expr(a.ctx(), Z3_mk_zero_ext(a.ctx(), i, a)); } - - /** - \brief Sign-extend of the given bit-vector to the (signed) equivalent bitvector of size m+i, where m is the size of the given bit-vector. - */ - inline expr sext(expr const & a, unsigned i) { return to_expr(a.ctx(), Z3_mk_sign_ext(a.ctx(), i, a)); } - + /** + \brief signed reminder operator for bitvectors + */ + inline expr srem(expr const & a, expr const & b) { return to_expr(a.ctx(), Z3_mk_bvsrem(a.ctx(), a, b)); } + inline expr srem(expr const & a, int b) { return srem(a, a.ctx().num_val(b, a.get_sort())); } + inline expr srem(int a, expr const & b) { return srem(b.ctx().num_val(a, b.get_sort()), b); } + + /** + \brief unsigned reminder operator for bitvectors + */ + inline expr urem(expr const & a, expr const & b) { return to_expr(a.ctx(), Z3_mk_bvurem(a.ctx(), a, b)); } + inline expr urem(expr const & a, int b) { return urem(a, a.ctx().num_val(b, a.get_sort())); } + inline expr urem(int a, expr const & b) { return urem(b.ctx().num_val(a, b.get_sort()), b); } + + /** + \brief shift left operator for bitvectors + */ + inline expr shl(expr const & a, expr const & b) { return to_expr(a.ctx(), Z3_mk_bvshl(a.ctx(), a, b)); } + inline expr shl(expr const & a, int b) { return shl(a, a.ctx().num_val(b, a.get_sort())); } + inline expr shl(int a, expr const & b) { return shl(b.ctx().num_val(a, b.get_sort()), b); } + + /** + \brief logic shift right operator for bitvectors + */ + inline expr lshr(expr const & a, expr const & b) { return to_expr(a.ctx(), Z3_mk_bvlshr(a.ctx(), a, b)); } + inline expr lshr(expr const & a, int b) { return lshr(a, a.ctx().num_val(b, a.get_sort())); } + inline expr lshr(int a, expr const & b) { return lshr(b.ctx().num_val(a, b.get_sort()), b); } + + /** + \brief arithmetic shift right operator for bitvectors + */ + inline expr ashr(expr const & a, expr const & b) { return to_expr(a.ctx(), Z3_mk_bvashr(a.ctx(), a, b)); } + inline expr ashr(expr const & a, int b) { return ashr(a, a.ctx().num_val(b, a.get_sort())); } + inline expr ashr(int a, expr const & b) { return ashr(b.ctx().num_val(a, b.get_sort()), b); } + + /** + \brief Extend the given bit-vector with zeros to the (unsigned) equivalent bitvector of size m+i, where m is the size of the given bit-vector. + */ + inline expr zext(expr const & a, unsigned i) { return to_expr(a.ctx(), Z3_mk_zero_ext(a.ctx(), i, a)); } + + /** + \brief Sign-extend of the given bit-vector to the (signed) equivalent bitvector of size m+i, where m is the size of the given bit-vector. + */ + inline expr sext(expr const & a, unsigned i) { return to_expr(a.ctx(), Z3_mk_sign_ext(a.ctx(), i, a)); } + template class cast_ast; template<> class cast_ast { @@ -1596,9 +1603,9 @@ namespace z3 { func_decl get_func_decl(unsigned i) const { Z3_func_decl r = Z3_model_get_func_decl(ctx(), m_model, i); check_error(); return func_decl(ctx(), r); } unsigned size() const { return num_consts() + num_funcs(); } func_decl operator[](int i) const { - assert(0 <= i); - return static_cast(i) < num_consts() ? get_const_decl(i) : get_func_decl(i - num_consts()); - } + assert(0 <= i); + 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 @@ -1619,8 +1626,8 @@ namespace z3 { // returns true iff the model contains an interpretation // for function f. bool has_interp(func_decl f) const { - check_context(*this, f); - return Z3_model_has_interp(ctx(), m_model, f); + check_context(*this, f); + return 0 != Z3_model_has_interp(ctx(), m_model, f); } friend std::ostream & operator<<(std::ostream & out, model const & m); @@ -1664,11 +1671,6 @@ namespace z3 { return out; } - inline check_result to_check_result(Z3_lbool l) { - if (l == Z3_L_TRUE) return sat; - else if (l == Z3_L_FALSE) return unsat; - return unknown; - } class solver : public object { Z3_solver m_solver; diff --git a/src/smt/theory_arith_eq.h b/src/smt/theory_arith_eq.h index de76b6838..8577f3553 100644 --- a/src/smt/theory_arith_eq.h +++ b/src/smt/theory_arith_eq.h @@ -216,7 +216,7 @@ namespace smt { void theory_arith::propagate_cheap_eq(unsigned rid) { if (!propagate_eqs()) return; - TRACE("arith_eq", tout << "checking if row " << rid << " can propagate equality.\n"; + TRACE("arith_eq_verbose", tout << "checking if row " << rid << " can propagate equality.\n"; display_row_info(tout, rid);); row const & r = m_rows[rid]; theory_var x; From c5dd441947c28dd2a3a6a74e17f21a40efeb6682 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 7 Sep 2016 11:50:26 -0700 Subject: [PATCH 170/536] fixes to consequence generation and cancellation Signed-off-by: Nikolaj Bjorner --- src/api/api_context.cpp | 37 ++++++++++++------------- src/api/api_context.h | 2 +- src/api/z3_replayer.cpp | 2 +- src/smt/asserted_formulas.cpp | 8 ++++-- src/smt/asserted_formulas.h | 1 + src/smt/smt_consequences.cpp | 52 +++++++++++++++-------------------- src/smt/smt_context.cpp | 8 ++++-- src/smt/smt_context.h | 2 ++ src/util/rlimit.cpp | 2 +- 9 files changed, 58 insertions(+), 56 deletions(-) diff --git a/src/api/api_context.cpp b/src/api/api_context.cpp index b6c3384e7..bcd3c60f2 100644 --- a/src/api/api_context.cpp +++ b/src/api/api_context.cpp @@ -70,22 +70,6 @@ namespace api { // // ------------------------ - context::set_interruptable::set_interruptable(context & ctx, event_handler & i): - m_ctx(ctx) { - #pragma omp critical (set_interruptable) - { - SASSERT(m_ctx.m_interruptable == 0); - m_ctx.m_interruptable = &i; - } - } - - context::set_interruptable::~set_interruptable() { - #pragma omp critical (set_interruptable) - { - m_ctx.m_interruptable = 0; - } - } - context::context(context_params * p, bool user_ref_count): m_params(p != 0 ? *p : context_params()), m_user_ref_count(user_ref_count), @@ -105,11 +89,10 @@ namespace api { m_print_mode = Z3_PRINT_SMTLIB_FULL; m_searching = false; - m_interruptable = 0; - m_smtlib_parser = 0; m_smtlib_parser_has_decls = false; - + + m_interruptable = 0; m_error_handler = &default_error_handler; m_basic_fid = m().get_basic_family_id(); @@ -139,6 +122,22 @@ namespace api { } } + context::set_interruptable::set_interruptable(context & ctx, event_handler & i): + m_ctx(ctx) { + #pragma omp critical (set_interruptable) + { + SASSERT(m_ctx.m_interruptable == 0); + m_ctx.m_interruptable = &i; + } + } + + context::set_interruptable::~set_interruptable() { + #pragma omp critical (set_interruptable) + { + m_ctx.m_interruptable = 0; + } + } + void context::interrupt() { #pragma omp critical (set_interruptable) { diff --git a/src/api/api_context.h b/src/api/api_context.h index d2c0b3ad4..4685fd04e 100644 --- a/src/api/api_context.h +++ b/src/api/api_context.h @@ -94,7 +94,7 @@ namespace api { event_handler * m_interruptable; // Reference to an object that can be interrupted by Z3_interrupt - public: + public: // Scoped obj for setting m_interruptable class set_interruptable { context & m_ctx; diff --git a/src/api/z3_replayer.cpp b/src/api/z3_replayer.cpp index 826e767f2..651cb730f 100644 --- a/src/api/z3_replayer.cpp +++ b/src/api/z3_replayer.cpp @@ -515,7 +515,7 @@ struct z3_replayer::imp { if (idx >= m_cmds.size()) throw z3_replayer_exception("invalid command"); try { - TRACE("z3_replayer_cmd", tout << m_cmds_names[idx] << "\n";); + TRACE("z3_replayer_cmd", tout << idx << ":" << m_cmds_names[idx] << "\n";); m_cmds[idx](m_owner); } catch (z3_error & ex) { diff --git a/src/smt/asserted_formulas.cpp b/src/smt/asserted_formulas.cpp index 3ba6693d9..3c67cadcf 100644 --- a/src/smt/asserted_formulas.cpp +++ b/src/smt/asserted_formulas.cpp @@ -543,8 +543,12 @@ void asserted_formulas::infer_patterns() { } void asserted_formulas::commit() { - m_macro_manager.mark_forbidden(m_asserted_formulas.size() - m_asserted_qhead, m_asserted_formulas.c_ptr() + m_asserted_qhead); - m_asserted_qhead = m_asserted_formulas.size(); + commit(m_asserted_formulas.size()); +} + +void asserted_formulas::commit(unsigned new_qhead) { + m_macro_manager.mark_forbidden(new_qhead - m_asserted_qhead, m_asserted_formulas.c_ptr() + m_asserted_qhead); + m_asserted_qhead = new_qhead; } void asserted_formulas::eliminate_term_ite() { diff --git a/src/smt/asserted_formulas.h b/src/smt/asserted_formulas.h index 75fb86703..9e9ecf33a 100644 --- a/src/smt/asserted_formulas.h +++ b/src/smt/asserted_formulas.h @@ -113,6 +113,7 @@ public: unsigned get_formulas_last_level() const; unsigned get_qhead() const { return m_asserted_qhead; } void commit(); + void commit(unsigned new_qhead); expr * get_formula(unsigned idx) const { return m_asserted_formulas.get(idx); } proof * get_formula_proof(unsigned idx) const { return m_manager.proofs_enabled() ? m_asserted_formula_prs.get(idx) : 0; } expr * const * get_formulas() const { return m_asserted_formulas.c_ptr(); } diff --git a/src/smt/smt_consequences.cpp b/src/smt/smt_consequences.cpp index df4f0f180..b1c277792 100644 --- a/src/smt/smt_consequences.cpp +++ b/src/smt/smt_consequences.cpp @@ -174,6 +174,9 @@ namespace smt { else if (e_internalized(k) && m.are_distinct(v, get_enode(k)->get_root()->get_owner())) { to_delete.push_back(k); } + else if (get_assignment(mk_diseq(k, v)) == l_true) { + to_delete.push_back(k); + } } for (unsigned i = 0; i < to_delete.size(); ++i) { var2val.remove(to_delete[i]); @@ -215,9 +218,7 @@ namespace smt { for (unsigned i = 0; i < literals.size(); ++i) { literals[i].neg(); } - eq = mk_eq_atom(k, v); - internalize_formula(eq, false); - literal lit(get_bool_var(eq), false); + literal lit = mk_diseq(k, v); literals.push_back(lit); mk_clause(literals.size(), literals.c_ptr(), 0); TRACE("context", display_literals_verbose(tout, literals.size(), literals.c_ptr());); @@ -229,6 +230,18 @@ namespace smt { return to_delete.size(); } + literal context::mk_diseq(expr* e, expr* val) { + ast_manager& m = m_manager; + if (m.is_bool(e)) { + return literal(get_bool_var(e), m.is_true(val)); + } + else { + expr_ref eq(mk_eq_atom(e, val), m); + internalize_formula(eq, false); + return literal(get_bool_var(eq), true); + } + } + lbool context::get_consequences(expr_ref_vector const& assumptions, expr_ref_vector const& vars, expr_ref_vector& conseq, @@ -288,18 +301,7 @@ namespace smt { // the opposite value of the current reference model. // If the variable is a non-Boolean, it means adding a disequality. // - literal lit; - if (m.is_bool(e)) { - lit = literal(get_bool_var(e), m.is_true(val)); - } - else { - eq = mk_eq_atom(e, val); - internalize_formula(eq, false); - lit = literal(get_bool_var(eq), true); - TRACE("context", tout << mk_pp(e, m) << " " << mk_pp(val, m) << "\n"; - display_literal_verbose(tout, lit); tout << "\n"; - tout << "Equal: " << are_equal(e, val) << "\n";); - } + literal lit = mk_diseq(e, val); mark_as_relevant(lit); push_scope(); assign(lit, b_justification::mk_axiom(), true); @@ -434,6 +436,7 @@ namespace smt { pop_to_base_lvl(); lbool is_sat = check(assumptions.size(), assumptions.c_ptr()); if (is_sat != l_true) { + TRACE("context", tout << is_sat << "\n";); return is_sat; } obj_map var2val; @@ -475,20 +478,12 @@ namespace smt { obj_map::iterator it = var2val.begin(), end = var2val.end(); unsigned num_vars = 0; for (; it != end && num_vars < chunk_size; ++it) { + if (get_cancel_flag()) { + return l_undef; + } expr* e = it->m_key; expr* val = it->m_value; - literal lit; - if (m.is_bool(e)) { - lit = literal(get_bool_var(e), m.is_true(val)); - } - else { - eq = mk_eq_atom(e, val); - internalize_formula(eq, false); - lit = literal(get_bool_var(eq), true); - TRACE("context", tout << mk_pp(e, m) << " " << mk_pp(val, m) << "\n"; - display_literal_verbose(tout, lit); tout << "\n"; - tout << "Equal: " << are_equal(e, val) << "\n";); - } + literal lit = mk_diseq(e, val); mark_as_relevant(lit); if (get_assignment(lit) != l_undef) { continue; @@ -504,9 +499,6 @@ namespace smt { m_not_l = null_literal; SASSERT(m_search_lvl == get_search_level()); } - if (get_cancel_flag()) { - return l_undef; - } } } SASSERT(!inconsistent()); diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index 0b3147d6b..5f258fc61 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -1833,7 +1833,7 @@ namespace smt { m_stats.m_num_decisions++; push_scope(); - TRACE("context", tout << "splitting, lvl: " << m_scope_lvl << "\n";); + TRACE("decide", tout << "splitting, lvl: " << m_scope_lvl << "\n";); TRACE("decide_detail", tout << mk_pp(bool_var2expr(var), m_manager) << "\n";); @@ -2949,7 +2949,11 @@ namespace smt { if (!m_asserted_formulas.inconsistent()) { unsigned sz = m_asserted_formulas.get_num_formulas(); unsigned qhead = m_asserted_formulas.get_qhead(); - while (qhead < sz && !m_manager.canceled()) { + while (qhead < sz) { + if (get_cancel_flag()) { + m_asserted_formulas.commit(qhead); + return; + } expr * f = m_asserted_formulas.get_formula(qhead); proof * pr = m_asserted_formulas.get_formula_proof(qhead); internalize_assertion(f, pr, 0); diff --git a/src/smt/smt_context.h b/src/smt/smt_context.h index dfb1389c2..01471c603 100644 --- a/src/smt/smt_context.h +++ b/src/smt/smt_context.h @@ -1356,6 +1356,8 @@ namespace smt { expr_ref antecedent2fml(uint_set const& ante); + literal mk_diseq(expr* v, expr* val); + void validate_consequences(expr_ref_vector const& assumptions, expr_ref_vector const& vars, expr_ref_vector const& conseq, expr_ref_vector const& unfixed); diff --git a/src/util/rlimit.cpp b/src/util/rlimit.cpp index b3f055955..37b1f7904 100644 --- a/src/util/rlimit.cpp +++ b/src/util/rlimit.cpp @@ -36,7 +36,7 @@ bool reslimit::inc() { bool reslimit::inc(unsigned offset) { m_count += offset; - return !m_cancel && (m_limit == 0 || m_count <= m_limit); + return m_cancel == 0 && (m_limit == 0 || m_count <= m_limit); } void reslimit::push(unsigned delta_limit) { From 76cf28d48baff191396b1a00e320e6e99a82a162 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 8 Sep 2016 13:34:59 -0700 Subject: [PATCH 171/536] move from uint_set to hashtable over unsigned to save memory overhead in consequence generation Signed-off-by: Nikolaj Bjorner --- src/smt/smt_consequences.cpp | 22 +++++++++++++--------- src/smt/smt_context.h | 12 +++++++----- src/util/hashtable.h | 3 +-- 3 files changed, 21 insertions(+), 16 deletions(-) diff --git a/src/smt/smt_consequences.cpp b/src/smt/smt_consequences.cpp index b1c277792..65dca4918 100644 --- a/src/smt/smt_consequences.cpp +++ b/src/smt/smt_consequences.cpp @@ -23,9 +23,9 @@ Revision History: namespace smt { - expr_ref context::antecedent2fml(uint_set const& vars) { + expr_ref context::antecedent2fml(index_set const& vars) { expr_ref_vector premises(m_manager); - uint_set::iterator it = vars.begin(), end = vars.end(); + index_set::iterator it = vars.begin(), end = vars.end(); for (; it != end; ++it) { expr* e = bool_var2expr(*it); premises.push_back(get_assignment(*it) != l_false ? e : m_manager.mk_not(e)); @@ -42,14 +42,14 @@ namespace smt { // - e is an equality between a variable and value that is to be fixed. // - e is a data-type recognizer of a variable that is to be fixed. // - void context::extract_fixed_consequences(literal lit, obj_map& vars, uint_set const& assumptions, expr_ref_vector& conseq) { + void context::extract_fixed_consequences(literal lit, obj_map& vars, index_set const& assumptions, expr_ref_vector& conseq) { ast_manager& m = m_manager; datatype_util dt(m); expr* e1, *e2; expr_ref fml(m); if (lit == true_literal) return; expr* e = bool_var2expr(lit.var()); - uint_set s; + index_set s; if (assumptions.contains(lit.var())) { s.insert(lit.var()); } @@ -86,7 +86,11 @@ namespace smt { } } m_antecedents.insert(lit.var(), s); - TRACE("context", display_literal_verbose(tout, lit); tout << " " << s << "\n";); + TRACE("context", display_literal_verbose(tout, lit); + for (index_set::iterator it = s.begin(), end = s.end(); it != end; ++it) { + tout << " " << *it; + } + tout << "\n";); bool found = false; if (vars.contains(e)) { found = true; @@ -116,7 +120,7 @@ namespace smt { } } - void context::extract_fixed_consequences(unsigned& start, obj_map& vars, uint_set const& assumptions, expr_ref_vector& conseq) { + void context::extract_fixed_consequences(unsigned& start, obj_map& vars, index_set const& assumptions, expr_ref_vector& conseq) { pop_to_search_lvl(); SASSERT(!inconsistent()); literal_vector const& lits = assigned_literals(); @@ -204,7 +208,7 @@ namespace smt { if (!m.is_bool(k) && are_equal(k, v)) { literal_vector literals; m_conflict_resolution->eq2literals(get_enode(v), get_enode(k), literals); - uint_set s; + index_set s; for (unsigned i = 0; i < literals.size(); ++i) { SASSERT(get_assign_level(literals[i]) <= get_search_level()); s |= m_antecedents.find(literals[i].var()); @@ -254,7 +258,7 @@ namespace smt { return is_sat; } obj_map var2val; - uint_set _assumptions; + index_set _assumptions; for (unsigned i = 0; i < assumptions.size(); ++i) { _assumptions.insert(get_literal(assumptions[i]).var()); } @@ -440,7 +444,7 @@ namespace smt { return is_sat; } obj_map var2val; - uint_set _assumptions; + index_set _assumptions; for (unsigned i = 0; i < assumptions.size(); ++i) { _assumptions.insert(get_literal(assumptions[i]).var()); } diff --git a/src/smt/smt_context.h b/src/smt/smt_context.h index 01471c603..98093d6ed 100644 --- a/src/smt/smt_context.h +++ b/src/smt/smt_context.h @@ -1343,10 +1343,12 @@ namespace smt { static literal translate_literal( literal lit, context& src_ctx, context& dst_ctx, vector b2v, ast_translation& tr); - - u_map m_antecedents; - void extract_fixed_consequences(literal lit, obj_map& var2val, uint_set const& assumptions, expr_ref_vector& conseq); - void extract_fixed_consequences(unsigned& idx, obj_map& var2val, uint_set const& assumptions, expr_ref_vector& conseq); + + typedef hashtable index_set; + //typedef uint_set index_set; + u_map m_antecedents; + void extract_fixed_consequences(literal lit, obj_map& var2val, index_set const& assumptions, expr_ref_vector& conseq); + void extract_fixed_consequences(unsigned& idx, obj_map& var2val, index_set const& assumptions, expr_ref_vector& conseq); void display_consequence_progress(std::ostream& out, unsigned it, unsigned nv, unsigned fixed, unsigned unfixed, unsigned eq); @@ -1354,7 +1356,7 @@ namespace smt { unsigned extract_fixed_eqs(obj_map& var2val, expr_ref_vector& conseq); - expr_ref antecedent2fml(uint_set const& ante); + expr_ref antecedent2fml(index_set const& ante); literal mk_diseq(expr* v, expr* val); diff --git a/src/util/hashtable.h b/src/util/hashtable.h index ddf40f39f..44e05319d 100644 --- a/src/util/hashtable.h +++ b/src/util/hashtable.h @@ -558,14 +558,13 @@ public: core_hashtable& operator|=(core_hashtable const& other) { if (this == &other) return *this; - iterator i = begin(), e = end(); + iterator i = other.begin(), e = other.end(); for (; i != e; ++i) { insert(*i); } return *this; } - core_hashtable& operator&=(core_hashtable const& other) { if (this == &other) return *this; core_hashtable copy(*this); From e485d1889c7adcb84f555df47ad0c43e31535791 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 8 Sep 2016 13:59:13 -0700 Subject: [PATCH 172/536] update replace semantics Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/seq_rewriter.cpp | 8 ++++++++ src/smt/theory_seq.cpp | 6 +++--- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/ast/rewriter/seq_rewriter.cpp b/src/ast/rewriter/seq_rewriter.cpp index 814b2168f..d36f61a85 100644 --- a/src/ast/rewriter/seq_rewriter.cpp +++ b/src/ast/rewriter/seq_rewriter.cpp @@ -637,6 +637,14 @@ br_status seq_rewriter::mk_seq_replace(expr* a, expr* b, expr* c, expr_ref& resu result = a; return BR_DONE; } + if (m_util.str.is_string(b, s1) && s2.length() == 0) { + result = m_util.str.mk_concat(a, c); + return BR_REWRITE1; + } + if (m_util.str.is_string(a, s1) && s1.length() == 0) { + result = a; + return BR_DONE; + } return BR_FAILED; } diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index 5b862b2d1..3f9369f14 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -2925,12 +2925,12 @@ void theory_seq::add_replace_axiom(expr* r) { expr_ref y = mk_skolem(m_indexof_right, a, s); expr_ref xty = mk_concat(x, t, y); expr_ref xsy = mk_concat(x, s, y); - literal cnt = mk_literal(m_util.str.mk_contains(a ,s)); + literal cnt = mk_literal(m_util.str.mk_contains(a, s)); literal a_emp = mk_eq_empty(a); literal s_emp = mk_eq_empty(s); - add_axiom(~a_emp, mk_seq_eq(r, a)); + add_axiom(~a_emp, s_emp, mk_seq_eq(r, a)); add_axiom(cnt, mk_seq_eq(r, a)); - add_axiom(~s_emp, mk_seq_eq(r, a)); + add_axiom(~s_emp, mk_seq_eq(r, mk_concat(t, a))); add_axiom(~cnt, a_emp, s_emp, mk_seq_eq(a, xsy)); add_axiom(~cnt, a_emp, s_emp, mk_seq_eq(r, xty)); tightest_prefix(s, x); From 2f67665c7edabd437b60abee8dd278737c52d7fc Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 10 Sep 2016 09:40:21 -0700 Subject: [PATCH 173/536] ensure stoi axiom even when no value is present for argument. Issue #731 Signed-off-by: Nikolaj Bjorner --- src/smt/theory_seq.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index 3f9369f14..2f0da7aad 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -2260,7 +2260,6 @@ bool theory_seq::add_itos_axiom(expr* e) { 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); -#if 1 // itos(n) = "25" <=> n = 25 literal eq1 = mk_eq(n1, n , false); literal eq2 = mk_eq(e, e1, false); @@ -2269,18 +2268,19 @@ bool theory_seq::add_itos_axiom(expr* e) { ctx.force_phase(eq1); ctx.force_phase(eq2); -#else - // "25" = itos(25) - // stoi(itos(n)) = n - app_ref e2(m_util.str.mk_stoi(e), m); - add_axiom(mk_eq(e2, n, false)); - add_axiom(mk_eq(m_util.str.mk_itos(n1), e1, false)); -#endif m_trail_stack.push(insert_map(m_itos_axioms, val)); m_trail_stack.push(push_replay(alloc(replay_axiom, m, e))); return true; - } + } } + else { + // stoi(itos(n)) = n + app_ref e2(m_util.str.mk_stoi(e), m); + add_axiom(mk_eq(e2, n, false)); + m_trail_stack.push(push_replay(alloc(replay_axiom, m, e))); + return true; + } + return false; } From cb140011bc9a574950a185ee29011d494001f944 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 10 Sep 2016 09:42:36 -0700 Subject: [PATCH 174/536] add missing rewrite rule. Issue #731 Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/seq_rewriter.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/ast/rewriter/seq_rewriter.cpp b/src/ast/rewriter/seq_rewriter.cpp index d36f61a85..0907ff4c7 100644 --- a/src/ast/rewriter/seq_rewriter.cpp +++ b/src/ast/rewriter/seq_rewriter.cpp @@ -890,6 +890,11 @@ br_status seq_rewriter::mk_str_stoi(expr* a, expr_ref& result) { result = m_autil.mk_numeral(r, true); return BR_DONE; } + expr* b; + if (m_util.str.is_itos(a, b)) { + result = b; + return BR_DONE; + } return BR_FAILED; } From 0b57829bddc59b147912c3cf1bcadc7a89e87a1a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 10 Sep 2016 11:04:29 -0700 Subject: [PATCH 175/536] fix heisenbug, unintialized variable, issue #720 Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/seq_rewriter.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ast/rewriter/seq_rewriter.cpp b/src/ast/rewriter/seq_rewriter.cpp index 0907ff4c7..4a82e5603 100644 --- a/src/ast/rewriter/seq_rewriter.cpp +++ b/src/ast/rewriter/seq_rewriter.cpp @@ -1496,7 +1496,7 @@ bool seq_rewriter::reduce_eq(expr_ref_vector& ls, expr_ref_vector& rs, expr_ref_ lchange = true; } - bool is_sat; + bool is_sat = true; unsigned szl = ls.size() - head1, szr = rs.size() - head2; expr* const* _ls = ls.c_ptr() + head1, * const* _rs = rs.c_ptr() + head2; @@ -1693,11 +1693,11 @@ bool seq_rewriter::solve_itos(unsigned szl, expr* const* ls, unsigned szr, expr* expr_ref_vector& lhs, expr_ref_vector& rhs, bool& is_sat) { expr* l, *r; + is_sat = true; if (szl == 1 && m_util.str.is_itos(ls[0], l)) { if (szr == 1 && m_util.str.is_itos(rs[0], r)) { lhs.push_back(l); rhs.push_back(r); - is_sat = true; return true; } zstring s; From 1450594fc65c875b78a3f81e3847fc98b5319d94 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 10 Sep 2016 12:15:49 -0700 Subject: [PATCH 176/536] add patch to deal with bug exposed in issue #721 Signed-off-by: Nikolaj Bjorner --- src/smt/theory_seq.cpp | 36 ++++++++++++++++++++++++++++++------ 1 file changed, 30 insertions(+), 6 deletions(-) diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index 2f0da7aad..641b9c053 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -2536,15 +2536,29 @@ public: model_value_proc * theory_seq::mk_value(enode * n, model_generator & mg) { - if (m_util.is_seq(n->get_owner())) { + app* e = n->get_owner(); + context& ctx = get_context(); + expr* e1, *e2, *e3; + if (m.is_ite(e, e1, e2, e3) && ctx.e_internalized(e2) && ctx.e_internalized(e3) && + (ctx.get_enode(e2)->get_root() == n->get_root() || + ctx.get_enode(e3)->get_root() == n->get_root())) { + if (ctx.get_enode(e2)->get_root() == n->get_root()) { + return mk_value(ctx.get_enode(e2), mg); + } + else { + return mk_value(ctx.get_enode(e3), mg); + } + } + else if (m_util.is_seq(e)) { ptr_vector concats; - get_concat(n->get_owner(), concats); - context& ctx = get_context(); - sort* srt = m.get_sort(n->get_owner()); + get_concat(e, concats); + sort* srt = m.get_sort(e); seq_value_proc* sv = alloc(seq_value_proc, *this, srt); - + + TRACE("seq", tout << mk_pp(e, m) << "\n";); for (unsigned i = 0; i < concats.size(); ++i) { expr* c = concats[i], *c1; + TRACE("seq", tout << mk_pp(c, m) << "\n";); if (m_util.str.is_unit(c, c1)) { if (ctx.e_internalized(c1)) { sv->add_dependency(ctx.get_enode(c1)); @@ -2560,7 +2574,7 @@ model_value_proc * theory_seq::mk_value(enode * n, model_generator & mg) { return sv; } else { - return alloc(expr_wrapper_proc, mk_value(n->get_owner())); + return alloc(expr_wrapper_proc, mk_value(e)); } } @@ -2683,6 +2697,15 @@ expr_ref theory_seq::expand(expr* e0, dependency*& eqs) { result = m_util.str.mk_index(expand(e1, deps), expand(e2, deps), e3); } else if (m.is_ite(e, e1, e2, e3)) { + if (ctx.e_internalized(e) && ctx.e_internalized(e2) && ctx.get_enode(e)->get_root() == ctx.get_enode(e2)->get_root()) { + result = expand(e2, deps); + add_dependency(deps, ctx.get_enode(e), ctx.get_enode(e2)); + } + else if (ctx.e_internalized(e) && ctx.e_internalized(e2) && ctx.get_enode(e)->get_root() == ctx.get_enode(e3)->get_root()) { + result = expand(e3, deps); + add_dependency(deps, ctx.get_enode(e), ctx.get_enode(e3)); + } + else { literal lit(mk_literal(e1)); #if 0 expr_ref sk_ite = mk_sk_ite(e1, e2, e3); @@ -2708,6 +2731,7 @@ expr_ref theory_seq::expand(expr* e0, dependency*& eqs) { break; } #endif + } } else if (m_util.str.is_itos(e, e1)) { rational val; From 5a86815f3413bf1acf3dbfa79162888b3be32dc9 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 11 Sep 2016 05:43:16 -0700 Subject: [PATCH 177/536] fix regression in seq-replace rewriting Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/seq_rewriter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ast/rewriter/seq_rewriter.cpp b/src/ast/rewriter/seq_rewriter.cpp index 4a82e5603..c343812fe 100644 --- a/src/ast/rewriter/seq_rewriter.cpp +++ b/src/ast/rewriter/seq_rewriter.cpp @@ -637,7 +637,7 @@ br_status seq_rewriter::mk_seq_replace(expr* a, expr* b, expr* c, expr_ref& resu result = a; return BR_DONE; } - if (m_util.str.is_string(b, s1) && s2.length() == 0) { + if (m_util.str.is_string(b, s2) && s2.length() == 0) { result = m_util.str.mk_concat(a, c); return BR_REWRITE1; } From 9f77759cd61f9cb79d913abcf04b0819cf488685 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 13 Sep 2016 10:34:34 -0700 Subject: [PATCH 178/536] ensure that status is displayed in SMT-LIB2 compliant way. Issue #734 Signed-off-by: Nikolaj Bjorner --- src/cmd_context/basic_cmds.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cmd_context/basic_cmds.cpp b/src/cmd_context/basic_cmds.cpp index 87cbd2738..d951f7710 100644 --- a/src/cmd_context/basic_cmds.cpp +++ b/src/cmd_context/basic_cmds.cpp @@ -631,7 +631,7 @@ public: ctx.regular_stream() << "(:status " << ctx.get_status() << ")" << std::endl; } else if (opt == m_reason_unknown) { - ctx.regular_stream() << "(:reason-unknown " << ctx.reason_unknown() << ")" << std::endl; + ctx.regular_stream() << "(:reason-unknown \"" << ctx.reason_unknown() << "\")" << std::endl; } else if (opt == m_all_statistics) { ctx.display_statistics(); From fa6cc19184f564b819b925aa22aa4fe9451f8321 Mon Sep 17 00:00:00 2001 From: Andrew Dutcher Date: Wed, 14 Sep 2016 01:33:07 -0700 Subject: [PATCH 179/536] Moved python bindings into package --- scripts/update_api.py | 4 ++-- src/api/python/z3/__init__.py | 10 ++++++++++ src/api/python/{ => z3}/z3.py | 8 ++++---- src/api/python/{ => z3}/z3num.py | 6 +++--- src/api/python/{ => z3}/z3poly.py | 2 +- src/api/python/{ => z3}/z3printer.py | 4 ++-- src/api/python/{ => z3}/z3rcf.py | 6 +++--- src/api/python/{ => z3}/z3types.py | 2 +- src/api/python/{ => z3}/z3util.py | 2 +- 9 files changed, 27 insertions(+), 17 deletions(-) create mode 100644 src/api/python/z3/__init__.py rename src/api/python/{ => z3}/z3.py (99%) rename src/api/python/{ => z3}/z3num.py (99%) rename src/api/python/{ => z3}/z3poly.py (98%) rename src/api/python/{ => z3}/z3printer.py (99%) rename src/api/python/{ => z3}/z3rcf.py (98%) rename src/api/python/{ => z3}/z3types.py (99%) rename src/api/python/{ => z3}/z3util.py (99%) diff --git a/scripts/update_api.py b/scripts/update_api.py index 733d5b1fa..5295b19b1 100755 --- a/scripts/update_api.py +++ b/scripts/update_api.py @@ -1600,8 +1600,8 @@ def write_core_py_preamble(core_py): core_py.write('# Automatically generated file\n') core_py.write('import sys, os\n') core_py.write('import ctypes\n') - core_py.write('from z3types import *\n') - core_py.write('from z3consts import *\n') + core_py.write('from .z3types import *\n') + core_py.write('from .z3consts import *\n') core_py.write( """ _lib = None diff --git a/src/api/python/z3/__init__.py b/src/api/python/z3/__init__.py new file mode 100644 index 000000000..c4f08371f --- /dev/null +++ b/src/api/python/z3/__init__.py @@ -0,0 +1,10 @@ +from .z3 import * + +from . import z3core +from . import z3num +from . import z3poly +from . import z3printer +from . import z3rcf +from . import z3types +from . import z3util +from . import z3consts diff --git a/src/api/python/z3.py b/src/api/python/z3/z3.py similarity index 99% rename from src/api/python/z3.py rename to src/api/python/z3/z3.py index 83e9eaae9..d7571a3c7 100644 --- a/src/api/python/z3.py +++ b/src/api/python/z3/z3.py @@ -41,10 +41,10 @@ Z3 exceptions: ... print("failed: %s" % ex) failed: sort mismatch """ -from z3core import * -from z3types import * -from z3consts import * -from z3printer import * +from .z3core import * +from .z3types import * +from .z3consts import * +from .z3printer import * from fractions import Fraction import sys import io diff --git a/src/api/python/z3num.py b/src/api/python/z3/z3num.py similarity index 99% rename from src/api/python/z3num.py rename to src/api/python/z3/z3num.py index b219829d3..14d8550e6 100644 --- a/src/api/python/z3num.py +++ b/src/api/python/z3/z3num.py @@ -5,9 +5,9 @@ # # Author: Leonardo de Moura (leonardo) ############################################ -from z3 import * -from z3core import * -from z3printer import * +from .z3 import * +from .z3core import * +from .z3printer import * from fractions import Fraction def _to_numeral(num, ctx=None): diff --git a/src/api/python/z3poly.py b/src/api/python/z3/z3poly.py similarity index 98% rename from src/api/python/z3poly.py rename to src/api/python/z3/z3poly.py index 0b8bf9457..4a5cac46c 100644 --- a/src/api/python/z3poly.py +++ b/src/api/python/z3/z3poly.py @@ -5,7 +5,7 @@ # # Author: Leonardo de Moura (leonardo) ############################################ -from z3 import * +from .z3 import * def subresultants(p, q, x): """ diff --git a/src/api/python/z3printer.py b/src/api/python/z3/z3printer.py similarity index 99% rename from src/api/python/z3printer.py rename to src/api/python/z3/z3printer.py index c8d69900a..e02c28a96 100644 --- a/src/api/python/z3printer.py +++ b/src/api/python/z3/z3printer.py @@ -6,8 +6,8 @@ # Author: Leonardo de Moura (leonardo) ############################################ import sys, io, z3 -from z3consts import * -from z3core import * +from .z3consts import * +from .z3core import * from ctypes import * ############################## diff --git a/src/api/python/z3rcf.py b/src/api/python/z3/z3rcf.py similarity index 98% rename from src/api/python/z3rcf.py rename to src/api/python/z3/z3rcf.py index 84c724910..9d6f2f6ad 100644 --- a/src/api/python/z3rcf.py +++ b/src/api/python/z3/z3rcf.py @@ -9,9 +9,9 @@ # # Author: Leonardo de Moura (leonardo) ############################################ -from z3 import * -from z3core import * -from z3printer import * +from .z3 import * +from .z3core import * +from .z3printer import * from fractions import Fraction def _to_rcfnum(num, ctx=None): diff --git a/src/api/python/z3types.py b/src/api/python/z3/z3types.py similarity index 99% rename from src/api/python/z3types.py rename to src/api/python/z3/z3types.py index 44b19d33a..8b585e0ee 100644 --- a/src/api/python/z3types.py +++ b/src/api/python/z3/z3types.py @@ -6,7 +6,7 @@ # Author: Leonardo de Moura (leonardo) ############################################ -import ctypes, z3core +import ctypes class Z3Exception(Exception): def __init__(self, value): diff --git a/src/api/python/z3util.py b/src/api/python/z3/z3util.py similarity index 99% rename from src/api/python/z3util.py rename to src/api/python/z3/z3util.py index 2494461cf..fe7e76b86 100644 --- a/src/api/python/z3util.py +++ b/src/api/python/z3/z3util.py @@ -11,7 +11,7 @@ Usage: import common_z3 as CM_Z3 """ -from z3 import * +from .z3 import * def vset(seq, idfun=None, as_list=True): # This functions preserves the order of arguments while removing duplicates. From 0bbd172af3693165ab7a3e9f16cf4268edbed703 Mon Sep 17 00:00:00 2001 From: Andrew Dutcher Date: Thu, 25 Aug 2016 19:25:12 -0500 Subject: [PATCH 180/536] First steps to a sane python build --- .gitignore | 4 +- contrib/cmake/src/api/python/CMakeLists.txt | 11 ++- scripts/mk_genfile_common.py | 2 +- scripts/mk_util.py | 17 ++-- scripts/update_api.py | 2 +- src/api/python/setup.py | 88 +++++++++++++++++++++ src/api/python/z3/__init__.py | 4 +- src/api/python/z3/z3poly.py | 4 +- src/api/python/z3/z3types.py | 1 - 9 files changed, 110 insertions(+), 23 deletions(-) create mode 100644 src/api/python/setup.py diff --git a/.gitignore b/.gitignore index fcff2132d..cc1c2a754 100644 --- a/.gitignore +++ b/.gitignore @@ -59,8 +59,8 @@ src/api/dotnet/Enumerations.cs src/api/dotnet/Native.cs src/api/dotnet/Properties/AssemblyInfo.cs src/api/dotnet/Microsoft.Z3.xml -src/api/python/z3consts.py -src/api/python/z3core.py +src/api/python/z3/z3consts.py +src/api/python/z3/z3core.py src/ast/pattern/database.h src/util/version.h src/api/java/Native.cpp diff --git a/contrib/cmake/src/api/python/CMakeLists.txt b/contrib/cmake/src/api/python/CMakeLists.txt index 555333c9f..6babb2069 100644 --- a/contrib/cmake/src/api/python/CMakeLists.txt +++ b/contrib/cmake/src/api/python/CMakeLists.txt @@ -9,7 +9,6 @@ set(z3py_files z3poly.py z3printer.py z3rcf.py - z3test.py z3types.py z3util.py ) @@ -18,12 +17,12 @@ set(z3py_bindings_build_dest "${CMAKE_BINARY_DIR}") set(build_z3_python_bindings_target_depends "") foreach (z3py_file ${z3py_files}) - add_custom_command(OUTPUT "${z3py_bindings_build_dest}/${z3py_file}" + add_custom_command(OUTPUT "${z3py_bindings_build_dest}/z3/${z3py_file}" COMMAND "${CMAKE_COMMAND}" "-E" "copy" - "${CMAKE_CURRENT_SOURCE_DIR}/${z3py_file}" - "${z3py_bindings_build_dest}" - DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/${z3py_file}" - COMMENT "Copying \"${z3py_file}\" to ${z3py_bindings_build_dest}" + "${CMAKE_CURRENT_SOURCE_DIR}/z3/${z3py_file}" + "${z3py_bindings_build_dest}/z3.py" + DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/z3/${z3py_file}" + COMMENT "Copying \"${z3py_file}\" to ${z3py_bindings_build_dest}/z3.py/${z3py_file}" ) list(APPEND build_z3_python_bindings_target_depends "${z3py_bindings_build_dest}/${z3py_file}") endforeach() diff --git a/scripts/mk_genfile_common.py b/scripts/mk_genfile_common.py index cbeb8a82d..2ecb06776 100644 --- a/scripts/mk_genfile_common.py +++ b/scripts/mk_genfile_common.py @@ -98,7 +98,7 @@ def mk_z3consts_py_internal(api_files, output_dir): openbrace_pat = re.compile("{ *") closebrace_pat = re.compile("}.*;") - z3consts = open(os.path.join(output_dir, 'z3consts.py'), 'w') + z3consts = open(os.path.join(output_dir, 'z3/z3consts.py'), 'w') z3consts_output_path = z3consts.name z3consts.write('# Automatically generated file\n\n') for api_file in api_files: diff --git a/scripts/mk_util.py b/scripts/mk_util.py index 66191e160..0d1555e5b 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -2737,6 +2737,8 @@ def mk_def_files(): def cp_z3py_to_build(): mk_dir(BUILD_DIR) + z3py_dest = os.path.join(BUILD_DIR, 'z3.py') + z3py_src = os.path.join(Z3PY_SRC_DIR, 'z3') # Erase existing .pyc files for root, dirs, files in os.walk(Z3PY_SRC_DIR): for f in files: @@ -2746,20 +2748,19 @@ def cp_z3py_to_build(): if compileall.compile_dir(Z3PY_SRC_DIR, force=1) != 1: raise MKException("failed to compile Z3Py sources") # Copy sources to build - for py in filter(lambda f: f.endswith('.py'), os.listdir(Z3PY_SRC_DIR)): - shutil.copyfile(os.path.join(Z3PY_SRC_DIR, py), os.path.join(BUILD_DIR, py)) - if is_verbose(): - print("Copied '%s'" % py) + shutil.copytree(z3py_src, z3py_dest) + if is_verbose(): + print("Copied python bindings") # Python 2.x support - for pyc in filter(lambda f: f.endswith('.pyc'), os.listdir(Z3PY_SRC_DIR)): - shutil.copyfile(os.path.join(Z3PY_SRC_DIR, pyc), os.path.join(BUILD_DIR, pyc)) + for pyc in filter(lambda f: f.endswith('.pyc'), os.listdir(z3py_src)): + shutil.copyfile(os.path.join(z3py_src, pyc), os.path.join(z3py_dest, pyc)) if is_verbose(): print("Generated '%s'" % pyc) # Python 3.x support - src_pycache = os.path.join(Z3PY_SRC_DIR, '__pycache__') + src_pycache = os.path.join(z3py_src, '__pycache__') if os.path.exists(src_pycache): for pyc in filter(lambda f: f.endswith('.pyc'), os.listdir(src_pycache)): - target_pycache = os.path.join(BUILD_DIR, '__pycache__') + target_pycache = os.path.join(z3py_dest, '__pycache__') mk_dir(target_pycache) shutil.copyfile(os.path.join(src_pycache, pyc), os.path.join(target_pycache, pyc)) if is_verbose(): diff --git a/scripts/update_api.py b/scripts/update_api.py index 5295b19b1..047564cde 100755 --- a/scripts/update_api.py +++ b/scripts/update_api.py @@ -1706,7 +1706,7 @@ def generate_files(api_files, with mk_file_or_temp(api_output_dir, 'api_log_macros.h') as log_h: with mk_file_or_temp(api_output_dir, 'api_log_macros.cpp') as log_c: with mk_file_or_temp(api_output_dir, 'api_commands.cpp') as exe_c: - with mk_file_or_temp(z3py_output_dir, 'z3core.py') as core_py: + with mk_file_or_temp(z3py_output_dir, 'z3/z3core.py') as core_py: # Write preambles write_log_h_preamble(log_h) write_log_c_preamble(log_c) diff --git a/src/api/python/setup.py b/src/api/python/setup.py new file mode 100644 index 000000000..9d17f431f --- /dev/null +++ b/src/api/python/setup.py @@ -0,0 +1,88 @@ +import os +import sys +import platform +import subprocess +import multiprocessing +from setuptools import setup +from distutils.errors import LibError +from distutils.command.build import build as _build +from setuptools.command.develop import develop as _develop + + +build_env = dict(os.environ) +build_env['PYTHON'] = sys.executable +build_env['CXXFLAGS'] = "-std=c++11" + +build_dir = os.path.abspath(os.path.dirname(__file__)) + +if sys.platform == 'darwin': + library_file = "libz3.dylib" +elif sys.platform == 'win32': + library_file = "libz3.dll" +else: + library_file = "libz3.so" + +def _configure_z3(): + if sys.platform == 'win32': + args = [sys.executable, os.path.join(build_dir, 'scripts', + 'mk_make.py')] + if platform.architecture()[0] == '64bit': + args += ['-x'] + + if subprocess.call(args, env=build_env, cwd=build_dir) != 0: + raise LibError("Unable to configure Z3.") + else: # linux and osx + if subprocess.call([os.path.join(build_dir, 'configure')], + env=build_env, cwd=build_dir) != 0: + raise LibError("Unable to configure Z3.") + +def _build_z3(): + if sys.platform == 'win32': + if subprocess.call(['nmake'], env=build_env, + cwd=os.path.join(build_dir, 'build')) != 0: + raise LibError("Unable to build Z3.") + else: # linux and osx + if subprocess.call(['make', '-C', os.path.join(build_dir, 'build'), + '-j', str(multiprocessing.cpu_count())], + env=build_env, cwd=build_dir) != 0: + raise LibError("Unable to build Z3.") + +class build(_build): + def run(self): + self.execute(_configure_z3, (), msg="Configuring Z3") + self.execute(_build_z3, (), msg="Building Z3") + +class develop(_develop): + def run(self): + self.execute(_configure_z3, (), msg="Configuring Z3") + self.execute(_build_z3, (), msg="Building Z3") + +# the build directory needs to exist +try: os.makedirs(os.path.join(build_dir, 'build')) +except OSError: pass + +setup( + name='angr-only-z3-custom', + version='4.4.1.post4', + description='pip installable distribution of The Z3 Theorem Prover, for use with angr. Please send all support requests to angr@lists.cs.ucsb.edu!', + long_description='Z3 is a theorem prover from Microsoft Research. This version is slightly modified by the angr project to enable installation via pip, making it unsupportable by the Z3 project. Please direct all support requests to angr@lists.cs.ucsb.edu!', + author="The Z3 Theorem Prover Project", + maintainer="Yan Shoshitaishvili", + maintainer_email="yans@yancomm.net", + url='https://github.com/angr/angr-z3', + license='MIT License', + keywords=['z3', 'smt', 'sat', 'prover', 'theorem'], + package_dir={'': 'build'}, + packages=[''], + data_files=[ + ('lib', (os.path.join(build_dir, 'build', library_file),)), + ('include', tuple(os.path.join(build_dir, f) for f in ('src/api/z3.h', + 'src/api/z3_v1.h', 'src/api/z3_macros.h', + 'src/api/z3_api.h', 'src/api/z3_algebraic.h', + 'src/api/z3_polynomial.h', 'src/api/z3_rcf.h', + 'src/api/z3_interp.h', 'src/api/z3_fpa.h', + 'src/api/c++/z3++.h') )), + ], + #scripts=[os.path.join(build_dir, 'build', 'z3')] if sys.version_info[0] == 2 else [], + cmdclass={'build': build, 'develop': develop}, +) diff --git a/src/api/python/z3/__init__.py b/src/api/python/z3/__init__.py index c4f08371f..f7aa29ab1 100644 --- a/src/api/python/z3/__init__.py +++ b/src/api/python/z3/__init__.py @@ -1,10 +1,12 @@ from .z3 import * -from . import z3core from . import z3num from . import z3poly from . import z3printer from . import z3rcf from . import z3types from . import z3util + +# generated files +from . import z3core from . import z3consts diff --git a/src/api/python/z3/z3poly.py b/src/api/python/z3/z3poly.py index 4a5cac46c..169944291 100644 --- a/src/api/python/z3/z3poly.py +++ b/src/api/python/z3/z3poly.py @@ -5,6 +5,7 @@ # # Author: Leonardo de Moura (leonardo) ############################################ + from .z3 import * def subresultants(p, q, x): @@ -32,6 +33,3 @@ if __name__ == "__main__": import doctest if doctest.testmod().failed: exit(1) - - - diff --git a/src/api/python/z3/z3types.py b/src/api/python/z3/z3types.py index 8b585e0ee..7cf61f49e 100644 --- a/src/api/python/z3/z3types.py +++ b/src/api/python/z3/z3types.py @@ -121,4 +121,3 @@ class FuncEntryObj(ctypes.c_void_p): class RCFNumObj(ctypes.c_void_p): def __init__(self, e): self._as_parameter_ = e def from_param(obj): return obj - From 704105306c013cb1d30ff9edb8e8943e8a782496 Mon Sep 17 00:00:00 2001 From: Andrew Dutcher Date: Sat, 27 Aug 2016 19:36:53 -0500 Subject: [PATCH 181/536] FINISH IT --- scripts/mk_util.py | 1 + scripts/update_api.py | 7 +- src/api/python/.gitignore | 7 ++ src/api/python/MANIFEST.in | 4 ++ src/api/python/setup.py | 135 +++++++++++++++++++++++++++---------- 5 files changed, 116 insertions(+), 38 deletions(-) create mode 100644 src/api/python/.gitignore create mode 100644 src/api/python/MANIFEST.in diff --git a/scripts/mk_util.py b/scripts/mk_util.py index 0d1555e5b..0d2b23a3e 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -2748,6 +2748,7 @@ def cp_z3py_to_build(): if compileall.compile_dir(Z3PY_SRC_DIR, force=1) != 1: raise MKException("failed to compile Z3Py sources") # Copy sources to build + shutil.rmtree(z3py_dest, ignore_errors=True) shutil.copytree(z3py_src, z3py_dest) if is_verbose(): print("Copied python bindings") diff --git a/scripts/update_api.py b/scripts/update_api.py index 047564cde..1f0ae4e4c 100755 --- a/scripts/update_api.py +++ b/scripts/update_api.py @@ -1600,6 +1600,7 @@ def write_core_py_preamble(core_py): core_py.write('# Automatically generated file\n') core_py.write('import sys, os\n') core_py.write('import ctypes\n') + core_py.write('import pkg_resources\n') core_py.write('from .z3types import *\n') core_py.write('from .z3consts import *\n') core_py.write( @@ -1608,15 +1609,15 @@ _lib = None def lib(): global _lib if _lib == None: - _dir = os.path.dirname(os.path.abspath(__file__)) + _dir = pkg_resources.resource_filename('z3', 'lib') for ext in ['dll', 'so', 'dylib']: try: - init('libz3.%s' % ext) + init(os.path.join(_dir, 'libz3.%s' % ext)) break except: pass try: - init(os.path.join(_dir, 'libz3.%s' % ext)) + init('libz3.%s' % ext) break except: pass diff --git a/src/api/python/.gitignore b/src/api/python/.gitignore new file mode 100644 index 000000000..a0a01631f --- /dev/null +++ b/src/api/python/.gitignore @@ -0,0 +1,7 @@ +MANIFEST +dist +core +build +*.egg-info +bin +z3/lib diff --git a/src/api/python/MANIFEST.in b/src/api/python/MANIFEST.in new file mode 100644 index 000000000..209e0cfa3 --- /dev/null +++ b/src/api/python/MANIFEST.in @@ -0,0 +1,4 @@ +include core/LICENSE.txt +recursive-include core/src * +recursive-include core/scripts * +recursive-include core/examples * diff --git a/src/api/python/setup.py b/src/api/python/setup.py index 9d17f431f..6ccd45c60 100644 --- a/src/api/python/setup.py +++ b/src/api/python/setup.py @@ -1,65 +1,135 @@ import os import sys +import shutil import platform import subprocess import multiprocessing from setuptools import setup from distutils.errors import LibError from distutils.command.build import build as _build +from distutils.command.sdist import sdist as _sdist from setuptools.command.develop import develop as _develop +from setuptools.command.bdist_egg import bdist_egg as _bdist_egg build_env = dict(os.environ) build_env['PYTHON'] = sys.executable build_env['CXXFLAGS'] = "-std=c++11" -build_dir = os.path.abspath(os.path.dirname(__file__)) +ROOT_DIR = os.path.abspath(os.path.dirname(__file__)) +SRC_DIR_LOCAL = os.path.join(ROOT_DIR, 'core') +SRC_DIR_REPO = os.path.join(ROOT_DIR, '../../..') +SRC_DIR = SRC_DIR_LOCAL if os.path.exists(SRC_DIR_LOCAL) else SRC_DIR_REPO +BUILD_DIR = os.path.join(SRC_DIR, 'build') # implicit in configure script +LIBS_DIR = os.path.join(ROOT_DIR, 'z3', 'lib') +HEADERS_DIR = os.path.join(ROOT_DIR, 'z3', 'include') +BINS_DIR = os.path.join(ROOT_DIR, 'bin') if sys.platform == 'darwin': - library_file = "libz3.dylib" -elif sys.platform == 'win32': - library_file = "libz3.dll" + LIBRARY_FILE = "libz3.dylib" +elif sys.platform in ('win32', 'cygwin'): + LIBRARY_FILE = "libz3.dll" else: - library_file = "libz3.so" + LIBRARY_FILE = "libz3.so" + +def _clean_bins(): + """ + Clean up the binary files and headers that are installed along with the bindings + """ + shutil.rmtree(LIBS_DIR, ignore_errors=True) + shutil.rmtree(BINS_DIR, ignore_errors=True) + shutil.rmtree(HEADERS_DIR, ignore_errors=True) def _configure_z3(): - if sys.platform == 'win32': - args = [sys.executable, os.path.join(build_dir, 'scripts', - 'mk_make.py')] - if platform.architecture()[0] == '64bit': - args += ['-x'] + args = [sys.executable, os.path.join(SRC_DIR, 'scripts', 'mk_make.py')] - if subprocess.call(args, env=build_env, cwd=build_dir) != 0: - raise LibError("Unable to configure Z3.") - else: # linux and osx - if subprocess.call([os.path.join(build_dir, 'configure')], - env=build_env, cwd=build_dir) != 0: - raise LibError("Unable to configure Z3.") + if sys.platform == 'win32' and platform.architecture()[0] == '64bit': + args += ['-x'] + + if subprocess.call(args, env=build_env, cwd=SRC_DIR) != 0: + raise LibError("Unable to configure Z3.") def _build_z3(): if sys.platform == 'win32': if subprocess.call(['nmake'], env=build_env, - cwd=os.path.join(build_dir, 'build')) != 0: + cwd=BUILD_DIR) != 0: raise LibError("Unable to build Z3.") else: # linux and osx - if subprocess.call(['make', '-C', os.path.join(build_dir, 'build'), - '-j', str(multiprocessing.cpu_count())], - env=build_env, cwd=build_dir) != 0: + if subprocess.call(['make', '-j', str(multiprocessing.cpu_count())], + env=build_env, cwd=BUILD_DIR) != 0: raise LibError("Unable to build Z3.") +def _copy_bins(): + """ + Copy the library and header files into their final destinations + """ + # STEP 1: If we're performing a build from a copied source tree, + # copy the generated python files into the package + + _clean_bins() + + if SRC_DIR == SRC_DIR_LOCAL: + shutil.copy(os.path.join(SRC_DIR, 'src/api/python/z3/z3core.py'), os.path.join(ROOT_DIR, 'z3')) + shutil.copy(os.path.join(SRC_DIR, 'src/api/python/z3/z3consts.py'), os.path.join(ROOT_DIR, 'z3')) + + # STEP 2: Copy the shared library, the executable and the headers + + os.mkdir(LIBS_DIR) + os.mkdir(BINS_DIR) + os.mkdir(HEADERS_DIR) + os.mkdir(os.path.join(HEADERS_DIR, 'c++')) + shutil.copy(os.path.join(BUILD_DIR, 'libz3.so'), LIBS_DIR) + shutil.copy(os.path.join(BUILD_DIR, 'z3'), BINS_DIR) + for fname in ('z3.h', 'z3_v1.h', 'z3_macros.h', 'z3_api.h', 'z3_algebraic.h', 'z3_polynomial.h', 'z3_rcf.h', 'z3_interp.h', 'z3_fpa.h', 'c++/z3++.h'): + shutil.copy(os.path.join(SRC_DIR, 'src/api', fname), os.path.join(HEADERS_DIR, fname)) + +def _copy_sources(): + """ + Prepare for a source distribution by assembling a minimal set of source files needed + for building + """ + shutil.rmtree(SRC_DIR_LOCAL, ignore_errors=True) + os.mkdir(SRC_DIR_LOCAL) + + shutil.copy(os.path.join(SRC_DIR_REPO, 'LICENSE.txt'), SRC_DIR_LOCAL) + shutil.copytree(os.path.join(SRC_DIR_REPO, 'scripts'), os.path.join(SRC_DIR_LOCAL, 'scripts')) + shutil.copytree(os.path.join(SRC_DIR_REPO, 'examples'), os.path.join(SRC_DIR_LOCAL, 'examples')) + shutil.copytree(os.path.join(SRC_DIR_REPO, 'src'), os.path.join(SRC_DIR_LOCAL, 'src'), + ignore=lambda src, names: ['python'] if 'api' in src else []) + + # stub python dir to make build happy + os.mkdir(os.path.join(SRC_DIR_LOCAL, 'src/api/python')) + os.mkdir(os.path.join(SRC_DIR_LOCAL, 'src/api/python/z3')) + open(os.path.join(SRC_DIR_LOCAL, 'src/api/python/z3/.placeholder'), 'w').close() + class build(_build): def run(self): self.execute(_configure_z3, (), msg="Configuring Z3") self.execute(_build_z3, (), msg="Building Z3") + self.execute(_copy_bins, (), msg="Copying binaries") + _build.run(self) class develop(_develop): def run(self): self.execute(_configure_z3, (), msg="Configuring Z3") self.execute(_build_z3, (), msg="Building Z3") + self.execute(_copy_bins, (), msg="Copying binaries") + _develop.run(self) + +class bdist_egg(_bdist_egg): + def run(self): + self.run_command('build') + _bdist_egg.run(self) + +class sdist(_sdist): + def run(self): + self.execute(_clean_bins, (), msg="Cleaning binary files") + self.execute(_copy_sources, (), msg="Copying source files") + _sdist.run(self) # the build directory needs to exist -try: os.makedirs(os.path.join(build_dir, 'build')) -except OSError: pass +#try: os.makedirs(os.path.join(ROOT_DIR, 'build')) +#except OSError: pass setup( name='angr-only-z3-custom', @@ -72,17 +142,12 @@ setup( url='https://github.com/angr/angr-z3', license='MIT License', keywords=['z3', 'smt', 'sat', 'prover', 'theorem'], - package_dir={'': 'build'}, - packages=[''], - data_files=[ - ('lib', (os.path.join(build_dir, 'build', library_file),)), - ('include', tuple(os.path.join(build_dir, f) for f in ('src/api/z3.h', - 'src/api/z3_v1.h', 'src/api/z3_macros.h', - 'src/api/z3_api.h', 'src/api/z3_algebraic.h', - 'src/api/z3_polynomial.h', 'src/api/z3_rcf.h', - 'src/api/z3_interp.h', 'src/api/z3_fpa.h', - 'src/api/c++/z3++.h') )), - ], - #scripts=[os.path.join(build_dir, 'build', 'z3')] if sys.version_info[0] == 2 else [], - cmdclass={'build': build, 'develop': develop}, + packages=['z3'], + include_package_data=True, + package_data={ + 'z3': ['lib/*', 'include/*'] + }, + scripts=['bin/z3'], + #scripts=[os.path.join(ROOT_DIR, 'build', 'z3')] if sys.version_info[0] == 2 else [], + cmdclass={'build': build, 'develop': develop, 'sdist': sdist, 'bdist_egg': bdist_egg}, ) From cb83c42100e7fc1a2bbf7182523b9e19cda53bdf Mon Sep 17 00:00:00 2001 From: Andrew Dutcher Date: Sat, 10 Sep 2016 11:41:04 -0700 Subject: [PATCH 182/536] Make python stuff live in a python directory in the build tree --- scripts/mk_project.py | 3 +- scripts/mk_util.py | 75 +++++++++++++++++++++++++------------------ scripts/update_api.py | 21 ++++++------ 3 files changed, 56 insertions(+), 43 deletions(-) diff --git a/scripts/mk_project.py b/scripts/mk_project.py index 78bc290f8..00b5cdef5 100644 --- a/scripts/mk_project.py +++ b/scripts/mk_project.py @@ -87,7 +87,8 @@ def init_project_def(): reexports=['api'], dll_name='libz3', static=build_static_lib(), - export_files=API_files) + export_files=API_files, + staging_link='python') add_dot_net_dll('dotnet', ['api_dll'], 'api/dotnet', dll_name='Microsoft.Z3', assembly_info_dir='Properties', default_key_file='src/api/dotnet/Microsoft.Z3.snk') add_java_dll('java', ['api_dll'], 'api/java', dll_name='libz3java', package_name="com.microsoft.z3", manifest_file='manifest') add_ml_lib('ml', ['api_dll'], 'api/ml', lib_name='libz3ml') diff --git a/scripts/mk_util.py b/scripts/mk_util.py index 0d2b23a3e..eca0c4738 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -1230,7 +1230,7 @@ def get_so_ext(): return 'dll' class DLLComponent(Component): - def __init__(self, name, dll_name, path, deps, export_files, reexports, install, static): + def __init__(self, name, dll_name, path, deps, export_files, reexports, install, static, staging_link=None): Component.__init__(self, name, path, deps) if dll_name is None: dll_name = name @@ -1239,6 +1239,7 @@ class DLLComponent(Component): self.reexports = reexports self.install = install self.static = static + self.staging_link = staging_link # link a copy of the shared object into this directory on build def get_link_name(self): if self.static: @@ -1294,6 +1295,11 @@ class DLLComponent(Component): out.write(' $(SLINK_EXTRA_FLAGS)') if IS_WINDOWS: out.write(' /DEF:%s.def' % os.path.join(self.to_src_dir, self.name)) + if self.staging_link: + if IS_WINDOWS or IS_OSX: + out.write('\n\tcp %s %s' % (self.dll_file(), self.staging_link)) + else: + out.write('\n\tln -s %s %s' % (os.path.join(reverse_path(self.staging_link), self.dll_file()), self.staging_link)) out.write('\n') if self.static: if IS_WINDOWS: @@ -1432,13 +1438,18 @@ class PythonInstallComponent(Component): def mk_install(self, out): if not is_python_install_enabled(): return - MakeRuleCmd.make_install_directory(out, self.pythonPkgDir, in_prefix=self.in_prefix_install) + MakeRuleCmd.make_install_directory(out, + os.path.join(self.pythonPkgDir, 'z3'), + in_prefix=self.in_prefix_install) + MakeRuleCmd.make_install_directory(out, + os.path.join(self.pythonPkgDir, 'z3', 'lib'), + in_prefix=self.in_prefix_install) # Sym-link or copy libz3 into python package directory if IS_WINDOWS or IS_OSX: MakeRuleCmd.install_files(out, self.libz3Component.dll_file(), - os.path.join(self.pythonPkgDir, + os.path.join(self.pythonPkgDir, 'z3', 'lib', self.libz3Component.dll_file()), in_prefix=self.in_prefix_install ) @@ -1449,34 +1460,29 @@ class PythonInstallComponent(Component): # staged installs that use DESTDIR). MakeRuleCmd.create_relative_symbolic_link(out, self.libz3Component.install_path(), - os.path.join(self.pythonPkgDir, + os.path.join(self.pythonPkgDir, 'z3', 'lib', self.libz3Component.dll_file() ), ) - MakeRuleCmd.install_files(out, 'z3*.py', self.pythonPkgDir, + MakeRuleCmd.install_files(out, os.path.join('python', 'z3', '*.py'), + os.path.join(self.pythonPkgDir, 'z3'), in_prefix=self.in_prefix_install) if sys.version >= "3": - pythonPycacheDir = os.path.join(self.pythonPkgDir, '__pycache__') + pythonPycacheDir = os.path.join(self.pythonPkgDir, 'z3', '__pycache__') MakeRuleCmd.make_install_directory(out, pythonPycacheDir, in_prefix=self.in_prefix_install) MakeRuleCmd.install_files(out, - '{}*.pyc'.format(os.path.join('__pycache__', 'z3')), + os.path.join('python', 'z3', '__pycache__', '*.pyc'), pythonPycacheDir, in_prefix=self.in_prefix_install) else: MakeRuleCmd.install_files(out, - 'z3*.pyc', + os.path.join('python', 'z3', '*.pyc'), self.pythonPkgDir, in_prefix=self.in_prefix_install) if PYTHON_PACKAGE_DIR != distutils.sysconfig.get_python_lib(): - if os.uname()[0] == 'Darwin': - LD_LIBRARY_PATH = "DYLD_LIBRARY_PATH" - else: - LD_LIBRARY_PATH = "LD_LIBRARY_PATH" - out.write('\t@echo Z3 shared libraries were installed at \'%s\', make sure this directory is in your %s environment variable.\n' % - (os.path.join(PREFIX, INSTALL_LIB_DIR), LD_LIBRARY_PATH)) out.write('\t@echo Z3Py was installed at \'%s\', make sure this directory is in your PYTHONPATH environment variable.' % PYTHON_PACKAGE_DIR) def mk_uninstall(self, out): @@ -1488,13 +1494,13 @@ class PythonInstallComponent(Component): in_prefix=self.in_prefix_install ) MakeRuleCmd.remove_installed_files(out, - '{}*.py'.format(os.path.join(self.pythonPkgDir, 'z3')), + os.path.join(self.pythonPkgDir, 'z3', '*.py'), in_prefix=self.in_prefix_install) MakeRuleCmd.remove_installed_files(out, - '{}*.pyc'.format(os.path.join(self.pythonPkgDir, 'z3')), + os.path.join(self.pythonPkgDir, 'z3', '*.pyc'), in_prefix=self.in_prefix_install) MakeRuleCmd.remove_installed_files(out, - '{}*.pyc'.format(os.path.join(self.pythonPkgDir, '__pycache__', 'z3')), + os.path.join(self.pythonPkgDir, 'z3', '__pycache__', '*.pyc'), in_prefix=self.in_prefix_install ) @@ -2157,9 +2163,9 @@ class PythonExampleComponent(ExampleComponent): def mk_makefile(self, out): full = os.path.join(EXAMPLE_DIR, self.path) for py in filter(lambda f: f.endswith('.py'), os.listdir(full)): - shutil.copyfile(os.path.join(full, py), os.path.join(BUILD_DIR, py)) + shutil.copyfile(os.path.join(full, py), os.path.join(BUILD_DIR, 'python', py)) if is_verbose(): - print("Copied Z3Py example '%s' to '%s'" % (py, BUILD_DIR)) + print("Copied Z3Py example '%s' to '%s'" % (py, os.path.join(BUILD_DIR, 'python'))) out.write('_ex_%s: \n\n' % self.name) @@ -2189,8 +2195,8 @@ def add_extra_exe(name, deps=[], path=None, exe_name=None, install=True): c = ExtraExeComponent(name, exe_name, path, deps, install) reg_component(name, c) -def add_dll(name, deps=[], path=None, dll_name=None, export_files=[], reexports=[], install=True, static=False): - c = DLLComponent(name, dll_name, path, deps, export_files, reexports, install, static) +def add_dll(name, deps=[], path=None, dll_name=None, export_files=[], reexports=[], install=True, static=False, staging_link=None): + c = DLLComponent(name, dll_name, path, deps, export_files, reexports, install, static, staging_link) reg_component(name, c) return c @@ -2519,9 +2525,9 @@ def mk_makefile(): if c.main_component(): out.write(' %s' % c.name) out.write('\n\t@echo Z3 was successfully built.\n') - out.write("\t@echo \"Z3Py scripts can already be executed in the \'%s\' directory.\"\n" % BUILD_DIR) + out.write("\t@echo \"Z3Py scripts can already be executed in the \'%s\' directory.\"\n" % os.path.join(BUILD_DIR, 'python')) pathvar = "DYLD_LIBRARY_PATH" if IS_OSX else "PATH" if IS_WINDOWS else "LD_LIBRARY_PATH" - out.write("\t@echo \"Z3Py scripts stored in arbitrary directories can be executed if the \'%s\' directory is added to the PYTHONPATH and %s environment variables.\"\n" % (BUILD_DIR, pathvar)) + out.write("\t@echo \"Z3Py scripts stored in arbitrary directories can be executed if the \'%s\' directory is added to the PYTHONPATH environment variable and the \'%s\' directory is added to the %s environment variable.\"\n" % (os.path.join(BUILD_DIR, 'python'), BUILD_DIR, pathvar)) if not IS_WINDOWS: out.write("\t@echo Use the following command to install Z3 at prefix $(PREFIX).\n") out.write('\t@echo " sudo make install"\n\n') @@ -2737,35 +2743,40 @@ def mk_def_files(): def cp_z3py_to_build(): mk_dir(BUILD_DIR) - z3py_dest = os.path.join(BUILD_DIR, 'z3.py') + mk_dir(os.path.join(BUILD_DIR, 'python')) + z3py_dest = os.path.join(BUILD_DIR, 'python', 'z3') z3py_src = os.path.join(Z3PY_SRC_DIR, 'z3') + # Erase existing .pyc files for root, dirs, files in os.walk(Z3PY_SRC_DIR): for f in files: if f.endswith('.pyc'): rmf(os.path.join(root, f)) # Compile Z3Py files - if compileall.compile_dir(Z3PY_SRC_DIR, force=1) != 1: + if compileall.compile_dir(z3py_src, force=1) != 1: raise MKException("failed to compile Z3Py sources") + if is_verbose: + print("Generated python bytecode") # Copy sources to build - shutil.rmtree(z3py_dest, ignore_errors=True) - shutil.copytree(z3py_src, z3py_dest) - if is_verbose(): - print("Copied python bindings") + mk_dir(z3py_dest) + for py in filter(lambda f: f.endswith('.py'), os.listdir(z3py_src)): + shutil.copyfile(os.path.join(z3py_src, py), os.path.join(z3py_dest, py)) + if is_verbose(): + print("Copied '%s'" % py) # Python 2.x support for pyc in filter(lambda f: f.endswith('.pyc'), os.listdir(z3py_src)): shutil.copyfile(os.path.join(z3py_src, pyc), os.path.join(z3py_dest, pyc)) if is_verbose(): - print("Generated '%s'" % pyc) + print("Copied '%s'" % pyc) # Python 3.x support src_pycache = os.path.join(z3py_src, '__pycache__') + target_pycache = os.path.join(z3py_dest, '__pycache__') if os.path.exists(src_pycache): for pyc in filter(lambda f: f.endswith('.pyc'), os.listdir(src_pycache)): - target_pycache = os.path.join(z3py_dest, '__pycache__') mk_dir(target_pycache) shutil.copyfile(os.path.join(src_pycache, pyc), os.path.join(target_pycache, pyc)) if is_verbose(): - print("Generated '%s'" % pyc) + print("Copied '%s'" % pyc) def mk_bindings(api_files): if not ONLY_MAKEFILES: diff --git a/scripts/update_api.py b/scripts/update_api.py index 1f0ae4e4c..48a4d6114 100755 --- a/scripts/update_api.py +++ b/scripts/update_api.py @@ -1605,23 +1605,20 @@ def write_core_py_preamble(core_py): core_py.write('from .z3consts import *\n') core_py.write( """ +_ext = 'dll' if sys.platform in ('win32', 'cygwin') else 'dylib' if sys.platform == 'darwin' else 'so' + _lib = None def lib(): global _lib - if _lib == None: - _dir = pkg_resources.resource_filename('z3', 'lib') - for ext in ['dll', 'so', 'dylib']: + if _lib is None: + _dirs = ['.', pkg_resources.resource_filename('z3', 'lib'), os.path.join(sys.prefix, 'lib'), ''] + for _dir in _dirs: try: - init(os.path.join(_dir, 'libz3.%s' % ext)) + init(_dir) break except: pass - try: - init('libz3.%s' % ext) - break - except: - pass - if _lib == None: + if _lib is None: raise Z3Exception("init(Z3_LIBRARY_PATH) must be invoked before using Z3-python") return _lib @@ -1644,6 +1641,10 @@ else: return "" def init(PATH): + PATH = os.path.realpath(PATH) + if os.path.isdir(PATH): + PATH = os.path.join(PATH, 'libz3.%s' % _ext) + global _lib _lib = ctypes.CDLL(PATH) """ From 02783d0bfba4cc6b424651327baefd0b8761aa38 Mon Sep 17 00:00:00 2001 From: Andrew Dutcher Date: Wed, 14 Sep 2016 01:10:44 -0700 Subject: [PATCH 183/536] Minor tweaks to make things more reliable/less obnoxious --- scripts/mk_util.py | 2 +- src/api/python/.gitignore | 1 + src/api/python/setup.py | 3 +++ 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/scripts/mk_util.py b/scripts/mk_util.py index eca0c4738..305f94609 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -1299,7 +1299,7 @@ class DLLComponent(Component): if IS_WINDOWS or IS_OSX: out.write('\n\tcp %s %s' % (self.dll_file(), self.staging_link)) else: - out.write('\n\tln -s %s %s' % (os.path.join(reverse_path(self.staging_link), self.dll_file()), self.staging_link)) + out.write('\n\tln -f -s %s %s' % (os.path.join(reverse_path(self.staging_link), self.dll_file()), self.staging_link)) out.write('\n') if self.static: if IS_WINDOWS: diff --git a/src/api/python/.gitignore b/src/api/python/.gitignore index a0a01631f..86e4bc9ce 100644 --- a/src/api/python/.gitignore +++ b/src/api/python/.gitignore @@ -5,3 +5,4 @@ build *.egg-info bin z3/lib +z3/include diff --git a/src/api/python/setup.py b/src/api/python/setup.py index 6ccd45c60..a43ded92e 100644 --- a/src/api/python/setup.py +++ b/src/api/python/setup.py @@ -41,6 +41,9 @@ def _clean_bins(): shutil.rmtree(HEADERS_DIR, ignore_errors=True) def _configure_z3(): + # bail out early if we don't need to do this - it forces a rebuild every time otherwise + if os.path.exists(BUILD_DIR): + return args = [sys.executable, os.path.join(SRC_DIR, 'scripts', 'mk_make.py')] if sys.platform == 'win32' and platform.architecture()[0] == '64bit': From a7e3a9df5a35a88e6ee11ee5ee2b85ee436a0f0e Mon Sep 17 00:00:00 2001 From: Mathieu Roger Date: Wed, 14 Sep 2016 19:10:49 +0200 Subject: [PATCH 184/536] Create socrates.py Classical syllogism in Z3. Many samples talks about integer, reals. Not much sample available on non integer things. --- examples/python/socrates.py | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 examples/python/socrates.py diff --git a/examples/python/socrates.py b/examples/python/socrates.py new file mode 100644 index 000000000..79a1b57f1 --- /dev/null +++ b/examples/python/socrates.py @@ -0,0 +1,33 @@ +############################################ +# Copyright (c) Microsoft Corporation. All Rights Reserved. +#  +# all humans are mortal +# Socrates is a human +# so Socrates mortal +############################################ + +from z3 import * + +set_param(proof=True) + +Object = DeclareSort('Object') + +Human = Function('Human', Object, BoolSort()) +Mortal = Function('Mortal', Object, BoolSort()) + +# a well known philosopher +socrates = Const('socrates', Object) + +# free variables used in forall must be declared Const in python +x = Const('x', Object) + +axioms = [ForAll([x], Implies(Human(x), Mortal(x))), + Human(socrates) == True] + + +s = Solver() +s.add(axioms) +# classical refutation +s.add(Mortal(socrates) == False) + +print(s.check()) # prints unsat so socrates is Mortal From e7f36a2d3550f265e9a49e25f16cd562062043e4 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 14 Sep 2016 10:32:17 -0700 Subject: [PATCH 185/536] remove special characters Signed-off-by: Nikolaj Bjorner --- examples/python/socrates.py | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/examples/python/socrates.py b/examples/python/socrates.py index 79a1b57f1..49067225f 100644 --- a/examples/python/socrates.py +++ b/examples/python/socrates.py @@ -1,9 +1,9 @@ ############################################ # Copyright (c) Microsoft Corporation. All Rights Reserved. -#  -# all humans are mortal -# Socrates is a human -# so Socrates mortal +# +# all humans are mortal +# Socrates is a human +# so Socrates mortal ############################################ from z3 import * @@ -15,10 +15,10 @@ Object = DeclareSort('Object') Human = Function('Human', Object, BoolSort()) Mortal = Function('Mortal', Object, BoolSort()) -# a well known philosopher +# a well known philosopher socrates = Const('socrates', Object) -# free variables used in forall must be declared Const in python +# free variables used in forall must be declared Const in python x = Const('x', Object) axioms = [ForAll([x], Implies(Human(x), Mortal(x))), @@ -27,7 +27,9 @@ axioms = [ForAll([x], Implies(Human(x), Mortal(x))), s = Solver() s.add(axioms) -# classical refutation +# classical refutation s.add(Mortal(socrates) == False) -print(s.check()) # prints unsat so socrates is Mortal +print(s.check()) # prints unsat so socrates is Mortal + +# print(s.proof()) # prints a low level (not readable) proof object. From 9245e61775d7d7b46b04461b3ae7161d09f8b172 Mon Sep 17 00:00:00 2001 From: Mathieu Roger Date: Wed, 14 Sep 2016 21:36:39 +0200 Subject: [PATCH 186/536] Update socrates.py --- examples/python/socrates.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/examples/python/socrates.py b/examples/python/socrates.py index 49067225f..8d44b41ea 100644 --- a/examples/python/socrates.py +++ b/examples/python/socrates.py @@ -8,8 +8,6 @@ from z3 import * -set_param(proof=True) - Object = DeclareSort('Object') Human = Function('Human', Object, BoolSort()) @@ -22,14 +20,15 @@ socrates = Const('socrates', Object) x = Const('x', Object) axioms = [ForAll([x], Implies(Human(x), Mortal(x))), - Human(socrates) == True] + Human(socrates)] s = Solver() s.add(axioms) + +print(s.check()) # prints sat so axioms are coherents + # classical refutation -s.add(Mortal(socrates) == False) +s.add(Not(Mortal(socrates))) print(s.check()) # prints unsat so socrates is Mortal - -# print(s.proof()) # prints a low level (not readable) proof object. From 02217d048be04e21bf3fc96be625c8869e41f601 Mon Sep 17 00:00:00 2001 From: Andrew Dutcher Date: Wed, 14 Sep 2016 14:19:10 -0700 Subject: [PATCH 187/536] replace all non-portable filepath slashes with os.path.join --- scripts/mk_genfile_common.py | 2 +- scripts/update_api.py | 2 +- src/api/python/setup.py | 21 ++++++++++----------- 3 files changed, 12 insertions(+), 13 deletions(-) diff --git a/scripts/mk_genfile_common.py b/scripts/mk_genfile_common.py index 2ecb06776..7e7cb5584 100644 --- a/scripts/mk_genfile_common.py +++ b/scripts/mk_genfile_common.py @@ -98,7 +98,7 @@ def mk_z3consts_py_internal(api_files, output_dir): openbrace_pat = re.compile("{ *") closebrace_pat = re.compile("}.*;") - z3consts = open(os.path.join(output_dir, 'z3/z3consts.py'), 'w') + z3consts = open(os.path.join(output_dir, 'z3', 'z3consts.py'), 'w') z3consts_output_path = z3consts.name z3consts.write('# Automatically generated file\n\n') for api_file in api_files: diff --git a/scripts/update_api.py b/scripts/update_api.py index 48a4d6114..d8b2bec58 100755 --- a/scripts/update_api.py +++ b/scripts/update_api.py @@ -1708,7 +1708,7 @@ def generate_files(api_files, with mk_file_or_temp(api_output_dir, 'api_log_macros.h') as log_h: with mk_file_or_temp(api_output_dir, 'api_log_macros.cpp') as log_c: with mk_file_or_temp(api_output_dir, 'api_commands.cpp') as exe_c: - with mk_file_or_temp(z3py_output_dir, 'z3/z3core.py') as core_py: + with mk_file_or_temp(z3py_output_dir, os.path.join('z3', 'z3core.py')) as core_py: # Write preambles write_log_h_preamble(log_h) write_log_c_preamble(log_c) diff --git a/src/api/python/setup.py b/src/api/python/setup.py index a43ded92e..c6d7d8824 100644 --- a/src/api/python/setup.py +++ b/src/api/python/setup.py @@ -18,7 +18,7 @@ build_env['CXXFLAGS'] = "-std=c++11" ROOT_DIR = os.path.abspath(os.path.dirname(__file__)) SRC_DIR_LOCAL = os.path.join(ROOT_DIR, 'core') -SRC_DIR_REPO = os.path.join(ROOT_DIR, '../../..') +SRC_DIR_REPO = os.path.join(ROOT_DIR, '..', '..', '..') SRC_DIR = SRC_DIR_LOCAL if os.path.exists(SRC_DIR_LOCAL) else SRC_DIR_REPO BUILD_DIR = os.path.join(SRC_DIR, 'build') # implicit in configure script LIBS_DIR = os.path.join(ROOT_DIR, 'z3', 'lib') @@ -72,8 +72,8 @@ def _copy_bins(): _clean_bins() if SRC_DIR == SRC_DIR_LOCAL: - shutil.copy(os.path.join(SRC_DIR, 'src/api/python/z3/z3core.py'), os.path.join(ROOT_DIR, 'z3')) - shutil.copy(os.path.join(SRC_DIR, 'src/api/python/z3/z3consts.py'), os.path.join(ROOT_DIR, 'z3')) + shutil.copy(os.path.join(SRC_DIR, 'src', 'api', 'python', 'z3', 'z3core.py'), os.path.join(ROOT_DIR, 'z3')) + shutil.copy(os.path.join(SRC_DIR, 'src', 'api', 'python', 'z3', 'z3consts.py'), os.path.join(ROOT_DIR, 'z3')) # STEP 2: Copy the shared library, the executable and the headers @@ -83,8 +83,8 @@ def _copy_bins(): os.mkdir(os.path.join(HEADERS_DIR, 'c++')) shutil.copy(os.path.join(BUILD_DIR, 'libz3.so'), LIBS_DIR) shutil.copy(os.path.join(BUILD_DIR, 'z3'), BINS_DIR) - for fname in ('z3.h', 'z3_v1.h', 'z3_macros.h', 'z3_api.h', 'z3_algebraic.h', 'z3_polynomial.h', 'z3_rcf.h', 'z3_interp.h', 'z3_fpa.h', 'c++/z3++.h'): - shutil.copy(os.path.join(SRC_DIR, 'src/api', fname), os.path.join(HEADERS_DIR, fname)) + for fname in ('z3.h', 'z3_v1.h', 'z3_macros.h', 'z3_api.h', 'z3_algebraic.h', 'z3_polynomial.h', 'z3_rcf.h', 'z3_interp.h', 'z3_fpa.h', os.path.join('c++', 'z3++.h')): + shutil.copy(os.path.join(SRC_DIR, 'src', 'api', fname), os.path.join(HEADERS_DIR, fname)) def _copy_sources(): """ @@ -101,9 +101,9 @@ def _copy_sources(): ignore=lambda src, names: ['python'] if 'api' in src else []) # stub python dir to make build happy - os.mkdir(os.path.join(SRC_DIR_LOCAL, 'src/api/python')) - os.mkdir(os.path.join(SRC_DIR_LOCAL, 'src/api/python/z3')) - open(os.path.join(SRC_DIR_LOCAL, 'src/api/python/z3/.placeholder'), 'w').close() + os.mkdir(os.path.join(SRC_DIR_LOCAL, 'src', 'api', 'python')) + os.mkdir(os.path.join(SRC_DIR_LOCAL, 'src', 'api', 'python', 'z3')) + open(os.path.join(SRC_DIR_LOCAL, 'src', 'api', 'python', 'z3', '.placeholder'), 'w').close() class build(_build): def run(self): @@ -148,9 +148,8 @@ setup( packages=['z3'], include_package_data=True, package_data={ - 'z3': ['lib/*', 'include/*'] + 'z3': [os.path.join('lib', '*'), os.path.join('include', '*')] }, - scripts=['bin/z3'], - #scripts=[os.path.join(ROOT_DIR, 'build', 'z3')] if sys.version_info[0] == 2 else [], + scripts=[os.path.join('bin', 'z3')], cmdclass={'build': build, 'develop': develop, 'sdist': sdist, 'bdist_egg': bdist_egg}, ) From 9e498536b6af7770570db41ab59ec505b59e1c30 Mon Sep 17 00:00:00 2001 From: Andrew Dutcher Date: Thu, 15 Sep 2016 00:28:19 -0700 Subject: [PATCH 188/536] Fix cmake build to work with the new system --- contrib/cmake/examples/CMakeLists.txt | 1 + contrib/cmake/examples/python/CMakeLists.txt | 24 ++++++++++ contrib/cmake/src/api/python/CMakeLists.txt | 49 +++++++++++++------- 3 files changed, 56 insertions(+), 18 deletions(-) create mode 100644 contrib/cmake/examples/python/CMakeLists.txt diff --git a/contrib/cmake/examples/CMakeLists.txt b/contrib/cmake/examples/CMakeLists.txt index 49ea72fdc..e596ed3dd 100644 --- a/contrib/cmake/examples/CMakeLists.txt +++ b/contrib/cmake/examples/CMakeLists.txt @@ -1,3 +1,4 @@ add_subdirectory(c) add_subdirectory(c++) add_subdirectory(tptp) +add_subdirectory(python) diff --git a/contrib/cmake/examples/python/CMakeLists.txt b/contrib/cmake/examples/python/CMakeLists.txt new file mode 100644 index 000000000..fdbb7891f --- /dev/null +++ b/contrib/cmake/examples/python/CMakeLists.txt @@ -0,0 +1,24 @@ +set(python_example_files + example.py + visitor.py +) + +set(z3py_bindings_build_dest "${CMAKE_BINARY_DIR}/python") + +set(build_z3_python_examples_target_depends "") +foreach (example_file ${python_example_files}) + add_custom_command(OUTPUT "${z3py_bindings_build_dest}/${example_file}" + COMMAND "${CMAKE_COMMAND}" "-E" "copy" + "${CMAKE_CURRENT_SOURCE_DIR}/${example_file}" + "${z3py_bindings_build_dest}/${example_file}" + DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/${example_file}" + COMMENT "Copying \"${example_file}\" to ${z3py_bindings_build_dest}/${example_file}" + ) + list(APPEND build_z3_python_examples_target_depends "${z3py_bindings_build_dest}/${example_file}") +endforeach() + +add_custom_target(build_z3_python_examples + ALL + DEPENDS + ${build_z3_python_examples_target_depends} +) diff --git a/contrib/cmake/src/api/python/CMakeLists.txt b/contrib/cmake/src/api/python/CMakeLists.txt index 6babb2069..375890c91 100644 --- a/contrib/cmake/src/api/python/CMakeLists.txt +++ b/contrib/cmake/src/api/python/CMakeLists.txt @@ -4,31 +4,34 @@ message(STATUS "Emitting rules to build Z3 python bindings") ############################################################################### # This allows the python bindings to be used directly from the build directory set(z3py_files - z3.py - z3num.py - z3poly.py - z3printer.py - z3rcf.py - z3types.py - z3util.py + z3/__init__.py + z3/z3.py + z3/z3num.py + z3/z3poly.py + z3/z3printer.py + z3/z3rcf.py + z3/z3types.py + z3/z3util.py ) -set(z3py_bindings_build_dest "${CMAKE_BINARY_DIR}") +set(z3py_bindings_build_dest "${CMAKE_BINARY_DIR}/python") +file(MAKE_DIRECTORY "${z3py_bindings_build_dest}") +file(MAKE_DIRECTORY "${z3py_bindings_build_dest}/z3") set(build_z3_python_bindings_target_depends "") foreach (z3py_file ${z3py_files}) - add_custom_command(OUTPUT "${z3py_bindings_build_dest}/z3/${z3py_file}" + add_custom_command(OUTPUT "${z3py_bindings_build_dest}/${z3py_file}" COMMAND "${CMAKE_COMMAND}" "-E" "copy" - "${CMAKE_CURRENT_SOURCE_DIR}/z3/${z3py_file}" - "${z3py_bindings_build_dest}/z3.py" - DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/z3/${z3py_file}" - COMMENT "Copying \"${z3py_file}\" to ${z3py_bindings_build_dest}/z3.py/${z3py_file}" + "${CMAKE_CURRENT_SOURCE_DIR}/${z3py_file}" + "${z3py_bindings_build_dest}/${z3py_file}" + DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/${z3py_file}" + COMMENT "Copying \"${z3py_file}\" to ${z3py_bindings_build_dest}/${z3py_file}" ) list(APPEND build_z3_python_bindings_target_depends "${z3py_bindings_build_dest}/${z3py_file}") endforeach() # Generate z3core.py -add_custom_command(OUTPUT "${z3py_bindings_build_dest}/z3core.py" +add_custom_command(OUTPUT "${z3py_bindings_build_dest}/z3/z3core.py" COMMAND "${PYTHON_EXECUTABLE}" "${CMAKE_SOURCE_DIR}/scripts/update_api.py" ${Z3_FULL_PATH_API_HEADER_FILES_TO_SCAN} @@ -43,10 +46,10 @@ add_custom_command(OUTPUT "${z3py_bindings_build_dest}/z3core.py" COMMENT "Generating z3core.py" ${ADD_CUSTOM_COMMAND_USES_TERMINAL_ARG} ) -list(APPEND build_z3_python_bindings_target_depends "${z3py_bindings_build_dest}/z3core.py") +list(APPEND build_z3_python_bindings_target_depends "${z3py_bindings_build_dest}/z3/z3core.py") # Generate z3consts.py -add_custom_command(OUTPUT "${z3py_bindings_build_dest}/z3consts.py" +add_custom_command(OUTPUT "${z3py_bindings_build_dest}/z3/z3consts.py" COMMAND "${PYTHON_EXECUTABLE}" "${CMAKE_SOURCE_DIR}/scripts/mk_consts_files.py" ${Z3_FULL_PATH_API_HEADER_FILES_TO_SCAN} @@ -59,13 +62,23 @@ add_custom_command(OUTPUT "${z3py_bindings_build_dest}/z3consts.py" COMMENT "Generating z3consts.py" ${ADD_CUSTOM_COMMAND_USES_TERMINAL_ARG} ) -list(APPEND build_z3_python_bindings_target_depends "${z3py_bindings_build_dest}/z3consts.py") +list(APPEND build_z3_python_bindings_target_depends "${z3py_bindings_build_dest}/z3/z3consts.py") + +# Link libz3 into the python directory so bindings work out of the box +add_custom_command(OUTPUT "${z3py_bindings_build_dest}/libz3${CMAKE_SHARED_MODULE_SUFFIX}" + COMMAND "${CMAKE_COMMAND}" "-E" "create_symlink" + "${CMAKE_BINARY_DIR}/libz3${CMAKE_SHARED_MODULE_SUFFIX}" + "${z3py_bindings_build_dest}/libz3${CMAKE_SHARED_MODULE_SUFFIX}" + DEPENDS libz3 + COMMENT "Linking libz3 into python directory" +) # Convenient top-level target add_custom_target(build_z3_python_bindings ALL DEPENDS ${build_z3_python_bindings_target_depends} + "${z3py_bindings_build_dest}/libz3${CMAKE_SHARED_MODULE_SUFFIX}" ) ############################################################################### @@ -116,7 +129,7 @@ if (INSTALL_PYTHON_BINDINGS) # Using DESTDIR still seems to work even if we use an absolute path message(STATUS "Python bindings will be installed to \"${CMAKE_INSTALL_PYTHON_PKG_DIR}\"") install(FILES ${build_z3_python_bindings_target_depends} - DESTINATION "${CMAKE_INSTALL_PYTHON_PKG_DIR}" + DESTINATION "${CMAKE_INSTALL_PYTHON_PKG_DIR}/z3" ) else() message(STATUS "Not emitting rules to install Z3 python bindings") From 5b1cb499739d795ea5b41be5da692d8d37a16cd9 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Tue, 23 Aug 2016 17:39:41 +0100 Subject: [PATCH 189/536] x64 clause allocator bug fix --- src/sat/sat_clause.cpp | 81 ++++++++++++++++++------------------------ src/sat/sat_clause.h | 20 +++++------ 2 files changed, 44 insertions(+), 57 deletions(-) diff --git a/src/sat/sat_clause.cpp b/src/sat/sat_clause.cpp index eb51cb6ac..845f864f7 100644 --- a/src/sat/sat_clause.cpp +++ b/src/sat/sat_clause.cpp @@ -41,11 +41,11 @@ namespace sat { var_approx_set clause::approx(unsigned num, literal const * lits) { var_approx_set r; - for (unsigned i = 0; i < num; i++) + for (unsigned i = 0; i < num; i++) r.insert(lits[i].var()); return r; } - + void clause::update_approx() { m_approx = approx(m_size, m_lits); } @@ -123,85 +123,80 @@ namespace sat { clause_allocator::clause_allocator(): m_allocator("clause-allocator") { -#if defined(_AMD64_) +#if defined(_AMD64_) m_num_segments = 0; -#if defined(Z3DEBUG) - m_overflow_valid = false; -#endif #endif } clause * clause_allocator::get_clause(clause_offset cls_off) const { -#if defined(_AMD64_) +#if defined(_AMD64_) #if defined (Z3DEBUG) clause const* result; - if (m_overflow_valid && m_cls_offset2ptr.find(cls_off, result)) { + if (((cls_off & c_alignment_mask) == c_last_segment)) { + unsigned id = cls_off >> c_cls_alignment; + bool check = m_last_seg_id2cls.find(id, result); + SASSERT(check); return const_cast(result); } #endif - return reinterpret_cast(m_segments[cls_off & c_aligment_mask] + (static_cast(cls_off) & ~c_aligment_mask)); + return reinterpret_cast(m_segments[cls_off & c_alignment_mask] + (static_cast(cls_off) & ~c_alignment_mask)); #else return reinterpret_cast(cls_off); #endif } -#if defined(_AMD64_) +#if defined(_AMD64_) unsigned clause_allocator::get_segment(clause const* cls) { size_t ptr = reinterpret_cast(cls); - SASSERT((ptr & c_aligment_mask) == 0); - ptr &= ~0xFFFFFFFFull; // Keep only high part + SASSERT((ptr & c_alignment_mask) == 0); + ptr &= 0xFFFFFFFF00000000ull; // Keep only high part unsigned i = 0; for (i = 0; i < m_num_segments; ++i) - if (m_segments[i] == ptr) - return i; + if (m_segments[i] == ptr) + return i; i = m_num_segments; #if defined(Z3DEBUG) - SASSERT(i < c_max_segments); - if (i + 1 == c_max_segments) { - m_overflow_valid = true; - i += c_max_segments * m_cls_offset2ptr.size(); - m_ptr2cls_offset.insert(ptr, i); - m_cls_offset2ptr.insert(i, cls); + SASSERT(i <= c_last_segment); + if (i == c_last_segment) { + if (!m_last_seg_id2cls.contains(cls->id())) + m_last_seg_id2cls.insert(cls->id(), cls); } else { ++m_num_segments; m_segments[i] = ptr; } #else - SASSERT(i <= c_max_segments); - if (i == c_max_segments) { + SASSERT(i <= c_last_segment); + if (i == c_last_segment) { throw default_exception("segment out of range"); } m_segments[i] = ptr; ++m_num_segments; #endif + return i; } #endif - clause_offset clause_allocator::get_offset(clause const * ptr) const { -#if defined(_AMD64_) - unsigned segment = const_cast(this)->get_segment(ptr); + clause_offset clause_allocator::get_offset(clause const * cls) const { +#if defined(_AMD64_) + unsigned segment = const_cast(this)->get_segment(cls); #if defined(Z3DEBUG) - if (segment >= c_max_segments) { - return m_ptr2cls_offset.find(reinterpret_cast(ptr)); + SASSERT(segment <= c_last_segment); + if (segment == c_last_segment) { + SASSERT(m_last_seg_id2cls.contains(cls->id())); + return (cls->id() << c_cls_alignment) | c_last_segment; } #endif - return static_cast(reinterpret_cast(ptr)) + segment; + return static_cast(reinterpret_cast(cls)) + segment; #else - return reinterpret_cast(ptr); + return reinterpret_cast(cls); #endif } - + clause * clause_allocator::mk_clause(unsigned num_lits, literal const * lits, bool learned) { size_t size = clause::get_obj_size(num_lits); -#if defined(_AMD64_) - size_t slot = size >> c_cls_alignment; - if ((size & c_aligment_mask) != 0) - slot++; - size = slot << c_cls_alignment; -#endif void * mem = m_allocator.allocate(size); clause * cls = new (mem) clause(m_id_gen.mk(), num_lits, lits, learned); TRACE("sat", tout << "alloc: " << cls->id() << " " << cls << " " << *cls << " " << (learned?"l":"a") << "\n";); @@ -213,12 +208,6 @@ namespace sat { TRACE("sat", tout << "delete: " << cls->id() << " " << cls << " " << *cls << "\n";); m_id_gen.recycle(cls->id()); size_t size = clause::get_obj_size(cls->m_capacity); -#if defined(_AMD64_) - size_t slot = size >> c_cls_alignment; - if ((size & c_aligment_mask) != 0) - slot++; - size = slot << c_cls_alignment; -#endif cls->~clause(); m_allocator.deallocate(size, cls); } @@ -244,16 +233,16 @@ namespace sat { } return out; } - - bool clause_wrapper::contains(literal l) const { + + bool clause_wrapper::contains(literal l) const { unsigned sz = size(); for (unsigned i = 0; i < sz; i++) if (operator[](i) == l) return true; return false; } - - bool clause_wrapper::contains(bool_var v) const { + + bool clause_wrapper::contains(bool_var v) const { unsigned sz = size(); for (unsigned i = 0; i < sz; i++) if (operator[](i).var() == v) diff --git a/src/sat/sat_clause.h b/src/sat/sat_clause.h index be17cc7d9..1662b429f 100644 --- a/src/sat/sat_clause.h +++ b/src/sat/sat_clause.h @@ -47,7 +47,7 @@ namespace sat { unsigned m_frozen:1; unsigned m_reinit_stack:1; unsigned m_inact_rounds:8; - unsigned m_glue:8; + unsigned m_glue:8; unsigned m_psm:8; // transient field used during gc literal m_lits[0]; @@ -125,17 +125,15 @@ namespace sat { class clause_allocator { small_object_allocator m_allocator; id_gen m_id_gen; -#if defined(_AMD64_) +#if defined(_AMD64_) unsigned get_segment(clause const* cls); - static const unsigned c_cls_alignment = 3; - static const unsigned c_max_segments = 1 << c_cls_alignment; - static const size_t c_aligment_mask = (1ull << c_cls_alignment) - 1ull; + static const unsigned c_cls_alignment = 3; + static const unsigned c_last_segment = (1ull << c_cls_alignment) - 1ull; + static const size_t c_alignment_mask = (1ull << c_cls_alignment) - 1ull; unsigned m_num_segments; - size_t m_segments[c_max_segments]; + size_t m_segments[c_last_segment]; #if defined(Z3DEBUG) - bool m_overflow_valid; - size_t_map m_ptr2cls_offset; - u_map m_cls_offset2ptr; + u_map m_last_seg_id2cls; #endif #endif public: @@ -149,7 +147,7 @@ namespace sat { /** \brief Wrapper for clauses & binary clauses. I do not create clause objects for binary clauses. - clause_ref wraps a clause object or a pair of literals (i.e., a binary clause). + clause_ref wraps a clause object or a pair of literals (i.e., a binary clause). */ class clause_wrapper { union { @@ -163,7 +161,7 @@ namespace sat { bool is_binary() const { return m_l2_idx != null_literal.to_uint(); } unsigned size() const { return is_binary() ? 2 : m_cls->size(); } - literal operator[](unsigned idx) const { + literal operator[](unsigned idx) const { SASSERT(idx < size()); if (is_binary()) return idx == 0 ? to_literal(m_l1_idx) : to_literal(m_l2_idx); From b70cc47a9d5b60aa11db97a93774fbd429cbc70d Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Tue, 23 Aug 2016 18:46:14 +0100 Subject: [PATCH 190/536] x64 clause allocator fix for del_clause --- src/sat/sat_clause.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/sat/sat_clause.cpp b/src/sat/sat_clause.cpp index 845f864f7..0f7d0d8a4 100644 --- a/src/sat/sat_clause.cpp +++ b/src/sat/sat_clause.cpp @@ -207,6 +207,11 @@ namespace sat { void clause_allocator::del_clause(clause * cls) { TRACE("sat", tout << "delete: " << cls->id() << " " << cls << " " << *cls << "\n";); m_id_gen.recycle(cls->id()); +#if defined(_AMD64_) +#if defined(Z3DEBUG) + m_last_seg_id2cls.remove(cls->id()); +#endif +#endif size_t size = clause::get_obj_size(cls->m_capacity); cls->~clause(); m_allocator.deallocate(size, cls); From 27ea7d8e9ddca7d19aa066da6a6caebc7db17c69 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Fri, 16 Sep 2016 19:34:48 +0100 Subject: [PATCH 191/536] style/formatting --- src/sat/sat_clause.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/sat/sat_clause.cpp b/src/sat/sat_clause.cpp index 0f7d0d8a4..15c14c31b 100644 --- a/src/sat/sat_clause.cpp +++ b/src/sat/sat_clause.cpp @@ -153,11 +153,11 @@ namespace sat { ptr &= 0xFFFFFFFF00000000ull; // Keep only high part unsigned i = 0; for (i = 0; i < m_num_segments; ++i) - if (m_segments[i] == ptr) - return i; + if (m_segments[i] == ptr) + return i; i = m_num_segments; -#if defined(Z3DEBUG) SASSERT(i <= c_last_segment); +#if defined(Z3DEBUG) if (i == c_last_segment) { if (!m_last_seg_id2cls.contains(cls->id())) m_last_seg_id2cls.insert(cls->id(), cls); @@ -167,7 +167,6 @@ namespace sat { m_segments[i] = ptr; } #else - SASSERT(i <= c_last_segment); if (i == c_last_segment) { throw default_exception("segment out of range"); } From ec47a1df50134f4dad392f1fb74fc86d9ed92753 Mon Sep 17 00:00:00 2001 From: Mikolas Janota Date: Thu, 1 Sep 2016 17:22:49 +0100 Subject: [PATCH 192/536] Adding bv preprocessing techniques. --- src/ast/rewriter/bv_bounds.cpp | 667 ++++++++++++++++++++++++ src/ast/rewriter/bv_bounds.h | 130 +++++ src/ast/rewriter/bv_rewriter.cpp | 434 +++++++++++++++ src/ast/rewriter/bv_rewriter.h | 14 + src/ast/rewriter/bv_rewriter_params.pyg | 7 +- src/ast/rewriter/bv_trailing.cpp | 10 +- src/ast/rewriter/rewriter_params.pyg | 1 + src/ast/rewriter/th_rewriter.cpp | 8 + src/tactic/bv/bv_bound_chk_tactic.cpp | 245 +++++++++ src/tactic/bv/bv_bound_chk_tactic.h | 30 ++ src/tactic/smtlogics/qfufbv_tactic.cpp | 2 + 11 files changed, 1545 insertions(+), 3 deletions(-) create mode 100644 src/ast/rewriter/bv_bounds.cpp create mode 100644 src/ast/rewriter/bv_bounds.h create mode 100644 src/tactic/bv/bv_bound_chk_tactic.cpp create mode 100644 src/tactic/bv/bv_bound_chk_tactic.h diff --git a/src/ast/rewriter/bv_bounds.cpp b/src/ast/rewriter/bv_bounds.cpp new file mode 100644 index 000000000..9d3ca8c76 --- /dev/null +++ b/src/ast/rewriter/bv_bounds.cpp @@ -0,0 +1,667 @@ +/*++ + Copyright (c) 2016 Microsoft Corporation + + Module Name: + + bv_bounds.cpp + + Abstract: + + + Author: + + Mikolas Janota (MikolasJanota) + + Revision History: +--*/ +#include"bv_bounds.h" +#include"ast_smt2_pp.h" + +bv_bounds::~bv_bounds() { + reset(); +} + +bv_bounds::conv_res bv_bounds::record(app * v, numeral lo, numeral hi, bool negated, vector& nis) { + TRACE("bv_bounds", tout << "record0 " << mk_ismt2_pp(v, m_m) << ":" << (negated ? "~[" : "[") << lo << ";" << hi << "]" << std::endl;); + const unsigned bv_sz = m_bv_util.get_bv_size(v); + const numeral& zero = numeral::zero(); + const numeral& one = numeral::one(); + SASSERT(zero <= lo); + SASSERT(lo <= hi); + SASSERT(hi < numeral::power_of_two(bv_sz)); + numeral vmax, vmin; + const bool has_upper = m_unsigned_uppers.find(v, vmax); + const bool has_lower = m_unsigned_lowers.find(v, vmin); + if (!has_lower) vmin = numeral::zero(); + if (!has_upper) vmax = (numeral::power_of_two(bv_sz) - one); + bool lo_min = lo <= vmin; + bool hi_max = hi >= vmax; + if (negated) { + if (lo_min && hi_max) return UNSAT; + if (lo > vmax) return CONVERTED; + if (hi < vmin) return CONVERTED; + if (lo_min) { + negated = false; lo = hi + one; hi = vmax; + lo_min = lo <= vmin; + hi_max = true; + } else if (hi_max) { + negated = false; hi = lo - one; lo = vmin; + hi_max = hi >= vmax; + lo_min = true; + } + SASSERT(zero <= lo); + SASSERT(lo <= hi); + SASSERT(hi < numeral::power_of_two(bv_sz)); + } + if (lo_min) lo = vmin; + if (hi_max) hi = vmax; + TRACE("bv_bounds", tout << "record1 " << mk_ismt2_pp(v, m_m) << ":" << (negated ? "~[" : "[") << lo << ";" << hi << "]" << std::endl;); + if (lo > hi) return negated ? CONVERTED : UNSAT; + if (lo_min && hi_max) return negated ? UNSAT : CONVERTED; + nis.resize(nis.size() + 1); + nis.back().v = v; + nis.back().lo = lo; + nis.back().hi = hi; + nis.back().negated = negated; + return CONVERTED; +} + +bool bv_bounds::is_uleq(expr * e, expr * & v, numeral & c) { + // To detect the following rewrite from bv_rewriter: + // m().mk_and( + // m().mk_eq(m_mk_extract(bv_sz - 1, first_non_zero + 1, a), m_util.mk_numeral(numeral(0), bv_sz - first_non_zero - 1)), + // m_util.mk_ule(m_mk_extract(first_non_zero, 0, a), m_mk_extract(first_non_zero, 0, b))); + expr * eq; + expr * eql; + expr * eqr; + expr * ule; + expr * ulel; + expr * uler; + numeral eqr_val, uleqr_val; + unsigned eqr_sz, uleqr_sz; + if (!m_m.is_and(e, eq, ule)) return false; + if (!m_m.is_eq(eq, eql, eqr)) return false; + if (!m_bv_util.is_bv_ule(ule, ulel, uler)) return false; + if (!m_bv_util.is_extract(eql)) return false; + expr * const eql0 = to_app(eql)->get_arg(0); + const unsigned eql0_sz = m_bv_util.get_bv_size(eql0); + if (!m_bv_util.get_extract_high(eql) == (eql0_sz - 1)) return false; + if (!m_bv_util.is_numeral(eqr, eqr_val, eqr_sz)) return false; + if (!eqr_val.is_zero()) return false; + if (!m_bv_util.is_extract(ulel)) return false; + expr * const ulel0 = to_app(ulel)->get_arg(0); + if (ulel0 != eql0) return false; + if ((m_bv_util.get_extract_high(ulel) + 1) != m_bv_util.get_extract_low(eql)) return false; + if (!m_bv_util.get_extract_low(ulel) == 0) return false; + if (!m_bv_util.is_numeral(uler, uleqr_val, uleqr_sz)) return false; + SASSERT(m_bv_util.get_bv_size(ulel0) == uleqr_sz + eqr_sz); + v = ulel0; + c = uleqr_val; + return true; +} + +bv_bounds::conv_res bv_bounds::convert(expr * e, vector& nis, bool negated) { + TRACE("bv_bounds", tout << "new constraint: " << (negated ? "~" : "" ) << mk_ismt2_pp(e, m_m) << std::endl;); + + if (m_m.is_not(e)) { + negated = !negated; + e = to_app(e)->get_arg(0); + } + + expr *lhs, *rhs; + numeral val, val1; + unsigned bv_sz1; + + if (0) { + if (m_m.is_eq(e, lhs, rhs) && to_bound(lhs) && m_bv_util.is_numeral(rhs, val, bv_sz1)) { + return record(to_app(lhs), val, val, negated, nis); + } + + if (m_m.is_eq(e, lhs, rhs) && to_bound(rhs) && m_bv_util.is_numeral(lhs, val, bv_sz1)) { + return record(to_app(rhs), val, val, negated, nis); + } + } + + if (is_uleq(e, lhs, val) && to_bound(lhs)) { + return record(to_app(lhs), numeral::zero(), val, negated, nis); + } + + if (1) { + numeral rhs_val; + unsigned rhs_sz; + if (m_m.is_eq(e, lhs, rhs) + && m_bv_util.is_numeral(rhs, rhs_val, rhs_sz) + && rhs_val.is_zero() + && m_bv_util.is_extract(lhs)) { + expr * const lhs0 = to_app(lhs)->get_arg(0); + const unsigned lhs0_sz = m_bv_util.get_bv_size(lhs0); + if (m_bv_util.get_extract_high(lhs)+1 == lhs0_sz) { + const numeral u = numeral::power_of_two(m_bv_util.get_extract_low(lhs)) - numeral::one(); + return record(to_app(lhs0), numeral::zero(), u, negated, nis); + } + } + } + + if (m_bv_util.is_bv_ule(e, lhs, rhs)) { + unsigned bv_sz = m_bv_util.get_bv_size(lhs); + // unsigned inequality with one variable and a constant + if (to_bound(lhs) && m_bv_util.is_numeral(rhs, val, bv_sz)) // v <= val + return record(to_app(lhs), numeral::zero(), val, negated, nis); + if (to_bound(rhs) && m_bv_util.is_numeral(lhs, val, bv_sz)) // val <= v + return record(to_app(rhs), val, numeral::power_of_two(bv_sz) - numeral::one(), negated, nis); + + // unsigned inequality with one variable, constant, and addition + expr *t1, *t2; + if (m_bv_util.is_bv_add(lhs, t1, t2) + && m_bv_util.is_numeral(t1, val, bv_sz) + && to_bound(t2) + && t2 == rhs) { // val + v <= v + if (val.is_zero()) return negated ? UNSAT : CONVERTED; + SASSERT(val.is_pos()); + const numeral mod = numeral::power_of_two(bv_sz); + return record(to_app(rhs), mod - val, mod - numeral::one(), negated, nis); + } + + if (m_bv_util.is_bv_add(rhs, t1, t2) + && m_bv_util.is_numeral(t1, val, bv_sz) + && to_bound(t2) + && m_bv_util.is_numeral(lhs, val1, bv_sz1)) { // val1 <= val + v + SASSERT(bv_sz1 == bv_sz); + const numeral mod = numeral::power_of_two(bv_sz); + if (val1.is_zero()) return negated ? UNSAT : CONVERTED; + if (val1 < val) { + const numeral nl = mod - val; + const numeral nh = mod + val1 - val - numeral::one(); + return nl <= nh ? record(to_app(t2), nl, nh, !negated, nis) : (negated ? UNSAT : CONVERTED); + } + else { + const numeral l = val1 - val; + const numeral h = mod - val - numeral::one(); + return l <= h ? record(to_app(t2), l, h, negated, nis) : (negated ? CONVERTED : UNSAT); + } + } + + if (m_bv_util.is_bv_add(lhs, t1, t2) + && m_bv_util.is_numeral(t1, val, bv_sz) + && to_bound(t2) + && m_bv_util.is_numeral(rhs, val1, bv_sz1)) { // val + v <= val1 + SASSERT(bv_sz1 == bv_sz); + if (!val.is_pos() || !val1.is_pos()) return UNDEF; + const numeral mod = numeral::power_of_two(bv_sz); + if (val <= val1) { + const numeral nl = val1 - val + numeral::one(); + const numeral nh = mod - val - numeral::one(); + return nl <= nh ? record(to_app(t2), nl, nh, !negated, nis) : (negated ? UNSAT : CONVERTED); + } + else { + const numeral l = mod - val; + const numeral h = l + val1; + return record(to_app(t2), l, h, negated, nis); + } + } + + // v + c1 <= v + c2 + app * v1(NULL), *v2(NULL); + numeral val1, val2; + if (is_constant_add(bv_sz, lhs, v1, val1) + && is_constant_add(bv_sz, rhs, v2, val2) + && v1 == v2) { + if (val1 == val2) return negated ? UNSAT : CONVERTED; + const numeral mod = numeral::power_of_two(bv_sz); + if (val1 < val2) { + SASSERT(val1 < (mod - numeral::one())); + SASSERT(val2 > numeral::zero()); + return record(v1, mod - val2, mod - val1 - numeral::one(), !negated, nis); + } + else { + SASSERT(val1 > val2); + SASSERT(val2 < (mod - numeral::one())); + SASSERT(val1 > numeral::zero()); + return record(v1, mod - val1, mod - val2 - numeral::one(), negated, nis); + } + } + } + + if (m_bv_util.is_bv_sle(e, lhs, rhs)) { + unsigned bv_sz = m_bv_util.get_bv_size(lhs); + // signed inequality with one variable and a constant + if (to_bound(lhs) && m_bv_util.is_numeral(rhs, val, bv_sz)) { // v <= val + val = m_bv_util.norm(val, bv_sz, true); + return convert_signed(to_app(lhs), -numeral::power_of_two(bv_sz - 1), val, negated, nis); + } + if (to_bound(rhs) && m_bv_util.is_numeral(lhs, val, bv_sz)) { // val <= v + val = m_bv_util.norm(val, bv_sz, true); + return convert_signed(to_app(rhs), val, numeral::power_of_two(bv_sz - 1) - numeral::one(), negated, nis); + } + } + + return UNDEF; +} + +void bv_bounds::reset() { + intervals_map::iterator it = m_negative_intervals.begin(); + const intervals_map::iterator end = m_negative_intervals.end(); + for (; it != end; ++it) dealloc(it->m_value); +} + +br_status bv_bounds::rewrite(unsigned limit, func_decl * f, unsigned num, expr * const * args, expr_ref& result) { + const family_id fid = f->get_family_id(); + if (!m_m.is_bool(f->get_range())) return BR_FAILED; + const decl_kind k = f->get_decl_kind(); + if ((k != OP_OR && k != OP_AND) || num > limit) return BR_FAILED; + const bool negated = k == OP_OR; + vector nis; + vector lengths; + vector ignore; + unsigned nis_head = 0; + for (unsigned i = 0; i < num && m_okay; ++i) { + expr * const curr = args[i]; + const conv_res cr = convert(curr, nis, negated); + ignore.push_back(cr == UNDEF); + switch (cr) { + case UNDEF: continue; + case UNSAT: m_okay = false; break; + case CONVERTED: + { + for (unsigned i = nis_head; i < nis.size(); ++i) { + const ninterval& ni = nis[i]; + m_okay = m_okay && add_bound_unsigned(ni.v, ni.lo, ni.hi, ni.negated); + } + lengths.push_back(nis.size()); + nis_head = nis.size(); + break; + } + default: UNREACHABLE(); + } + } + if (!m_okay || !is_sat()) { + result = negated ? m_m.mk_true() : m_m.mk_false(); + return BR_DONE; + } + nis_head = 0; + unsigned count = 0; + expr_ref_vector nargs(m_m); + bool has_singls = false; + for (unsigned i = 0; i < num && m_okay; ++i) { + TRACE("bv_bounds", tout << "check red: " << mk_ismt2_pp(args[i], m_m) << std::endl;); + if (ignore[i]) { + TRACE("bv_bounds", tout << "unprocessed" << std::endl;); + nargs.push_back(args[i]); + continue; + } + SASSERT(nis_head <= lengths[count]); + const bool redundant = nis_head == lengths[count]; + bool is_singl = false; + if (nis_head < lengths[count]) { + app * const v = nis[nis_head].v; + numeral th, tl; + const unsigned bv_sz = m_bv_util.get_bv_size(v); + const bool has_upper = m_unsigned_uppers.find(v, th); + const bool has_lower = m_unsigned_lowers.find(v, tl); + const numeral& one = numeral::one(); + if (!has_lower) tl = numeral::zero(); + if (!has_upper) th = (numeral::power_of_two(bv_sz) - one); + TRACE("bv_bounds", tout << "bounds: " << mk_ismt2_pp(v, m_m) << "[" << tl << "-" << th << "]" << std::endl;); + is_singl = tl == th; + nis_head = lengths[count]; + } + if (!redundant && !is_singl) nargs.push_back(args[i]); + has_singls |= is_singl; + CTRACE("bv_bounds", redundant, tout << "redundant: " << mk_ismt2_pp(args[i], m_m) << std::endl;); + ++count; + } + + if (nargs.size() == num && !has_singls) return BR_FAILED; + + expr_ref eq(m_m); + for (bv_bounds::bound_map::iterator i = m_singletons.begin(); i != m_singletons.end(); ++i) { + app * const v = i->m_key; + const rational val = i->m_value; + eq = m_m.mk_eq(v, bvu().mk_numeral(val, v->get_decl()->get_range())); + if (negated) eq = m_m.mk_not(eq); + nargs.push_back(eq); + } + + switch (nargs.size()) { + case 0: result = negated ? m_m.mk_false() : m_m.mk_true(); return BR_DONE; + case 1: result = nargs.get(0); return BR_DONE; + default: result = negated ? m_m.mk_or(nargs.size(), nargs.c_ptr()) + : m_m.mk_and(nargs.size(), nargs.c_ptr()); + return BR_DONE; + } +} + +bool bv_bounds::add_constraint(expr* e) { + TRACE("bv_bounds", tout << "new constraint" << mk_ismt2_pp(e, m_m) << std::endl;); + if (!m_okay) return false; + + bool negated = false; + if (m_m.is_not(e)) { + negated = true; + e = to_app(e)->get_arg(0); + } + + expr *lhs, *rhs; + numeral val, val1; + unsigned bv_sz1; + + if (0) { + if (m_m.is_eq(e, lhs, rhs) && to_bound(lhs) && m_bv_util.is_numeral(rhs, val, bv_sz1)) { + return add_bound_unsigned(to_app(lhs), val, val, negated); + } + + if (m_m.is_eq(e, lhs, rhs) && to_bound(rhs) && m_bv_util.is_numeral(lhs, val, bv_sz1)) { + return add_bound_unsigned(to_app(rhs), val, val, negated); + } + } + + + if (m_bv_util.is_bv_ule(e, lhs, rhs)) { + unsigned bv_sz = m_bv_util.get_bv_size(lhs); + // unsigned inequality with one variable and a constant + if (to_bound(lhs) && m_bv_util.is_numeral(rhs, val, bv_sz)) // v <= val + return add_bound_unsigned(to_app(lhs), numeral::zero(), val, negated); + if (to_bound(rhs) && m_bv_util.is_numeral(lhs, val, bv_sz)) // val <= v + return add_bound_unsigned(to_app(rhs), val, numeral::power_of_two(bv_sz) - numeral::one(), negated); + + // unsigned inequality with one variable, constant, and addition + expr *t1, *t2; + if (m_bv_util.is_bv_add(lhs, t1, t2) + && m_bv_util.is_numeral(t1, val, bv_sz) + && to_bound(t2) + && t2 == rhs) { // val + v <= v + if (!val.is_pos()) return m_okay; + const numeral mod = numeral::power_of_two(bv_sz); + return add_bound_unsigned(to_app(rhs), mod - val, mod - numeral::one(), negated); + } + + if (m_bv_util.is_bv_add(rhs, t1, t2) + && m_bv_util.is_numeral(t1, val, bv_sz) + && to_bound(t2) + && m_bv_util.is_numeral(lhs, val1, bv_sz1)) { // val1 <= val + v + SASSERT(bv_sz1 == bv_sz); + if (!val.is_pos() || !val1.is_pos()) return m_okay; + const numeral mod = numeral::power_of_two(bv_sz); + if (val1 < val) { + const numeral nl = mod - val; + const numeral nh = mod + val1 - val - numeral::one(); + return nl <= nh ? add_bound_unsigned(to_app(t2), nl, nh, !negated) : m_okay; + } + else { + const numeral l = val1 - val; + const numeral h = mod - val - numeral::one(); + return l <= h ? add_bound_unsigned(to_app(t2), l, h, negated) : m_okay; + } + } + + if (m_bv_util.is_bv_add(lhs, t1, t2) + && m_bv_util.is_numeral(t1, val, bv_sz) + && to_bound(t2) + && m_bv_util.is_numeral(rhs, val1, bv_sz1)) { // val + v <= val1 + SASSERT(bv_sz1 == bv_sz); + if (!val.is_pos() || !val1.is_pos()) return m_okay; + const numeral mod = numeral::power_of_two(bv_sz); + if (val <= val1) { + const numeral nl = val1 - val + numeral::one(); + const numeral nh = mod - val - numeral::one(); + return nl <= nh ? add_bound_unsigned(to_app(t2), nl, nh, !negated) : m_okay; + } + else { + const numeral l = mod - val; + const numeral h = l + val1; + return add_bound_unsigned(to_app(t2), l, h, negated); + } + } + + // v + c1 <= v + c2 + app * v1(NULL), *v2(NULL); + numeral val1, val2; + if (is_constant_add(bv_sz, lhs, v1, val1) + && is_constant_add(bv_sz, rhs, v2, val2) + && v1 == v2) { + if (val1 == val2) return m_okay; + const numeral mod = numeral::power_of_two(bv_sz); + if (val1 < val2) { + SASSERT(val1 < (mod - numeral::one())); + SASSERT(val2 > numeral::zero()); + return add_bound_unsigned(v1, mod - val2, mod - val1 - numeral::one(), !negated); + } + else { + SASSERT(val1 > val2); + SASSERT(val2 < (mod - numeral::one())); + SASSERT(val1 > numeral::zero()); + return add_bound_unsigned(v1, mod - val1, mod - val2 - numeral::one(), negated); + } + } + } + + if (m_bv_util.is_bv_sle(e, lhs, rhs)) { + unsigned bv_sz = m_bv_util.get_bv_size(lhs); + // signed inequality with one variable and a constant + if (to_bound(lhs) && m_bv_util.is_numeral(rhs, val, bv_sz)) { // v <= val + val = m_bv_util.norm(val, bv_sz, true); + return add_bound_signed(to_app(lhs), -numeral::power_of_two(bv_sz - 1), val, negated); + } + if (to_bound(rhs) && m_bv_util.is_numeral(lhs, val, bv_sz)) { // val <= v + val = m_bv_util.norm(val, bv_sz, true); + return add_bound_signed(to_app(rhs), val, numeral::power_of_two(bv_sz - 1) - numeral::one(), negated); + } + } + + return m_okay; +} + +bool bv_bounds::add_bound_unsigned(app * v, numeral a, numeral b, bool negate) { + TRACE("bv_bounds", tout << "bound_unsigned " << mk_ismt2_pp(v, m_m) << ": " << (negate ? "~[" : "[") << a << ";" << b << "]" << std::endl;); + const unsigned bv_sz = m_bv_util.get_bv_size(v); + const numeral& zero = numeral::zero(); + const numeral& one = numeral::one(); + SASSERT(zero <= a); + SASSERT(a <= b); + SASSERT(b < numeral::power_of_two(bv_sz)); + const bool a_min = a == zero; + const bool b_max = b == (numeral::power_of_two(bv_sz) - one); + if (negate) { + if (a_min && b_max) return m_okay = false; + if (a_min) return bound_lo(v, b + one); + if (b_max) return bound_up(v, a - one); + return add_neg_bound(v, a, b); + } + else { + if (!a_min) m_okay &= bound_lo(v, a); + if (!b_max) m_okay &= bound_up(v, b); + return m_okay; + } +} + +bv_bounds::conv_res bv_bounds::convert_signed(app * v, numeral a, numeral b, bool negate, vector& nis) { + TRACE("bv_bounds", tout << "convert_signed " << mk_ismt2_pp(v, m_m) << ":" << (negate ? "~[" : "[") << a << ";" << b << "]" << std::endl;); + const unsigned bv_sz = m_bv_util.get_bv_size(v); + SASSERT(a <= b); + const numeral& zero = numeral::zero(); + const numeral& one = numeral::one(); + const bool a_neg = a < zero; + const bool b_neg = b < zero; + if (!a_neg && !b_neg) return record(v, a, b, negate, nis); + const numeral mod = numeral::power_of_two(bv_sz); + if (a_neg && b_neg) return record(v, mod + a, mod + b, negate, nis); + SASSERT(a_neg && !b_neg); + if (negate) { + const conv_res r1 = record(v, mod + a, mod - one, true, nis); + const conv_res r2 = record(v, zero, b, true, nis); + return r1 == UNSAT || r2 == UNSAT ? UNSAT : CONVERTED; + } + else { + const numeral l = b + one; + const numeral u = mod + a - one; + return l <= u ? record(v, l, u, true, nis) : CONVERTED; + } +} + +bool bv_bounds::add_bound_signed(app * v, numeral a, numeral b, bool negate) { + TRACE("bv_bounds", tout << "bound_signed " << mk_ismt2_pp(v, m_m) << ":" << (negate ? "~" : " ") << a << ";" << b << std::endl;); + const unsigned bv_sz = m_bv_util.get_bv_size(v); + SASSERT(a <= b); + const numeral& zero = numeral::zero(); + const numeral& one = numeral::one(); + const bool a_neg = a < zero; + const bool b_neg = b < zero; + if (!a_neg && !b_neg) return add_bound_unsigned(v, a, b, negate); + const numeral mod = numeral::power_of_two(bv_sz); + if (a_neg && b_neg) return add_bound_unsigned(v, mod + a, mod + b, negate); + SASSERT(a_neg && !b_neg); + if (negate) { + return add_bound_unsigned(v, mod + a, mod - one, true) + && add_bound_unsigned(v, zero, b, true); + } + else { + const numeral l = b + one; + const numeral u = mod + a - one; + return (l <= u) ? add_bound_unsigned(v, l, u, true) : m_okay; + } +} + +bool bv_bounds::bound_lo(app * v, numeral l) { + SASSERT(in_range(v, l)); + TRACE("bv_bounds", tout << "lower " << mk_ismt2_pp(v, m_m) << ":" << l << std::endl;); + // l <= v + bound_map::obj_map_entry * const entry = m_unsigned_lowers.insert_if_not_there2(v, l); + if (!(entry->get_data().m_value < l)) return m_okay; + // improve bound + entry->get_data().m_value = l; + return m_okay; +} + +bool bv_bounds::bound_up(app * v, numeral u) { + SASSERT(in_range(v, u)); + TRACE("bv_bounds", tout << "upper " << mk_ismt2_pp(v, m_m) << ":" << u << std::endl;); + // v <= u + bound_map::obj_map_entry * const entry = m_unsigned_uppers.insert_if_not_there2(v, u); + if (!(u < entry->get_data().m_value)) return m_okay; + // improve bound + entry->get_data().m_value = u; + return m_okay; +} + +bool bv_bounds::add_neg_bound(app * v, numeral a, numeral b) { + TRACE("bv_bounds", tout << "negative bound " << mk_ismt2_pp(v, m_m) << ":" << a << ";" << b << std::endl;); + bv_bounds::interval negative_interval(a, b); + SASSERT(m_bv_util.is_bv(v)); + SASSERT(a >= numeral::zero()); + SASSERT(b < numeral::power_of_two(m_bv_util.get_bv_size(v))); + SASSERT(a <= b); + + intervals_map::obj_map_entry * const e = m_negative_intervals.find_core(v); + intervals * ivs(NULL); + if (e == 0) { + ivs = alloc(intervals); + m_negative_intervals.insert(v, ivs); + } + else { + ivs = e->get_data().get_value(); + } + ivs->push_back(negative_interval); + return m_okay; +} + + +bool bv_bounds::is_sat() { + if (!m_okay) return false; + obj_hashtable seen; + obj_hashtable::entry *dummy; + + for (bound_map::iterator i = m_unsigned_lowers.begin(); i != m_unsigned_lowers.end(); ++i) { + app * const v = i->m_key; + if (!seen.insert_if_not_there_core(v, dummy)) continue; + if (!is_sat(v)) return false; + } + + for (bound_map::iterator i = m_unsigned_uppers.begin(); i != m_unsigned_uppers.end(); ++i) { + app * const v = i->m_key; + if (!seen.insert_if_not_there_core(v, dummy)) continue; + if (!is_sat(v)) return false; + } + + for (intervals_map::iterator i = m_negative_intervals.begin(); i != m_negative_intervals.end(); ++i) { + app * const v = i->m_key; + if (!seen.insert_if_not_there_core(v, dummy)) continue; + if (!is_sat(v)) return false; + } + + return true; +} + +struct interval_comp_t { + bool operator() (bv_bounds::interval i, bv_bounds::interval j) { + return (i.first < j.first); + } +} interval_comp; + + +void bv_bounds::record_singleton(app * v, numeral& singleton_value) { + TRACE("bv_bounds", tout << "singleton:" << mk_ismt2_pp(v, m_m) << ":" << singleton_value << std::endl;); + SASSERT(!m_singletons.find(v, singleton_value)); + m_singletons.insert(v, singleton_value); +} + +bool bv_bounds::is_sat(app * v) { + TRACE("bv_bounds", tout << "is_sat " << mk_ismt2_pp(v, m_m) << std::endl;); + const bool rv = is_sat_core(v); + TRACE("bv_bounds", tout << "is_sat " << mk_ismt2_pp(v, m_m) << "\nres: " << rv << std::endl;); + return rv; +} + +bool bv_bounds::is_sat_core(app * v) { + SASSERT(m_bv_util.is_bv(v)); + if (!m_okay) return false; + func_decl * const d = v->get_decl(); + unsigned const bv_sz = m_bv_util.get_bv_size(v); + numeral lower, upper; + const bool has_upper = m_unsigned_uppers.find(v, upper); + const bool has_lower = m_unsigned_lowers.find(v, lower); + if (has_upper && has_lower && lower > upper) return false; + const numeral& one = numeral::one(); + if (!has_lower) lower = numeral::zero(); + if (!has_upper) upper = (numeral::power_of_two(bv_sz) - one); + TRACE("bv_bounds", tout << "is_sat bound:" << lower << "-" << upper << std::endl;); + intervals * negative_intervals(NULL); + const bool has_neg_intervals = m_negative_intervals.find(v, negative_intervals); + bool is_sat(false); + numeral new_lo = lower; + numeral new_hi = lower - one; + numeral ptr = lower; + if (has_neg_intervals) { + SASSERT(negative_intervals != NULL); + std::sort(negative_intervals->begin(), negative_intervals->end(), interval_comp); + intervals::const_iterator e = negative_intervals->end(); + for (intervals::const_iterator i = negative_intervals->begin(); i != e; ++i) { + const numeral negative_lower = i->first; + const numeral negative_upper = i->second; + if (ptr > negative_upper) continue; + if (ptr < negative_lower) { + if (!is_sat) new_lo = ptr; + new_hi = negative_lower - one; + if (new_hi > upper) new_hi = upper; + is_sat = true; + } + TRACE("bv_bounds", tout << "is_sat new_lo, new_hi:" << new_lo << "-" << new_hi << std::endl;); + ptr = negative_upper + one; + TRACE("bv_bounds", tout << "is_sat ptr, new_hi:" << ptr << "-" << new_hi << std::endl;); + if (ptr > upper) break; + } + } + + if (ptr <= upper) { + if (!is_sat) new_lo = ptr; + new_hi = upper; + is_sat = true; + } + if (new_hi < upper) bound_up(v, new_hi); + if (new_lo > lower) bound_lo(v, new_lo); + TRACE("bv_bounds", tout << "is_sat new_lo, new_hi:" << new_lo << "-" << new_hi << std::endl;); + + const bool is_singleton = is_sat && new_hi == new_lo; + if (is_singleton) record_singleton(v, new_lo); + + return is_sat; +} diff --git a/src/ast/rewriter/bv_bounds.h b/src/ast/rewriter/bv_bounds.h new file mode 100644 index 000000000..eeefc2c11 --- /dev/null +++ b/src/ast/rewriter/bv_bounds.h @@ -0,0 +1,130 @@ + /*++ + Copyright (c) 2016 Microsoft Corporation + + Module Name: + + bv_bounds.h + + Abstract: + + A class used to determine bounds on bit-vector variables. + The satisfiability procedure is polynomial. + + + Author: + + Mikolas Janota (MikolasJanota) + + Revision History: + --*/ +#ifndef BV_BOUNDS_H_23754 +#define BV_BOUNDS_H_23754 +#include"ast.h" +#include"bv_decl_plugin.h" +#include"rewriter_types.h" + +/* \brief A class to analyze constraints on bit vectors. + + The objective is to identify inconsistencies in polynomial time. + All bounds/intervals are closed. Methods that add new constraints + return false if inconsistency has already been reached. + Typical usage is to call repeatedly add_constraint(e) and call is_sat() in the end. + */ +class bv_bounds { +public: + typedef rational numeral; + typedef std::pair interval; + typedef obj_map bound_map; + bv_bounds(ast_manager& m) : m_m(m), m_bv_util(m), m_okay(true) {}; + ~bv_bounds(); +public: // bounds addition methods + br_status rewrite(unsigned limit, func_decl * f, unsigned num, expr * const * args, expr_ref& result); + + /** \brief Add a constraint to the system. + + The added constraints are to be considered by is_sat. + Currently, only special types of inequalities are supported, e.g. v <= v+1. + Other constraints are ignored. + Returns false if the system became trivially unsatisfiable + **/ + bool add_constraint(expr* e); + + bool bound_up(app * v, numeral u); // v <= u + bool bound_lo(app * v, numeral l); // l <= v + inline bool add_neg_bound(app * v, numeral a, numeral b); // not (a<=v<=b) + bool add_bound_signed(app * v, numeral a, numeral b, bool negate); + bool add_bound_unsigned(app * v, numeral a, numeral b, bool negate); +public: + bool is_sat(); ///< Determine if the set of considered constraints is satisfiable. + bool is_okay(); + const bound_map& singletons() { return m_singletons; } + bv_util& bvu() { return m_bv_util; } + void reset(); +protected: + struct ninterval { + //ninterval(app * v, numeral lo, numeral hi, bool negated) : v(v), lo(lo), hi(hi), negated(negated) {} + app * v; + numeral lo, hi; + bool negated; + }; + enum conv_res { CONVERTED, UNSAT, UNDEF }; + conv_res convert(expr * e, vector& nis, bool negated); + conv_res record(app * v, numeral lo, numeral hi, bool negated, vector& nis); + conv_res convert_signed(app * v, numeral a, numeral b, bool negate, vector& nis); + + typedef vector intervals; + typedef obj_map intervals_map; + ast_manager& m_m; + bound_map m_unsigned_lowers; + bound_map m_unsigned_uppers; + intervals_map m_negative_intervals; + bound_map m_singletons; + bv_util m_bv_util; + bool m_okay; + bool is_sat(app * v); + bool is_sat_core(app * v); + inline bool in_range(app *v, numeral l); + inline bool is_constant_add(unsigned bv_sz, expr * e, app*& v, numeral& val); + void record_singleton(app * v, numeral& singleton_value); + inline bool to_bound(const expr * e) const; + bool is_uleq(expr * e, expr * & v, numeral & c); +}; + + +inline bool bv_bounds::is_okay() { return m_okay; } + +inline bool bv_bounds::to_bound(const expr * e) const { + return is_app(e) && m_bv_util.is_bv(e) + && !m_bv_util.is_bv_add(e) + && !m_bv_util.is_numeral(e); +} + +inline bool bv_bounds::in_range(app *v, bv_bounds::numeral n) { + const unsigned bv_sz = m_bv_util.get_bv_size(v); + const bv_bounds::numeral zero(0); + const bv_bounds::numeral mod(rational::power_of_two(bv_sz)); + return (zero <= n) && (n < mod); +} + +inline bool bv_bounds::is_constant_add(unsigned bv_sz, expr * e, app*& v, numeral& val) { + SASSERT(e && !v); + SASSERT(m_bv_util.get_bv_size(e) == bv_sz); + expr *lhs(NULL), *rhs(NULL); + if (!m_bv_util.is_bv_add(e, lhs, rhs)) { + v = to_app(e); + val = rational(0); + return true; + } + if (to_bound(lhs) && m_bv_util.is_numeral(rhs, val, bv_sz)) { + v = to_app(lhs); + return true; + } + if (to_bound(rhs) && m_bv_util.is_numeral(lhs, val, bv_sz)) { + v = to_app(rhs); + return true; + } + return false; +} + + +#endif /* BV_BOUNDS_H_23754 */ diff --git a/src/ast/rewriter/bv_rewriter.cpp b/src/ast/rewriter/bv_rewriter.cpp index 07e97364e..dcb5ba681 100644 --- a/src/ast/rewriter/bv_rewriter.cpp +++ b/src/ast/rewriter/bv_rewriter.cpp @@ -29,12 +29,18 @@ void bv_rewriter::updt_local_params(params_ref const & _p) { m_mul2concat = p.mul2concat(); m_bit2bool = p.bit2bool(); m_trailing = p.bv_trailing(); + m_urem_simpl = p.bv_urem_simpl(); m_blast_eq_value = p.blast_eq_value(); m_split_concat_eq = p.split_concat_eq(); m_udiv2mul = p.udiv2mul(); m_bvnot2arith = p.bvnot2arith(); + m_bvnot_simpl = p.bv_not_simpl(); m_bv_sort_ac = p.bv_sort_ac(); m_mkbv2num = _p.get_bool("mkbv2num", false); + m_extract_prop = p.bv_extract_prop(); + m_ite2id = p.bv_ite2id(); + m_le_extra = p.bv_le_extra(); + set_sort_sums(p.bv_sort_ac()); } void bv_rewriter::updt_params(params_ref const & p) { @@ -234,6 +240,198 @@ br_status bv_rewriter::mk_slt(expr * a, expr * b, expr_ref & result) { return BR_REWRITE2; } +// short-circuited concat +expr * bv_rewriter::concat(unsigned num_args, expr * const * args) { + SASSERT(num_args); + switch (num_args) { + case 0: return m_util.mk_concat(num_args, args); + case 1: return args[0]; + default: return m_util.mk_concat(num_args, args); + } +} + +// finds a commonality in sums, e.g. 2 + x + y and 5 + x + y +bool bv_rewriter::are_eq_upto_num(expr * _a, expr * _b, + expr_ref& common, + numeral& a0_val, numeral& b0_val) { + const bool aadd = m_util.is_bv_add(_a); + const bool badd = m_util.is_bv_add(_b); + const bool has_num_a = aadd && to_app(_a)->get_num_args() && is_numeral(to_app(_a)->get_arg(0)); + const bool has_num_b = badd && to_app(_b)->get_num_args() && is_numeral(to_app(_b)->get_arg(0)); + a0_val = numeral::zero(); + b0_val = numeral::zero(); + if (!aadd && !badd) { + if (_a == _b) { + common = _a; + return true; + } else { + return false; + } + } + if (!aadd && badd) { + if (to_app(_a)->get_num_args() != 2 || !has_num_a || to_app(_a)->get_arg(0) != _b) + return false; + common = _b; + return true; + } + if (aadd && !badd) { + if (to_app(_b)->get_num_args() != 2 || !has_num_b || to_app(_b)->get_arg(0) != _a) + return false; + common = _a; + return true; + } + SASSERT(aadd && badd); + app * const a = to_app(_a); + app * const b = to_app(_b); + const unsigned numa = a->get_num_args(); + const unsigned numb = b->get_num_args(); + if (!numa || !numb) return false; + if ((numa - (has_num_a ? 1 : 0)) != (numb - (has_num_b ? 1 : 0))) return false; + unsigned ai = has_num_a ? 1 : 0; + unsigned bi = has_num_b ? 1 : 0; + while (ai < numa) { + if (a->get_arg(ai) != b->get_arg(bi)) return false; + ++ai; + ++bi; + } + a0_val = numeral::zero(); + b0_val = numeral::zero(); + const unsigned sz = m_util.get_bv_size(a); + unsigned a0_sz(sz), b0_sz(sz); + if (has_num_a) is_numeral(a->get_arg(0), a0_val, a0_sz); + if (has_num_b) is_numeral(b->get_arg(0), b0_val, b0_sz); + SASSERT(a0_sz == m_util.get_bv_size(a) && b0_sz == m_util.get_bv_size(a)); + if (has_num_a && numa > 2) { + common = m().mk_app(m_util.get_fid(), add_decl_kind(), numa - 1, a->get_args() + 1); + } + else { + common = has_num_a ? a->get_arg(1) : a; + } + return true; +} + +// simplifies expressions as (bvuleq (X + c1) (X + c2)) for some common expression X and numerals c1, c2 +br_status bv_rewriter::rw_leq_overflow(bool is_signed, expr * a, expr * b, expr_ref & result) { + if (is_signed) return BR_FAILED; + expr_ref common(m()); + numeral a0_val, b0_val; + if (!are_eq_upto_num(a, b, common, a0_val, b0_val)) return BR_FAILED; + SASSERT(a0_val.is_nonneg() && b0_val.is_nonneg()); + const unsigned sz = m_util.get_bv_size(a); + if (a0_val == b0_val) { + result = m().mk_true(); + return BR_DONE; + } + if (a0_val < b0_val) { + result = m_util.mk_ule(m_util.mk_numeral(b0_val - a0_val, sz), b); + return BR_REWRITE2; + } + SASSERT(a0_val > b0_val); + SASSERT(!a0_val.is_zero()); + const numeral lower = rational::power_of_two(sz) - a0_val; + const numeral upper = rational::power_of_two(sz) - b0_val - numeral::one(); + if (lower == upper) { + result = m().mk_eq(common, mk_numeral(lower, sz)); + } + else if (b0_val.is_zero()) { + result = m_util.mk_ule(mk_numeral(lower, sz), common); + } + else { + SASSERT(lower.is_pos()); + result = m().mk_and(m_util.mk_ule(mk_numeral(lower, sz), common), + m_util.mk_ule(common, mk_numeral(upper, sz))); + } + return BR_REWRITE2; +} + +// simplification for leq comparison between two concatenations +br_status bv_rewriter::rw_leq_concats(bool is_signed, expr * _a, expr * _b, expr_ref & result) { + if (!m_util.is_concat(_a) || !m_util.is_concat(_b)) + return BR_FAILED; + const app * const a = to_app(_a); + const app * const b = to_app(_b); + const unsigned numa = a->get_num_args(); + const unsigned numb = b->get_num_args(); + const unsigned num_min = std::min(numa, numb); + + if (numa && numb) { // first arg numeral + numeral af, bf; + unsigned af_sz, bf_sz; + if ( is_numeral(a->get_arg(0), af, af_sz) + && is_numeral(b->get_arg(0), bf, bf_sz) ) { + const unsigned sz_min = std::min(af_sz, bf_sz); + const numeral hi_af = m_util.norm(af_sz > sz_min ? div(af, rational::power_of_two(af_sz - sz_min)) : af, + sz_min, is_signed); + const numeral hi_bf = m_util.norm(bf_sz > sz_min ? div(bf, rational::power_of_two(bf_sz - sz_min)) : bf, + sz_min, is_signed); + if (hi_af != hi_bf) { + result = hi_af < hi_bf ? m().mk_true() : m().mk_false(); + return BR_DONE; + } + expr_ref new_a(m()); + expr_ref new_b(m()); + if (af_sz > sz_min) { + ptr_buffer new_args; + new_args.push_back(mk_numeral(af, af_sz - sz_min)); + for (unsigned i = 1; i < numa; ++i) new_args.push_back(a->get_arg(i)); + new_a = concat(new_args.size(), new_args.c_ptr()); + } else { + new_a = concat(numa - 1, a->get_args() + 1); + } + if (bf_sz > sz_min) { + ptr_buffer new_args; + new_args.push_back(mk_numeral(bf, bf_sz - sz_min)); + for (unsigned i = 1; i < numb; ++i) new_args.push_back(b->get_arg(i)); + new_b = concat(new_args.size(), new_args.c_ptr()); + } else { + new_b = concat(numb - 1, b->get_args() + 1); + } + result = m_util.mk_ule(new_a, new_b); + return BR_REWRITE2; + } + } + + { // common prefix + unsigned common = 0; + while (common < num_min && m().are_equal(a->get_arg(common), b->get_arg(common))) ++common; + SASSERT((common == numa) == (common == numb)); + if (common == numa) { + SASSERT(0); // shouldn't get here as both sides are equal + result = m().mk_true(); + return BR_DONE; + } + if (common > 0) { + result = m_util.mk_ule(concat(numa - common, a->get_args() + common), + concat(numb - common, b->get_args() + common)); + return BR_REWRITE2; + } + } + + { // common postfix + unsigned new_numa = a->get_num_args(); + unsigned new_numb = b->get_num_args(); + while (new_numa && new_numb) { + expr * const last_a = a->get_arg(new_numa - 1); + expr * const last_b = b->get_arg(new_numb - 1); + if (!m().are_equal(last_a, last_b)) break; + new_numa--; + new_numb--; + } + if (new_numa == 0) { + SASSERT(0); // shouldn't get here as both sides are equal + result = m().mk_true(); + return BR_DONE; + } + if (new_numa != numa) { + result = is_signed ? m_util.mk_sle(concat(new_numa, a->get_args()), concat(new_numb, b->get_args())) + : m_util.mk_ule(concat(new_numa, a->get_args()), concat(new_numb, b->get_args())); + return BR_REWRITE2; + } + } + + return BR_FAILED; +} + br_status bv_rewriter::mk_leq_core(bool is_signed, expr * a, expr * b, expr_ref & result) { numeral r1, r2, r3; @@ -309,6 +507,24 @@ br_status bv_rewriter::mk_leq_core(bool is_signed, expr * a, expr * b, expr_ref return BR_REWRITE2; } + if (m_le_extra) { + const br_status cst = rw_leq_concats(is_signed, a, b, result); + if (cst != BR_FAILED) { + TRACE("le_extra", tout << (is_signed ? "bv_sle\n" : "bv_ule\n") + << mk_ismt2_pp(a, m(), 2) << "\n" << mk_ismt2_pp(b, m(), 2) << "\n--->\n"<< mk_ismt2_pp(result, m(), 2) << "\n";); + return cst; + } + } + + if (m_le_extra) { + const br_status cst = rw_leq_overflow(is_signed, a, b, result); + if (cst != BR_FAILED) { + TRACE("le_extra", tout << (is_signed ? "bv_sle\n" : "bv_ule\n") + << mk_ismt2_pp(a, m(), 2) << "\n" << mk_ismt2_pp(b, m(), 2) << "\n--->\n"<< mk_ismt2_pp(result, m(), 2) << "\n";); + return cst; + } + } + #if 0 if (!is_signed && m_util.is_concat(b) && to_app(b)->get_num_args() == 2 && m_util.is_zero(to_app(b)->get_arg(0))) { // @@ -366,6 +582,89 @@ br_status bv_rewriter::mk_leq_core(bool is_signed, expr * a, expr * b, expr_ref return BR_FAILED; } +// attempt to chop off bits that are above the position high for bv_mul and bv_add, +// returns how many bits were chopped off +// e.g. (bvadd(concat #b11 p) #x1)) with high=1, returns 2 and sets result = p + #b01 +// the sz of results is the sz of arg minus the return value +unsigned bv_rewriter::propagate_extract(unsigned high, expr * arg, expr_ref & result) { + if (!m_util.is_bv_add(arg) && !m_util.is_bv_mul(arg)) + return 0; + const unsigned sz = m_util.get_bv_size(arg); + const unsigned to_remove = high + 1 < sz ? sz - high - 1 : 0; + if (to_remove == 0) + return 0; // high goes to the top, nothing to do + const app * const a = to_app(arg); + const unsigned num = a->get_num_args(); + bool all_numerals = true; + unsigned removable = to_remove; + numeral val; + unsigned curr_first_sz = -1; + // calculate how much can be removed + for (unsigned i = 0; i < num; i++) { + expr * const curr = a->get_arg(i); + const bool curr_is_conc = m_util.is_concat(curr); + if (curr_is_conc && to_app(curr)->get_num_args() == 0) continue; + expr * const curr_first = curr_is_conc ? to_app(curr)->get_arg(0) : curr; + if (!all_numerals) { + if (removable != m_util.get_bv_size(curr_first)) + return 0; + continue; + } + if (is_numeral(curr_first, val, curr_first_sz)) { + removable = std::min(removable, curr_first_sz); + } else { + all_numerals = false; + curr_first_sz = m_util.get_bv_size(curr_first); + if (curr_first_sz > removable) return 0; + removable = curr_first_sz; + } + if (removable == 0) return 0; + } + // perform removal + SASSERT(removable <= to_remove); + const unsigned new_sz = sz - removable; + ptr_buffer new_args; + ptr_buffer new_concat_args; + for (unsigned i = 0; i < num; i++) { + expr * const curr = a->get_arg(i); + const bool curr_is_conc = m_util.is_concat(curr); + if (curr_is_conc && to_app(curr)->get_num_args() == 0) continue; + expr * const curr_first = curr_is_conc ? to_app(curr)->get_arg(0) : curr; + expr * new_first = NULL; + if (is_numeral(curr_first, val, curr_first_sz)) { + SASSERT(curr_first_sz >= removable); + const unsigned new_num_sz = curr_first_sz - removable; + new_first = new_num_sz ? mk_numeral(val, new_num_sz) : NULL; + } + expr * new_arg = NULL; + if (curr_is_conc) { + const unsigned conc_num = to_app(curr)->get_num_args(); + if (new_first) { + new_concat_args.reset(); + new_concat_args.push_back(new_first); + for (unsigned j = 1; j < conc_num; ++j) + new_concat_args.push_back(to_app(curr)->get_arg(j)); + new_arg = m_util.mk_concat(new_concat_args.size(), new_concat_args.c_ptr()); + } else { + // remove first element of concat + expr * const * const old_conc_args = to_app(curr)->get_args(); + switch (conc_num) { + case 0: UNREACHABLE(); break; + case 1: new_arg = NULL; break; + case 2: new_arg = to_app(curr)->get_arg(1); break; + default: new_arg = m_util.mk_concat(conc_num - 1, old_conc_args + 1); + } + } + } else { + new_arg = new_first; + } + if (new_arg) new_args.push_back(new_arg); + } + result = m().mk_app(get_fid(), a->get_decl()->get_decl_kind(), new_args.size(), new_args.c_ptr()); + SASSERT(m_util.is_bv(result)); + return removable; +} + br_status bv_rewriter::mk_extract(unsigned high, unsigned low, expr * arg, expr_ref & result) { unsigned sz = get_bv_size(arg); SASSERT(sz > 0); @@ -469,6 +768,17 @@ br_status bv_rewriter::mk_extract(unsigned high, unsigned low, expr * arg, expr_ return BR_REWRITE2; } + if (m_extract_prop && (high >= low)) { + expr_ref ep_res(m()); + const unsigned ep_rm = propagate_extract(high, arg, ep_res); + if (ep_rm != 0) { + result = m_mk_extract(high, low, ep_res); + TRACE("extract_prop", tout << mk_ismt2_pp(arg, m()) << "\n[" << high <<"," << low << "]\n" << ep_rm << "---->\n" + << mk_ismt2_pp(result.get(), m()) << "\n";); + return BR_REWRITE2; + } + } + if (m().is_ite(arg)) { result = m().mk_ite(to_app(arg)->get_arg(0), m_mk_extract(high, low, to_app(arg)->get_arg(1)), @@ -842,6 +1152,22 @@ bool bv_rewriter::is_minus_one_core(expr * arg) const { return false; } +bool bv_rewriter::is_negatable(expr * arg, expr_ref& x) { + numeral r; + unsigned bv_size; + if (is_numeral(arg, r, bv_size)) { + r = bitwise_not(bv_size, r); + x = mk_numeral(r, bv_size); + return true; + } + if (m_util.is_bv_not(arg)) { + SASSERT(to_app(arg)->get_num_args() == 1); + x = to_app(arg)->get_arg(0); + return true; + } + return false; +} + bool bv_rewriter::is_x_minus_one(expr * arg, expr * & x) { if (is_add(arg) && to_app(arg)->get_num_args() == 2) { if (is_minus_one_core(to_app(arg)->get_arg(0))) { @@ -1046,6 +1372,7 @@ br_status bv_rewriter::mk_bv2int(expr * arg, expr_ref & result) { return BR_FAILED; } + br_status bv_rewriter::mk_concat(unsigned num_args, expr * const * args, expr_ref & result) { expr_ref_buffer new_args(m()); numeral v1; @@ -1534,6 +1861,35 @@ br_status bv_rewriter::mk_bv_not(expr * arg, expr_ref & result) { return BR_REWRITE1; } + if (m_bvnot_simpl) { + expr *s(0), *t(0); + if (m_util.is_bv_mul(arg, s, t)) { + // ~(-1 * x) --> (x - 1) + bv_size = m_util.get_bv_size(s); + if (m_util.is_allone(s)) { + rational minus_one = (rational::power_of_two(bv_size) - rational::one()); + result = m_util.mk_bv_add(m_util.mk_numeral(minus_one, bv_size), t); + return BR_REWRITE1; + } + if (m_util.is_allone(t)) { + rational minus_one = (rational::power_of_two(bv_size) - rational::one()); + result = m_util.mk_bv_add(m_util.mk_numeral(minus_one, bv_size), s); + return BR_REWRITE1; + } + } + if (m_util.is_bv_add(arg, s, t)) { + expr_ref ns(m()); + expr_ref nt(m()); + // ~(x + y) --> (~x + ~y + 1) when x and y are easy to negate + if (is_negatable(t, nt) && is_negatable(s, ns)) { + bv_size = m_util.get_bv_size(s); + expr * nargs[3] = { m_util.mk_numeral(rational::one(), bv_size), ns.get(), nt.get() }; + result = m().mk_app(m_util.get_fid(), OP_BADD, 3, nargs); + return BR_REWRITE1; + } + } + } + return BR_FAILED; } @@ -2076,6 +2432,16 @@ br_status bv_rewriter::mk_mul_eq(expr * lhs, expr * rhs, expr_ref & result) { return BR_FAILED; } +bool bv_rewriter::is_urem_any(expr * e, expr * & dividend, expr * & divisor) { + if (!m_util.is_bv_urem(e) && !m_util.is_bv_uremi(e)) + return false; + const app * const a = to_app(e); + SASSERT(a->get_num_args() == 2); + dividend = a->get_arg(0); + divisor = a->get_arg(1); + return true; +} + br_status bv_rewriter::mk_eq_core(expr * lhs, expr * rhs, expr_ref & result) { if (lhs == rhs) { result = m().mk_true(); @@ -2127,6 +2493,25 @@ br_status bv_rewriter::mk_eq_core(expr * lhs, expr * rhs, expr_ref & result) { return st; } + if (m_urem_simpl) { + expr * dividend; + expr * divisor; + numeral divisor_val, rhs_val; + unsigned divisor_sz, rhs_sz; + if (is_urem_any(lhs, dividend, divisor) + && is_numeral(rhs, rhs_val, rhs_sz) + && is_numeral(divisor, divisor_val, divisor_sz)) { + if (rhs_val >= divisor_val) {//(= (bvurem x c1) c2) where c2 >= c1 + result = m().mk_false(); + return BR_DONE; + } + if ((divisor_val + rhs_val) >= rational::power_of_two(divisor_sz)) {//(= (bvurem x c1) c2) where c1+c2 >= 2^width + result = m().mk_eq(dividend, rhs); + return BR_REWRITE2; + } + } + } + expr_ref new_lhs(m()); expr_ref new_rhs(m()); @@ -2194,6 +2579,55 @@ br_status bv_rewriter::mk_mkbv(unsigned num, expr * const * args, expr_ref & res return BR_FAILED; } +br_status bv_rewriter::mk_ite_core(expr * c, expr * t, expr * e, expr_ref & result) { + TRACE("bv_ite", tout << "mk_ite_core:\n" << mk_ismt2_pp(c, m()) << "?\n" + << mk_ismt2_pp(t, m()) << "\n:" << mk_ismt2_pp(e, m()) << "\n";); + if (m().are_equal(t, e)) { + result = e; + return BR_REWRITE1; + } + if (m().is_not(c)) { + result = m().mk_ite(to_app(c)->get_arg(0), e, t); + return BR_REWRITE1; + } + + if (m_ite2id && m().is_eq(c) && is_bv(t) && is_bv(e)) { + // detect when ite is actually some simple function based on the pattern (lhs=rhs) ? t : e + expr * lhs = to_app(c)->get_arg(0); + expr * rhs = to_app(c)->get_arg(1); + + if (is_bv(rhs)) { + if (is_numeral(lhs)) + std::swap(lhs, rhs); + + if ( (m().are_equal(lhs, t) && m().are_equal(rhs, e)) + || (m().are_equal(lhs, e) && m().are_equal(rhs, t))) { + // (a = b ? a : b) is b. (a = b ? b : a) is a + result = e; + return BR_REWRITE1; + } + + const unsigned sz = m_util.get_bv_size(rhs); + if (sz == 1) { // detect (lhs = N) ? C : D, where N, C, D are 1 bit numberals + numeral rhs_n, e_n, t_n; + unsigned rhs_sz, e_sz, t_sz; + if (is_numeral(rhs, rhs_n, rhs_sz) + && is_numeral(t, t_n, t_sz) && is_numeral(e, e_n, e_sz)) { + if (t_sz == 1) { + SASSERT(rhs_sz == sz && e_sz == sz && t_sz == sz); + SASSERT(!m().are_equal(t, e)); + result = m().are_equal(rhs, t) ? lhs : m_util.mk_bv_not(lhs); + return BR_REWRITE1; + } + } + } + } + + + } + return BR_FAILED; +} + br_status bv_rewriter::mk_bvsmul_no_overflow(unsigned num, expr * const * args, expr_ref & result) { SASSERT(num == 2); unsigned bv_sz; diff --git a/src/ast/rewriter/bv_rewriter.h b/src/ast/rewriter/bv_rewriter.h index a8db05013..5d47fb99d 100644 --- a/src/ast/rewriter/bv_rewriter.h +++ b/src/ast/rewriter/bv_rewriter.h @@ -56,11 +56,16 @@ class bv_rewriter : public poly_rewriter { bool m_bit2bool; bool m_blast_eq_value; bool m_mkbv2num; + bool m_ite2id; bool m_split_concat_eq; bool m_udiv2mul; bool m_bvnot2arith; bool m_bv_sort_ac; bool m_trailing; + bool m_extract_prop; + bool m_bvnot_simpl; + bool m_le_extra; + bool m_urem_simpl; bool is_zero_bit(expr * x, unsigned idx); @@ -70,13 +75,19 @@ class bv_rewriter : public poly_rewriter { br_status mk_sle(expr * a, expr * b, expr_ref & result); br_status mk_sge(expr * a, expr * b, expr_ref & result); br_status mk_slt(expr * a, expr * b, expr_ref & result); + br_status rw_leq_concats(bool is_signed, expr * a, expr * b, expr_ref & result); + bool are_eq_upto_num(expr * a, expr * b, expr_ref& common, numeral& a0_val, numeral& b0_val); + br_status rw_leq_overflow(bool is_signed, expr * _a, expr * _b, expr_ref & result); br_status mk_leq_core(bool is_signed, expr * a, expr * b, expr_ref & result); + br_status fuse_concat(unsigned num_args, expr * const * args, expr_ref & result); br_status mk_concat(unsigned num_args, expr * const * args, expr_ref & result); + unsigned propagate_extract(unsigned high, expr * arg, expr_ref & result); br_status mk_extract(unsigned high, unsigned low, expr * arg, expr_ref & result); br_status mk_repeat(unsigned n, expr * arg, expr_ref & result); br_status mk_zero_extend(unsigned n, expr * arg, expr_ref & result); br_status mk_sign_extend(unsigned n, expr * arg, expr_ref & result); + bool is_negatable(expr * arg, expr_ref& x); br_status mk_bv_not(expr * arg, expr_ref & result); br_status mk_bv_or(unsigned num, expr * const * args, expr_ref & result); br_status mk_bv_xor(unsigned num, expr * const * args, expr_ref & result); @@ -139,6 +150,7 @@ class bv_rewriter : public poly_rewriter { void updt_local_params(params_ref const & p); + expr * concat(unsigned num_args, expr * const * args); public: bv_rewriter(ast_manager & m, params_ref const & p = params_ref()): poly_rewriter(m, p), @@ -167,7 +179,9 @@ public: result = m().mk_app(f, num_args, args); } + bool is_urem_any(expr * e, expr * & dividend, expr * & divisor); br_status mk_eq_core(expr * lhs, expr * rhs, expr_ref & result); + br_status mk_ite_core(expr * c, expr * t, expr * e, expr_ref & resul); bool hi_div0() const { return m_hi_div0; } diff --git a/src/ast/rewriter/bv_rewriter_params.pyg b/src/ast/rewriter/bv_rewriter_params.pyg index 0f0163fb1..984a48b37 100644 --- a/src/ast/rewriter/bv_rewriter_params.pyg +++ b/src/ast/rewriter/bv_rewriter_params.pyg @@ -10,5 +10,10 @@ def_module_params(module_name='rewriter', ("mul2concat", BOOL, False, "replace multiplication by a power of two into a concatenation"), ("bvnot2arith", BOOL, False, "replace (bvnot x) with (bvsub -1 x)"), ("bv_sort_ac", BOOL, False, "sort the arguments of all AC operators"), - ("bv_trailing", BOOL, False, "lean removal of trailing zeros") + ("bv_trailing", BOOL, False, "lean removal of trailing zeros"), + ("bv_extract_prop", BOOL, False, "attempt to partially propagate extraction inwards"), + ("bv_not_simpl", BOOL, False, "apply simplifications for bvnot"), + ("bv_ite2id", BOOL, False, "rewrite ite that can be simplified to identity"), + ("bv_le_extra", BOOL, False, "additional bu_(u/s)le simplifications"), + ("bv_urem_simpl", BOOL, False, "additional simplification for bvurem") )) diff --git a/src/ast/rewriter/bv_trailing.cpp b/src/ast/rewriter/bv_trailing.cpp index 31e9121ec..f0b96a91f 100644 --- a/src/ast/rewriter/bv_trailing.cpp +++ b/src/ast/rewriter/bv_trailing.cpp @@ -36,11 +36,14 @@ struct bv_trailing::imp { : m_mk_extract(mk_extract) , m_util(mk_extract.bvutil()) , m(mk_extract.m()) { + TRACE("bv-trailing", tout << "ctor\n";); + for (unsigned i = 0; i <= TRAILING_DEPTH; ++i) m_count_cache[i] = NULL; } virtual ~imp() { + TRACE("bv-trailing", tout << "dtor\n";); reset_cache(0); } @@ -337,6 +340,7 @@ struct bv_trailing::imp { if (depth == 0) return; if (m_count_cache[depth] == NULL) m_count_cache[depth] = alloc(map); + SASSERT(!m_count_cache[depth]->contains(e)); m.inc_ref(e); m_count_cache[depth]->insert(e, std::make_pair(min, max)); TRACE("bv-trailing", tout << "caching@" << depth <<": " << mk_ismt2_pp(e, m) << '[' << m_util.get_bv_size(e) << "]\n: " << min << '-' << max << "\n";); @@ -359,11 +363,13 @@ struct bv_trailing::imp { return true; } - void reset_cache(unsigned condition) { + void reset_cache(const unsigned condition) { SASSERT(m_count_cache[0] == NULL); for (unsigned i = 1; i <= TRAILING_DEPTH; ++i) { if (m_count_cache[i] == NULL) continue; - if (m_count_cache[i]->size() < condition) continue; + TRACE("bv-trailing", tout << "may reset cache " << i << " " << condition << "\n";); + if (condition && m_count_cache[i]->size() < condition) continue; + TRACE("bv-trailing", tout << "reset cache " << i << "\n";); map::iterator it = m_count_cache[i]->begin(); map::iterator end = m_count_cache[i]->end(); for (; it != end; ++it) m.dec_ref(it->m_key); diff --git a/src/ast/rewriter/rewriter_params.pyg b/src/ast/rewriter/rewriter_params.pyg index 3a8ed5d5e..5bd17f556 100644 --- a/src/ast/rewriter/rewriter_params.pyg +++ b/src/ast/rewriter/rewriter_params.pyg @@ -7,5 +7,6 @@ def_module_params('rewriter', ("push_ite_arith", BOOL, False, "push if-then-else over arithmetic terms."), ("push_ite_bv", BOOL, False, "push if-then-else over bit-vector terms."), ("pull_cheap_ite", BOOL, False, "pull if-then-else terms when cheap."), + ("bv_ineq_consistency_test_max", UINT, 0, "max size of conjunctions on which to perform consistency test based on inequalities on bitvectors."), ("cache_all", BOOL, False, "cache all intermediate results."))) diff --git a/src/ast/rewriter/th_rewriter.cpp b/src/ast/rewriter/th_rewriter.cpp index ff6a10274..0c57ea609 100644 --- a/src/ast/rewriter/th_rewriter.cpp +++ b/src/ast/rewriter/th_rewriter.cpp @@ -189,6 +189,14 @@ struct th_rewriter_cfg : public default_rewriter_cfg { if (st != BR_FAILED) return st; } + if (k == OP_ITE) { + SASSERT(num == 3); + family_id s_fid = m().get_sort(args[1])->get_family_id(); + if (s_fid == m_bv_rw.get_fid()) + st = m_bv_rw.mk_ite_core(args[0], args[1], args[2], result); + if (st != BR_FAILED) + return st; + } return m_b_rw.mk_app_core(f, num, args, result); } if (fid == m_a_rw.get_fid()) diff --git a/src/tactic/bv/bv_bound_chk_tactic.cpp b/src/tactic/bv/bv_bound_chk_tactic.cpp new file mode 100644 index 000000000..c3f32aaaf --- /dev/null +++ b/src/tactic/bv/bv_bound_chk_tactic.cpp @@ -0,0 +1,245 @@ +/*++ + Copyright (c) 2016 Microsoft Corporation + + Module Name: + + bv_bound_chk_tactic.cpp + + Abstract: + + + Author: + + Mikolas Janota + + Revision History: +--*/ +#include"bv_bound_chk_tactic.h" +#include"ast.h" +#include"rewriter.h" +#include"rewriter_def.h" +#include"bv_bounds.h" +#include"rewriter_params.hpp" +#include"bool_rewriter.h" +#include"cooperate.h" + +struct bv_bound_chk_stats { + unsigned m_unsats; + unsigned m_singletons; + unsigned m_reduces; + bv_bound_chk_stats() : m_unsats(0), m_singletons(0), m_reduces(0) {}; +}; + +struct bv_bound_chk_rewriter_cfg : public default_rewriter_cfg { + ast_manager & m_m; + unsigned m_bv_ineq_consistency_test_max; + bool_rewriter m_b_rw; + unsigned long long m_max_steps; + unsigned long long m_max_memory; // in bytes + bv_bound_chk_stats& m_stats; + + + bv_bound_chk_rewriter_cfg(ast_manager & m, bv_bound_chk_stats& stats) + : m_m(m), m_b_rw(m), m_stats(stats) {} + + ~bv_bound_chk_rewriter_cfg() {} + + void updt_params(params_ref const & _p) { + rewriter_params p(_p); + m_bv_ineq_consistency_test_max = p.bv_ineq_consistency_test_max(); + m_max_memory = p.max_memory(); + m_max_steps = p.max_steps(); + + } + + ast_manager & m() const { return m_m; } + + bool rewrite_patterns() const { return false; } + + bool flat_assoc(func_decl * f) const { return true; } + + br_status reduce_app(func_decl * f, unsigned num, expr * const * args, expr_ref & result, proof_ref & result_pr) { + const br_status st = reduce_app_core(f, num, args, result, result_pr); + CTRACE("bv_bound_chk_step", st != BR_FAILED, + tout << f->get_name() << "\n"; + for (unsigned i = 0; i < num; i++) tout << mk_ismt2_pp(args[i], m()) << "\n"; + tout << "---------->\n" << mk_ismt2_pp(result, m()) << "\n";); + return st; + } + + br_status reduce_app_core(func_decl * f, unsigned num, expr * const * args, expr_ref & result, proof_ref & result_pr) { + result_pr = 0; + const family_id fid = f->get_family_id(); + if (fid != m_b_rw.get_fid()) return BR_FAILED; + const decl_kind k = f->get_decl_kind(); + bv_bounds bvb(m()); + const br_status rv = bvb.rewrite(m_bv_ineq_consistency_test_max, f, num, args, result); + if (rv != BR_FAILED && (m_m.is_false(result) || m_m.is_true(result))) m_stats.m_unsats++; + else if (rv != BR_FAILED && bvb.singletons().size()) m_stats.m_singletons++; + else if (rv != BR_FAILED && is_app(result) && to_app(result)->get_num_args() < num) m_stats.m_reduces++; + return rv; + } + + bool max_steps_exceeded(unsigned long long num_steps) const { + cooperate("bv-bound-chk"); + if (num_steps > m_max_steps) + return true; + if (memory::get_allocation_size() > m_max_memory) + throw tactic_exception(TACTIC_MAX_MEMORY_MSG); + return false; + } + + void reset_statistics() { + m_stats.m_unsats = 0; + m_stats.m_singletons = 0; + m_stats.m_reduces = 0; + } + + void collect_statistics(statistics & st) const { + st.update("unsat bv bounds", m_stats.m_unsats); + st.update("bv singletons", m_stats.m_singletons); + st.update("bv reduces", m_stats.m_reduces); + } +}; + +struct bv_bound_chk_rewriter : public rewriter_tpl { + bv_bound_chk_rewriter_cfg m_cfg; + + bv_bound_chk_rewriter(ast_manager & m, params_ref const & p, bv_bound_chk_stats& stats) + : rewriter_tpl(m, false, m_cfg) + , m_cfg(m, stats) + { + updt_params(p); + } + + virtual ~bv_bound_chk_rewriter() {} + + void updt_params(params_ref const & _p) { + m_cfg.updt_params(_p); + } + + void collect_statistics(statistics & st) const { + m_cfg.collect_statistics(st); + } + + + void reset_statistics() { + m_cfg.reset_statistics(); + } + +}; + +class bv_bound_chk_tactic : public tactic { + class imp; + imp * m_imp; + params_ref m_params; + bv_bound_chk_stats m_stats; +public: + bv_bound_chk_tactic(ast_manager & m, params_ref const & p); + virtual ~bv_bound_chk_tactic(); + void operator()(goal_ref const & g, + goal_ref_buffer & result, + model_converter_ref & mc, + proof_converter_ref & pc, + expr_dependency_ref & core); + virtual tactic * translate(ast_manager & m); + virtual void updt_params(params_ref const & p); + void cleanup(); + void collect_statistics(statistics & st) const; + void reset_statistics(); +}; + +class bv_bound_chk_tactic::imp { + bv_bound_chk_rewriter m_rw; +public: + imp(ast_manager & m, params_ref const & p, bv_bound_chk_stats& stats) + : m_rw(m, p, stats) { } + + virtual ~imp() { } + + ast_manager& m() { return m_rw.m(); } + + void operator()(goal_ref const & g) { + SASSERT(g->is_well_sorted()); + tactic_report report("bv-bound-chk", *g); + ast_manager& m(g->m()); + expr_ref new_curr(m); + const unsigned size = g->size(); + for (unsigned idx = 0; idx < size; idx++) { + if (g->inconsistent()) break; + expr * curr = g->form(idx); + m_rw(curr, new_curr); + g->update(idx, new_curr); + } + m_rw.m_cfg.cleanup(); + } + + virtual void updt_params(params_ref const & p) { + m_rw.updt_params(p); + } + + void collect_statistics(statistics & st) const { + m_rw.collect_statistics(st); + } + + void reset_statistics() { + m_rw.reset_statistics(); + } +}; + +bv_bound_chk_tactic::bv_bound_chk_tactic(ast_manager & m, params_ref const & p) +: m_params(p) +{ + m_imp = alloc(imp, m, p, m_stats); +} + + +bv_bound_chk_tactic::~bv_bound_chk_tactic() { + dealloc(m_imp); +} + +void bv_bound_chk_tactic::operator()(goal_ref const & g, + goal_ref_buffer & result, + model_converter_ref & mc, + proof_converter_ref & pc, + expr_dependency_ref & core) { + SASSERT(g->is_well_sorted()); + fail_if_proof_generation("bv-bound-chk", g); + fail_if_unsat_core_generation("bv-bound-chk", g); + TRACE("bv-bound-chk", g->display(tout << "before:"); tout << std::endl;); + mc = 0; pc = 0; core = 0; result.reset(); + m_imp->operator()(g); + g->inc_depth(); + result.push_back(g.get()); + TRACE("bv-bound-chk", g->display(tout << "after:");); + SASSERT(g->is_well_sorted()); +} + +tactic * bv_bound_chk_tactic::translate(ast_manager & m) { + return alloc(bv_bound_chk_tactic, m, m_params); +} + + +void bv_bound_chk_tactic::updt_params(params_ref const & p) { + m_params = p; + m_imp->updt_params(p); +} + +void bv_bound_chk_tactic::cleanup() { + imp * d = alloc(imp, m_imp->m(), m_params, m_stats); + std::swap(d, m_imp); + dealloc(d); +} + +void bv_bound_chk_tactic::collect_statistics(statistics & st) const { + m_imp->collect_statistics(st); +} + +void bv_bound_chk_tactic::reset_statistics() { + m_imp->reset_statistics(); +} + + +tactic* mk_bv_bound_chk_tactic(ast_manager & m, params_ref const & p) { + return alloc(bv_bound_chk_tactic, m, p); +} diff --git a/src/tactic/bv/bv_bound_chk_tactic.h b/src/tactic/bv/bv_bound_chk_tactic.h new file mode 100644 index 000000000..f134d42ab --- /dev/null +++ b/src/tactic/bv/bv_bound_chk_tactic.h @@ -0,0 +1,30 @@ + /*++ + Copyright (c) 2016 Microsoft Corporation + + Module Name: + + bv_bound_chk_tactic.h + + Abstract: + + + Author: + + Mikolas Janota + + Revision History: + --*/ +#ifndef BV_BOUND_CHK_TACTIC_H_ +#define BV_BOUND_CHK_TACTIC_H_ + +#include"tactical.h" +#include"params.h" +#include"ast.h" + +tactic* mk_bv_bound_chk_tactic(ast_manager & m, params_ref const & p = params_ref()); + +/* + ADD_TACTIC("bv_bound_chk", "attempts to detect inconsistencies of bounds on bv expressions.", "mk_bv_bound_chk_tactic(m, p)") +*/ + +#endif /* BV_BOUND_CHK_TACTIC_H_*/ diff --git a/src/tactic/smtlogics/qfufbv_tactic.cpp b/src/tactic/smtlogics/qfufbv_tactic.cpp index 3ee97308a..e0e1a60e4 100644 --- a/src/tactic/smtlogics/qfufbv_tactic.cpp +++ b/src/tactic/smtlogics/qfufbv_tactic.cpp @@ -39,6 +39,7 @@ Notes: #include"qfaufbv_tactic.h" #include"qfbv_tactic.h" #include"tactic2solver.h" +#include"bv_bound_chk_tactic.h" /////////////// class qfufbv_ackr_tactic : public tactic { @@ -149,6 +150,7 @@ static tactic * mk_qfufbv_preamble1(ast_manager & m, params_ref const & p) { return and_then( mk_simplify_tactic(m), mk_propagate_values_tactic(m), + if_no_proofs(if_no_unsat_cores(mk_bv_bound_chk_tactic(m))), //using_params(mk_ctx_simplify_tactic(m_m), ctx_simp_p), mk_solve_eqs_tactic(m), mk_elim_uncnstr_tactic(m), From 147c0f8152fed35588ff3a3a839201afa67edb37 Mon Sep 17 00:00:00 2001 From: Mikolas Janota Date: Tue, 6 Sep 2016 18:25:55 +0100 Subject: [PATCH 193/536] Removing an unused method from bv_rewriter. --- src/ast/rewriter/bv_rewriter.h | 1 - 1 file changed, 1 deletion(-) diff --git a/src/ast/rewriter/bv_rewriter.h b/src/ast/rewriter/bv_rewriter.h index 5d47fb99d..b5482e5fa 100644 --- a/src/ast/rewriter/bv_rewriter.h +++ b/src/ast/rewriter/bv_rewriter.h @@ -80,7 +80,6 @@ class bv_rewriter : public poly_rewriter { br_status rw_leq_overflow(bool is_signed, expr * _a, expr * _b, expr_ref & result); br_status mk_leq_core(bool is_signed, expr * a, expr * b, expr_ref & result); - br_status fuse_concat(unsigned num_args, expr * const * args, expr_ref & result); br_status mk_concat(unsigned num_args, expr * const * args, expr_ref & result); unsigned propagate_extract(unsigned high, expr * arg, expr_ref & result); br_status mk_extract(unsigned high, unsigned low, expr * arg, expr_ref & result); From 7f2967484248701de5a7ec145ae0be64bbfffb5e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 16 Sep 2016 14:56:10 -0700 Subject: [PATCH 194/536] add option to bypass compression of unbound tails, issue #738 Signed-off-by: Nikolaj Bjorner --- contrib/cmake/src/ast/rewriter/CMakeLists.txt | 1 + contrib/cmake/src/tactic/bv/CMakeLists.txt | 1 + src/muz/base/dl_context.cpp | 1 + src/muz/base/dl_context.h | 1 + src/muz/base/fixedpoint_params.pyg | 1 + src/muz/transforms/dl_mk_unbound_compressor.cpp | 5 +++++ 6 files changed, 10 insertions(+) diff --git a/contrib/cmake/src/ast/rewriter/CMakeLists.txt b/contrib/cmake/src/ast/rewriter/CMakeLists.txt index 14bcebf46..47323d821 100644 --- a/contrib/cmake/src/ast/rewriter/CMakeLists.txt +++ b/contrib/cmake/src/ast/rewriter/CMakeLists.txt @@ -4,6 +4,7 @@ z3_add_component(rewriter array_rewriter.cpp ast_counter.cpp bool_rewriter.cpp + bv_bounds.cpp bv_rewriter.cpp datatype_rewriter.cpp der.cpp diff --git a/contrib/cmake/src/tactic/bv/CMakeLists.txt b/contrib/cmake/src/tactic/bv/CMakeLists.txt index b39d77a0a..90ed65e3f 100644 --- a/contrib/cmake/src/tactic/bv/CMakeLists.txt +++ b/contrib/cmake/src/tactic/bv/CMakeLists.txt @@ -5,6 +5,7 @@ z3_add_component(bv_tactics bv1_blaster_tactic.cpp bvarray2uf_rewriter.cpp bvarray2uf_tactic.cpp + bv_bound_chk_tactic.cpp bv_bounds_tactic.cpp bv_size_reduction_tactic.cpp dt2bv_tactic.cpp diff --git a/src/muz/base/dl_context.cpp b/src/muz/base/dl_context.cpp index a90d420cb..08fc0b9d7 100644 --- a/src/muz/base/dl_context.cpp +++ b/src/muz/base/dl_context.cpp @@ -303,6 +303,7 @@ namespace datalog { bool context::karr() const { return m_params->xform_karr(); } bool context::scale() const { return m_params->xform_scale(); } bool context::magic() const { return m_params->xform_magic(); } + bool context::compress_unbound() const { return m_params->xform_compress_unbound(); } bool context::quantify_arrays() const { return m_params->xform_quantify_arrays(); } bool context::instantiate_quantifiers() const { return m_params->xform_instantiate_quantifiers(); } diff --git a/src/muz/base/dl_context.h b/src/muz/base/dl_context.h index 3d8b56beb..3c1a7bfaa 100644 --- a/src/muz/base/dl_context.h +++ b/src/muz/base/dl_context.h @@ -272,6 +272,7 @@ namespace datalog { bool karr() const; bool scale() const; bool magic() const; + bool compress_unbound() const; bool quantify_arrays() const; bool instantiate_quantifiers() const; bool xform_bit_blast() const; diff --git a/src/muz/base/fixedpoint_params.pyg b/src/muz/base/fixedpoint_params.pyg index 86cfb30ac..8e7d6a7cb 100644 --- a/src/muz/base/fixedpoint_params.pyg +++ b/src/muz/base/fixedpoint_params.pyg @@ -131,6 +131,7 @@ def_module_params('fixedpoint', ('xform.inline_eager', BOOL, True, "try eager inlining of rules"), ('xform.inline_linear_branch', BOOL, False, "try linear inlining method with potential expansion"), + ('xform.compress_unbound', BOOL, True, "compress tails with unbound variables"), ('xform.fix_unbound_vars', BOOL, False, "fix unbound variables in tail"), ('xform.unfold_rules', UINT, 0, "unfold rules statically using iterative squarring"), diff --git a/src/muz/transforms/dl_mk_unbound_compressor.cpp b/src/muz/transforms/dl_mk_unbound_compressor.cpp index 7d103568a..41b181450 100644 --- a/src/muz/transforms/dl_mk_unbound_compressor.cpp +++ b/src/muz/transforms/dl_mk_unbound_compressor.cpp @@ -344,6 +344,11 @@ namespace datalog { rule_set * mk_unbound_compressor::operator()(rule_set const & source) { // TODO mc + + if (!m_context.compress_unbound()) { + return 0; + } + m_modified = false; SASSERT(m_rules.empty()); From cda967ead20531454ff023d313fb8ebd7f0ca43c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 16 Sep 2016 15:36:40 -0700 Subject: [PATCH 195/536] guard verbose output by verbosity level for datalog command-line tool Signed-off-by: Nikolaj Bjorner --- src/shell/datalog_frontend.cpp | 36 ++++++++++++++++++---------------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/src/shell/datalog_frontend.cpp b/src/shell/datalog_frontend.cpp index 43ef383d2..83b900c5c 100644 --- a/src/shell/datalog_frontend.cpp +++ b/src/shell/datalog_frontend.cpp @@ -67,25 +67,27 @@ static void display_statistics( p.set_uint("profile_milliseconds_threshold", 100); ctx.updt_params(p); - out << "--------------\n"; - out << "original rules\n"; - orig_rules.display(out); + IF_VERBOSE(2, + out << "--------------\n"; + out << "original rules\n"; + orig_rules.display(out); + + out << "---------------\n"; + out << "generated rules\n"; + ctx.display_rules(out); - out << "---------------\n"; - out << "generated rules\n"; - ctx.display_rules(out); - - out << "--------------\n"; - out << "instructions \n"; - code.display(ex_ctx, out); - - out << "--------------\n"; - out << "big relations \n"; - ex_ctx.report_big_relations(1000, out); + out << "--------------\n"; + out << "instructions \n"; + code.display(ex_ctx, out); + + out << "--------------\n"; + out << "big relations \n"; + ex_ctx.report_big_relations(1000, out);); } - out << "--------------\n"; - out << "relation sizes\n"; - ctx.get_rel_context()->get_rmanager().display_relation_sizes(out); + IF_VERBOSE(2, + out << "--------------\n"; + out << "relation sizes\n"; + ctx.get_rel_context()->get_rmanager().display_relation_sizes(out);); if (verbose) { out << "--------------\n"; From 77b245b3d822f65515267173522e92837ea6beca Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 17 Sep 2016 17:29:19 -0700 Subject: [PATCH 196/536] fix proof production to avoid crash. Issue #733 Signed-off-by: Nikolaj Bjorner --- src/smt/smt_conflict_resolution.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/smt/smt_conflict_resolution.cpp b/src/smt/smt_conflict_resolution.cpp index 8fb8f9f70..b28c4e773 100644 --- a/src/smt/smt_conflict_resolution.cpp +++ b/src/smt/smt_conflict_resolution.cpp @@ -948,7 +948,7 @@ namespace smt { // // So, the test "m_ctx.get_justification(l.var()) == js" is used to check // if l was assigned before ~l. - if (m_ctx.is_marked(l.var()) && m_ctx.get_justification(l.var()) == js) { + if ((m_ctx.is_marked(l.var()) && m_ctx.get_justification(l.var()) == js) || (js.get_kind() == b_justification::AXIOM)) { expr_ref l_expr(m_manager); m_ctx.literal2expr(l, l_expr); proof * pr = m_manager.mk_hypothesis(l_expr.get()); @@ -1065,7 +1065,7 @@ namespace smt { m_js2proof.reset(); literal_vector::iterator it = m_lemma.begin(); literal_vector::iterator end = m_lemma.end(); - for (; it != end; ++it) + for (; it != end; ++it) m_ctx.set_mark((*it).var()); } @@ -1076,6 +1076,8 @@ namespace smt { return true; SASSERT(js.get_kind() != b_justification::BIN_CLAUSE); CTRACE("visit_b_justification_bug", js.get_kind() == b_justification::AXIOM, tout << "l: " << l << "\n"; m_ctx.display(tout);); + if (js.get_kind() == b_justification::AXIOM) + return true; SASSERT(js.get_kind() != b_justification::AXIOM); if (js.get_kind() == b_justification::CLAUSE) { clause * cls = js.get_clause(); From 527c5191a60b2bca8155a078175a34daf64a6529 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 21 Sep 2016 12:24:24 -0700 Subject: [PATCH 197/536] Add C++ functions for set operations per stackoverflow post, set relevancy = 2 for quantified maxsmt per example from Aaron Gember, fix conversion of default weights based on bug report from Patrick Trentin on maxsat. Annotating soft constraints with weight=0 caused the weight to be adjusted to 1 and therefore produce wrong results Signed-off-by: Nikolaj Bjorner --- src/api/c++/z3++.h | 65 ++++++++++++++++++++++++++++++++++++++--- src/opt/opt_cmds.cpp | 5 +--- src/opt/opt_context.cpp | 27 ++++++----------- src/opt/opt_solver.cpp | 3 ++ 4 files changed, 74 insertions(+), 26 deletions(-) diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index 4d832afd6..0efb3dcce 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -2331,11 +2331,68 @@ namespace z3 { inline expr store(expr const & a, int i, int v) { return store(a, a.ctx().num_val(i, a.get_sort().array_domain()), a.ctx().num_val(v, a.get_sort().array_range())); } + +#define MK_EXPR1(_fn, _arg) \ + Z3_ast r = _fn(_arg.ctx(), _arg); \ + _arg.check_error(); \ + return expr(_arg.ctx(), r); + +#define MK_EXPR2(_fn, _arg1, _arg2) \ + check_context(_arg1, _arg2); \ + Z3_ast r = _fn(_arg1.ctx(), _arg1, _arg2); \ + _arg1.check_error(); \ + return expr(_arg1.ctx(), r); + inline expr const_array(sort const & d, expr const & v) { - check_context(d, v); - Z3_ast r = Z3_mk_const_array(d.ctx(), d, v); - d.check_error(); - return expr(d.ctx(), r); + MK_EXPR2(Z3_mk_const_array, d, v); + } + + inline expr empty_set(sort const& s) { + MK_EXPR1(Z3_mk_empty_set, s); + } + + inline expr full_set(sort const& s) { + MK_EXPR1(Z3_mk_full_set, s); + } + + inline expr set_add(expr const& s, expr const& e) { + MK_EXPR2(Z3_mk_set_add, s, e); + } + + inline expr set_del(expr const& s, expr const& e) { + MK_EXPR2(Z3_mk_set_del, s, e); + } + + inline expr set_union(expr const& a, expr const& b) { + check_context(a, b); + Z3_ast es[2] = { a, b }; + Z3_ast r = Z3_mk_set_union(a.ctx(), 2, es); + a.check_error(); + return expr(a.ctx(), r); + } + + inline expr set_intersect(expr const& a, expr const& b) { + check_context(a, b); + Z3_ast es[2] = { a, b }; + Z3_ast r = Z3_mk_set_intersect(a.ctx(), 2, es); + a.check_error(); + return expr(a.ctx(), r); + } + + inline expr set_difference(expr const& a, expr const& b) { + MK_EXPR2(Z3_mk_set_difference, a, b); + } + + inline expr set_complement(expr const& a) { + MK_EXPR1(Z3_mk_set_complement, a); + } + + inline expr set_member(expr const& s, expr const& e) { + MK_EXPR2(Z3_mk_set_member, s, e); + } + + inline expr set_subset(expr const& a, expr const& b) { + MK_EXPR2(Z3_mk_set_subset, a, b); } // sequence and regular expression operations. diff --git a/src/opt/opt_cmds.cpp b/src/opt/opt_cmds.cpp index 5406eaca3..571c26e2d 100644 --- a/src/opt/opt_cmds.cpp +++ b/src/opt/opt_cmds.cpp @@ -97,10 +97,7 @@ public: virtual void execute(cmd_context & ctx) { symbol w("weight"); - rational weight = ps().get_rat(symbol("weight"), rational(0)); - if (weight.is_zero()) { - weight = rational::one(); - } + rational weight = ps().get_rat(symbol("weight"), rational::one()); symbol id = ps().get_sym(symbol("id"), symbol::null); get_opt(ctx, m_opt).add_soft_constraint(m_formula, weight, id); reset(ctx); diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index aad034130..68a5dc302 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -91,10 +91,7 @@ namespace opt { unsigned context::scoped_state::add(expr* f, rational const& w, symbol const& id) { if (w.is_neg()) { - throw default_exception("Negative weight supplied. Weight should be positive"); - } - if (w.is_zero()) { - throw default_exception("Zero weight supplied. Weight should be positive"); + throw default_exception("Negative weight supplied. Weight should be non-negative"); } if (!m.is_bool(f)) { throw default_exception("Soft constraint should be Boolean"); @@ -105,9 +102,11 @@ namespace opt { } SASSERT(m_indices.contains(id)); unsigned idx = m_indices[id]; - m_objectives[idx].m_terms.push_back(f); - m_objectives[idx].m_weights.push_back(w); - m_objectives_term_trail.push_back(idx); + if (w.is_pos()) { + m_objectives[idx].m_terms.push_back(f); + m_objectives[idx].m_weights.push_back(w); + m_objectives_term_trail.push_back(idx); + } return idx; } @@ -852,9 +851,7 @@ namespace opt { func_decl* f = m.mk_fresh_func_decl(name,"", domain.size(), domain.c_ptr(), m.mk_bool_sort()); m_objective_fns.insert(f, index); m_objective_refs.push_back(f); - if (sz > 0) { - m_objective_orig.insert(f, args[0]); - } + m_objective_orig.insert(f, sz > 0 ? args[0] : 0); return m.mk_app(f, sz, args); } @@ -873,10 +870,7 @@ namespace opt { } void context::from_fmls(expr_ref_vector const& fmls) { - TRACE("opt", - for (unsigned i = 0; i < fmls.size(); ++i) { - tout << mk_pp(fmls[i], m) << "\n"; - }); + TRACE("opt", tout << fmls << "\n";); m_hard_constraints.reset(); expr_ref orig_term(m); for (unsigned i = 0; i < fmls.size(); ++i) { @@ -1054,10 +1048,7 @@ namespace opt { break; } } - TRACE("opt", - for (unsigned i = 0; i < fmls.size(); ++i) { - tout << mk_pp(fmls[i].get(), m) << "\n"; - }); + TRACE("opt", tout << fmls << "\n";); } void context::internalize() { diff --git a/src/opt/opt_solver.cpp b/src/opt/opt_solver.cpp index 7637da1e8..64ab2823f 100644 --- a/src/opt/opt_solver.cpp +++ b/src/opt/opt_solver.cpp @@ -78,6 +78,9 @@ namespace opt { } void opt_solver::assert_expr(expr * t) { + if (has_quantifiers(t)) { + m_params.m_relevancy_lvl = 2; + } m_context.assert_expr(t); } From f451363a8f8430d665be9e3a81ca8f0de7cc6578 Mon Sep 17 00:00:00 2001 From: Andrew Dutcher Date: Wed, 21 Sep 2016 15:15:21 -0700 Subject: [PATCH 198/536] use copy instead of create_symlink when not on unix --- contrib/cmake/src/api/python/CMakeLists.txt | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/contrib/cmake/src/api/python/CMakeLists.txt b/contrib/cmake/src/api/python/CMakeLists.txt index 375890c91..dcd6f09e0 100644 --- a/contrib/cmake/src/api/python/CMakeLists.txt +++ b/contrib/cmake/src/api/python/CMakeLists.txt @@ -64,9 +64,15 @@ add_custom_command(OUTPUT "${z3py_bindings_build_dest}/z3/z3consts.py" ) list(APPEND build_z3_python_bindings_target_depends "${z3py_bindings_build_dest}/z3/z3consts.py") +if (UNIX) + set(LINK_COMMAND "create_symlink") +else() + set(LINK_COMMAND "copy") +endif() + # Link libz3 into the python directory so bindings work out of the box add_custom_command(OUTPUT "${z3py_bindings_build_dest}/libz3${CMAKE_SHARED_MODULE_SUFFIX}" - COMMAND "${CMAKE_COMMAND}" "-E" "create_symlink" + COMMAND "${CMAKE_COMMAND}" "-E" "${LINK_COMMAND}" "${CMAKE_BINARY_DIR}/libz3${CMAKE_SHARED_MODULE_SUFFIX}" "${z3py_bindings_build_dest}/libz3${CMAKE_SHARED_MODULE_SUFFIX}" DEPENDS libz3 From ef0dd74c53e10d51c42b98bf0f02b7163eda374e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 21 Sep 2016 16:14:27 -0700 Subject: [PATCH 199/536] try copy instead of cp Signed-off-by: Nikolaj Bjorner --- scripts/mk_util.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/scripts/mk_util.py b/scripts/mk_util.py index 305f94609..1e91c2d0d 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -1296,7 +1296,9 @@ class DLLComponent(Component): if IS_WINDOWS: out.write(' /DEF:%s.def' % os.path.join(self.to_src_dir, self.name)) if self.staging_link: - if IS_WINDOWS or IS_OSX: + if IS_WINDOWS: + out.write('\n\tcopy %s %s' % (self.dll_file(), self.staging_link)) + elif IS_OSX: out.write('\n\tcp %s %s' % (self.dll_file(), self.staging_link)) else: out.write('\n\tln -f -s %s %s' % (os.path.join(reverse_path(self.staging_link), self.dll_file()), self.staging_link)) From cf56da8482b054f6b653882047df9b94407328ac Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 21 Sep 2016 16:33:30 -0700 Subject: [PATCH 200/536] add z3test to cmakelists.txt Signed-off-by: Nikolaj Bjorner --- contrib/cmake/src/api/python/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/contrib/cmake/src/api/python/CMakeLists.txt b/contrib/cmake/src/api/python/CMakeLists.txt index dcd6f09e0..6efdc15ef 100644 --- a/contrib/cmake/src/api/python/CMakeLists.txt +++ b/contrib/cmake/src/api/python/CMakeLists.txt @@ -10,6 +10,7 @@ set(z3py_files z3/z3poly.py z3/z3printer.py z3/z3rcf.py + z3test.py z3/z3types.py z3/z3util.py ) From 4801a27c2df48162c771aa94fe395253b989a3bc Mon Sep 17 00:00:00 2001 From: Andrew Dutcher Date: Wed, 21 Sep 2016 16:55:24 -0700 Subject: [PATCH 201/536] Fix up z3test to a) exist and b) work --- scripts/mk_util.py | 2 ++ src/api/python/setup.py | 2 +- src/api/python/z3/z3.py | 1 + src/api/python/z3/z3num.py | 5 ----- src/api/python/z3test.py | 13 ++++++++++--- 5 files changed, 14 insertions(+), 9 deletions(-) diff --git a/scripts/mk_util.py b/scripts/mk_util.py index 1e91c2d0d..57f2c7ad1 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -2779,6 +2779,8 @@ def cp_z3py_to_build(): shutil.copyfile(os.path.join(src_pycache, pyc), os.path.join(target_pycache, pyc)) if is_verbose(): print("Copied '%s'" % pyc) + # Copy z3test.py + shutil.copyfile(os.path.join(Z3PY_SRC_DIR, 'z3test.py'), os.path.join(BUILD_DIR, 'python', 'z3test.py')) def mk_bindings(api_files): if not ONLY_MAKEFILES: diff --git a/src/api/python/setup.py b/src/api/python/setup.py index c6d7d8824..45da4d085 100644 --- a/src/api/python/setup.py +++ b/src/api/python/setup.py @@ -148,7 +148,7 @@ setup( packages=['z3'], include_package_data=True, package_data={ - 'z3': [os.path.join('lib', '*'), os.path.join('include', '*')] + 'z3': [os.path.join('lib', '*'), os.path.join('include', '*.h'), os.path.join('include', 'c++', '*.h')] }, scripts=[os.path.join('bin', 'z3')], cmdclass={'build': build, 'develop': develop, 'sdist': sdist, 'bdist_egg': bdist_egg}, diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index d7571a3c7..4ee5883ed 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -41,6 +41,7 @@ Z3 exceptions: ... print("failed: %s" % ex) failed: sort mismatch """ +from . import z3core from .z3core import * from .z3types import * from .z3consts import * diff --git a/src/api/python/z3/z3num.py b/src/api/python/z3/z3num.py index 14d8550e6..c8f15e7b8 100644 --- a/src/api/python/z3/z3num.py +++ b/src/api/python/z3/z3num.py @@ -572,9 +572,4 @@ def isolate_roots(p, vs=[]): _vs[i] = vs[i].ast _roots = AstVector(Z3_algebraic_roots(p.ctx_ref(), p.as_ast(), num, _vs), p.ctx) return [ Numeral(r) for r in _roots ] - -if __name__ == "__main__": - import doctest - if doctest.testmod().failed: - exit(1) diff --git a/src/api/python/z3test.py b/src/api/python/z3test.py index 38939cebf..9c544f623 100644 --- a/src/api/python/z3test.py +++ b/src/api/python/z3test.py @@ -5,9 +5,16 @@ # # Author: Leonardo de Moura (leonardo) ############################################ -import z3, doctest +import z3, doctest, sys + +if len(sys.argv) < 2 or sys.argv[1] == 'z3': + r = doctest.testmod(z3.z3) +elif sys.argv[1] == 'z3num': + r = doctest.testmod(z3.z3num) +else: + print 'Usage: z3test.py (z3 | z3num)' + sys.exit(1) -r = doctest.testmod(z3) if r.failed != 0: - exit(1) + sys.exit(1) From 092c52e5b7e8e5f9f2883502b10da9f0bc9c91ad Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 22 Sep 2016 18:29:26 -0700 Subject: [PATCH 202/536] fix for package directory. issue #744 Signed-off-by: Nikolaj Bjorner --- scripts/mk_util.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/mk_util.py b/scripts/mk_util.py index 57f2c7ad1..309b08297 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -1482,7 +1482,7 @@ class PythonInstallComponent(Component): else: MakeRuleCmd.install_files(out, os.path.join('python', 'z3', '*.pyc'), - self.pythonPkgDir, + os.path.join(self.pythonPkgDir,'z3'), in_prefix=self.in_prefix_install) if PYTHON_PACKAGE_DIR != distutils.sysconfig.get_python_lib(): out.write('\t@echo Z3Py was installed at \'%s\', make sure this directory is in your PYTHONPATH environment variable.' % PYTHON_PACKAGE_DIR) From b758a7a508775ad0a848ab54349c13c2f9f8c2dc Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 22 Sep 2016 19:53:48 -0700 Subject: [PATCH 203/536] disable smt-lib success printing when locally parsing database of common pattern rules. Issue #743 Signed-off-by: Nikolaj Bjorner --- src/ast/pattern/expr_pattern_match.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/ast/pattern/expr_pattern_match.cpp b/src/ast/pattern/expr_pattern_match.cpp index 86cad58f8..e18831650 100644 --- a/src/ast/pattern/expr_pattern_match.cpp +++ b/src/ast/pattern/expr_pattern_match.cpp @@ -388,7 +388,10 @@ expr_pattern_match::initialize(char const * spec_string) { std::istringstream is(spec_string); cmd_context ctx(true, &m_manager); + bool ps = ctx.print_success_enabled(); + ctx.set_print_success(false); VERIFY(parse_smt2_commands(ctx, is)); + ctx.set_print_success(ps); ptr_vector::const_iterator it = ctx.begin_assertions(); ptr_vector::const_iterator end = ctx.end_assertions(); From 8cf356224e08c872c6656eb7d2cf2c3422c6a2b2 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 22 Sep 2016 22:24:43 -0700 Subject: [PATCH 204/536] fix python for 3.x Signed-off-by: Nikolaj Bjorner --- src/api/python/z3test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/python/z3test.py b/src/api/python/z3test.py index 9c544f623..4554657e4 100644 --- a/src/api/python/z3test.py +++ b/src/api/python/z3test.py @@ -12,7 +12,7 @@ if len(sys.argv) < 2 or sys.argv[1] == 'z3': elif sys.argv[1] == 'z3num': r = doctest.testmod(z3.z3num) else: - print 'Usage: z3test.py (z3 | z3num)' + print('Usage: z3test.py (z3 | z3num)') sys.exit(1) if r.failed != 0: From 9c48fbba2e4cde49540fd7662740e05e9b507637 Mon Sep 17 00:00:00 2001 From: Gianfranco Costamagna Date: Mon, 26 Sep 2016 08:05:15 +0200 Subject: [PATCH 205/536] Update mpff.cpp to fix build with clang and new gcc --- src/test/mpff.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/test/mpff.cpp b/src/test/mpff.cpp index 35afcccf3..44930f2bd 100644 --- a/src/test/mpff.cpp +++ b/src/test/mpff.cpp @@ -207,7 +207,7 @@ static void tst_set64(unsigned N, unsigned prec) { mpff_manager fm(prec); scoped_mpff a(fm); - fm.set(a, INT64_MAX); + fm.set(a, static_cast(INT64_MAX)); SASSERT(fm.is_int64(a)); SASSERT(fm.is_uint64(a)); fm.inc(a); @@ -221,7 +221,7 @@ static void tst_set64(unsigned N, unsigned prec) { SASSERT(fm.is_int64(a)); SASSERT(fm.is_uint64(a)); - fm.set(a, INT64_MIN); + fm.set(a, static_cast(INT64_MIN)); SASSERT(fm.is_int64(a)); SASSERT(!fm.is_uint64(a)); fm.dec(a); @@ -235,7 +235,7 @@ static void tst_set64(unsigned N, unsigned prec) { SASSERT(fm.is_int64(a)); SASSERT(!fm.is_uint64(a)); - fm.set(a, UINT64_MAX); + fm.set(a, static_cast(UINT64_MAX)); SASSERT(fm.is_uint64(a)); SASSERT(!fm.is_int64(a)); fm.inc(a); @@ -600,7 +600,7 @@ static void tst_div(unsigned prec) { scoped_mpff a(m), b(m), c(m); m.round_to_plus_inf(); m.set(a, 1); - m.set(b, UINT64_MAX); + m.set(b, static_cast(UINT64_MAX)); m.div(a, b, c); m.display_raw(std::cout, a); std::cout << "\n"; m.display_raw(std::cout, b); std::cout << "\n"; From 4817b87b7d7727f76ae534c76c10c4828c79816c Mon Sep 17 00:00:00 2001 From: Gianfranco Costamagna Date: Mon, 26 Sep 2016 08:06:38 +0200 Subject: [PATCH 206/536] fix build with new gcc and clang compilers --- src/test/mpz.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/mpz.cpp b/src/test/mpz.cpp index d7944ae95..ee7cf39f1 100644 --- a/src/test/mpz.cpp +++ b/src/test/mpz.cpp @@ -280,7 +280,7 @@ void tst_int_min_bug() { mpz big; mpz expected; mpz r; - m.set(big, UINT64_MAX); + m.set(big, static_cast(UINT64_MAX)); m.set(expected, "18446744075857035263"); m.sub(big, intmin, r); std::cout << "r: " << m.to_string(r) << "\nexpected: " << m.to_string(expected) << "\n"; From 476b06fa14c7bc5641150f8c359b5dbf14bac711 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 28 Sep 2016 16:42:07 -0700 Subject: [PATCH 207/536] fix compiler warnings, gcc Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/bv_bounds.cpp | 4 +--- src/ast/rewriter/bv_rewriter.cpp | 1 - src/smt/smt_consequences.cpp | 2 -- src/smt/smt_model_checker.cpp | 2 ++ 4 files changed, 3 insertions(+), 6 deletions(-) diff --git a/src/ast/rewriter/bv_bounds.cpp b/src/ast/rewriter/bv_bounds.cpp index 9d3ca8c76..0f82a85c9 100644 --- a/src/ast/rewriter/bv_bounds.cpp +++ b/src/ast/rewriter/bv_bounds.cpp @@ -85,7 +85,7 @@ bool bv_bounds::is_uleq(expr * e, expr * & v, numeral & c) { if (!m_bv_util.is_extract(eql)) return false; expr * const eql0 = to_app(eql)->get_arg(0); const unsigned eql0_sz = m_bv_util.get_bv_size(eql0); - if (!m_bv_util.get_extract_high(eql) == (eql0_sz - 1)) return false; + if (m_bv_util.get_extract_high(eql) != (eql0_sz - 1)) return false; if (!m_bv_util.is_numeral(eqr, eqr_val, eqr_sz)) return false; if (!eqr_val.is_zero()) return false; if (!m_bv_util.is_extract(ulel)) return false; @@ -245,7 +245,6 @@ void bv_bounds::reset() { } br_status bv_bounds::rewrite(unsigned limit, func_decl * f, unsigned num, expr * const * args, expr_ref& result) { - const family_id fid = f->get_family_id(); if (!m_m.is_bool(f->get_range())) return BR_FAILED; const decl_kind k = f->get_decl_kind(); if ((k != OP_OR && k != OP_AND) || num > limit) return BR_FAILED; @@ -614,7 +613,6 @@ bool bv_bounds::is_sat(app * v) { bool bv_bounds::is_sat_core(app * v) { SASSERT(m_bv_util.is_bv(v)); if (!m_okay) return false; - func_decl * const d = v->get_decl(); unsigned const bv_sz = m_bv_util.get_bv_size(v); numeral lower, upper; const bool has_upper = m_unsigned_uppers.find(v, upper); diff --git a/src/ast/rewriter/bv_rewriter.cpp b/src/ast/rewriter/bv_rewriter.cpp index dcb5ba681..0246f2b16 100644 --- a/src/ast/rewriter/bv_rewriter.cpp +++ b/src/ast/rewriter/bv_rewriter.cpp @@ -622,7 +622,6 @@ unsigned bv_rewriter::propagate_extract(unsigned high, expr * arg, expr_ref & re } // perform removal SASSERT(removable <= to_remove); - const unsigned new_sz = sz - removable; ptr_buffer new_args; ptr_buffer new_concat_args; for (unsigned i = 0; i < num; i++) { diff --git a/src/smt/smt_consequences.cpp b/src/smt/smt_consequences.cpp index 65dca4918..8619ff815 100644 --- a/src/smt/smt_consequences.cpp +++ b/src/smt/smt_consequences.cpp @@ -473,9 +473,7 @@ namespace smt { tout << "lits: " << num_units << "\n";); m_case_split_queue->init_search_eh(); unsigned num_iterations = 0; - unsigned model_threshold = 2; unsigned num_fixed_eqs = 0; - unsigned num_reiterations = 0; unsigned chunk_size = 100; while (!var2val.empty()) { diff --git a/src/smt/smt_model_checker.cpp b/src/smt/smt_model_checker.cpp index 980270ded..c17211664 100644 --- a/src/smt/smt_model_checker.cpp +++ b/src/smt/smt_model_checker.cpp @@ -158,11 +158,13 @@ namespace smt { TRACE("model_checker", tout << "Could not get value for " << sk_d->get_name() << "\n";); return false; // get_some_value failed... giving up } + TRACE("model_checker", tout << "Got some value " << sk_value << "\n";); } if (use_inv) { unsigned sk_term_gen; expr * sk_term = m_model_finder.get_inv(q, i, sk_value, sk_term_gen); if (sk_term != 0) { + TRACE("model_checker", tout << "Found inverse " << mk_pp(sk_term, m) << "\n";); SASSERT(!m.is_model_value(sk_term)); if (sk_term_gen > max_generation) max_generation = sk_term_gen; From 7816c533527139944cdb183d3ff8d472d34fb843 Mon Sep 17 00:00:00 2001 From: Andrew Dutcher Date: Wed, 28 Sep 2016 20:54:38 -0700 Subject: [PATCH 208/536] allow python to load libz3 using loader's default search --- scripts/update_api.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/scripts/update_api.py b/scripts/update_api.py index d8b2bec58..4ca11938c 100755 --- a/scripts/update_api.py +++ b/scripts/update_api.py @@ -1611,7 +1611,7 @@ _lib = None def lib(): global _lib if _lib is None: - _dirs = ['.', pkg_resources.resource_filename('z3', 'lib'), os.path.join(sys.prefix, 'lib'), ''] + _dirs = ['.', pkg_resources.resource_filename('z3', 'lib'), os.path.join(sys.prefix, 'lib'), None] for _dir in _dirs: try: init(_dir) @@ -1641,9 +1641,12 @@ else: return "" def init(PATH): - PATH = os.path.realpath(PATH) - if os.path.isdir(PATH): - PATH = os.path.join(PATH, 'libz3.%s' % _ext) + if PATH: + PATH = os.path.realpath(PATH) + if os.path.isdir(PATH): + PATH = os.path.join(PATH, 'libz3.%s' % _ext) + else: + PATH = 'libz3.%s' % _ext global _lib _lib = ctypes.CDLL(PATH) From 279621c1d753832bc429ccdaabd3cf5801305091 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 30 Sep 2016 07:21:39 -0700 Subject: [PATCH 209/536] duplicating private member from z3 to avoid build regressions under some environments Signed-off-by: Nikolaj Bjorner --- src/api/python/z3/z3printer.py | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/src/api/python/z3/z3printer.py b/src/api/python/z3/z3printer.py index e02c28a96..2e3a528bf 100644 --- a/src/api/python/z3/z3printer.py +++ b/src/api/python/z3/z3printer.py @@ -10,6 +10,10 @@ from .z3consts import * from .z3core import * from ctypes import * +def _z3_assert(cond, msg): + if not cond: + raise Z3Exception(msg) + ############################## # # Configuration @@ -580,14 +584,14 @@ class Formatter: return to_format(a.as_string()) def pp_fprm_value(self, a): - z3._z3_assert(z3.is_fprm_value(a), 'expected FPRMNumRef') + _z3_assert(z3.is_fprm_value(a), 'expected FPRMNumRef') if self.fpa_pretty and (a.decl().kind() in _z3_op_to_fpa_pretty_str): return to_format(_z3_op_to_fpa_pretty_str.get(a.decl().kind())) else: return to_format(_z3_op_to_fpa_normal_str.get(a.decl().kind())) def pp_fp_value(self, a): - z3._z3_assert(isinstance(a, z3.FPNumRef), 'type mismatch') + _z3_assert(isinstance(a, z3.FPNumRef), 'type mismatch') if not self.fpa_pretty: r = [] if (a.isNaN()): @@ -612,7 +616,7 @@ class Formatter: else: return to_format('+zero') else: - z3._z3_assert(z3.is_fp_value(a), 'expecting FP num ast') + _z3_assert(z3.is_fp_value(a), 'expecting FP num ast') r = [] sgn = c_int(0) sgnb = Z3_fpa_get_numeral_sign(a.ctx_ref(), a.ast, byref(sgn)) @@ -642,7 +646,7 @@ class Formatter: else: return to_format(_z3_op_to_fpa_pretty_str[Z3_OP_FPA_PLUS_ZERO]) else: - z3._z3_assert(z3.is_fp_value(a), 'expecting FP num ast') + _z3_assert(z3.is_fp_value(a), 'expecting FP num ast') r = [] sgn = (ctypes.c_int)(0) sgnb = Z3_fpa_get_numeral_sign(a.ctx_ref(), a.ast, byref(sgn)) @@ -659,7 +663,7 @@ class Formatter: def pp_fp(self, a, d, xs): - z3._z3_assert(isinstance(a, z3.FPRef), "type mismatch") + _z3_assert(isinstance(a, z3.FPRef), "type mismatch") k = a.decl().kind() op = '?' if (self.fpa_pretty and k in _z3_op_to_fpa_pretty_str): @@ -1164,12 +1168,12 @@ def set_pp_option(k, v): return True val = getattr(_PP, k, None) if val != None: - z3._z3_assert(type(v) == type(val), "Invalid pretty print option value") + _z3_assert(type(v) == type(val), "Invalid pretty print option value") setattr(_PP, k, v) return True val = getattr(_Formatter, k, None) if val != None: - z3._z3_assert(type(v) == type(val), "Invalid pretty print option value") + _z3_assert(type(v) == type(val), "Invalid pretty print option value") setattr(_Formatter, k, v) return True return False @@ -1219,13 +1223,13 @@ def pp(a): print(a) def print_matrix(m): - z3._z3_assert(isinstance(m, list) or isinstance(m, tuple), "matrix expected") + _z3_assert(isinstance(m, list) or isinstance(m, tuple), "matrix expected") if not in_html_mode(): print(obj_to_string(m)) else: print('') for r in m: - z3._z3_assert(isinstance(r, list) or isinstance(r, tuple), "matrix expected") + _z3_assert(isinstance(r, list) or isinstance(r, tuple), "matrix expected") print('') for c in r: print('' % c) From 136f724445181183cadde32b7fb27127fcffc403 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 30 Sep 2016 14:18:34 -0700 Subject: [PATCH 210/536] update python API with facilities for Pseudo-Booleans and += shorthand for adding constraints Signed-off-by: Nikolaj Bjorner --- src/api/python/z3/z3.py | 48 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index 4ee5883ed..00539a663 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -1291,6 +1291,19 @@ class BoolRef(ExprRef): def sort(self): return BoolSortRef(Z3_get_sort(self.ctx_ref(), self.as_ast()), self.ctx) + def __rmul__(self, other): + return self * other + + def __mul__(self, other): + """Create the Z3 expression `self * other`. + """ + if other == 1: + return self + if other == 0: + return 0 + return If(self, other, 0) + + def is_bool(a): """Return `True` if `a` is a Z3 Boolean expression. @@ -6001,6 +6014,10 @@ class Solver(Z3PPObject): """ self.assert_exprs(*args) + def __iadd__(self, fml): + self.add(fml) + return self + def append(self, *args): """Assert constraints into the solver. @@ -6349,6 +6366,10 @@ class Fixedpoint(Z3PPObject): """Assert constraints as background axioms for the fixedpoint solver. Alias for assert_expr.""" self.assert_exprs(*args) + def __iadd__(self, fml): + self.add(fml) + return self + def append(self, *args): """Assert constraints as background axioms for the fixedpoint solver. Alias for assert_expr.""" self.assert_exprs(*args) @@ -6703,6 +6724,10 @@ class Optimize(Z3PPObject): """Assert constraints as background axioms for the optimize solver. Alias for assert_expr.""" self.assert_exprs(*args) + def __iadd__(self, fml): + self.add(fml) + return self + def add_soft(self, arg, weight = "1", id = None): """Add soft constraint with optional weight and optional identifier. If no weight is supplied, then the penalty for violating the soft constraint @@ -7575,6 +7600,29 @@ def AtMost(*args): _args, sz = _to_ast_array(args1) return BoolRef(Z3_mk_atmost(ctx.ref(), sz, _args, k), ctx) +def AtLeast(*args): + """Create an at-most Pseudo-Boolean k constraint. + + >>> a, b, c = Bools('a b c') + >>> f = AtLeast(a, b, c, 2) + """ + def mk_not(a): + if is_not(a): + return a.arg(0) + else: + return Not(a) + args = _get_args(args) + if __debug__: + _z3_assert(len(args) > 1, "Non empty list of arguments expected") + ctx = _ctx_from_ast_arg_list(args) + if __debug__: + _z3_assert(ctx is not None, "At least one of the arguments must be a Z3 expression") + args1 = _coerce_expr_list(args[:-1], ctx) + args1 = [ mk_not(a) for a in args1 ] + k = len(args1) - args[-1] + _args, sz = _to_ast_array(args1) + return BoolRef(Z3_mk_atmost(ctx.ref(), sz, _args, k), ctx) + def PbLe(args, k): """Create a Pseudo-Boolean inequality k constraint. From 57ebf7bd386a931cf494ed2039d0d30518df78a3 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 2 Oct 2016 10:08:23 -0700 Subject: [PATCH 211/536] accepting floats Signed-off-by: Nikolaj Bjorner --- src/api/python/z3/z3.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index 4ee5883ed..7e58a724c 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -6712,6 +6712,8 @@ class Optimize(Z3PPObject): """ if _is_int(weight): weight = "%d" % weight + elif isinstance(weight, (float, double)): + weight = "%f" % weight if not isinstance(weight, str): raise Z3Exception("weight should be a string or an integer") if id is None: From b2db2f1eb6433f1ff0ec0d8100557eaeafb7eb0a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 2 Oct 2016 10:21:58 -0700 Subject: [PATCH 212/536] allow negative weights for weighted maxsat Signed-off-by: Nikolaj Bjorner --- src/api/python/z3/z3.py | 2 +- src/opt/opt_context.cpp | 19 +++++++++++-------- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index 7e58a724c..581815c09 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -6712,7 +6712,7 @@ class Optimize(Z3PPObject): """ if _is_int(weight): weight = "%d" % weight - elif isinstance(weight, (float, double)): + elif isinstance(weight, float): weight = "%f" % weight if not isinstance(weight, str): raise Z3Exception("weight should be a string or an integer") diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 68a5dc302..07bb8385b 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -90,9 +90,6 @@ namespace opt { } unsigned context::scoped_state::add(expr* f, rational const& w, symbol const& id) { - if (w.is_neg()) { - throw default_exception("Negative weight supplied. Weight should be non-negative"); - } if (!m.is_bool(f)) { throw default_exception("Soft constraint should be Boolean"); } @@ -102,7 +99,7 @@ namespace opt { } SASSERT(m_indices.contains(id)); unsigned idx = m_indices[id]; - if (w.is_pos()) { + if (!w.is_zero()) { m_objectives[idx].m_terms.push_back(f); m_objectives[idx].m_weights.push_back(w); m_objectives_term_trail.push_back(idx); @@ -743,16 +740,22 @@ namespace opt { app* a = to_app(fml); if (m_objective_fns.find(a->get_decl(), index) && m_objectives[index].m_type == O_MAXSMT) { for (unsigned i = 0; i < a->get_num_args(); ++i) { - expr* arg = a->get_arg(i); - if (m.is_true(arg)) { + expr_ref arg(a->get_arg(i), m); + rational weight = m_objectives[index].m_weights[i]; + if (weight.is_neg()) { + weight.neg(); + arg = mk_not(m, arg); + offset -= weight; + } + if (m.is_true(arg) || weight.is_zero()) { // skip } else if (m.is_false(arg)) { - offset += m_objectives[index].m_weights[i]; + offset += weight; } else { terms.push_back(arg); - weights.push_back(m_objectives[index].m_weights[i]); + weights.push_back(weight); } } id = m_objectives[index].m_id; From e3f0aff318b5873cfe858191b8e73ed716405b59 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 3 Oct 2016 16:22:13 -0700 Subject: [PATCH 213/536] address ubuntu warning and add shortcuts for maxsat Signed-off-by: Nikolaj Bjorner --- src/api/python/z3/z3.py | 17 ++++++------ src/ast/rewriter/bv_bounds.cpp | 2 +- src/opt/maxsmt.cpp | 6 ++-- src/tactic/arith/card2bv_tactic.cpp | 40 +++++++++++++++++++++++++++ src/tactic/arith/card2bv_tactic.h | 2 ++ src/tactic/bv/bv_bound_chk_tactic.cpp | 1 - 6 files changed, 56 insertions(+), 12 deletions(-) diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index 5c677c4f3..c360a9bdc 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -7548,11 +7548,11 @@ def Sum(*args): a__0 + a__1 + a__2 + a__3 + a__4 """ args = _get_args(args) - if __debug__: - _z3_assert(len(args) > 0, "Non empty list of arguments expected") + if len(args) == 0: + return 0 ctx = _ctx_from_ast_arg_list(args) - if __debug__: - _z3_assert(ctx is not None, "At least one of the arguments must be a Z3 expression") + if ctx is None: + return _reduce(lambda a, b: a + b, args, 0) args = _coerce_expr_list(args, ctx) if is_bv(args[0]): return _reduce(lambda a, b: a + b, args, 0) @@ -7560,6 +7560,7 @@ def Sum(*args): _args, sz = _to_ast_array(args) return ArithRef(Z3_mk_add(ctx.ref(), sz, _args), ctx) + def Product(*args): """Create the product of the Z3 expressions. @@ -7573,11 +7574,11 @@ def Product(*args): a__0*a__1*a__2*a__3*a__4 """ args = _get_args(args) - if __debug__: - _z3_assert(len(args) > 0, "Non empty list of arguments expected") + if len(args) == 0: + return 1 ctx = _ctx_from_ast_arg_list(args) - if __debug__: - _z3_assert(ctx is not None, "At least one of the arguments must be a Z3 expression") + if ctx is None: + return _reduce(lambda a, b: a * b, args, 1) args = _coerce_expr_list(args, ctx) if is_bv(args[0]): return _reduce(lambda a, b: a * b, args, 1) diff --git a/src/ast/rewriter/bv_bounds.cpp b/src/ast/rewriter/bv_bounds.cpp index 0f82a85c9..22decbb7c 100644 --- a/src/ast/rewriter/bv_bounds.cpp +++ b/src/ast/rewriter/bv_bounds.cpp @@ -92,7 +92,7 @@ bool bv_bounds::is_uleq(expr * e, expr * & v, numeral & c) { expr * const ulel0 = to_app(ulel)->get_arg(0); if (ulel0 != eql0) return false; if ((m_bv_util.get_extract_high(ulel) + 1) != m_bv_util.get_extract_low(eql)) return false; - if (!m_bv_util.get_extract_low(ulel) == 0) return false; + if (m_bv_util.get_extract_low(ulel) != 0) return false; if (!m_bv_util.is_numeral(uler, uleqr_val, uleqr_sz)) return false; SASSERT(m_bv_util.get_bv_size(ulel0) == uleqr_sz + eqr_sz); v = ulel0; diff --git a/src/opt/maxsmt.cpp b/src/opt/maxsmt.cpp index 1ad2a09be..fa4897046 100644 --- a/src/opt/maxsmt.cpp +++ b/src/opt/maxsmt.cpp @@ -267,8 +267,10 @@ namespace opt { void maxsmt::display_answer(std::ostream& out) const { for (unsigned i = 0; i < m_soft_constraints.size(); ++i) { - out << mk_pp(m_soft_constraints[i], m) - << (get_assignment(i)?" |-> true\n":" |-> false\n"); + expr* e = m_soft_constraints[i]; + bool is_not = m.is_not(e, e); + out << mk_pp(e, m) + << ((is_not != get_assignment(i))?" |-> true\n":" |-> false\n"); } } diff --git a/src/tactic/arith/card2bv_tactic.cpp b/src/tactic/arith/card2bv_tactic.cpp index 7d7097958..2b551229d 100644 --- a/src/tactic/arith/card2bv_tactic.cpp +++ b/src/tactic/arith/card2bv_tactic.cpp @@ -116,6 +116,9 @@ namespace pb { result = m.mk_and(sz, args); return BR_DONE; } + if (is_atmost1(f, sz, args, result)) { + return BR_DONE; + } br_status st = mk_shannon(f, sz, args, result); if (st == BR_FAILED) { mk_bv(f, sz, args, result); @@ -165,6 +168,43 @@ namespace pb { return BR_FAILED; } + expr_ref card2bv_rewriter::mk_atmost1(unsigned sz, expr * const* args) { + expr_ref f1(m), f2(m), f3(m), result(m); + f1 = bv.mk_bv(sz, args); + f2 = bv.mk_bv_sub(f1, bv.mk_numeral(rational(1), sz)); + f3 = m.mk_app(bv.get_fid(), OP_BAND, f1, f2); + result = m.mk_eq(f3, bv.mk_numeral(rational(0), sz)); + return result; + } + + bool card2bv_rewriter::is_atmost1(func_decl* f, unsigned sz, expr * const* args, expr_ref& result) { + switch (f->get_decl_kind()) { + case OP_AT_MOST_K: + case OP_PB_LE: + if (pb.get_k(f).is_one() && pb.has_unit_coefficients(f)) { + result = mk_atmost1(sz, args); + return true; + } + return false; + case OP_AT_LEAST_K: + case OP_PB_GE: + if (pb.get_k(f) == rational(sz-1) && pb.has_unit_coefficients(f)) { + expr_ref_vector nargs(m); + for (unsigned i = 0; i < sz; ++i) { + nargs.push_back(mk_not(args[i])); + } + result = mk_atmost1(nargs.size(), nargs.c_ptr()); + return true; + } + return false; + case OP_PB_EQ: + return false; + default: + UNREACHABLE(); + return false; + } + } + bool card2bv_rewriter::is_or(func_decl* f) { switch (f->get_decl_kind()) { case OP_AT_MOST_K: diff --git a/src/tactic/arith/card2bv_tactic.h b/src/tactic/arith/card2bv_tactic.h index 30a91416d..91ed68969 100644 --- a/src/tactic/arith/card2bv_tactic.h +++ b/src/tactic/arith/card2bv_tactic.h @@ -52,6 +52,8 @@ namespace pb { expr* mk_ite(expr* c, expr* hi, expr* lo); bool is_or(func_decl* f); bool is_and(func_decl* f); + bool is_atmost1(func_decl* f, unsigned sz, expr * const* args, expr_ref& result); + expr_ref mk_atmost1(unsigned sz, expr * const* args); public: card2bv_rewriter(ast_manager& m); diff --git a/src/tactic/bv/bv_bound_chk_tactic.cpp b/src/tactic/bv/bv_bound_chk_tactic.cpp index c3f32aaaf..1b90e05b1 100644 --- a/src/tactic/bv/bv_bound_chk_tactic.cpp +++ b/src/tactic/bv/bv_bound_chk_tactic.cpp @@ -71,7 +71,6 @@ struct bv_bound_chk_rewriter_cfg : public default_rewriter_cfg { result_pr = 0; const family_id fid = f->get_family_id(); if (fid != m_b_rw.get_fid()) return BR_FAILED; - const decl_kind k = f->get_decl_kind(); bv_bounds bvb(m()); const br_status rv = bvb.rewrite(m_bv_ineq_consistency_test_max, f, num, args, result); if (rv != BR_FAILED && (m_m.is_false(result) || m_m.is_true(result))) m_stats.m_unsats++; From 0bd06930aef34b2bd0bbdf01331d51bef4a8de01 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Tue, 4 Oct 2016 18:04:00 +0100 Subject: [PATCH 214/536] whitespace --- src/ast/fpa/fpa2bv_converter.cpp | 24 ++++++++++++------------ src/ast/fpa/fpa2bv_rewriter.cpp | 6 +++--- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/ast/fpa/fpa2bv_converter.cpp b/src/ast/fpa/fpa2bv_converter.cpp index d3257ac55..90007b330 100644 --- a/src/ast/fpa/fpa2bv_converter.cpp +++ b/src/ast/fpa/fpa2bv_converter.cpp @@ -264,7 +264,7 @@ void fpa2bv_converter::mk_function(func_decl * f, unsigned num, expr * const * a rng = f->get_range(); fapp = m.mk_app(f, num, args); if (m_util.is_float(rng)) { - sort_ref bv_rng(m); + sort_ref bv_rng(m); expr_ref new_eq(m); unsigned ebits = m_util.get_ebits(rng); unsigned sbits = m_util.get_sbits(rng); @@ -290,7 +290,7 @@ void fpa2bv_converter::mk_function(func_decl * f, unsigned num, expr * const * a m_extra_assertions.push_back(new_eq); result = flt_app; } - else + else result = fapp; TRACE("fpa2bv", tout << "UF result: " << mk_ismt2_pp(result, m) << std::endl; ); @@ -1057,7 +1057,7 @@ void fpa2bv_converter::mk_rem(sort * s, expr_ref & x, expr_ref & y, expr_ref & r // (x is 0) -> x c5 = x_is_zero; v5 = pzero; - + // exp(x) < exp(y) -> x unsigned ebits = m_util.get_ebits(s); unsigned sbits = m_util.get_sbits(s); @@ -1117,15 +1117,15 @@ void fpa2bv_converter::mk_rem(sort * s, expr_ref & x, expr_ref & y, expr_ref & r dbg_decouple("fpa2bv_rem_exp_diff", exp_diff); // CMW: This creates _huge_ bit-vectors, which is potentially sub-optimal, - // but calculating this via rem = x - y * nearest(x/y) creates huge + // but calculating this via rem = x - y * nearest(x/y) creates huge // circuits, too. Lazy instantiation seems the way to go in the long run - // (using the lazy bit-blaster helps on simple instances). + // (using the lazy bit-blaster helps on simple instances). expr_ref a_sig_ext(m), b_sig_ext(m), lshift(m), rshift(m), shifted(m), huge_rem(m); a_sig_ext = m_bv_util.mk_concat(m_bv_util.mk_zero_extend(max_exp_diff_ui, a_sig), m_bv_util.mk_numeral(0, 3)); b_sig_ext = m_bv_util.mk_concat(m_bv_util.mk_zero_extend(max_exp_diff_ui, b_sig), m_bv_util.mk_numeral(0, 3)); lshift = m_bv_util.mk_zero_extend(max_exp_diff_ui + sbits - (ebits+2) + 3, exp_diff); rshift = m_bv_util.mk_zero_extend(max_exp_diff_ui + sbits - (ebits+2) + 3, neg_exp_diff); - shifted = m.mk_ite(exp_diff_is_neg, m_bv_util.mk_bv_ashr(a_sig_ext, rshift), + shifted = m.mk_ite(exp_diff_is_neg, m_bv_util.mk_bv_ashr(a_sig_ext, rshift), m_bv_util.mk_bv_shl(a_sig_ext, lshift)); huge_rem = m_bv_util.mk_bv_urem(shifted, b_sig_ext); dbg_decouple("fpa2bv_rem_huge_rem", huge_rem); @@ -1142,7 +1142,7 @@ void fpa2bv_converter::mk_rem(sort * s, expr_ref & x, expr_ref & y, expr_ref & r expr_ref r_ge_y_half(m), r_gt_ny_half(m), r_le_y_half(m), r_lt_ny_half(m); expr_ref r_ge_zero(m), r_le_zero(m); expr_ref rounded_sub_y(m), rounded_add_y(m); - mpf zero, two; + mpf zero, two; m_mpf_manager.set(two, ebits, sbits, 2); m_mpf_manager.set(zero, ebits, sbits, 0); mk_numeral(s, two, two_e); @@ -1151,7 +1151,7 @@ void fpa2bv_converter::mk_rem(sort * s, expr_ref & x, expr_ref & y, expr_ref & r mk_neg(s, y_half, ny_half); mk_is_zero(y_half, y_half_is_zero); y_half_is_nz = m.mk_not(y_half_is_zero); - + mk_float_ge(s, rndd, y_half, r_ge_y_half); mk_float_gt(s, rndd, ny_half, r_gt_ny_half); mk_float_le(s, rndd, y_half, r_le_y_half); @@ -1161,8 +1161,8 @@ void fpa2bv_converter::mk_rem(sort * s, expr_ref & x, expr_ref & y, expr_ref & r mk_add(s, rne_bv, rndd, y, rounded_add_y); expr_ref sub_cnd(m), add_cnd(m); - sub_cnd = m.mk_and(y_half_is_nz, - m.mk_or(m.mk_and(y_is_pos, r_ge_y_half), + sub_cnd = m.mk_and(y_half_is_nz, + m.mk_or(m.mk_and(y_is_pos, r_ge_y_half), m.mk_and(y_is_neg, r_le_y_half))); add_cnd = m.mk_and(y_half_is_nz, m.mk_or(m.mk_and(y_is_pos, r_lt_ny_half), @@ -1170,7 +1170,7 @@ void fpa2bv_converter::mk_rem(sort * s, expr_ref & x, expr_ref & y, expr_ref & r mk_ite(add_cnd, rounded_add_y, rndd, v7); mk_ite(sub_cnd, rounded_sub_y, v7, v7); - + // And finally, we tie them together. mk_ite(c6, v6, v7, result); mk_ite(c5, v5, result, result); @@ -3698,7 +3698,7 @@ void fpa2bv_converter::dbg_decouple(const char * prefix, expr_ref & e) { // CMW: This works only for quantifier-free formulas. if (m_util.is_fp(e)) { expr_ref new_bv(m); - expr *e_sgn, *e_sig, *e_exp; + expr *e_sgn, *e_sig, *e_exp; split_fp(e, e_sgn, e_exp, e_sig); unsigned ebits = m_bv_util.get_bv_size(e_exp); unsigned sbits = m_bv_util.get_bv_size(e_sig) + 1; diff --git a/src/ast/fpa/fpa2bv_rewriter.cpp b/src/ast/fpa/fpa2bv_rewriter.cpp index 0845393f4..65862bf90 100644 --- a/src/ast/fpa/fpa2bv_rewriter.cpp +++ b/src/ast/fpa/fpa2bv_rewriter.cpp @@ -103,7 +103,7 @@ br_status fpa2bv_rewriter_cfg::reduce_app(func_decl * f, unsigned num, expr * co } return BR_FAILED; } - + if (m_conv.is_float_family(f)) { switch (f->get_decl_kind()) { case OP_FPA_RM_NEAREST_TIES_TO_AWAY: @@ -157,7 +157,7 @@ br_status fpa2bv_rewriter_cfg::reduce_app(func_decl * f, unsigned num, expr * co case OP_FPA_INTERNAL_BVWRAP: case OP_FPA_INTERNAL_BV2RM: - + case OP_FPA_INTERNAL_TO_REAL_UNSPECIFIED: case OP_FPA_INTERNAL_TO_UBV_UNSPECIFIED: case OP_FPA_INTERNAL_TO_SBV_UNSPECIFIED: @@ -169,7 +169,7 @@ br_status fpa2bv_rewriter_cfg::reduce_app(func_decl * f, unsigned num, expr * co NOT_IMPLEMENTED_YET(); } } - else + else { SASSERT(!m_conv.is_float_family(f)); if (m_conv.fu().contains_floats(f)) { From acdaeca826179a8395c051b888cd5ef9befb407b Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Tue, 4 Oct 2016 18:04:56 +0100 Subject: [PATCH 215/536] Bugfix for ITEs over FP rounding modes. Fixes #751. --- src/ast/fpa/fpa2bv_converter.cpp | 31 ++++++++++++++++++++----------- src/ast/fpa/fpa2bv_rewriter.cpp | 4 ++-- 2 files changed, 22 insertions(+), 13 deletions(-) diff --git a/src/ast/fpa/fpa2bv_converter.cpp b/src/ast/fpa/fpa2bv_converter.cpp index 90007b330..6bba4663d 100644 --- a/src/ast/fpa/fpa2bv_converter.cpp +++ b/src/ast/fpa/fpa2bv_converter.cpp @@ -90,19 +90,28 @@ void fpa2bv_converter::mk_eq(expr * a, expr * b, expr_ref & result) { } void fpa2bv_converter::mk_ite(expr * c, expr * t, expr * f, expr_ref & result) { - SASSERT(m_util.is_fp(t) && m_util.is_fp(f)); + if (m_util.is_fp(t) && m_util.is_fp(f)) { + expr *t_sgn, *t_sig, *t_exp; + expr *f_sgn, *f_sig, *f_exp; + split_fp(t, t_sgn, t_exp, t_sig); + split_fp(f, f_sgn, f_exp, f_sig); - expr *t_sgn, *t_sig, *t_exp; - expr *f_sgn, *f_sig, *f_exp; - split_fp(t, t_sgn, t_exp, t_sig); - split_fp(f, f_sgn, f_exp, f_sig); + expr_ref sgn(m), s(m), e(m); + m_simp.mk_ite(c, t_sgn, f_sgn, sgn); + m_simp.mk_ite(c, t_sig, f_sig, s); + m_simp.mk_ite(c, t_exp, f_exp, e); - expr_ref sgn(m), s(m), e(m); - m_simp.mk_ite(c, t_sgn, f_sgn, sgn); - m_simp.mk_ite(c, t_sig, f_sig, s); - m_simp.mk_ite(c, t_exp, f_exp, e); - - result = m_util.mk_fp(sgn, e, s); + result = m_util.mk_fp(sgn, e, s); + } + else if (m_util.is_rm(t) && m_util.is_rm(f)) + { + SASSERT(m_util.is_bv2rm(t) && m_util.is_bv2rm(f)); + TRACE("fpa2bv", tout << "ite rm: t=" << mk_ismt2_pp(t, m) << " f=" << mk_ismt2_pp(f, m) << std::endl; ); + m_simp.mk_ite(c, to_app(t)->get_arg(0), to_app(f)->get_arg(0), result); + result = m_util.mk_bv2rm(result); + } + else + UNREACHABLE(); } void fpa2bv_converter::mk_distinct(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { diff --git a/src/ast/fpa/fpa2bv_rewriter.cpp b/src/ast/fpa/fpa2bv_rewriter.cpp index 65862bf90..5f89e12db 100644 --- a/src/ast/fpa/fpa2bv_rewriter.cpp +++ b/src/ast/fpa/fpa2bv_rewriter.cpp @@ -86,10 +86,10 @@ br_status fpa2bv_rewriter_cfg::reduce_app(func_decl * f, unsigned num, expr * co return BR_DONE; } return BR_FAILED; - } + } else if (m().is_ite(f)) { SASSERT(num == 3); - if (m_conv.is_float(args[1])) { + if (m_conv.is_float(args[1]) || m_conv.is_rm(args[1])) { m_conv.mk_ite(args[0], args[1], args[2], result); return BR_DONE; } From f4fd72174140d7e0246987d83520e5fec357354c Mon Sep 17 00:00:00 2001 From: Dionna Amalie Glaze Date: Tue, 4 Oct 2016 13:02:31 -0500 Subject: [PATCH 216/536] Z3_query_constructor documentation clarification Hit a segfault when I assumed the API would allocate these _out parameters for me. --- src/api/z3_api.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/api/z3_api.h b/src/api/z3_api.h index 666485a7f..cd889b3be 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -1997,9 +1997,9 @@ extern "C" { \param c logical context. \param constr constructor container. The container must have been passed in to a #Z3_mk_datatype call. \param num_fields number of accessor fields in the constructor. - \param constructor constructor function declaration. - \param tester constructor test function declaration. - \param accessors array of accessor function declarations. + \param constructor constructor function declaration, allocated by user. + \param tester constructor test function declaration, allocated by user. + \param accessors array of accessor function declarations allocated by user. The array must contain num_fields elements. def_API('Z3_query_constructor', VOID, (_in(CONTEXT), _in(CONSTRUCTOR), _in(UINT), _out(FUNC_DECL), _out(FUNC_DECL), _out_array(2, FUNC_DECL))) */ From f452895f5fadb13e5fb1469b2744db0d75642638 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 4 Oct 2016 14:45:23 -0700 Subject: [PATCH 217/536] add mutex pass Signed-off-by: Nikolaj Bjorner --- src/opt/maxres.cpp | 38 ++++++++++++++++++++++++ src/solver/solver.cpp | 69 +++++++++++++++++++++++++++++++++++++++++++ src/solver/solver.h | 10 +++++++ 3 files changed, 117 insertions(+) diff --git a/src/opt/maxres.cpp b/src/opt/maxres.cpp index b6950f674..a976de8be 100644 --- a/src/opt/maxres.cpp +++ b/src/opt/maxres.cpp @@ -194,6 +194,8 @@ public: if (!init()) return l_undef; init_local(); trace(); + is_sat = process_mutex(); + if (is_sat != l_true) return is_sat; while (m_lower < m_upper) { TRACE("opt", display_vec(tout, m_asms); @@ -269,6 +271,42 @@ public: return l_true; } + lbool process_mutex() { +#if 0 + vector mutexes; + lbool is_sat = s().find_mutexes(m_asms, mutexes); + if (is_sat != l_true) { + return is_sat; + } + for (unsigned i = 0; i < mutexes.size(); ++i) { + process_mutex(mutexes[i]); + } +#endif + return l_true; + } + + void process_mutex(expr_ref_vector& mutex) { + TRACE("opt", tout << mutex << "\n";); + if (mutex.size() <= 1) { + return; + } + sort_assumptions(mutex); + ptr_vector core(mutex.size(), mutex.c_ptr()); + remove_soft(core, m_asms); + rational weight(0); + while (!mutex.empty()) { + expr_ref soft = mk_or(mutex); + rational w = get_weight(mutex.back()); + weight = w - weight; + m_lower += weight*rational(mutex.size()-1); + add_soft(soft, weight); + mutex.pop_back(); + while (!mutex.empty() && get_weight(mutex.back()) == w) { + mutex.pop_back(); + } + weight = w; + } + } lbool check_sat_hill_climb(expr_ref_vector& asms1) { expr_ref_vector asms(asms1); diff --git a/src/solver/solver.cpp b/src/solver/solver.cpp index 5e732075d..6ef828787 100644 --- a/src/solver/solver.cpp +++ b/src/solver/solver.cpp @@ -136,4 +136,73 @@ lbool solver::get_consequences_core(expr_ref_vector const& asms, expr_ref_vector return l_true; } +lbool solver::find_mutexes(expr_ref_vector const& vars, vector& mutexes) { + mutexes.reset(); + ast_manager& m = vars.get_manager(); + + typedef obj_hashtable expr_set; + + expr_set A, P; + + for (unsigned i = 0; i < vars.size(); ++i) { + A.insert(vars[i]); + } + + while (!A.empty()) { + P = A; + expr_ref_vector mutex(m); + while (!P.empty()) { + expr_ref_vector asms(m); + expr* p = *P.begin(); + P.remove(p); + if (!is_literal(m, p)) { + break; + } + mutex.push_back(p); + asms.push_back(p); + expr_set Q; + expr_set::iterator it = P.begin(), end = P.end(); + for (; it != end; ++it) { + expr* q = *it; + scoped_assumption_push _scoped_push(asms, q); + if (is_literal(m, q)) { + lbool is_sat = check_sat(asms); + switch (is_sat) { + case l_false: + Q.insert(q); + break; + case l_true: + break; + case l_undef: + return l_undef; + } + } + } + P = Q; + } + if (mutex.size() > 1) { + mutexes.push_back(mutex); + } + for (unsigned i = 0; i < mutex.size(); ++i) { + A.remove(mutex[i].get()); + } + } + + // While A != {}: + // R = {} + // P = ~A + // While P != {}: + // Pick p in ~P, + // R = R u { p } + // Let Q be consequences over P of p modulo F. + // Let P &= Q + // If |R| > 1: Yield R + // A \= R + + return l_true; +} + +bool solver::is_literal(ast_manager& m, expr* e) { + return is_uninterp_const(e) || (m.is_not(e, e) && is_uninterp_const(e)); +} diff --git a/src/solver/solver.h b/src/solver/solver.h index 7f36e2ad7..15932fd5d 100644 --- a/src/solver/solver.h +++ b/src/solver/solver.h @@ -158,6 +158,14 @@ public: virtual lbool get_consequences(expr_ref_vector const& asms, expr_ref_vector const& vars, expr_ref_vector& consequences); + + /** + \brief Find maximal subsets A' of A such that |A'| <= 1. These subsets look somewhat similar to cores: cores have the property + that |~A'| >= 1, where ~A' is the set of negated formulas from A' + */ + + virtual lbool find_mutexes(expr_ref_vector const& vars, vector& mutexes); + /** \brief Display the content of this solver. */ @@ -176,6 +184,8 @@ protected: virtual lbool get_consequences_core(expr_ref_vector const& asms, expr_ref_vector const& vars, expr_ref_vector& consequences); + bool is_literal(ast_manager& m, expr* e); + }; #endif From d495b086395ac8693151e0561938c3fddfbb1d76 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Wed, 5 Oct 2016 15:34:02 +0100 Subject: [PATCH 218/536] Build/test fix for python3 --- src/api/python/z3/z3num.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/api/python/z3/z3num.py b/src/api/python/z3/z3num.py index c8f15e7b8..2943b0796 100644 --- a/src/api/python/z3/z3num.py +++ b/src/api/python/z3/z3num.py @@ -10,6 +10,8 @@ from .z3core import * from .z3printer import * from fractions import Fraction +from .z3 import _get_ctx + def _to_numeral(num, ctx=None): if isinstance(num, Numeral): return num From 4956f6ef5bceeee429d83d8179ec3a7b45f01f4b Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Wed, 5 Oct 2016 16:11:07 +0100 Subject: [PATCH 219/536] Test fix for python3 --- src/api/python/z3/z3num.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/python/z3/z3num.py b/src/api/python/z3/z3num.py index 2943b0796..b1af58dc3 100644 --- a/src/api/python/z3/z3num.py +++ b/src/api/python/z3/z3num.py @@ -88,7 +88,7 @@ class Numeral: def __init__(self, num, ctx=None): if isinstance(num, Ast): self.ast = num - self.ctx = z3._get_ctx(ctx) + self.ctx = _get_ctx(ctx) elif isinstance(num, RatNumRef) or isinstance(num, AlgebraicNumRef): self.ast = num.ast self.ctx = num.ctx From 9548b88e711d2abedd5db7c8af3e30c8ac2f200d Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Thu, 6 Oct 2016 16:24:49 +0100 Subject: [PATCH 220/536] Added dummy code contracts for .NET Core/CoreCLR builds. --- src/api/dotnet/core/DummyContracts.cs | 59 +++++++++++++++++++++++++++ src/api/dotnet/core/project.json | 21 ++++++++++ 2 files changed, 80 insertions(+) create mode 100644 src/api/dotnet/core/DummyContracts.cs create mode 100644 src/api/dotnet/core/project.json diff --git a/src/api/dotnet/core/DummyContracts.cs b/src/api/dotnet/core/DummyContracts.cs new file mode 100644 index 000000000..e0002e5be --- /dev/null +++ b/src/api/dotnet/core/DummyContracts.cs @@ -0,0 +1,59 @@ +/*++ +Copyright () 2016 Microsoft Corporation + +Module Name: + + Contracts.cs + +Abstract: + + Z3 Managed API: Dummy Code Contracts class for .NET + frameworks that don't support them (e.g., CoreCLR). + +Author: + + Christoph Wintersteiger (cwinter) 2016-10-06 + +Notes: + +--*/ + +namespace System.Diagnostics.Contracts +{ + public class ContractClass : Attribute + { + public ContractClass(Type t) { } + } + + public class ContractClassFor : Attribute + { + public ContractClassFor(Type t) { } + } + + public class ContractInvariantMethod : Attribute + { + public ContractInvariantMethod() { } + } + + public class ContractVerification : Attribute + { + public ContractVerification(bool b) { } + } + + public class Pure : Attribute { } + + public static class Contract + { + public static void Ensures(bool b) { } + public static void Requires(bool b) { } + public static void Assume(bool b, string msg) { } + public static void Assert(bool b) { } + public static bool ForAll(bool b) { return true; } + public static bool ForAll(Object c, Func p) { return true; } + public static bool ForAll(int from, int to, Predicate p) { return true; } + public static void Invariant(bool b) { } + public static T[] Result() { return new T[1]; } + public static void EndContractBlock() { } + public static T ValueAtReturn(out T v) { T[] t = new T[1]; v = t[0]; return v; } + } +} \ No newline at end of file diff --git a/src/api/dotnet/core/project.json b/src/api/dotnet/core/project.json new file mode 100644 index 000000000..afe281a50 --- /dev/null +++ b/src/api/dotnet/core/project.json @@ -0,0 +1,21 @@ +{ + "version": "1.0.0-*", + "buildOptions": { + "debugType": "portable", + "emitEntryPoint": false, + "outputName": "Microsoft.Z3", + "compile": [ "../*.cs", "*.cs" ] + }, + "dependencies": { }, + "frameworks": { + "netcoreapp1.0": { + "dependencies": { + "Microsoft.NETCore.App": { + "type": "platform", + "version": "1.0.1" + } + }, + "imports": "dnxcore50" + } + } +} From 5dec919217354afe7b09edafecce618a0c9e2e42 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Thu, 6 Oct 2016 16:36:19 +0100 Subject: [PATCH 221/536] Remove unnecessary "unsafe" qualifier on internal .NET API class. --- scripts/update_api.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/update_api.py b/scripts/update_api.py index 4ca11938c..04378b371 100755 --- a/scripts/update_api.py +++ b/scripts/update_api.py @@ -363,7 +363,7 @@ def mk_dotnet(dotnet): dotnet.write(' {\n\n') dotnet.write(' [UnmanagedFunctionPointer(CallingConvention.Cdecl)]\n') dotnet.write(' public delegate void Z3_error_handler(Z3_context c, Z3_error_code e);\n\n') - dotnet.write(' public unsafe class LIB\n') + dotnet.write(' public class LIB\n') dotnet.write(' {\n') dotnet.write(' const string Z3_DLL_NAME = \"libz3.dll\";\n' ' \n') From 619cce0a524fd5ec3183bd3d7505eea9ea3e3f6b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 7 Oct 2016 12:42:08 -0700 Subject: [PATCH 222/536] add mutex preprocessing to maxsat, add parsing functions to C++ API Signed-off-by: Nikolaj Bjorner --- src/api/c++/z3++.h | 46 +++- src/opt/maxres.cpp | 10 +- src/sat/sat_solver.cpp | 296 +++++++++++++++++++++++--- src/sat/sat_solver.h | 32 +++ src/sat/sat_solver/inc_sat_solver.cpp | 28 +++ src/sat/sat_types.h | 13 ++ src/solver/solver.cpp | 19 +- 7 files changed, 395 insertions(+), 49 deletions(-) diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index 0efb3dcce..e72acf3d6 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -63,7 +63,6 @@ namespace z3 { class func_entry; class statistics; class apply_result; - class fixedpoint; template class ast_vector_tpl; typedef ast_vector_tpl ast_vector; typedef ast_vector_tpl expr_vector; @@ -286,6 +285,15 @@ namespace z3 { expr num_val(int n, sort const & s); + /** + \brief parsing + */ + expr parse_string(char const* s); + expr parse_file(char const* file); + + expr parse_string(char const* s, sort_vector const& sorts, func_decl_vector const& decls); + expr parse_file(char const* s, sort_vector const& sorts, func_decl_vector const& decls); + /** \brief Interpolation support */ @@ -442,7 +450,10 @@ namespace z3 { \brief Return the internal sort kind. */ Z3_sort_kind sort_kind() const { return Z3_get_sort_kind(*m_ctx, *this); } - + /** + \brief Return name of sort. + */ + symbol name() const { Z3_symbol s = Z3_get_sort_name(ctx(), *this); check_error(); return symbol(ctx(), s); } /** \brief Return true if this sort is the Boolean sort. */ @@ -2454,6 +2465,37 @@ namespace z3 { return expr(a.ctx(), Z3_mk_interpolant(a.ctx(), a)); } + inline expr context::parse_string(char const* s) { + Z3_ast r = Z3_parse_smtlib2_string(*this, s, 0, 0, 0, 0, 0, 0); + check_error(); + return expr(*this, r); + + } + inline expr context::parse_file(char const* s) { + Z3_ast r = Z3_parse_smtlib2_file(*this, s, 0, 0, 0, 0, 0, 0); + check_error(); + return expr(*this, r); + } + + inline expr context::parse_string(char const* s, sort_vector const& sorts, func_decl_vector const& decls) { + array sort_names(sorts.size()); + array decl_names(decls.size()); + array sorts1(sorts); + array decls1(decls); + for (unsigned i = 0; i < sorts.size(); ++i) { + sort_names[i] = sorts[i].name(); + } + for (unsigned i = 0; i < decls.size(); ++i) { + decl_names[i] = decls[i].name(); + } + Z3_ast r = Z3_parse_smtlib2_string(*this, s, sorts.size(), sort_names.ptr(), sorts1.ptr(), decls.size(), decl_names.ptr(), decls1.ptr()); + check_error(); + return expr(*this, r); + } + + // inline expr context::parse_file(char const* s, sort_vector const& sorts, func_decl_vector const& decls); + + inline check_result context::compute_interpolant(expr const& pat, params const& p, expr_vector& i, model& m) { Z3_ast_vector interp = 0; Z3_model mdl = 0; diff --git a/src/opt/maxres.cpp b/src/opt/maxres.cpp index a976de8be..d9f060784 100644 --- a/src/opt/maxres.cpp +++ b/src/opt/maxres.cpp @@ -197,6 +197,7 @@ public: is_sat = process_mutex(); if (is_sat != l_true) return is_sat; while (m_lower < m_upper) { + if (m_lower >= m_upper) break; TRACE("opt", display_vec(tout, m_asms); s().display(tout); @@ -235,8 +236,10 @@ public: init_local(); trace(); exprs cs; + lbool is_sat = process_mutex(); + if (is_sat != l_true) return is_sat; while (m_lower < m_upper) { - lbool is_sat = check_sat_hill_climb(m_asms); + is_sat = check_sat_hill_climb(m_asms); if (m.canceled()) { return l_undef; } @@ -272,7 +275,6 @@ public: } lbool process_mutex() { -#if 0 vector mutexes; lbool is_sat = s().find_mutexes(m_asms, mutexes); if (is_sat != l_true) { @@ -281,7 +283,9 @@ public: for (unsigned i = 0; i < mutexes.size(); ++i) { process_mutex(mutexes[i]); } -#endif + if (!mutexes.empty()) { + trace(); + } return l_true; } diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index d8d273f2b..f553acb29 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -835,48 +835,66 @@ namespace sat { lbool solver::bounded_search() { while (true) { checkpoint(); - while (true) { - propagate(true); - if (!inconsistent()) - break; - if (!resolve_conflict()) - return l_false; - if (m_conflicts > m_config.m_max_conflicts) - return l_undef; - if (m_conflicts_since_restart > m_restart_threshold) - return l_undef; - if (scope_lvl() == 0) { - cleanup(); // cleaner may propagate frozen clauses - if (inconsistent()) { - TRACE("sat", tout << "conflict at level 0\n";); - return l_false; - } - gc(); - } + bool done = false; + while (!done) { + lbool is_sat = propagate_and_backjump_step(done); + if (is_sat != l_true) return is_sat; } gc(); if (!decide()) { - if (m_ext) { - switch (m_ext->check()) { - case CR_DONE: - mk_model(); - return l_true; - case CR_CONTINUE: - break; - case CR_GIVEUP: - throw abort_solver(); - } - } - else { - mk_model(); - return l_true; + lbool is_sat = final_check(); + if (is_sat != l_undef) { + return is_sat; } } } } + lbool solver::propagate_and_backjump_step(bool& done) { + done = true; + propagate(true); + if (!inconsistent()) + return l_true; + if (!resolve_conflict()) + return l_false; + if (m_conflicts > m_config.m_max_conflicts) + return l_undef; + if (m_conflicts_since_restart > m_restart_threshold) + return l_undef; + if (scope_lvl() == 0) { + cleanup(); // cleaner may propagate frozen clauses + if (inconsistent()) { + TRACE("sat", tout << "conflict at level 0\n";); + return l_false; + } + gc(); + } + done = false; + return l_true; + } + + lbool solver::final_check() { + if (m_ext) { + switch (m_ext->check()) { + case CR_DONE: + mk_model(); + return l_true; + case CR_CONTINUE: + break; + case CR_GIVEUP: + throw abort_solver(); + } + return l_undef; + } + else { + mk_model(); + return l_true; + } + } + + bool solver::check_inconsistent() { if (inconsistent()) { if (tracking_assumptions()) @@ -3035,6 +3053,220 @@ namespace sat { return r; } + lbool solver::find_mutexes(literal_vector const& lits, vector & mutexes) { + literal_vector ps(lits); + m_user_bin_clauses.reset(); + m_binary_clause_graph.reset(); + collect_bin_clauses(m_user_bin_clauses, true); + collect_bin_clauses(m_user_bin_clauses, false); + for (unsigned i = 0; i < m_user_bin_clauses.size(); ++i) { + literal l1 = m_user_bin_clauses[i].first; + literal l2 = m_user_bin_clauses[i].second; + m_binary_clause_graph.reserve(l1.index() + 1); + m_binary_clause_graph.reserve(l2.index() + 1); + m_binary_clause_graph.reserve((~l1).index() + 1); + m_binary_clause_graph.reserve((~l2).index() + 1); + m_binary_clause_graph[l1.index()].push_back(l2); + m_binary_clause_graph[l2.index()].push_back(l1); + } + while (!ps.empty()) { + literal_vector mutex; + literal_set other(ps); + while (!other.empty()) { + literal_set conseq; + literal p = other.pop(); + mutex.push_back(p); + if (other.empty()) { + break; + } + get_reachable(p, other, conseq); + other = conseq; + } + if (mutex.size() > 1) { + mutexes.push_back(mutex); + } + for (unsigned i = 0; i < mutex.size(); ++i) { + ps.erase(mutex[i]); + } + } + return l_true; + } + + void solver::get_reachable(literal p, literal_set const& goal, literal_set& reachable) { + literal_set seen; + literal_vector todo; + todo.push_back(p); + while (!todo.empty()) { + p = todo.back(); + todo.pop_back(); + if (seen.contains(p)) { + continue; + } + seen.insert(p); + literal np = ~p; + if (goal.contains(np)) { + reachable.insert(np); + } + todo.append(m_binary_clause_graph[np.index()]); + } + } + + lbool solver::get_consequences(literal_vector const& asms, bool_var_vector const& vars, vector& conseq) { + literal_vector lits; + lbool is_sat = check(asms.size(), asms.c_ptr()); + if (is_sat != l_true) { + return is_sat; + } + for (unsigned i = 0; i < vars.size(); ++i) { + bool_var v = vars[i]; + switch (get_model()[v]) { + case l_true: lits.push_back(literal(v, false)); break; + case l_false: lits.push_back(literal(v, true)); break; + default: break; + } + } + return get_consequences(asms, lits, conseq); + } + + lbool solver::get_consequences(literal_vector const& asms, literal_vector const& lits, vector& conseq) { + m_antecedents.reset(); + literal_set unfixed(lits), assumptions(asms); + + pop_to_base_level(); + if (inconsistent()) return l_false; + init_search(); + propagate(false); + if (inconsistent()) return l_false; + init_assumptions(asms.size(), asms.c_ptr(), 0, 0); + propagate(false); + if (check_inconsistent()) return l_false; + + unsigned num_units = 0; + extract_fixed_consequences(num_units, assumptions, unfixed, conseq); + while (!unfixed.empty()) { + checkpoint(); + literal_set::iterator it = unfixed.begin(), end = unfixed.end(); + unsigned chunk_size = 100; + for (; it != end && chunk_size > 0; ++it) { + literal lit = *it; + if (value(lit) != l_undef) { + continue; + } + --chunk_size; + push(); + assign(~lit, justification()); + propagate(false); + while (inconsistent()) { + if (!resolve_conflict()) { + TRACE("sat", tout << "inconsistent\n";); + return l_false; + } + propagate(false); + } + } + lbool is_sat; + while (true) { + is_sat = bounded_search(); + if (is_sat == l_undef) { + restart(); + continue; + } + break; + } + if (is_sat == l_false) { + TRACE("sat", tout << "unsat\n";); + m_inconsistent = false; + } + if (is_sat == l_true) { + delete_unfixed(unfixed); + } + extract_fixed_consequences(num_units, assumptions, unfixed, conseq); + } + return l_true; + } + + void solver::delete_unfixed(literal_set& unfixed) { + literal_set to_keep; + literal_set::iterator it = unfixed.begin(), end = unfixed.end(); + for (; it != end; ++it) { + literal lit = *it; + if (value(lit) == l_true) { + to_keep.insert(lit); + } + } + unfixed = to_keep; + } + + void solver::extract_fixed_consequences(unsigned& start, literal_set const& assumptions, literal_set& unfixed, vector& conseq) { + if (scope_lvl() > 1) { + pop(scope_lvl() - 1); + } + SASSERT(!inconsistent()); + unsigned sz = m_trail.size(); + for (unsigned i = start; i < sz; ++i) { + extract_fixed_consequences(m_trail[i], assumptions, unfixed, conseq); + } + start = sz; + } + + void solver::extract_assumptions(literal lit, index_set& s) { + justification js = m_justification[lit.var()]; + switch (js.get_kind()) { + case justification::NONE: + break; + case justification::BINARY: + s |= m_antecedents.find(js.get_literal().var()); + break; + case justification::TERNARY: + s |= m_antecedents.find(js.get_literal1().var()); + s |= m_antecedents.find(js.get_literal2().var()); + break; + case justification::CLAUSE: { + clause & c = *(m_cls_allocator.get_clause(js.get_clause_offset())); + for (unsigned i = 0; i < c.size(); ++i) { + if (c[i] != lit) { + s |= m_antecedents.find(c[i].var()); + } + } + break; + } + case justification::EXT_JUSTIFICATION: { + fill_ext_antecedents(lit, js); + literal_vector::iterator it = m_ext_antecedents.begin(); + literal_vector::iterator end = m_ext_antecedents.end(); + for (; it != end; ++it) { + s |= m_antecedents.find(it->var()); + } + break; + } + default: + UNREACHABLE(); + break; + } + } + + void solver::extract_fixed_consequences(literal lit, literal_set const& assumptions, literal_set& unfixed, vector& conseq) { + index_set s; + if (assumptions.contains(lit)) { + s.insert(lit.index()); + } + else { + add_assumption(lit); + extract_assumptions(lit, s); + } + m_antecedents.insert(lit.var(), s); + if (unfixed.contains(lit)) { + literal_vector cons; + cons.push_back(lit); + index_set::iterator it = s.begin(), end = s.end(); + for (; it != end; ++it) { + cons.push_back(to_literal(*it)); + } + unfixed.remove(lit); + conseq.push_back(cons); + } + } + void solver::asymmetric_branching() { if (scope_lvl() > 0 || inconsistent()) return; diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index 95988f3ca..785bc6856 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -300,6 +300,8 @@ namespace sat { bool decide(); bool_var next_var(); lbool bounded_search(); + lbool final_check(); + lbool propagate_and_backjump_step(bool& done); void init_search(); literal_vector m_min_core; @@ -409,6 +411,7 @@ namespace sat { void gc_lit(clause_vector& clauses, literal lit); void gc_bin(bool learned, literal nlit); void gc_var(bool_var v); + bool_var max_var(clause_vector& clauses, bool_var v); bool_var max_var(bool learned, bool_var v); @@ -428,6 +431,35 @@ namespace sat { void asymmetric_branching(); unsigned scc_bin(); + // ----------------------- + // + // Auxiliary methods. + // + // ----------------------- + public: + lbool find_mutexes(literal_vector const& lits, vector & mutexes); + + lbool get_consequences(literal_vector const& assms, bool_var_vector const& vars, vector& conseq); + + private: + + typedef hashtable index_set; + + u_map m_antecedents; + vector m_binary_clause_graph; + + void extract_assumptions(literal lit, index_set& s); + + void get_reachable(literal p, literal_set const& goal, literal_set& reachable); + + lbool get_consequences(literal_vector const& assms, literal_vector const& lits, vector& conseq); + + void delete_unfixed(literal_set& unfixed); + + void extract_fixed_consequences(unsigned& start, literal_set const& assumptions, literal_set& unfixed, vector& conseq); + + void extract_fixed_consequences(literal lit, literal_set const& assumptions, literal_set& unfixed, vector& conseq); + // ----------------------- // // Activity related stuff diff --git a/src/sat/sat_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp index ce6b199d6..6139b3e22 100644 --- a/src/sat/sat_solver/inc_sat_solver.cpp +++ b/src/sat/sat_solver/inc_sat_solver.cpp @@ -107,6 +107,7 @@ public: return check_sat(num_assumptions, assumptions, 0, 0); } + void display_weighted(std::ostream& out, unsigned sz, expr * const * assumptions, unsigned const* weights) { m_weights.reset(); if (weights != 0) { @@ -231,6 +232,33 @@ public: return 0; } + virtual lbool find_mutexes(expr_ref_vector const& vars, vector& mutexes) { + sat::literal_vector ls; + u_map lit2var; + for (unsigned i = 0; i < vars.size(); ++i) { + expr* e = vars[i]; + bool neg = m.is_not(e, e); + sat::bool_var v = m_map.to_bool_var(e); + if (v != sat::null_bool_var) { + sat::literal lit(v, neg); + ls.push_back(lit); + lit2var.insert(lit.index(), vars[i]); + } + } + vector ls_mutexes; + m_solver.find_mutexes(ls, ls_mutexes); + for (unsigned i = 0; i < ls_mutexes.size(); ++i) { + sat::literal_vector const ls_mutex = ls_mutexes[i]; + expr_ref_vector mutex(m); + for (unsigned j = 0; j < ls_mutex.size(); ++j) { + mutex.push_back(lit2var.find(ls_mutex[j].index())); + } + mutexes.push_back(mutex); + } + return l_true; + } + + virtual std::string reason_unknown() const { return m_unknown; } diff --git a/src/sat/sat_types.h b/src/sat/sat_types.h index c0c087e59..697af2e2d 100644 --- a/src/sat/sat_types.h +++ b/src/sat/sat_types.h @@ -105,6 +105,7 @@ namespace sat { inline std::ostream & operator<<(std::ostream & out, literal l) { out << (l.sign() ? "-" : "") << l.var(); return out; } typedef svector literal_vector; + typedef std::pair literal_pair; typedef unsigned clause_offset; typedef unsigned ext_constraint_idx; @@ -161,6 +162,17 @@ namespace sat { m_set.push_back(v); } + void remove(unsigned v) { + if (contains(v)) { + m_in_set[v] = false; + unsigned i = 0; + for (i = 0; i < m_set.size() && m_set[i] != v; ++i); + SASSERT(i < m_set.size()); + m_set[i] = m_set.back(); + m_set.pop_back(); + } + } + uint_set& operator=(uint_set const& other) { m_in_set = other.m_in_set; m_set = other.m_set; @@ -228,6 +240,7 @@ namespace sat { return result; } void insert(literal l) { m_set.insert(l.index()); } + void remove(literal l) { m_set.remove(l.index()); } literal pop() { return to_literal(m_set.erase()); } bool contains(literal l) const { return m_set.contains(l.index()); } bool empty() const { return m_set.empty(); } diff --git a/src/solver/solver.cpp b/src/solver/solver.cpp index 6ef828787..c75088246 100644 --- a/src/solver/solver.cpp +++ b/src/solver/solver.cpp @@ -137,6 +137,11 @@ lbool solver::get_consequences_core(expr_ref_vector const& asms, expr_ref_vector } lbool solver::find_mutexes(expr_ref_vector const& vars, vector& mutexes) { + return l_true; +#if 0 + // complete for literals, but inefficient. + // see more efficient (incomplete) version in sat_solver + mutexes.reset(); ast_manager& m = vars.get_manager(); @@ -187,19 +192,9 @@ lbool solver::find_mutexes(expr_ref_vector const& vars, vector& A.remove(mutex[i].get()); } } - - // While A != {}: - // R = {} - // P = ~A - // While P != {}: - // Pick p in ~P, - // R = R u { p } - // Let Q be consequences over P of p modulo F. - // Let P &= Q - // If |R| > 1: Yield R - // A \= R - return l_true; +#endif + } bool solver::is_literal(ast_manager& m, expr* e) { From 5d9820f3e2d4c49389536092a90aca1be720555d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 7 Oct 2016 12:57:07 -0700 Subject: [PATCH 223/536] add example of parsing with external declarations Signed-off-by: Nikolaj Bjorner --- examples/c++/example.cpp | 12 ++++++++++++ src/api/c++/z3++.h | 17 +++++++++++++++-- 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/examples/c++/example.cpp b/examples/c++/example.cpp index a1240543f..2d7d051c5 100644 --- a/examples/c++/example.cpp +++ b/examples/c++/example.cpp @@ -1129,6 +1129,17 @@ void consequence_example() { std::cout << consequences << "\n"; } +static void parse_example() { + std::cout << "parse example\n"; + context c; + sort_vector sorts(c); + func_decl_vector decls(c); + sort B = c.bool_sort(); + decls.push_back(c.function("a", 0, 0, B)); + expr a = c.parse_string("(assert a)", sorts, decls); + std::cout << a << "\n"; +} + int main() { try { @@ -1173,6 +1184,7 @@ int main() { param_descrs_example(); std::cout << "\n"; sudoku_example(); std::cout << "\n"; consequence_example(); std::cout << "\n"; + parse_example(); std::cout << "\n"; std::cout << "done\n"; } catch (exception & ex) { diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index e72acf3d6..b03e38b7e 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -2460,7 +2460,6 @@ namespace z3 { return expr(re.ctx(), r); } - inline expr interpolant(expr const& a) { return expr(a.ctx(), Z3_mk_interpolant(a.ctx(), a)); } @@ -2493,7 +2492,21 @@ namespace z3 { return expr(*this, r); } - // inline expr context::parse_file(char const* s, sort_vector const& sorts, func_decl_vector const& decls); + inline expr context::parse_file(char const* s, sort_vector const& sorts, func_decl_vector const& decls) { + array sort_names(sorts.size()); + array decl_names(decls.size()); + array sorts1(sorts); + array decls1(decls); + for (unsigned i = 0; i < sorts.size(); ++i) { + sort_names[i] = sorts[i].name(); + } + for (unsigned i = 0; i < decls.size(); ++i) { + decl_names[i] = decls[i].name(); + } + Z3_ast r = Z3_parse_smtlib2_file(*this, s, sorts.size(), sort_names.ptr(), sorts1.ptr(), decls.size(), decl_names.ptr(), decls1.ptr()); + check_error(); + return expr(*this, r); + } inline check_result context::compute_interpolant(expr const& pat, params const& p, expr_vector& i, model& m) { From 67a788918833058ba588e6d23da62387721653e9 Mon Sep 17 00:00:00 2001 From: Andrew Dutcher Date: Thu, 22 Sep 2016 13:02:22 -0700 Subject: [PATCH 224/536] Update metadata for new distribution --- src/api/python/setup.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/api/python/setup.py b/src/api/python/setup.py index 45da4d085..9d77a66d6 100644 --- a/src/api/python/setup.py +++ b/src/api/python/setup.py @@ -135,14 +135,14 @@ class sdist(_sdist): #except OSError: pass setup( - name='angr-only-z3-custom', - version='4.4.1.post4', - description='pip installable distribution of The Z3 Theorem Prover, for use with angr. Please send all support requests to angr@lists.cs.ucsb.edu!', - long_description='Z3 is a theorem prover from Microsoft Research. This version is slightly modified by the angr project to enable installation via pip, making it unsupportable by the Z3 project. Please direct all support requests to angr@lists.cs.ucsb.edu!', + name='z3-solver', + version='4.4.2.1', + description='an efficient SMT solver library', + long_description='Z3 is a theorem prover from Microsoft Research with support for bitvectors, booleans, arrays, floating point numbers, strings, and other data types.\n\nFor documentation, please read http://z3prover.github.io/api/html/z3.html\n\nIn the event of technical difficulties related to configuration, compiliation, or installation, please submit issues to https://github.com/angr/angr-z3', author="The Z3 Theorem Prover Project", - maintainer="Yan Shoshitaishvili", - maintainer_email="yans@yancomm.net", - url='https://github.com/angr/angr-z3', + maintainer="Andrew Dutcher", + maintainer_email="andrew@andrewdutcher.com", + url='https://github.com/Z3Prover/z3', license='MIT License', keywords=['z3', 'smt', 'sat', 'prover', 'theorem'], packages=['z3'], From bd80f7b4d5e5fc54182b6e60b68e6c36dc665a48 Mon Sep 17 00:00:00 2001 From: Andrew Dutcher Date: Thu, 22 Sep 2016 14:08:26 -0700 Subject: [PATCH 225/536] fix some issues with the windows build --- src/api/python/setup.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/api/python/setup.py b/src/api/python/setup.py index 9d77a66d6..95843aac0 100644 --- a/src/api/python/setup.py +++ b/src/api/python/setup.py @@ -27,10 +27,13 @@ BINS_DIR = os.path.join(ROOT_DIR, 'bin') if sys.platform == 'darwin': LIBRARY_FILE = "libz3.dylib" + EXECUTABLE_FILE = "z3" elif sys.platform in ('win32', 'cygwin'): LIBRARY_FILE = "libz3.dll" + EXECUTABLE_FILE = "z3.exe" else: LIBRARY_FILE = "libz3.so" + EXECUTABLE_FILE = "z3" def _clean_bins(): """ @@ -81,8 +84,8 @@ def _copy_bins(): os.mkdir(BINS_DIR) os.mkdir(HEADERS_DIR) os.mkdir(os.path.join(HEADERS_DIR, 'c++')) - shutil.copy(os.path.join(BUILD_DIR, 'libz3.so'), LIBS_DIR) - shutil.copy(os.path.join(BUILD_DIR, 'z3'), BINS_DIR) + shutil.copy(os.path.join(BUILD_DIR, LIBRARY_FILE), LIBS_DIR) + shutil.copy(os.path.join(BUILD_DIR, EXECUTABLE_FILE), BINS_DIR) for fname in ('z3.h', 'z3_v1.h', 'z3_macros.h', 'z3_api.h', 'z3_algebraic.h', 'z3_polynomial.h', 'z3_rcf.h', 'z3_interp.h', 'z3_fpa.h', os.path.join('c++', 'z3++.h')): shutil.copy(os.path.join(SRC_DIR, 'src', 'api', fname), os.path.join(HEADERS_DIR, fname)) @@ -150,6 +153,6 @@ setup( package_data={ 'z3': [os.path.join('lib', '*'), os.path.join('include', '*.h'), os.path.join('include', 'c++', '*.h')] }, - scripts=[os.path.join('bin', 'z3')], + scripts=[os.path.join('bin', EXECUTABLE_FILE)], cmdclass={'build': build, 'develop': develop, 'sdist': sdist, 'bdist_egg': bdist_egg}, ) From 8d2b70a5e259044c19cc2c24bc133bf088f2517e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 10 Oct 2016 23:46:03 -0700 Subject: [PATCH 226/536] better encodings for at-most-1, #755 Signed-off-by: Nikolaj Bjorner --- src/ast/pb_decl_plugin.h | 2 + src/opt/opt_solver.cpp | 5 + src/opt/opt_solver.h | 1 + src/sat/sat_solver.cpp | 12 ++ src/smt/smt_consequences.cpp | 244 +++++++--------------------- src/smt/smt_context.h | 12 +- src/smt/smt_kernel.cpp | 10 +- src/smt/smt_kernel.h | 5 + src/smt/smt_solver.cpp | 5 + src/smt/theory_pb.cpp | 7 +- src/solver/solver.cpp | 57 ------- src/solver/solver_na2as.cpp | 6 + src/solver/solver_na2as.h | 1 + src/tactic/arith/card2bv_tactic.cpp | 40 ++++- src/tactic/arith/card2bv_tactic.h | 1 + src/test/sorting_network.cpp | 25 +++ src/util/sorting_network.h | 52 ++++++ 17 files changed, 232 insertions(+), 253 deletions(-) diff --git a/src/ast/pb_decl_plugin.h b/src/ast/pb_decl_plugin.h index e1b16f0c9..d0649729b 100644 --- a/src/ast/pb_decl_plugin.h +++ b/src/ast/pb_decl_plugin.h @@ -119,6 +119,8 @@ public: app* mk_fresh_bool(); + expr_ref mk_at_most_1(unsigned num_args, expr * const * args); + private: rational to_rational(parameter const& p) const; diff --git a/src/opt/opt_solver.cpp b/src/opt/opt_solver.cpp index 64ab2823f..0d0283232 100644 --- a/src/opt/opt_solver.cpp +++ b/src/opt/opt_solver.cpp @@ -194,6 +194,11 @@ namespace opt { } } + lbool opt_solver::find_mutexes(expr_ref_vector const& vars, vector& mutexes) { + return m_context.find_mutexes(vars, mutexes); + } + + /** \brief maximize the value of objective i in the current state. diff --git a/src/opt/opt_solver.h b/src/opt/opt_solver.h index b2fa18ad8..16c2061c7 100644 --- a/src/opt/opt_solver.h +++ b/src/opt/opt_solver.h @@ -106,6 +106,7 @@ namespace opt { virtual expr * get_assertion(unsigned idx) const; virtual std::ostream& display(std::ostream & out) const; virtual ast_manager& get_manager() const { return m; } + virtual lbool find_mutexes(expr_ref_vector const& vars, vector& mutexes); void set_logic(symbol const& logic); smt::theory_var add_objective(app* term); diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index f553acb29..f2279b3c4 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -3053,6 +3053,12 @@ namespace sat { return r; } + // ----------------------- + // + // Extraction of mutexes + // + // ----------------------- + lbool solver::find_mutexes(literal_vector const& lits, vector & mutexes) { literal_vector ps(lits); m_user_bin_clauses.reset(); @@ -3111,6 +3117,12 @@ namespace sat { } } + // ----------------------- + // + // Consequence generation. + // + // ----------------------- + lbool solver::get_consequences(literal_vector const& asms, bool_var_vector const& vars, vector& conseq) { literal_vector lits; lbool is_sat = check(asms.size(), asms.c_ptr()); diff --git a/src/smt/smt_consequences.cpp b/src/smt/smt_consequences.cpp index 8619ff815..e44782a31 100644 --- a/src/smt/smt_consequences.cpp +++ b/src/smt/smt_consequences.cpp @@ -251,191 +251,6 @@ namespace smt { expr_ref_vector& conseq, expr_ref_vector& unfixed) { - m_antecedents.reset(); - pop_to_base_lvl(); - lbool is_sat = check(assumptions.size(), assumptions.c_ptr()); - if (is_sat != l_true) { - return is_sat; - } - obj_map var2val; - index_set _assumptions; - for (unsigned i = 0; i < assumptions.size(); ++i) { - _assumptions.insert(get_literal(assumptions[i]).var()); - } - model_ref mdl; - get_model(mdl); - ast_manager& m = m_manager; - expr_ref_vector trail(m); - model_evaluator eval(*mdl.get()); - expr_ref val(m); - TRACE("context", model_pp(tout, *mdl);); - for (unsigned i = 0; i < vars.size(); ++i) { - eval(vars[i], val); - if (m.is_value(val)) { - trail.push_back(val); - var2val.insert(vars[i], val); - } - else { - unfixed.push_back(vars[i]); - } - } - unsigned num_units = 0; - extract_fixed_consequences(num_units, var2val, _assumptions, conseq); - app_ref eq(m); - TRACE("context", - tout << "vars: " << vars.size() << "\n"; - tout << "lits: " << num_units << "\n";); - m_case_split_queue->init_search_eh(); - unsigned num_iterations = 0; - unsigned model_threshold = 2; - unsigned num_fixed_eqs = 0; - unsigned num_reiterations = 0; - while (!var2val.empty()) { - obj_map::iterator it = var2val.begin(); - expr* e = it->m_key; - expr* val = it->m_value; - - TRACE("context", tout << "scope level: " << get_scope_level() << "\n";); - SASSERT(!inconsistent()); - - // - // The current variable is checked to be a backbone - // We add the negation of the reference assignment to the variable. - // If the variable is a Boolean, it means adding literal that has - // the opposite value of the current reference model. - // If the variable is a non-Boolean, it means adding a disequality. - // - literal lit = mk_diseq(e, val); - mark_as_relevant(lit); - push_scope(); - assign(lit, b_justification::mk_axiom(), true); - flet l(m_searching, true); - - // - // We check if the current assignment stack can be extended to a - // satisfying assignment. bounded search may decide to restart, - // in which case it returns l_undef and clears search failure. - // - while (true) { - is_sat = bounded_search(); - TRACE("context", tout << "search result: " << is_sat << "\n";); - if (is_sat != l_true && m_last_search_failure != OK) { - return is_sat; - } - if (is_sat == l_undef) { - TRACE("context", tout << "restart\n";); - inc_limits(); - continue; - } - break; - } - // - // If the state is satisfiable with the current variable assigned to - // a different value from the reference model, it is unfixed. - // - // If it is assigned above the search level we can't conclude anything - // about its value. - // extract_fixed_consequences pops the assignment stack to the search level - // so this sets up the state to retry finding fixed values. - // - // Otherwise, the variable is fixed. - // - it is either assigned at the search level to l_false, or - // - the state is l_false, which means that the variable is fixed by - // the background constraints (and does not depend on assumptions). - // - if (is_sat == l_true && get_assignment(lit) == l_true && is_relevant(lit)) { - var2val.erase(e); - unfixed.push_back(e); - SASSERT(!are_equal(e, val)); - TRACE("context", tout << mk_pp(e, m) << " is unfixed\n"; - display_literal_verbose(tout, lit); tout << "\n"; - tout << "relevant: " << is_relevant(lit) << "\n"; - display(tout);); - } - else if (is_sat == l_true && (get_assign_level(lit) > get_search_level() || !is_relevant(lit))) { - TRACE("context", tout << "Retry fixing: " << mk_pp(e, m) << "\n";); - extract_fixed_consequences(num_units, var2val, _assumptions, conseq); - ++num_reiterations; - continue; - } - else { - // - // The state can be labeled as inconsistent when the implied consequence does - // not depend on assumptions, then the conflict level sits at the search level - // which causes the conflict resolver to decide that the state is unsat. - // - if (l_false == is_sat) { - SASSERT(inconsistent()); - m_conflict = null_b_justification; - m_not_l = null_literal; - } - TRACE("context", tout << "Fixed: " << mk_pp(e, m) << " " << is_sat << "\n"; - if (is_sat == l_false) display(tout);); - - } - ++num_iterations; - - // - // Check the slow pass: it retrieves an updated model and checks if the - // values in the updated model differ from the values in the reference - // model. - // - bool apply_slow_pass = model_threshold <= num_iterations || num_iterations <= 2; - if (apply_slow_pass && is_sat == l_true) { - delete_unfixed(var2val, unfixed); - // The next time we check the model is after 1.5 additional iterations. - model_threshold *= 3; - model_threshold /= 2; - } - - // - // Walk the assignment stack at level 1 for learned consequences. - // The current literal should be assigned at the search level unless - // the state is is_sat == l_true and the assignment to lit is l_true. - // This condition is checked above. - // - extract_fixed_consequences(num_units, var2val, _assumptions, conseq); - - // - // Fixed equalities can be extracted by walking all variables and checking - // if the congruence roots are equal at the search level. - // - if (apply_slow_pass) { - num_fixed_eqs += extract_fixed_eqs(var2val, conseq); - IF_VERBOSE(1, display_consequence_progress(verbose_stream(), num_iterations, var2val.size(), conseq.size(), - unfixed.size(), num_fixed_eqs);); - TRACE("context", display_consequence_progress(tout, num_iterations, var2val.size(), conseq.size(), - unfixed.size(), num_fixed_eqs);); - } - TRACE("context", tout << "finishing " << mk_pp(e, m) << "\n";); - SASSERT(!inconsistent()); - - // - // This becomes unnecessary when the fixed consequence are - // completely extracted. - // - if (var2val.contains(e)) { - TRACE("context", tout << "Fixed value to " << mk_pp(e, m) << " was not processed\n";); - expr_ref fml(m); - fml = m.mk_eq(e, var2val.find(e)); - if (!m_antecedents.contains(lit.var())) { - extract_fixed_consequences(lit, var2val, _assumptions, conseq); - } - fml = m.mk_implies(antecedent2fml(m_antecedents[lit.var()]), fml); - conseq.push_back(fml); - var2val.erase(e); - } - } - end_search(); - DEBUG_CODE(validate_consequences(assumptions, vars, conseq, unfixed);); - return l_true; - } - - lbool context::get_consequences2(expr_ref_vector const& assumptions, - expr_ref_vector const& vars, - expr_ref_vector& conseq, - expr_ref_vector& unfixed) { - m_antecedents.reset(); pop_to_base_lvl(); lbool is_sat = check(assumptions.size(), assumptions.c_ptr()); @@ -552,6 +367,65 @@ namespace smt { } + lbool context::find_mutexes(expr_ref_vector const& vars, vector& mutexes) { + index_set lits; + for (unsigned i = 0; i < vars.size(); ++i) { + expr* n = vars[i]; + bool neg = m_manager.is_not(n, n); + if (b_internalized(n)) { + lits.insert(literal(get_bool_var(n), !neg).index()); + } + } + while (!lits.empty()) { + literal_vector mutex; + index_set other(lits); + while (!other.empty()) { + index_set conseq; + literal p = to_literal(*other.begin()); + other.erase(p.index()); + mutex.push_back(p); + if (other.empty()) { + break; + } + get_reachable(p, other, conseq); + other = conseq; + } + if (mutex.size() > 1) { + expr_ref_vector mux(m_manager); + for (unsigned i = 0; i < mutex.size(); ++i) { + expr_ref e(m_manager); + literal2expr(mutex[i], e); + mux.push_back(e); + } + mutexes.push_back(mux); + } + for (unsigned i = 0; i < mutex.size(); ++i) { + lits.remove(mutex[i].index()); + } + } + return l_true; + } + + void context::get_reachable(literal p, index_set& goal, index_set& reachable) { + index_set seen; + literal_vector todo; + todo.push_back(p); + while (!todo.empty()) { + p = todo.back(); + todo.pop_back(); + if (seen.contains(p.index())) { + continue; + } + seen.insert(p.index()); + literal np = ~p; + if (goal.contains(np.index())) { + reachable.insert(np.index()); + } + watch_list & w = m_watches[np.index()]; + todo.append(static_cast(w.end_literals() - w.begin_literals()), w.begin_literals()); + } + } + // // Validate, in a slow pass, that the current consequences are correctly // extracted. diff --git a/src/smt/smt_context.h b/src/smt/smt_context.h index 98093d6ed..d9f24ddf6 100644 --- a/src/smt/smt_context.h +++ b/src/smt/smt_context.h @@ -1344,6 +1344,9 @@ namespace smt { literal lit, context& src_ctx, context& dst_ctx, vector b2v, ast_translation& tr); + /* + \brief Utilities for consequence finding. + */ typedef hashtable index_set; //typedef uint_set index_set; u_map m_antecedents; @@ -1358,11 +1361,17 @@ namespace smt { expr_ref antecedent2fml(index_set const& ante); + literal mk_diseq(expr* v, expr* val); void validate_consequences(expr_ref_vector const& assumptions, expr_ref_vector const& vars, expr_ref_vector const& conseq, expr_ref_vector const& unfixed); + /* + \brief Auxiliry function for mutex finding. + */ + + void get_reachable(literal p, index_set& goal, index_set& reached); public: context(ast_manager & m, smt_params & fp, params_ref const & p = params_ref()); @@ -1404,7 +1413,8 @@ namespace smt { lbool check(unsigned num_assumptions = 0, expr * const * assumptions = 0, bool reset_cancel = true); lbool get_consequences(expr_ref_vector const& assumptions, expr_ref_vector const& vars, expr_ref_vector& conseq, expr_ref_vector& unfixed); - lbool get_consequences2(expr_ref_vector const& assumptions, expr_ref_vector const& vars, expr_ref_vector& conseq, expr_ref_vector& unfixed); + + lbool find_mutexes(expr_ref_vector const& vars, vector& mutexes); lbool setup_and_check(bool reset_cancel = true); diff --git a/src/smt/smt_kernel.cpp b/src/smt/smt_kernel.cpp index e5a8a639e..3819f05cb 100644 --- a/src/smt/smt_kernel.cpp +++ b/src/smt/smt_kernel.cpp @@ -112,7 +112,11 @@ namespace smt { } lbool get_consequences(expr_ref_vector const& assumptions, expr_ref_vector const& vars, expr_ref_vector& conseq, expr_ref_vector& unfixed) { - return m_kernel.get_consequences2(assumptions, vars, conseq, unfixed); + return m_kernel.get_consequences(assumptions, vars, conseq, unfixed); + } + + lbool find_mutexes(expr_ref_vector const& vars, vector& mutexes) { + return m_kernel.find_mutexes(vars, mutexes); } void get_model(model_ref & m) const { @@ -272,6 +276,10 @@ namespace smt { return m_imp->get_consequences(assumptions, vars, conseq, unfixed); } + lbool kernel::find_mutexes(expr_ref_vector const& vars, vector& mutexes) { + return m_imp->find_mutexes(vars, mutexes); + } + void kernel::get_model(model_ref & m) const { m_imp->get_model(m); } diff --git a/src/smt/smt_kernel.h b/src/smt/smt_kernel.h index a10961207..0fec4a21b 100644 --- a/src/smt/smt_kernel.h +++ b/src/smt/smt_kernel.h @@ -132,6 +132,11 @@ namespace smt { lbool get_consequences(expr_ref_vector const& assumptions, expr_ref_vector const& vars, expr_ref_vector& conseq, expr_ref_vector& unfixed); + /* + \brief find mutually exclusive variables. + */ + lbool find_mutexes(expr_ref_vector const& vars, vector& mutexes); + /** \brief Return the model associated with the last check command. */ diff --git a/src/smt/smt_solver.cpp b/src/smt/smt_solver.cpp index f9da1bf60..2ea4fea20 100644 --- a/src/smt/smt_solver.cpp +++ b/src/smt/smt_solver.cpp @@ -73,6 +73,10 @@ namespace smt { return m_context.get_consequences(assumptions, vars, conseq, unfixed); } + virtual lbool find_mutexes(expr_ref_vector const& vars, vector& mutexes) { + return m_context.find_mutexes(vars, mutexes); + } + virtual void assert_expr(expr * t) { m_context.assert_expr(t); } @@ -160,6 +164,7 @@ namespace smt { SASSERT(idx < get_num_assertions()); return m_context.get_formulas()[idx]; } + }; }; diff --git a/src/smt/theory_pb.cpp b/src/smt/theory_pb.cpp index a85f9aa80..2461a9db2 100644 --- a/src/smt/theory_pb.cpp +++ b/src/smt/theory_pb.cpp @@ -519,6 +519,7 @@ namespace smt { c->m_compilation_threshold = th; IF_VERBOSE(2, verbose_stream() << "(smt.pb setting compilation threhshold to " << th << ")\n";); TRACE("pb", tout << "compilation threshold: " << th << "\n";); + compile_ineq(*c); } else { c->m_compilation_threshold = UINT_MAX; @@ -1216,7 +1217,7 @@ namespace smt { void theory_pb::inc_propagations(ineq& c) { ++c.m_num_propagations; - if (c.m_compiled == l_false && c.m_num_propagations > c.m_compilation_threshold) { + if (c.m_compiled == l_false && c.m_num_propagations >= c.m_compilation_threshold) { c.m_compiled = l_undef; m_to_compile.push_back(&c); } @@ -1263,12 +1264,14 @@ namespace smt { n -= rational::one(); } } + + if (ctx.get_assignment(thl) == l_true && ctx.get_assign_level(thl) == ctx.get_base_level()) { psort_expr ps(ctx, *this); psort_nw sortnw(ps); sortnw.m_stats.reset(); - at_least_k = sortnw.ge(false, k, in.size(), in.c_ptr()); + at_least_k = sortnw.ge(false, k, in.size(), in.c_ptr()); ctx.mk_clause(~thl, at_least_k, justify(~thl, at_least_k)); m_stats.m_num_compiled_vars += sortnw.m_stats.m_num_compiled_vars; m_stats.m_num_compiled_clauses += sortnw.m_stats.m_num_compiled_clauses; diff --git a/src/solver/solver.cpp b/src/solver/solver.cpp index c75088246..8f32019d5 100644 --- a/src/solver/solver.cpp +++ b/src/solver/solver.cpp @@ -138,63 +138,6 @@ lbool solver::get_consequences_core(expr_ref_vector const& asms, expr_ref_vector lbool solver::find_mutexes(expr_ref_vector const& vars, vector& mutexes) { return l_true; -#if 0 - // complete for literals, but inefficient. - // see more efficient (incomplete) version in sat_solver - - mutexes.reset(); - ast_manager& m = vars.get_manager(); - - typedef obj_hashtable expr_set; - - expr_set A, P; - - for (unsigned i = 0; i < vars.size(); ++i) { - A.insert(vars[i]); - } - - while (!A.empty()) { - P = A; - expr_ref_vector mutex(m); - while (!P.empty()) { - expr_ref_vector asms(m); - expr* p = *P.begin(); - P.remove(p); - if (!is_literal(m, p)) { - break; - } - mutex.push_back(p); - asms.push_back(p); - expr_set Q; - expr_set::iterator it = P.begin(), end = P.end(); - for (; it != end; ++it) { - expr* q = *it; - scoped_assumption_push _scoped_push(asms, q); - if (is_literal(m, q)) { - lbool is_sat = check_sat(asms); - switch (is_sat) { - case l_false: - Q.insert(q); - break; - case l_true: - break; - case l_undef: - return l_undef; - } - } - } - P = Q; - } - if (mutex.size() > 1) { - mutexes.push_back(mutex); - } - for (unsigned i = 0; i < mutex.size(); ++i) { - A.remove(mutex[i].get()); - } - } - return l_true; -#endif - } bool solver::is_literal(ast_manager& m, expr* e) { diff --git a/src/solver/solver_na2as.cpp b/src/solver/solver_na2as.cpp index 29ce4864f..31895b8ef 100644 --- a/src/solver/solver_na2as.cpp +++ b/src/solver/solver_na2as.cpp @@ -22,6 +22,7 @@ Notes: #include"solver_na2as.h" #include"ast_smt2_pp.h" + solver_na2as::solver_na2as(ast_manager & m): m(m), m_assumptions(m) { @@ -71,6 +72,11 @@ lbool solver_na2as::get_consequences(expr_ref_vector const& asms, expr_ref_vecto return get_consequences_core(m_assumptions, vars, consequences); } +lbool solver_na2as::find_mutexes(expr_ref_vector const& vars, vector& mutexes) { + return l_true; +} + + void solver_na2as::push() { m_scopes.push_back(m_assumptions.size()); push_core(); diff --git a/src/solver/solver_na2as.h b/src/solver/solver_na2as.h index 45253e950..aaa48efe7 100644 --- a/src/solver/solver_na2as.h +++ b/src/solver/solver_na2as.h @@ -46,6 +46,7 @@ public: virtual unsigned get_num_assumptions() const { return m_assumptions.size(); } virtual expr * get_assumption(unsigned idx) const { return m_assumptions[idx]; } virtual lbool get_consequences(expr_ref_vector const& asms, expr_ref_vector const& vars, expr_ref_vector& consequences); + virtual lbool find_mutexes(expr_ref_vector const& vars, vector& mutexes); protected: virtual lbool check_sat_core(unsigned num_assumptions, expr * const * assumptions) = 0; virtual void push_core() = 0; diff --git a/src/tactic/arith/card2bv_tactic.cpp b/src/tactic/arith/card2bv_tactic.cpp index 2b551229d..5019b6550 100644 --- a/src/tactic/arith/card2bv_tactic.cpp +++ b/src/tactic/arith/card2bv_tactic.cpp @@ -168,13 +168,39 @@ namespace pb { return BR_FAILED; } - expr_ref card2bv_rewriter::mk_atmost1(unsigned sz, expr * const* args) { - expr_ref f1(m), f2(m), f3(m), result(m); - f1 = bv.mk_bv(sz, args); - f2 = bv.mk_bv_sub(f1, bv.mk_numeral(rational(1), sz)); - f3 = m.mk_app(bv.get_fid(), OP_BAND, f1, f2); - result = m.mk_eq(f3, bv.mk_numeral(rational(0), sz)); - return result; + expr_ref card2bv_rewriter::mk_atmost1(unsigned n, expr * const* xs) { + expr_ref_vector result(m), in(m); + in.append(n, xs); + unsigned inc_size = 4; + while (!in.empty()) { + expr_ref_vector ors(m); + unsigned i = 0; + unsigned n = in.size(); + bool last = n <= inc_size; + for (; i + inc_size < n; i += inc_size) { + mk_at_most_1_small(last, inc_size, in.c_ptr() + i, result, ors); + } + if (i < n) { + mk_at_most_1_small(last, n - i, in.c_ptr() + i, result, ors); + } + if (last) { + break; + } + in.reset(); + in.append(ors); + } + return mk_and(result); + } + + void card2bv_rewriter::mk_at_most_1_small(bool last, unsigned n, literal const* xs, expr_ref_vector& result, expr_ref_vector& ors) { + if (!last) { + ors.push_back(m.mk_or(n, xs)); + } + for (unsigned i = 0; i < n; ++i) { + for (unsigned j = i + 1; j < n; ++j) { + result.push_back(m.mk_not(m.mk_and(xs[i], xs[j]))); + } + } } bool card2bv_rewriter::is_atmost1(func_decl* f, unsigned sz, expr * const* args, expr_ref& result) { diff --git a/src/tactic/arith/card2bv_tactic.h b/src/tactic/arith/card2bv_tactic.h index 91ed68969..9bf21d2c3 100644 --- a/src/tactic/arith/card2bv_tactic.h +++ b/src/tactic/arith/card2bv_tactic.h @@ -54,6 +54,7 @@ namespace pb { bool is_and(func_decl* f); bool is_atmost1(func_decl* f, unsigned sz, expr * const* args, expr_ref& result); expr_ref mk_atmost1(unsigned sz, expr * const* args); + void mk_at_most_1_small(bool last, unsigned n, literal const* xs, expr_ref_vector& result, expr_ref_vector& ors); public: card2bv_rewriter(ast_manager& m); diff --git a/src/test/sorting_network.cpp b/src/test/sorting_network.cpp index 4802e2bec..57e818542 100644 --- a/src/test/sorting_network.cpp +++ b/src/test/sorting_network.cpp @@ -332,7 +332,32 @@ void test_sorting5(unsigned n, unsigned k) { test_sorting_ge(n, k); } +void test_at_most_1(unsigned n) { + ast_manager m; + reg_decl_plugins(m); + expr_ref_vector in(m), out(m); + for (unsigned i = 0; i < n; ++i) { + in.push_back(m.mk_fresh_const("a",m.mk_bool_sort())); + } + + + ast_ext2 ext(m); + psort_nw sn(ext); + expr_ref result(m); + result = sn.le(false, 1, in.size(), in.c_ptr()); + std::cout << result << "\n"; + std::cout << ext.m_clauses << "\n"; +} + void tst_sorting_network() { + test_at_most_1(1); + test_at_most_1(2); + test_at_most_1(3); + test_at_most_1(4); + test_at_most_1(5); + test_at_most_1(10); + return; + test_sorting_eq(11,7); for (unsigned n = 3; n < 20; n += 2) { for (unsigned k = 1; k < n; ++k) { diff --git a/src/util/sorting_network.h b/src/util/sorting_network.h index b106117ea..a29428dbc 100644 --- a/src/util/sorting_network.h +++ b/src/util/sorting_network.h @@ -201,7 +201,11 @@ Notes: if (dualize(k, n, xs, in)) { return ge(full, k, n, in.c_ptr()); } + else if (k == 1) { + return mk_at_most_1(full, n, xs); + } else { + std::cout << "sort " << k << "\n"; SASSERT(2*k <= n); m_t = full?LE_FULL:LE; card(k + 1, n, xs, out); @@ -230,6 +234,54 @@ Notes: private: + literal mk_at_most_1(bool full, unsigned n, literal const* xs) { + literal_vector in(n, xs); + literal result = ctx.fresh(); + unsigned inc_size = 4; + while (!in.empty()) { + literal_vector ors; + unsigned i = 0; + unsigned n = in.size(); + bool last = n <= inc_size; + for (; i + inc_size < n; i += inc_size) { + mk_at_most_1_small(full, last, inc_size, in.c_ptr() + i, result, ors); + } + if (i < n) { + mk_at_most_1_small(full, last, n - i, in.c_ptr() + i, result, ors); + } + if (last) { + break; + } + in.reset(); + in.append(ors); + ors.reset(); + } + return result; + } + + void mk_at_most_1_small(bool full, bool last, unsigned n, literal const* xs, literal result, literal_vector& ors) { + if (!last) { + literal ex = ctx.fresh(); + for (unsigned j = 0; j < n; ++j) { + add_clause(ctx.mk_not(xs[j]), ex); + } + if (full) { + literal_vector lits(n, xs); + lits.push_back(ctx.mk_not(ex)); + add_clause(lits.size(), lits.c_ptr()); + } + ors.push_back(ex); + } + for (unsigned i = 0; i < n; ++i) { + for (unsigned j = i + 1; j < n; ++j) { + add_clause(ctx.mk_not(result), ctx.mk_not(xs[i]), ctx.mk_not(xs[j])); + } + if (full) { + add_clause(result, xs[i]); + } + } + } + std::ostream& pp(std::ostream& out, unsigned n, literal const* lits) { for (unsigned i = 0; i < n; ++i) ctx.pp(out, lits[i]) << " "; return out; From 487f15f90a73f47889a13ed8eba3dbe84129d6f3 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 10 Oct 2016 23:49:45 -0700 Subject: [PATCH 227/536] better encodings for at-most-1, #755 Signed-off-by: Nikolaj Bjorner --- src/ast/pb_decl_plugin.h | 2 -- src/util/sorting_network.h | 1 - 2 files changed, 3 deletions(-) diff --git a/src/ast/pb_decl_plugin.h b/src/ast/pb_decl_plugin.h index d0649729b..e1b16f0c9 100644 --- a/src/ast/pb_decl_plugin.h +++ b/src/ast/pb_decl_plugin.h @@ -119,8 +119,6 @@ public: app* mk_fresh_bool(); - expr_ref mk_at_most_1(unsigned num_args, expr * const * args); - private: rational to_rational(parameter const& p) const; diff --git a/src/util/sorting_network.h b/src/util/sorting_network.h index a29428dbc..242d4f43e 100644 --- a/src/util/sorting_network.h +++ b/src/util/sorting_network.h @@ -205,7 +205,6 @@ Notes: return mk_at_most_1(full, n, xs); } else { - std::cout << "sort " << k << "\n"; SASSERT(2*k <= n); m_t = full?LE_FULL:LE; card(k + 1, n, xs, out); From bc257211d60d04a2b2e86d483643c2c0d3281d84 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Wed, 12 Oct 2016 18:36:44 +0100 Subject: [PATCH 228/536] Whitespace --- src/ast/fpa/fpa2bv_converter.cpp | 1 - src/ast/fpa/fpa2bv_converter.h | 4 +-- src/ast/fpa_decl_plugin.h | 10 +++--- src/ast/rewriter/fpa_rewriter.cpp | 2 +- src/smt/theory_fpa.cpp | 40 +++++++++++------------ src/tactic/fpa/fpa2bv_model_converter.cpp | 18 +++++----- 6 files changed, 37 insertions(+), 38 deletions(-) diff --git a/src/ast/fpa/fpa2bv_converter.cpp b/src/ast/fpa/fpa2bv_converter.cpp index 6bba4663d..460aff29f 100644 --- a/src/ast/fpa/fpa2bv_converter.cpp +++ b/src/ast/fpa/fpa2bv_converter.cpp @@ -165,7 +165,6 @@ void fpa2bv_converter::mk_numeral(sort * s, mpf const & v, expr_ref & result) { result = m_util.mk_fp(bv_sgn, biased_exp, bv_sig); TRACE("fpa2bv_dbg", tout << "value of [" << sign << " " << m_mpz_manager.to_string(sig) << " " << exp << "] is " << mk_ismt2_pp(result, m) << std::endl;); - } } diff --git a/src/ast/fpa/fpa2bv_converter.h b/src/ast/fpa/fpa2bv_converter.h index 3f5e76c66..436f44364 100644 --- a/src/ast/fpa/fpa2bv_converter.h +++ b/src/ast/fpa/fpa2bv_converter.h @@ -71,9 +71,9 @@ public: bool is_rm(expr * e) { return is_app(e) && m_util.is_rm(e); } bool is_rm(sort * s) { return m_util.is_rm(s); } bool is_float_family(func_decl * f) { return f->get_family_id() == m_util.get_family_id(); } - + void mk_fp(func_decl * f, unsigned num, expr * const * args, expr_ref & result); - + void split_fp(expr * e, expr * & sgn, expr * & exp, expr * & sig) const; void split_fp(expr * e, expr_ref & sgn, expr_ref & exp, expr_ref & sig) const; diff --git a/src/ast/fpa_decl_plugin.h b/src/ast/fpa_decl_plugin.h index ee7325014..a3215dd6f 100644 --- a/src/ast/fpa_decl_plugin.h +++ b/src/ast/fpa_decl_plugin.h @@ -259,7 +259,7 @@ public: bool is_rm(sort * s) const { return is_sort_of(s, m_fid, ROUNDING_MODE_SORT); } bool is_float(expr * e) const { return is_float(m_manager.get_sort(e)); } bool is_rm(expr * e) const { return is_rm(m_manager.get_sort(e)); } - bool is_fp(expr * e) const { return is_app_of(e, m_fid, OP_FPA_FP); } + bool is_fp(expr * e) const { return is_app_of(e, m_fid, OP_FPA_FP); } unsigned get_ebits(sort * s) const; unsigned get_sbits(sort * s) const; @@ -294,13 +294,13 @@ public: bool is_pzero(expr * n) { scoped_mpf v(fm()); return is_numeral(n, v) && fm().is_pzero(v); } bool is_nzero(expr * n) { scoped_mpf v(fm()); return is_numeral(n, v) && fm().is_nzero(v); } - app * mk_fp(expr * sgn, expr * exp, expr * sig) { + app * mk_fp(expr * sgn, expr * exp, expr * sig) { SASSERT(m_bv_util.is_bv(sgn) && m_bv_util.get_bv_size(sgn) == 1); SASSERT(m_bv_util.is_bv(exp)); - SASSERT(m_bv_util.is_bv(sig)); - return m().mk_app(m_fid, OP_FPA_FP, sgn, exp, sig); + SASSERT(m_bv_util.is_bv(sig)); + return m().mk_app(m_fid, OP_FPA_FP, sgn, exp, sig); } - + app * mk_to_fp(sort * s, expr * bv_t) { SASSERT(is_float(s) && s->get_num_parameters() == 2); return m().mk_app(m_fid, OP_FPA_TO_FP, 2, s->get_parameters(), 1, &bv_t); diff --git a/src/ast/rewriter/fpa_rewriter.cpp b/src/ast/rewriter/fpa_rewriter.cpp index b8d9c232f..92b373ca0 100644 --- a/src/ast/rewriter/fpa_rewriter.cpp +++ b/src/ast/rewriter/fpa_rewriter.cpp @@ -98,7 +98,7 @@ br_status fpa_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * con case OP_FPA_INTERNAL_MIN_UNSPECIFIED: case OP_FPA_INTERNAL_MAX_UNSPECIFIED: SASSERT(num_args == 2); st = BR_FAILED; break; - + case OP_FPA_INTERNAL_BVWRAP: SASSERT(num_args == 1); st = mk_bvwrap(args[0], result); break; case OP_FPA_INTERNAL_BV2RM: SASSERT(num_args == 1); st = mk_bv2rm(args[0], result); break; diff --git a/src/smt/theory_fpa.cpp b/src/smt/theory_fpa.cpp index ee7559500..fec7922c7 100644 --- a/src/smt/theory_fpa.cpp +++ b/src/smt/theory_fpa.cpp @@ -116,15 +116,15 @@ namespace smt { SASSERT(m_trail_stack.get_num_scopes() == 0); SASSERT(m_conversions.empty()); - SASSERT(m_is_added_to_model.empty()); - } + SASSERT(m_is_added_to_model.empty()); + } void theory_fpa::init(context * ctx) { smt::theory::init(ctx); m_is_initialized = true; } app * theory_fpa::fpa_value_proc::mk_value(model_generator & mg, ptr_vector & values) { - TRACE("t_fpa_detail", + TRACE("t_fpa_detail", ast_manager & m = m_th.get_manager(); for (unsigned i = 0; i < values.size(); i++) tout << "value[" << i << "] = " << mk_ismt2_pp(values[i], m) << std::endl;); @@ -201,7 +201,7 @@ namespace smt { app * theory_fpa::fpa_rm_value_proc::mk_value(model_generator & mg, ptr_vector & values) { SASSERT(values.size() == 1); - TRACE("t_fpa_detail", + TRACE("t_fpa_detail", ast_manager & m = m_th.get_manager(); for (unsigned i = 0; i < values.size(); i++) tout << "value[" << i << "] = " << mk_ismt2_pp(values[i], m) << std::endl;); @@ -235,12 +235,12 @@ namespace smt { app_ref res(m); if (m_fpa_util.is_fp(e)) { - expr * cargs[3] = { to_app(e)->get_arg(0), to_app(e)->get_arg(1), to_app(e)->get_arg(2) }; + expr * cargs[3] = { to_app(e)->get_arg(0), to_app(e)->get_arg(1), to_app(e)->get_arg(2) }; res = m_bv_util.mk_concat(3, cargs); m_th_rw((expr_ref&)res); } else { - sort * es = m.get_sort(e); + sort * es = m.get_sort(e); sort_ref bv_srt(m); if (m_converter.is_rm(es)) @@ -264,7 +264,7 @@ namespace smt { SASSERT(!m_fpa_util.is_fp(e)); SASSERT(m_bv_util.is_bv(e)); SASSERT(m_fpa_util.is_float(s) || m_fpa_util.is_rm(s)); - ast_manager & m = get_manager(); + ast_manager & m = get_manager(); app_ref res(m); unsigned bv_sz = m_bv_util.get_bv_size(e); @@ -285,7 +285,7 @@ namespace smt { m_bv_util.mk_extract(bv_sz - 2, sbits - 1, e), m_bv_util.mk_extract(sbits - 2, 0, e)); } - + return res; } @@ -312,7 +312,7 @@ namespace smt { TRACE("t_fpa_detail", tout << "term: " << mk_ismt2_pp(e, get_manager()) << std::endl; tout << "converted term: " << mk_ismt2_pp(e_conv, get_manager()) << std::endl;); - if (m_fpa_util.is_rm(e)) { + if (m_fpa_util.is_rm(e)) { SASSERT(m_fpa_util.is_bv2rm(e_conv)); expr_ref bv_rm(m); m_th_rw(to_app(e_conv)->get_arg(0), bv_rm); @@ -329,7 +329,7 @@ namespace smt { } else UNREACHABLE(); - + return res; } @@ -362,7 +362,7 @@ namespace smt { res = convert_atom(e); else if (m_fpa_util.is_float(e) || m_fpa_util.is_rm(e)) res = convert_term(e); - else + else res = convert_conversion_term(e); TRACE("t_fpa_detail", tout << "converted; caching:" << std::endl; @@ -448,7 +448,7 @@ namespace smt { TRACE("t_fpa_internalize", tout << "internalizing term: " << mk_ismt2_pp(term, get_manager()) << "\n";); SASSERT(term->get_family_id() == get_family_id()); SASSERT(!get_context().e_internalized(term)); - + ast_manager & m = get_manager(); context & ctx = get_context(); @@ -494,7 +494,7 @@ namespace smt { SASSERT(n->get_owner()->get_decl()->get_range() == s); ast_manager & m = get_manager(); - context & ctx = get_context(); + context & ctx = get_context(); app_ref owner(n->get_owner(), m); if (!is_attached_to_var(n)) { @@ -510,7 +510,7 @@ namespace smt { assert_cnstr(valid); } } - + if (!ctx.relevancy()) relevant_eh(owner); } @@ -600,7 +600,7 @@ namespace smt { xe_eq_ye = m.mk_eq(xe, ye); not_xe_eq_ye = m.mk_not(xe_eq_ye); c_eq_iff = m.mk_iff(not_xe_eq_ye, c); - assert_cnstr(c_eq_iff); + assert_cnstr(c_eq_iff); assert_cnstr(mk_side_conditions()); return; @@ -689,10 +689,10 @@ namespace smt { pop_scope_eh(m_trail_stack.get_num_scopes()); m_converter.reset(); m_rw.reset(); - m_th_rw.reset(); - m_trail_stack.pop_scope(m_trail_stack.get_num_scopes()); + m_th_rw.reset(); + m_trail_stack.pop_scope(m_trail_stack.get_num_scopes()); if (m_factory) { - dealloc(m_factory); + dealloc(m_factory); m_factory = 0; } ast_manager & m = get_manager(); @@ -862,8 +862,8 @@ namespace smt { } bool theory_fpa::include_func_interp(func_decl * f) { - TRACE("t_fpa", tout << "f = " << mk_ismt2_pp(f, get_manager()) << std::endl;); - + TRACE("t_fpa", tout << "f = " << mk_ismt2_pp(f, get_manager()) << std::endl;); + if (f->get_family_id() == get_family_id()) { bool include = m_fpa_util.is_min_unspecified(f) || diff --git a/src/tactic/fpa/fpa2bv_model_converter.cpp b/src/tactic/fpa/fpa2bv_model_converter.cpp index 20d8bbbcc..05fedb37f 100644 --- a/src/tactic/fpa/fpa2bv_model_converter.cpp +++ b/src/tactic/fpa/fpa2bv_model_converter.cpp @@ -234,7 +234,7 @@ fpa2bv_model_converter::array_model fpa2bv_model_converter::convert_array_func_i array_util arr_util(m); array_model am(m); - sort_ref_vector array_domain(m); + sort_ref_vector array_domain(m); unsigned arity = f->get_range()->get_num_parameters()-1; expr_ref as_arr_mdl(m); @@ -245,21 +245,21 @@ fpa2bv_model_converter::array_model fpa2bv_model_converter::convert_array_func_i for (unsigned i = 0; i < arity; i++) array_domain.push_back(to_sort(f->get_range()->get_parameter(i).get_ast())); sort * rng = to_sort(f->get_range()->get_parameter(arity).get_ast()); - + bv_f = arr_util.get_as_array_func_decl(to_app(as_arr_mdl)); am.new_float_fd = m.mk_fresh_func_decl(arity, array_domain.c_ptr(), rng); - am.new_float_fi = convert_func_interp(am.new_float_fd, bv_f, bv_mdl); + am.new_float_fi = convert_func_interp(am.new_float_fd, bv_f, bv_mdl); am.bv_fd = bv_f; am.result = arr_util.mk_as_array(f->get_range(), am.new_float_fd); return am; } -func_interp * fpa2bv_model_converter::convert_func_interp(func_decl * f, func_decl * bv_f, model * bv_mdl) { +func_interp * fpa2bv_model_converter::convert_func_interp(func_decl * f, func_decl * bv_f, model * bv_mdl) { SASSERT(f->get_arity() > 0); func_interp * result = 0; sort * rng = f->get_range(); - sort * const * dmn = f->get_domain(); + sort * const * dmn = f->get_domain(); unsigned arity = bv_f->get_arity(); func_interp * bv_fi = bv_mdl->get_func_interp(bv_f); @@ -276,7 +276,7 @@ func_interp * fpa2bv_model_converter::convert_func_interp(func_decl * f, func_de for (unsigned j = 0; j < arity; j++) { sort * ft_dj = dmn[j]; - expr * bv_aj = bv_args[j]; + expr * bv_aj = bv_args[j]; ai = rebuild_floats(bv_mdl, ft_dj, bv_aj); m_th_rw(ai); new_args.push_back(ai); @@ -293,7 +293,7 @@ func_interp * fpa2bv_model_converter::convert_func_interp(func_decl * f, func_de bv_els = bv_fi->get_else(); ft_els = rebuild_floats(bv_mdl, rng, bv_els); m_th_rw(ft_els); - result->set_else(ft_els); + result->set_else(ft_els); } return result; @@ -409,7 +409,7 @@ void fpa2bv_model_converter::convert(model * bv_mdl, model * float_mdl) { it++) { seen.insert(it->m_value); - func_decl * f = it->m_key; + func_decl * f = it->m_key; if (f->get_arity() == 0) { array_util au(m); @@ -426,7 +426,7 @@ void fpa2bv_model_converter::convert(model * bv_mdl, model * float_mdl) { bv_mdl->eval(it->m_value, val); if (val) float_mdl->register_decl(f, val); } - } + } else { func_interp * fmv = convert_func_interp(f, it->m_value, bv_mdl); if (fmv) float_mdl->register_decl(f, fmv); From 7e705a2d3287cc800a5fd871d0deca757b4c0075 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Wed, 12 Oct 2016 18:37:41 +0100 Subject: [PATCH 229/536] Bug fixes for underspecified FP operations. --- src/ast/fpa/fpa2bv_converter.cpp | 79 ++++++++++++--------- src/ast/fpa/fpa2bv_converter.h | 4 +- src/ast/fpa/fpa2bv_rewriter.cpp | 4 +- src/ast/fpa_decl_plugin.h | 40 +++++------ src/ast/rewriter/fpa_rewriter.cpp | 87 ++++++++++++------------ src/ast/rewriter/fpa_rewriter_params.pyg | 2 +- src/smt/theory_fpa.cpp | 30 ++++++-- 7 files changed, 139 insertions(+), 107 deletions(-) diff --git a/src/ast/fpa/fpa2bv_converter.cpp b/src/ast/fpa/fpa2bv_converter.cpp index 460aff29f..8db839e24 100644 --- a/src/ast/fpa/fpa2bv_converter.cpp +++ b/src/ast/fpa/fpa2bv_converter.cpp @@ -3072,13 +3072,57 @@ void fpa2bv_converter::mk_to_ieee_bv(func_decl * f, unsigned num, expr * const * m_bv_util.mk_concat(m_bv_util.mk_numeral(-1, ebits), m_bv_util.mk_concat(m_bv_util.mk_numeral(0, sbits - 2), m_bv_util.mk_numeral(1, 1)))); - else - nanv = mk_to_ieee_bv_unspecified(ebits, sbits); + else { + expr_ref unspec_bits(m); + unspec_bits = m_util.mk_internal_to_ieee_bv_unspecified(ebits, sbits); + nanv = m_bv_util.mk_concat(m_bv_util.mk_extract(sbits-1, sbits-1, unspec_bits), + m_bv_util.mk_concat(m_bv_util.mk_numeral(-1, ebits), + m_bv_util.mk_extract(sbits-2, 0, unspec_bits))); + } expr_ref sgn_e_s(m); sgn_e_s = m_bv_util.mk_concat(m_bv_util.mk_concat(sgn, e), s); m_simp.mk_ite(x_is_nan, nanv, sgn_e_s, result); + TRACE("fpa2bv_to_ieee_bv", tout << "result=" << mk_ismt2_pp(result, m) << std::endl;); + SASSERT(is_well_sorted(m, result)); +} + +void fpa2bv_converter::mk_to_ieee_bv_unspecified(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { + SASSERT(num == 0); + unsigned ebits = f->get_parameter(0).get_int(); + unsigned sbits = f->get_parameter(1).get_int(); + + if (m_hi_fp_unspecified) { + result = m_bv_util.mk_concat(m_bv_util.mk_concat( + m_bv_util.mk_numeral(0, 1), + m_bv_util.mk_numeral(-1, ebits)), + m_bv_util.mk_numeral(1, sbits-1)); + } + else { + func_decl * fd; + if (m_uf2bvuf.find(f, fd)) + result = m.mk_const(fd); + else { + fd = m.mk_fresh_func_decl(0, 0, 0, f->get_range()); + m_uf2bvuf.insert(f, fd); + m.inc_ref(f); + m.inc_ref(fd); + result = m.mk_const(fd); + + expr_ref exp_bv(m), exp_all_ones(m); + exp_bv = m_bv_util.mk_extract(ebits+sbits-2, sbits-1, result); + exp_all_ones = m.mk_eq(exp_bv, m_bv_util.mk_numeral(-1, ebits)); + m_extra_assertions.push_back(exp_all_ones); + + expr_ref sig_bv(m), sig_is_non_zero(m); + sig_bv = m_bv_util.mk_extract(sbits-2, 0, result); + sig_is_non_zero = m.mk_not(m.mk_eq(sig_bv, m_bv_util.mk_numeral(0, sbits-1))); + m_extra_assertions.push_back(sig_is_non_zero); + } + } + + TRACE("fpa2bv_to_ieee_bv_unspecified", tout << "result=" << mk_ismt2_pp(result, m) << std::endl;); SASSERT(is_well_sorted(m, result)); } @@ -3308,41 +3352,10 @@ expr_ref fpa2bv_converter::mk_to_real_unspecified(unsigned ebits, unsigned sbits m.inc_ref(fd); } result = m.mk_const(fd); - result = unspec; } return result; } -expr_ref fpa2bv_converter::mk_to_ieee_bv_unspecified(unsigned ebits, unsigned sbits) { - expr_ref result(m); - - app_ref unspec(m); - unspec = m_util.mk_internal_to_ieee_bv_unspecified(ebits, sbits); - func_decl * unspec_fd = unspec->get_decl(); - func_decl * fd; - if (!m_uf2bvuf.find(unspec_fd, fd)) { - app_ref bvc(m); - bvc = m.mk_fresh_const(0, unspec_fd->get_range()); - fd = bvc->get_decl(); - m_uf2bvuf.insert(unspec_fd, fd); - m.inc_ref(unspec_fd); - m.inc_ref(fd); - } - result = m.mk_const(fd); - - app_ref mask(m), extra(m), result_and_mask(m); - mask = m_bv_util.mk_concat(m_bv_util.mk_numeral(0, 1), - m_bv_util.mk_concat(m_bv_util.mk_numeral(-1, ebits), - m_bv_util.mk_concat(m_bv_util.mk_numeral(0, sbits - 2), - m_bv_util.mk_numeral(1, 1)))); - expr * args[2] = { result, mask }; - result_and_mask = m.mk_app(m_bv_util.get_fid(), OP_BAND, 2, args); - extra = m.mk_eq(result_and_mask, mask); - m_extra_assertions.push_back(extra); - - return result; -} - void fpa2bv_converter::mk_fp(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { SASSERT(num == 3); SASSERT(m_bv_util.get_bv_size(args[0]) == 1); diff --git a/src/ast/fpa/fpa2bv_converter.h b/src/ast/fpa/fpa2bv_converter.h index 436f44364..4fcfe42f6 100644 --- a/src/ast/fpa/fpa2bv_converter.h +++ b/src/ast/fpa/fpa2bv_converter.h @@ -133,6 +133,7 @@ public: void mk_to_fp_signed(func_decl * f, unsigned num, expr * const * args, expr_ref & result); void mk_to_fp_unsigned(func_decl * f, unsigned num, expr * const * args, expr_ref & result); void mk_to_ieee_bv(func_decl * f, unsigned num, expr * const * args, expr_ref & result); + void mk_to_ieee_bv_unspecified(func_decl * f, unsigned num, expr * const * args, expr_ref & result); void mk_to_fp_real(func_decl * f, sort * s, expr * rm, expr * x, expr_ref & result); void mk_to_fp_real_int(func_decl * f, unsigned num, expr * const * args, expr_ref & result); @@ -152,13 +153,12 @@ public: expr_ref mk_to_ubv_unspecified(unsigned ebits, unsigned sbits, unsigned width); expr_ref mk_to_sbv_unspecified(unsigned ebits, unsigned sbits, unsigned width); expr_ref mk_to_real_unspecified(unsigned ebits, unsigned sbits); - expr_ref mk_to_ieee_bv_unspecified(unsigned ebits, unsigned sbits); void reset(void); void dbg_decouple(const char * prefix, expr_ref & e); expr_ref_vector m_extra_assertions; - + special_t const & get_min_max_specials() const { return m_min_max_specials; }; const2bv_t const & get_const2bv() const { return m_const2bv; }; const2bv_t const & get_rm_const2bv() const { return m_rm_const2bv; }; diff --git a/src/ast/fpa/fpa2bv_rewriter.cpp b/src/ast/fpa/fpa2bv_rewriter.cpp index 5f89e12db..6d4f24856 100644 --- a/src/ast/fpa/fpa2bv_rewriter.cpp +++ b/src/ast/fpa/fpa2bv_rewriter.cpp @@ -145,7 +145,8 @@ br_status fpa2bv_rewriter_cfg::reduce_app(func_decl * f, unsigned num, expr * co case OP_FPA_TO_UBV: m_conv.mk_to_ubv(f, num, args, result); return BR_DONE; case OP_FPA_TO_SBV: m_conv.mk_to_sbv(f, num, args, result); return BR_DONE; case OP_FPA_TO_REAL: m_conv.mk_to_real(f, num, args, result); return BR_DONE; - case OP_FPA_TO_IEEE_BV: m_conv.mk_to_ieee_bv(f, num, args, result); return BR_DONE; + case OP_FPA_TO_IEEE_BV: m_conv.mk_to_ieee_bv(f, num, args, result); return BR_REWRITE_FULL; + case OP_FPA_INTERNAL_TO_IEEE_BV_UNSPECIFIED: m_conv.mk_to_ieee_bv_unspecified(f, num, args, result); return BR_DONE; case OP_FPA_MIN: m_conv.mk_min(f, num, args, result); return BR_REWRITE_FULL; case OP_FPA_MAX: m_conv.mk_max(f, num, args, result); return BR_REWRITE_FULL; @@ -161,7 +162,6 @@ br_status fpa2bv_rewriter_cfg::reduce_app(func_decl * f, unsigned num, expr * co case OP_FPA_INTERNAL_TO_REAL_UNSPECIFIED: case OP_FPA_INTERNAL_TO_UBV_UNSPECIFIED: case OP_FPA_INTERNAL_TO_SBV_UNSPECIFIED: - case OP_FPA_INTERNAL_TO_IEEE_BV_UNSPECIFIED: return BR_FAILED; default: TRACE("fpa2bv", tout << "unsupported operator: " << f->get_name() << "\n"; diff --git a/src/ast/fpa_decl_plugin.h b/src/ast/fpa_decl_plugin.h index a3215dd6f..c00bed7ae 100644 --- a/src/ast/fpa_decl_plugin.h +++ b/src/ast/fpa_decl_plugin.h @@ -377,28 +377,28 @@ public: app * mk_internal_to_ieee_bv_unspecified(unsigned ebits, unsigned sbits); app * mk_internal_to_real_unspecified(unsigned ebits, unsigned sbits); - bool is_bvwrap(expr * e) const { return is_app_of(e, get_family_id(), OP_FPA_INTERNAL_BVWRAP); } - bool is_bvwrap(func_decl * f) const { return f->get_family_id() == get_family_id() && f->get_decl_kind() == OP_FPA_INTERNAL_BVWRAP; } - bool is_bv2rm(expr * e) const { return is_app_of(e, get_family_id(), OP_FPA_INTERNAL_BV2RM); } - bool is_bv2rm(func_decl * f) const { return f->get_family_id() == get_family_id() && f->get_decl_kind() == OP_FPA_INTERNAL_BV2RM; } + bool is_bvwrap(expr const * e) const { return is_app_of(e, get_family_id(), OP_FPA_INTERNAL_BVWRAP); } + bool is_bvwrap(func_decl const * f) const { return f->get_family_id() == get_family_id() && f->get_decl_kind() == OP_FPA_INTERNAL_BVWRAP; } + bool is_bv2rm(expr const * e) const { return is_app_of(e, get_family_id(), OP_FPA_INTERNAL_BV2RM); } + bool is_bv2rm(func_decl const * f) const { return f->get_family_id() == get_family_id() && f->get_decl_kind() == OP_FPA_INTERNAL_BV2RM; } - bool is_min_interpreted(expr * e) { return is_app_of(e, get_family_id(), OP_FPA_INTERNAL_MIN_I); } - bool is_min_unspecified(expr * e) { return is_app_of(e, get_family_id(), OP_FPA_INTERNAL_MIN_UNSPECIFIED); } - bool is_max_interpreted(expr * e) { return is_app_of(e, get_family_id(), OP_FPA_INTERNAL_MAX_I); } - bool is_max_unspecified(expr * e) { return is_app_of(e, get_family_id(), OP_FPA_INTERNAL_MAX_UNSPECIFIED); } - bool is_to_ubv_unspecified(expr * e) { return is_app_of(e, get_family_id(), OP_FPA_INTERNAL_TO_UBV_UNSPECIFIED); } - bool is_to_sbv_unspecified(expr * e) { return is_app_of(e, get_family_id(), OP_FPA_INTERNAL_TO_SBV_UNSPECIFIED); } - bool is_to_ieee_bv_unspecified(expr * e) { return is_app_of(e, get_family_id(), OP_FPA_INTERNAL_TO_IEEE_BV_UNSPECIFIED); } - bool is_to_real_unspecified(expr * e) { return is_app_of(e, get_family_id(), OP_FPA_INTERNAL_TO_REAL_UNSPECIFIED); } + bool is_min_interpreted(expr const * e) const { return is_app_of(e, get_family_id(), OP_FPA_INTERNAL_MIN_I); } + bool is_min_unspecified(expr const * e) const { return is_app_of(e, get_family_id(), OP_FPA_INTERNAL_MIN_UNSPECIFIED); } + bool is_max_interpreted(expr const * e) const { return is_app_of(e, get_family_id(), OP_FPA_INTERNAL_MAX_I); } + bool is_max_unspecified(expr const * e) const { return is_app_of(e, get_family_id(), OP_FPA_INTERNAL_MAX_UNSPECIFIED); } + bool is_to_ubv_unspecified(expr const * e) const { return is_app_of(e, get_family_id(), OP_FPA_INTERNAL_TO_UBV_UNSPECIFIED); } + bool is_to_sbv_unspecified(expr const * e) const { return is_app_of(e, get_family_id(), OP_FPA_INTERNAL_TO_SBV_UNSPECIFIED); } + bool is_to_ieee_bv_unspecified(expr const * e) const { return is_app_of(e, get_family_id(), OP_FPA_INTERNAL_TO_IEEE_BV_UNSPECIFIED); } + bool is_to_real_unspecified(expr const * e) const { return is_app_of(e, get_family_id(), OP_FPA_INTERNAL_TO_REAL_UNSPECIFIED); } - bool is_min_interpreted(func_decl * f) { return f->get_family_id() == get_family_id() && f->get_decl_kind() == OP_FPA_INTERNAL_MIN_I; } - bool is_min_unspecified(func_decl * f) { return f->get_family_id() == get_family_id() && f->get_decl_kind() == OP_FPA_INTERNAL_MIN_UNSPECIFIED; } - bool is_max_interpreted(func_decl * f) { return f->get_family_id() == get_family_id() && f->get_decl_kind() == OP_FPA_INTERNAL_MAX_I; } - bool is_max_unspecified(func_decl * f) { return f->get_family_id() == get_family_id() && f->get_decl_kind() == OP_FPA_INTERNAL_MAX_UNSPECIFIED; } - bool is_to_ubv_unspecified(func_decl * f) { return f->get_family_id() == get_family_id() && f->get_decl_kind() == OP_FPA_INTERNAL_TO_UBV_UNSPECIFIED; } - bool is_to_sbv_unspecified(func_decl * f) { return f->get_family_id() == get_family_id() && f->get_decl_kind() == OP_FPA_INTERNAL_TO_SBV_UNSPECIFIED; } - bool is_to_ieee_bv_unspecified(func_decl * f) { return f->get_family_id() == get_family_id() && f->get_decl_kind() == OP_FPA_INTERNAL_TO_IEEE_BV_UNSPECIFIED; } - bool is_to_real_unspecified(func_decl * f) { return f->get_family_id() == get_family_id() && f->get_decl_kind() == OP_FPA_INTERNAL_TO_REAL_UNSPECIFIED; } + bool is_min_interpreted(func_decl const * f) const { return f->get_family_id() == get_family_id() && f->get_decl_kind() == OP_FPA_INTERNAL_MIN_I; } + bool is_min_unspecified(func_decl const * f) const { return f->get_family_id() == get_family_id() && f->get_decl_kind() == OP_FPA_INTERNAL_MIN_UNSPECIFIED; } + bool is_max_interpreted(func_decl const * f) const { return f->get_family_id() == get_family_id() && f->get_decl_kind() == OP_FPA_INTERNAL_MAX_I; } + bool is_max_unspecified(func_decl const * f) const { return f->get_family_id() == get_family_id() && f->get_decl_kind() == OP_FPA_INTERNAL_MAX_UNSPECIFIED; } + bool is_to_ubv_unspecified(func_decl const * f) const { return f->get_family_id() == get_family_id() && f->get_decl_kind() == OP_FPA_INTERNAL_TO_UBV_UNSPECIFIED; } + bool is_to_sbv_unspecified(func_decl const * f) const { return f->get_family_id() == get_family_id() && f->get_decl_kind() == OP_FPA_INTERNAL_TO_SBV_UNSPECIFIED; } + bool is_to_ieee_bv_unspecified(func_decl const * f) const { return f->get_family_id() == get_family_id() && f->get_decl_kind() == OP_FPA_INTERNAL_TO_IEEE_BV_UNSPECIFIED; } + bool is_to_real_unspecified(func_decl const * f) const { return f->get_family_id() == get_family_id() && f->get_decl_kind() == OP_FPA_INTERNAL_TO_REAL_UNSPECIFIED; } bool contains_floats(ast * a); }; diff --git a/src/ast/rewriter/fpa_rewriter.cpp b/src/ast/rewriter/fpa_rewriter.cpp index 92b373ca0..26487c5a4 100644 --- a/src/ast/rewriter/fpa_rewriter.cpp +++ b/src/ast/rewriter/fpa_rewriter.cpp @@ -18,11 +18,12 @@ Notes: --*/ #include"fpa_rewriter.h" #include"fpa_rewriter_params.hpp" +#include"ast_smt2_pp.h" fpa_rewriter::fpa_rewriter(ast_manager & m, params_ref const & p) : m_util(m), m_fm(m_util.fm()), - m_hi_fp_unspecified(true) { + m_hi_fp_unspecified(false) { updt_params(p); } @@ -117,34 +118,40 @@ br_status fpa_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * con br_status fpa_rewriter::mk_to_ubv_unspecified(unsigned ebits, unsigned sbits, unsigned width, expr_ref & result) { bv_util bu(m()); - if (m_hi_fp_unspecified) + if (m_hi_fp_unspecified) { // The "hardware interpretation" is 0. result = bu.mk_numeral(0, width); - else + return BR_DONE; + } + else { result = m_util.mk_internal_to_ubv_unspecified(ebits, sbits, width); - - return BR_DONE; + return BR_REWRITE1; + } } br_status fpa_rewriter::mk_to_sbv_unspecified(unsigned ebits, unsigned sbits, unsigned width, expr_ref & result) { bv_util bu(m()); - if (m_hi_fp_unspecified) + if (m_hi_fp_unspecified) { // The "hardware interpretation" is 0. result = bu.mk_numeral(0, width); - else + return BR_DONE; + } + else { result = m_util.mk_internal_to_sbv_unspecified(ebits, sbits, width); - - return BR_DONE; + return BR_REWRITE1; + } } br_status fpa_rewriter::mk_to_real_unspecified(unsigned ebits, unsigned sbits, expr_ref & result) { - if (m_hi_fp_unspecified) + if (m_hi_fp_unspecified) { // The "hardware interpretation" is 0. result = m_util.au().mk_numeral(rational(0), false); - else + return BR_DONE; + } + else { result = m_util.mk_internal_to_real_unspecified(ebits, sbits); - - return BR_DONE; + return BR_REWRITE1; + } } br_status fpa_rewriter::mk_to_fp(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result) { @@ -776,10 +783,8 @@ br_status fpa_rewriter::mk_to_ubv(func_decl * f, expr * arg1, expr * arg2, expr_ m_util.is_numeral(arg2, v)) { const mpf & x = v.get(); - if (m_fm.is_nan(v) || m_fm.is_inf(v) || m_fm.is_neg(v)) { - mk_to_ubv_unspecified(x.get_ebits(), x.get_sbits(), bv_sz, result); - return BR_REWRITE_FULL; - } + if (m_fm.is_nan(v) || m_fm.is_inf(v) || m_fm.is_neg(v)) + return mk_to_ubv_unspecified(x.get_ebits(), x.get_sbits(), bv_sz, result); bv_util bu(m()); scoped_mpq q(m_fm.mpq_manager()); @@ -789,11 +794,13 @@ br_status fpa_rewriter::mk_to_ubv(func_decl * f, expr * arg1, expr * arg2, expr_ rational ul, ll; ul = m_fm.m_powers2.m1(bv_sz); ll = rational(0); - if (r >= ll && r <= ul) + if (r >= ll && r <= ul) { result = bu.mk_numeral(r, bv_sz); + return BR_DONE; + } else - mk_to_ubv_unspecified(x.get_ebits(), x.get_sbits(), bv_sz, result); - return BR_DONE; + return mk_to_ubv_unspecified(x.get_ebits(), x.get_sbits(), bv_sz, result); + } return BR_FAILED; @@ -810,10 +817,8 @@ br_status fpa_rewriter::mk_to_sbv(func_decl * f, expr * arg1, expr * arg2, expr_ m_util.is_numeral(arg2, v)) { const mpf & x = v.get(); - if (m_fm.is_nan(v) || m_fm.is_inf(v)) { - mk_to_sbv_unspecified(x.get_ebits(), x.get_sbits(), bv_sz, result); - return BR_REWRITE_FULL; - } + if (m_fm.is_nan(v) || m_fm.is_inf(v)) + return mk_to_sbv_unspecified(x.get_ebits(), x.get_sbits(), bv_sz, result); bv_util bu(m()); scoped_mpq q(m_fm.mpq_manager()); @@ -823,46 +828,42 @@ br_status fpa_rewriter::mk_to_sbv(func_decl * f, expr * arg1, expr * arg2, expr_ rational ul, ll; ul = m_fm.m_powers2.m1(bv_sz - 1); ll = - m_fm.m_powers2(bv_sz - 1); - if (r >= ll && r <= ul) + if (r >= ll && r <= ul) { result = bu.mk_numeral(r, bv_sz); + return BR_DONE; + } else - mk_to_sbv_unspecified(x.get_ebits(), x.get_sbits(), bv_sz, result); - return BR_DONE; + return mk_to_sbv_unspecified(x.get_ebits(), x.get_sbits(), bv_sz, result); } return BR_FAILED; } br_status fpa_rewriter::mk_to_ieee_bv(func_decl * f, expr * arg, expr_ref & result) { + TRACE("fp_rewriter", tout << "to_ieee_bv of " << mk_ismt2_pp(arg, m()) << std::endl;); scoped_mpf v(m_fm); if (m_util.is_numeral(arg, v)) { + TRACE("fp_rewriter", tout << "to_ieee_bv numeral: " << m_fm.to_string(v) << std::endl;); bv_util bu(m()); const mpf & x = v.get(); if (m_fm.is_nan(v)) { if (m_hi_fp_unspecified) { - result = bu.mk_concat(bu.mk_numeral(0, 1), - bu.mk_concat(bu.mk_numeral(-1, x.get_ebits()), - bu.mk_concat(bu.mk_numeral(0, x.get_sbits() - 2), - bu.mk_numeral(1, 1)))); + expr * args[4] = { bu.mk_numeral(0, 1), + bu.mk_numeral(-1, x.get_ebits()), + bu.mk_numeral(0, x.get_sbits() - 2), + bu.mk_numeral(1, 1) }; + result = bu.mk_concat(4, args); } - else { - app_ref unspec(m()), mask(m()), extra(m()); - unspec = m_util.mk_internal_to_ieee_bv_unspecified(x.get_ebits(), x.get_sbits()); - mask = bu.mk_concat(bu.mk_numeral(0, 1), - bu.mk_concat(bu.mk_numeral(-1, x.get_ebits()), - bu.mk_concat(bu.mk_numeral(0, x.get_sbits() - 2), - bu.mk_numeral(1, 1)))); - expr * args[2] = { unspec, mask }; - result = m().mk_app(bu.get_fid(), OP_BOR, 2, args); - } - return BR_REWRITE_FULL; + else + result = m_util.mk_internal_to_ieee_bv_unspecified(x.get_ebits(), x.get_sbits()); + + return BR_REWRITE1; } else { scoped_mpz rz(m_fm.mpq_manager()); m_fm.to_ieee_bv_mpz(v, rz); - result = bu.mk_numeral(rational(rz), x.get_ebits() + x.get_sbits()); return BR_DONE; } diff --git a/src/ast/rewriter/fpa_rewriter_params.pyg b/src/ast/rewriter/fpa_rewriter_params.pyg index 85973e744..f0cfbdf55 100644 --- a/src/ast/rewriter/fpa_rewriter_params.pyg +++ b/src/ast/rewriter/fpa_rewriter_params.pyg @@ -1,5 +1,5 @@ def_module_params(module_name='rewriter', class_name='fpa_rewriter_params', export=True, - params=(("hi_fp_unspecified", BOOL, True, "use the 'hardware interpretation' for unspecified values in fp.to_ubv, fp.to_sbv, and fp.to_real"), + params=(("hi_fp_unspecified", BOOL, False, "use the 'hardware interpretation' for unspecified values in fp.to_ubv, fp.to_sbv, fp.to_real, and fp.to_ieee_bv"), )) diff --git a/src/smt/theory_fpa.cpp b/src/smt/theory_fpa.cpp index fec7922c7..288b61748 100644 --- a/src/smt/theory_fpa.cpp +++ b/src/smt/theory_fpa.cpp @@ -715,14 +715,14 @@ namespace smt { fpa2bv_converter::uf2bvuf_t const & uf2bvuf = m_converter.get_uf2bvuf(); for (fpa2bv_converter::uf2bvuf_t::iterator it = uf2bvuf.begin(); - it != uf2bvuf.end(); - it++) { - mg.hide(it->m_value); + it != uf2bvuf.end(); + it++) { + //mg.hide(it->m_value); } fpa2bv_converter::special_t const & specials = m_converter.get_min_max_specials(); for (fpa2bv_converter::special_t::iterator it = specials.begin(); - it != specials.end(); - it++) { + it != specials.end(); + it++) { mg.hide(it->m_value.first->get_decl()); mg.hide(it->m_value.second->get_decl()); } @@ -811,7 +811,25 @@ namespace smt { return res; } - void theory_fpa::finalize_model(model_generator & mg) {} + void theory_fpa::finalize_model(model_generator & mg) { + ast_manager & m = get_manager(); + proto_model & mdl = mg.get_model(); + + fpa2bv_converter::uf2bvuf_t const & uf2bvuf = m_converter.get_uf2bvuf(); + for (fpa2bv_converter::uf2bvuf_t::iterator it = uf2bvuf.begin(); + it != uf2bvuf.end(); + it++) { + func_decl * bv_fd = it->m_value; + if (bv_fd->get_arity() == 0) { + expr_ref bve(m), v(m); + bve = m.mk_const(bv_fd); + mdl.eval(bve, v, true); + mdl.register_decl(it->m_key, v); + } + else + NOT_IMPLEMENTED_YET(); + } + } void theory_fpa::display(std::ostream & out) const { From 58af4cae1452ef1da104122b4fe1f491d19ad08a Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Sat, 15 Oct 2016 17:40:22 +0200 Subject: [PATCH 230/536] More consistent fp.* operators. --- src/ast/fpa_decl_plugin.cpp | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/ast/fpa_decl_plugin.cpp b/src/ast/fpa_decl_plugin.cpp index 6c8b7ac6f..d8bf70e80 100644 --- a/src/ast/fpa_decl_plugin.cpp +++ b/src/ast/fpa_decl_plugin.cpp @@ -665,14 +665,14 @@ func_decl * fpa_decl_plugin::mk_to_real(decl_kind k, unsigned num_parameters, pa func_decl * fpa_decl_plugin::mk_to_ieee_bv(decl_kind k, unsigned num_parameters, parameter const * parameters, unsigned arity, sort * const * domain, sort * range) { if (arity != 1) - m_manager->raise_exception("invalid number of arguments to to_ieee_bv"); + m_manager->raise_exception("invalid number of arguments to fp.to_ieee_bv"); if (!is_float_sort(domain[0])) m_manager->raise_exception("sort mismatch, expected argument of FloatingPoint sort"); unsigned float_sz = domain[0]->get_parameter(0).get_int() + domain[0]->get_parameter(1).get_int(); parameter ps[] = { parameter(float_sz) }; sort * bv_srt = m_bv_plugin->mk_sort(BV_SORT, 1, ps); - symbol name("to_ieee_bv"); + symbol name("fp.to_ieee_bv"); return m_manager->mk_func_decl(name, 1, domain, bv_srt, func_decl_info(m_family_id, k)); } @@ -758,15 +758,15 @@ func_decl * fpa_decl_plugin::mk_internal_to_ieee_bv_unspecified( decl_kind k, unsigned num_parameters, parameter const * parameters, unsigned arity, sort * const * domain, sort * range) { if (arity != 0) - m_manager->raise_exception("invalid number of arguments to to_ieee_bv_unspecified; expecting none"); + m_manager->raise_exception("invalid number of arguments to fp.to_ieee_bv_unspecified; expecting none"); if (num_parameters != 2) - m_manager->raise_exception("invalid number of parameters to to_ieee_bv_unspecified; expecting 2"); + m_manager->raise_exception("invalid number of parameters to fp.to_ieee_bv_unspecified; expecting 2"); if (!parameters[0].is_int() || !parameters[1].is_int()) - m_manager->raise_exception("invalid parameters type provided to to_ieee_bv_unspecified; expecting 2 integers"); + m_manager->raise_exception("invalid parameters type provided to fp.to_ieee_bv_unspecified; expecting 2 integers"); parameter width_p[1] = { parameter(parameters[0].get_int() + parameters[1].get_int()) }; sort * bv_srt = m_bv_plugin->mk_sort(m_bv_fid, 1, width_p); - return m_manager->mk_func_decl(symbol("to_ieee_bv_unspecified"), 0, domain, bv_srt, func_decl_info(m_family_id, k, num_parameters, parameters)); + return m_manager->mk_func_decl(symbol("fp.to_ieee_bv_unspecified"), 0, domain, bv_srt, func_decl_info(m_family_id, k, num_parameters, parameters)); } @@ -915,7 +915,8 @@ void fpa_decl_plugin::get_op_names(svector & op_names, symbol cons op_names.push_back(builtin_name("to_fp_unsigned", OP_FPA_TO_FP_UNSIGNED)); /* Extensions */ - op_names.push_back(builtin_name("to_ieee_bv", OP_FPA_TO_IEEE_BV)); + op_names.push_back(builtin_name("to_ieee_bv", OP_FPA_TO_IEEE_BV)); + op_names.push_back(builtin_name("fp.to_ieee_bv", OP_FPA_TO_IEEE_BV)); } void fpa_decl_plugin::get_sort_names(svector & sort_names, symbol const & logic) { From ab4bb8194ec612f1231c8364c97f15b45f54f1e2 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Sat, 15 Oct 2016 17:40:42 +0200 Subject: [PATCH 231/536] Added unregister_decl to model_core --- src/model/model_core.cpp | 16 ++++++++++++++++ src/model/model_core.h | 1 + 2 files changed, 17 insertions(+) diff --git a/src/model/model_core.cpp b/src/model/model_core.cpp index 3c10f8704..bef2e6494 100644 --- a/src/model/model_core.cpp +++ b/src/model/model_core.cpp @@ -87,3 +87,19 @@ void model_core::register_decl(func_decl * d, func_interp * fi) { } } +void model_core::unregister_decl(func_decl * d) { + decl2expr::obj_map_entry * ec = m_interp.find_core(d); + if (ec && ec->get_data().m_value != 0) { + m_manager.dec_ref(ec->get_data().m_key); + m_manager.dec_ref(ec->get_data().m_value); + m_interp.remove(d); + return; + } + + decl2finterp::obj_map_entry * ef = m_finterp.find_core(d); + if (ef && ef->get_data().m_value != 0) { + m_manager.dec_ref(ef->get_data().m_key); + dealloc(ef->get_data().m_value); + m_finterp.remove(d); + } +} \ No newline at end of file diff --git a/src/model/model_core.h b/src/model/model_core.h index 8527a0bca..371106b05 100644 --- a/src/model/model_core.h +++ b/src/model/model_core.h @@ -60,6 +60,7 @@ public: void register_decl(func_decl * d, expr * v); void register_decl(func_decl * f, func_interp * fi); + void unregister_decl(func_decl * d); virtual expr * get_some_value(sort * s) = 0; From 009af4455d60e0affb376e36f48e3ab42fcf67d0 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Sat, 15 Oct 2016 18:16:44 +0200 Subject: [PATCH 232/536] Refactored and fixed model conversion for fpa2bv conversion of unspecified values via theory_fpa. --- scripts/mk_project.py | 2 +- src/ast/fpa/bv2fpa_converter.cpp | 543 ++++++++++++++++++++++ src/ast/fpa/bv2fpa_converter.h | 74 +++ src/ast/fpa/fpa2bv_converter.cpp | 190 ++++---- src/ast/fpa/fpa2bv_converter.h | 13 +- src/ast/fpa/fpa2bv_rewriter.cpp | 10 +- src/smt/theory_fpa.cpp | 69 ++- src/tactic/fpa/fpa2bv_model_converter.cpp | 468 ++----------------- src/tactic/fpa/fpa2bv_model_converter.h | 92 +--- 9 files changed, 817 insertions(+), 644 deletions(-) create mode 100644 src/ast/fpa/bv2fpa_converter.cpp create mode 100644 src/ast/fpa/bv2fpa_converter.h diff --git a/scripts/mk_project.py b/scripts/mk_project.py index 00b5cdef5..c03d76b5f 100644 --- a/scripts/mk_project.py +++ b/scripts/mk_project.py @@ -45,7 +45,7 @@ def init_project_def(): # Simplifier module will be deleted in the future. # It has been replaced with rewriter module. add_lib('simplifier', ['rewriter'], 'ast/simplifier') - add_lib('fpa', ['ast', 'util', 'simplifier'], 'ast/fpa') + add_lib('fpa', ['ast', 'util', 'simplifier', 'model'], 'ast/fpa') add_lib('macros', ['simplifier'], 'ast/macros') add_lib('pattern', ['normal_forms', 'smt2parser', 'simplifier'], 'ast/pattern') add_lib('bit_blaster', ['rewriter', 'simplifier'], 'ast/rewriter/bit_blaster') diff --git a/src/ast/fpa/bv2fpa_converter.cpp b/src/ast/fpa/bv2fpa_converter.cpp new file mode 100644 index 000000000..fb3af396c --- /dev/null +++ b/src/ast/fpa/bv2fpa_converter.cpp @@ -0,0 +1,543 @@ +/*++ + Copyright (c) 2012 Microsoft Corporation + +Module Name: + + bv2fpa_converter.cpp + +Abstract: + + Model conversion for fpa2bv_converter + +Author: + + Christoph (cwinter) 2016-10-15 + +Notes: + +--*/ +#include + +#include"ast_smt2_pp.h" +#include"well_sorted.h" +#include"th_rewriter.h" +#include"fpa_rewriter.h" + +#include"bv2fpa_converter.h" + + +bv2fpa_converter::bv2fpa_converter(ast_manager & m) : + m(m), + m_fpa_util(m), + m_bv_util(m), + m_th_rw(m) { +} + +bv2fpa_converter::bv2fpa_converter(ast_manager & m, fpa2bv_converter & conv) : + m(m), + m_fpa_util(m), + m_bv_util(m), + m_th_rw(m) { + for (obj_map::iterator it = conv.m_const2bv.begin(); + it != conv.m_const2bv.end(); + it++) + { + m_const2bv.insert(it->m_key, it->m_value); + m.inc_ref(it->m_key); + m.inc_ref(it->m_value); + } + for (obj_map::iterator it = conv.m_rm_const2bv.begin(); + it != conv.m_rm_const2bv.end(); + it++) + { + m_rm_const2bv.insert(it->m_key, it->m_value); + m.inc_ref(it->m_key); + m.inc_ref(it->m_value); + } + for (obj_map::iterator it = conv.m_uf2bvuf.begin(); + it != conv.m_uf2bvuf.end(); + it++) + { + m_uf2bvuf.insert(it->m_key, it->m_value); + m.inc_ref(it->m_key); + m.inc_ref(it->m_value); + } + for (obj_map >::iterator it = conv.m_min_max_specials.begin(); + it != conv.m_min_max_specials.end(); + it++) { + m_specials.insert(it->m_key, it->m_value); + m.inc_ref(it->m_key); + m.inc_ref(it->m_value.first); + m.inc_ref(it->m_value.second); + } +} + +bv2fpa_converter::~bv2fpa_converter() { + dec_ref_map_key_values(m, m_const2bv); + dec_ref_map_key_values(m, m_rm_const2bv); + dec_ref_map_key_values(m, m_uf2bvuf); + for (obj_map >::iterator it = m_specials.begin(); + it != m_specials.end(); + it++) { + m.dec_ref(it->m_key); + m.dec_ref(it->m_value.first); + m.dec_ref(it->m_value.second); + } +} + +expr_ref bv2fpa_converter::convert_bv2fp(sort * s, expr * sgn, expr * exp, expr * sig) { + unsynch_mpz_manager & mpzm = m_fpa_util.fm().mpz_manager(); + unsynch_mpq_manager & mpqm = m_fpa_util.fm().mpq_manager(); + + expr_ref res(m); + mpf fp_val; + + unsigned ebits = m_fpa_util.get_ebits(s); + unsigned sbits = m_fpa_util.get_sbits(s); + + unsigned sgn_sz = 1; + unsigned exp_sz = ebits; + unsigned sig_sz = sbits - 1; + + rational sgn_q(0), sig_q(0), exp_q(0); + + if (sgn) m_bv_util.is_numeral(sgn, sgn_q, sgn_sz); + if (exp) m_bv_util.is_numeral(exp, exp_q, exp_sz); + if (sig) m_bv_util.is_numeral(sig, sig_q, sig_sz); + + // un-bias exponent + rational exp_unbiased_q; + exp_unbiased_q = exp_q - m_fpa_util.fm().m_powers2.m1(ebits - 1); + + mpz sig_z; mpf_exp_t exp_z; + mpzm.set(sig_z, sig_q.to_mpq().numerator()); + exp_z = mpzm.get_int64(exp_unbiased_q.to_mpq().numerator()); + + m_fpa_util.fm().set(fp_val, ebits, sbits, !mpqm.is_zero(sgn_q.to_mpq()), exp_z, sig_z); + + mpzm.del(sig_z); + + res = m_fpa_util.mk_value(fp_val); + + TRACE("bv2fpa", tout << "[" << mk_ismt2_pp(sgn, m) << + " " << mk_ismt2_pp(exp, m) << + " " << mk_ismt2_pp(sig, m) << "] == " << + mk_ismt2_pp(res, m) << std::endl;); + m_fpa_util.fm().del(fp_val); + + return res; +} + +expr_ref bv2fpa_converter::convert_bv2fp(model_core * mc, sort * s, app * bv) { + SASSERT(m_bv_util.is_bv(bv)); + + unsigned ebits = m_fpa_util.get_ebits(s); + unsigned sbits = m_fpa_util.get_sbits(s); + unsigned bv_sz = sbits + ebits; + + expr_ref bv_num(m); + if (m_bv_util.is_numeral(bv)) + bv_num = bv; + else if (!mc->eval(bv->get_decl(), bv_num)) + bv_num = m_bv_util.mk_numeral(0, m_bv_util.get_bv_size(bv)); + + expr_ref sgn(m), exp(m), sig(m); + sgn = m_bv_util.mk_extract(bv_sz - 1, bv_sz - 1, bv_num); + exp = m_bv_util.mk_extract(bv_sz - 2, sbits - 1, bv_num); + sig = m_bv_util.mk_extract(sbits - 2, 0, bv_num); + + expr_ref v_sgn(m), v_exp(m), v_sig(m); + m_th_rw(sgn, v_sgn); + m_th_rw(exp, v_exp); + m_th_rw(sig, v_sig); + + return convert_bv2fp(s, v_sgn, v_exp, v_sig); +} + +expr_ref bv2fpa_converter::convert_bv2rm(expr * bv_rm) { + expr_ref res(m); + rational bv_val(0); + unsigned sz = 0; + + if (m_bv_util.is_numeral(bv_rm, bv_val, sz)) { + SASSERT(bv_val.is_uint64()); + switch (bv_val.get_uint64()) { + case BV_RM_TIES_TO_AWAY: res = m_fpa_util.mk_round_nearest_ties_to_away(); break; + case BV_RM_TIES_TO_EVEN: res = m_fpa_util.mk_round_nearest_ties_to_even(); break; + case BV_RM_TO_NEGATIVE: res = m_fpa_util.mk_round_toward_negative(); break; + case BV_RM_TO_POSITIVE: res = m_fpa_util.mk_round_toward_positive(); break; + case BV_RM_TO_ZERO: + default: res = m_fpa_util.mk_round_toward_zero(); + } + } + + return res; +} + +expr_ref bv2fpa_converter::convert_bv2rm(model_core * mc, app * val) { + expr_ref res(m); + + if (val) { + expr_ref eval_v(m); + if (m_bv_util.is_numeral(val)) + res = convert_bv2rm(val); + else if (mc->eval(val->get_decl(), eval_v)) + res = convert_bv2rm(eval_v); + else + res = m_fpa_util.mk_round_toward_zero(); + } + + return res; +} + +expr_ref bv2fpa_converter::rebuild_floats(model_core * mc, sort * s, app * e) { + expr_ref result(m); + TRACE("bv2fpa", tout << "rebuild floats in " << mk_ismt2_pp(s, m) << " for "; + if (e) tout << mk_ismt2_pp(e, m); + else tout << "nil"; + tout << std::endl; ); + + if (m_fpa_util.is_float(s)) { + if (e == 0) + result = m_fpa_util.mk_pzero(s); + else if (m_fpa_util.is_numeral(e)) + result = e; + else { + SASSERT(m_bv_util.is_bv(e) && m_bv_util.get_bv_size(e) == (m_fpa_util.get_ebits(s) + m_fpa_util.get_sbits(s))); + result = convert_bv2fp(mc, s, e); + } + } + else if (m_fpa_util.is_rm(s)) { + if (e == 0) + result = m_fpa_util.mk_round_toward_zero(); + else if (m_fpa_util.is_rm_numeral(e)) + result = e; + else { + SASSERT(m_bv_util.is_bv(e) && m_bv_util.get_bv_size(e) == 3); + result = convert_bv2rm(mc, e); + } + } + else if (is_app(e)) { + app * a = to_app(e); + expr_ref_vector new_args(m); + for (unsigned i = 0; i < a->get_num_args(); i++) + new_args.push_back(rebuild_floats(mc, a->get_decl()->get_domain()[i], to_app(a->get_arg(i)))); + result = m.mk_app(a->get_decl(), new_args.size(), new_args.c_ptr()); + } + + return result; +} + +bv2fpa_converter::array_model bv2fpa_converter::convert_array_func_interp(model_core * mc, func_decl * f, func_decl * bv_f) { + SASSERT(f->get_arity() == 0); + array_util arr_util(m); + + array_model am(m); + sort_ref_vector array_domain(m); + unsigned arity = f->get_range()->get_num_parameters()-1; + + expr_ref as_arr_mdl(m); + as_arr_mdl = mc->get_const_interp(bv_f); + if (as_arr_mdl == 0) return am; + TRACE("bv2fpa", tout << "arity=0 func_interp for " << mk_ismt2_pp(f, m) << " := " << mk_ismt2_pp(as_arr_mdl, m) << std::endl;); + SASSERT(arr_util.is_as_array(as_arr_mdl)); + for (unsigned i = 0; i < arity; i++) + array_domain.push_back(to_sort(f->get_range()->get_parameter(i).get_ast())); + sort * rng = to_sort(f->get_range()->get_parameter(arity).get_ast()); + + bv_f = arr_util.get_as_array_func_decl(to_app(as_arr_mdl)); + + am.new_float_fd = m.mk_fresh_func_decl(arity, array_domain.c_ptr(), rng); + am.new_float_fi = convert_func_interp(mc, am.new_float_fd, bv_f); + am.bv_fd = bv_f; + am.result = arr_util.mk_as_array(f->get_range(), am.new_float_fd); + return am; +} + +func_interp * bv2fpa_converter::convert_func_interp(model_core * mc, func_decl * f, func_decl * bv_f) { + SASSERT(f->get_arity() > 0); + func_interp * result = 0; + sort * rng = f->get_range(); + sort * const * dmn = f->get_domain(); + + unsigned arity = bv_f->get_arity(); + func_interp * bv_fi = mc->get_func_interp(bv_f); + + if (bv_fi != 0) { + fpa_rewriter rw(m); + expr_ref ai(m); + result = alloc(func_interp, m, arity); + + for (unsigned i = 0; i < bv_fi->num_entries(); i++) { + func_entry const * bv_fe = bv_fi->get_entry(i); + expr * const * bv_args = bv_fe->get_args(); + expr_ref_buffer new_args(m); + + for (unsigned j = 0; j < arity; j++) { + sort * ft_dj = dmn[j]; + expr * bv_aj = bv_args[j]; + ai = rebuild_floats(mc, ft_dj, to_app(bv_aj)); + m_th_rw(ai); + new_args.push_back(ai); + } + + expr_ref bv_fres(m), ft_fres(m); + bv_fres = bv_fe->get_result(); + ft_fres = rebuild_floats(mc, rng, to_app(bv_fres)); + m_th_rw(ft_fres); + result->insert_new_entry(new_args.c_ptr(), ft_fres); + } + + app_ref bv_els(m); + expr_ref ft_els(m); + bv_els = (app*)bv_fi->get_else(); + ft_els = rebuild_floats(mc, rng, bv_els); + m_th_rw(ft_els); + result->set_else(ft_els); + } + + return result; +} + +void bv2fpa_converter::convert_consts(model_core * mc, model_core * target_model, obj_hashtable & seen) { + for (obj_map::iterator it = m_const2bv.begin(); + it != m_const2bv.end(); + it++) + { + func_decl * var = it->m_key; + app * val = to_app(it->m_value); + SASSERT(m_fpa_util.is_float(var->get_range())); + SASSERT(var->get_range()->get_num_parameters() == 2); + unsigned ebits = m_fpa_util.get_ebits(var->get_range()); + unsigned sbits = m_fpa_util.get_sbits(var->get_range()); + + app * a0 = to_app(val->get_arg(0)); + app * a1 = to_app(val->get_arg(1)); + app * a2 = to_app(val->get_arg(2)); + + expr_ref v0(m), v1(m), v2(m); + v0 = mc->get_const_interp(a0->get_decl()); + v1 = mc->get_const_interp(a1->get_decl()); + v2 = mc->get_const_interp(a2->get_decl()); + + if (!v0) v0 = m_bv_util.mk_numeral(0, 1); + if (!v1) v1 = m_bv_util.mk_numeral(0, ebits); + if (!v2) v2 = m_bv_util.mk_numeral(0, sbits-1); + + expr_ref sgn(m), exp(m), sig(m); + m_th_rw(v0, sgn); + m_th_rw(v1, exp); + m_th_rw(v2, sig); + + SASSERT(val->is_app_of(m_fpa_util.get_family_id(), OP_FPA_FP)); + +#ifdef Z3DEBUG + SASSERT(to_app(val->get_arg(0))->get_decl()->get_arity() == 0); + SASSERT(to_app(val->get_arg(1))->get_decl()->get_arity() == 0); + SASSERT(to_app(val->get_arg(2))->get_decl()->get_arity() == 0); + seen.insert(to_app(val->get_arg(0))->get_decl()); + seen.insert(to_app(val->get_arg(1))->get_decl()); + seen.insert(to_app(val->get_arg(2))->get_decl()); +#else + SASSERT(a->get_arg(0)->get_kind() == OP_EXTRACT); + SASSERT(to_app(a->get_arg(0))->get_arg(0)->get_kind() == OP_EXTRACT); + seen.insert(to_app(to_app(val->get_arg(0))->get_arg(0))->get_decl()); +#endif + + if (!sgn && !sig && !exp) + continue; + + expr_ref cv(m); + cv = convert_bv2fp(var->get_range(), sgn, exp, sig); + target_model->register_decl(var, cv); + + TRACE("bv2fpa", tout << var->get_name() << " == " << mk_ismt2_pp(cv, m) << std::endl;); + } +} + +void bv2fpa_converter::convert_rm_consts(model_core * mc, model_core * target_model, obj_hashtable & seen) { + for (obj_map::iterator it = m_rm_const2bv.begin(); + it != m_rm_const2bv.end(); + it++) + { + func_decl * var = it->m_key; + SASSERT(m_fpa_util.is_rm(var->get_range())); + expr * val = it->m_value; + SASSERT(m_fpa_util.is_bv2rm(val)); + expr * bvval = to_app(val)->get_arg(0); + expr_ref fv(m); + fv = convert_bv2rm(mc, to_app(bvval)); + TRACE("bv2fpa", tout << var->get_name() << " == " << mk_ismt2_pp(fv, m) << ")" << std::endl;); + target_model->register_decl(var, fv); + seen.insert(to_app(bvval)->get_decl()); + } +} + +void bv2fpa_converter::convert_min_max_specials(model_core * mc, model_core * target_model, obj_hashtable & seen) { + for (obj_map >::iterator it = m_specials.begin(); + it != m_specials.end(); + it++) { + func_decl * f = it->m_key; + app * pn_cnst = it->m_value.first; + app * np_cnst = it->m_value.second; + + expr_ref pzero(m), nzero(m); + pzero = m_fpa_util.mk_pzero(f->get_range()); + nzero = m_fpa_util.mk_nzero(f->get_range()); + + expr_ref pn(m), np(m); + if (!mc->eval(pn_cnst->get_decl(), pn)) pn = pzero; + if (!mc->eval(np_cnst->get_decl(), np)) np = pzero; + seen.insert(pn_cnst->get_decl()); + seen.insert(np_cnst->get_decl()); + + rational pn_num, np_num; + unsigned bv_sz; + m_bv_util.is_numeral(pn, pn_num, bv_sz); + m_bv_util.is_numeral(np, np_num, bv_sz); + + func_interp * flt_fi = alloc(func_interp, m, f->get_arity()); + expr * pn_args[2] = { pzero, nzero }; + if (pn != np) flt_fi->insert_new_entry(pn_args, (pn_num.is_one() ? nzero : pzero)); + flt_fi->set_else(np_num.is_one() ? nzero : pzero); + + target_model->register_decl(f, flt_fi); + TRACE("bv2fpa", tout << "fp.min/fp.max special: " << std::endl << + mk_ismt2_pp(f, m) << " == " << mk_ismt2_pp(flt_fi->get_interp(), m) << std::endl;); + } +} + +void bv2fpa_converter::convert_uf2bvuf(model_core * mc, model_core * target_model, obj_hashtable & seen) { + for (obj_map::iterator it = m_uf2bvuf.begin(); + it != m_uf2bvuf.end(); + it++) { + seen.insert(it->m_value); + + func_decl * f = it->m_key; + if (f->get_arity() == 0) + { + array_util au(m); + if (au.is_array(f->get_range())) { + array_model am = convert_array_func_interp(mc, f, it->m_value); + if (am.new_float_fd) target_model->register_decl(am.new_float_fd, am.new_float_fi); + if (am.result) target_model->register_decl(f, am.result); + if (am.bv_fd) seen.insert(am.bv_fd); + } + else { + // Just keep. + SASSERT(!m_fpa_util.is_float(f->get_range()) && !m_fpa_util.is_rm(f->get_range())); + expr_ref var(m), val(m); + if (mc->eval(it->m_value, val)) + target_model->register_decl(f, val); + } + } + else { + func_interp * fmv = convert_func_interp(mc, f, it->m_value); + if (fmv) target_model->register_decl(f, fmv); + } + } +} + +void bv2fpa_converter::display(std::ostream & out) { + out << "(fpa2bv-model-converter"; + for (obj_map::iterator it = m_const2bv.begin(); + it != m_const2bv.end(); + it++) { + const symbol & n = it->m_key->get_name(); + out << "\n (" << n << " "; + unsigned indent = n.size() + 4; + out << mk_ismt2_pp(it->m_value, m, indent) << ")"; + } + for (obj_map::iterator it = m_rm_const2bv.begin(); + it != m_rm_const2bv.end(); + it++) { + const symbol & n = it->m_key->get_name(); + out << "\n (" << n << " "; + unsigned indent = n.size() + 4; + out << mk_ismt2_pp(it->m_value, m, indent) << ")"; + } + for (obj_map::iterator it = m_uf2bvuf.begin(); + it != m_uf2bvuf.end(); + it++) { + const symbol & n = it->m_key->get_name(); + out << "\n (" << n << " "; + unsigned indent = n.size() + 4; + out << mk_ismt2_pp(it->m_value, m, indent) << ")"; + } + for (obj_map >::iterator it = m_specials.begin(); + it != m_specials.end(); + it++) { + const symbol & n = it->m_key->get_name(); + out << "\n (" << n << " "; + unsigned indent = n.size() + 4; + out << mk_ismt2_pp(it->m_value.first, m, indent) << "; " << + mk_ismt2_pp(it->m_value.second, m, indent) << ")"; + } + out << ")"; +} + +bv2fpa_converter * bv2fpa_converter::translate(ast_translation & translator) { + bv2fpa_converter * res = alloc(bv2fpa_converter, translator.to()); + for (obj_map::iterator it = m_const2bv.begin(); + it != m_const2bv.end(); + it++) + { + func_decl * k = translator(it->m_key); + expr * v = translator(it->m_value); + res->m_const2bv.insert(k, v); + translator.to().inc_ref(k); + translator.to().inc_ref(v); + } + for (obj_map::iterator it = m_rm_const2bv.begin(); + it != m_rm_const2bv.end(); + it++) + { + func_decl * k = translator(it->m_key); + expr * v = translator(it->m_value); + res->m_rm_const2bv.insert(k, v); + translator.to().inc_ref(k); + translator.to().inc_ref(v); + } + for (obj_map::iterator it = m_uf2bvuf.begin(); + it != m_uf2bvuf.end(); + it++) { + func_decl * k = translator(it->m_key); + func_decl * v = translator(it->m_value); + res->m_uf2bvuf.insert(k, v); + translator.to().inc_ref(k); + translator.to().inc_ref(v); + } + for (obj_map >::iterator it = m_specials.begin(); + it != m_specials.end(); + it++) { + func_decl * k = translator(it->m_key); + app * v1 = translator(it->m_value.first); + app * v2 = translator(it->m_value.second); + res->m_specials.insert(k, std::pair(v1, v2)); + translator.to().inc_ref(k); + translator.to().inc_ref(v1); + translator.to().inc_ref(v2); + } + return res; +} + +void bv2fpa_converter::convert(model_core * mc, model_core * float_mdl) { + TRACE("bv2fpa", tout << "BV Model: " << std::endl; + for (unsigned i = 0; i < mc->get_num_constants(); i++) + tout << mc->get_constant(i)->get_name() << " --> " << + mk_ismt2_pp(mc->get_const_interp(mc->get_constant(i)), m) << std::endl; + for (unsigned i = 0; i < mc->get_num_functions(); i++) { + func_decl * f = mc->get_function(i); + tout << f->get_name() << "(...) := " << std::endl; + func_interp * fi = mc->get_func_interp(f); + for (unsigned j = 0; j < fi->num_entries(); j++) { + func_entry const * fe = fi->get_entry(j); + for (unsigned k = 0; k < f->get_arity(); k++) { + tout << mk_ismt2_pp(fe->get_arg(k), m) << " "; + } + tout << "--> " << mk_ismt2_pp(fe->get_result(), m) << std::endl; + } + tout << "else " << mk_ismt2_pp(fi->get_else(), m) << std::endl; + }); + +} \ No newline at end of file diff --git a/src/ast/fpa/bv2fpa_converter.h b/src/ast/fpa/bv2fpa_converter.h new file mode 100644 index 000000000..c441ea6ff --- /dev/null +++ b/src/ast/fpa/bv2fpa_converter.h @@ -0,0 +1,74 @@ +/*++ + Copyright (c) 2016 Microsoft Corporation + +Module Name: + + bv2fpa_converter.h + +Abstract: + + Model conversion for fpa2bv_converter + +Author: + + Christoph (cwinter) 2016-10-15 + +Notes: + +--*/ +#ifndef BV2FPA_CONVERTER_H_ +#define BV2FPA_CONVERTER_H_ + +#include"fpa_decl_plugin.h" +#include"bv_decl_plugin.h" +#include"th_rewriter.h" +#include"model_core.h" +#include"fpa2bv_converter.h" + + +class bv2fpa_converter { + ast_manager & m; + fpa_util m_fpa_util; + bv_util m_bv_util; + th_rewriter m_th_rw; + + obj_map m_const2bv; + obj_map m_rm_const2bv; + obj_map m_uf2bvuf; + obj_map > m_specials; + +public: + bv2fpa_converter(ast_manager & m); + bv2fpa_converter(ast_manager & m, fpa2bv_converter & conv); + virtual ~bv2fpa_converter(); + + void display(std::ostream & out); + bv2fpa_converter * translate(ast_translation & translator); + + expr_ref convert_bv2fp(sort * s, expr * sgn, expr * exp, expr * sig); + expr_ref convert_bv2fp(model_core * mc, sort * s, app * bv); + expr_ref convert_bv2rm(expr * eval_v); + expr_ref convert_bv2rm(model_core * mc, app * val); + + void convert(model_core * mc, model_core * float_mdl); + void convert_consts(model_core * mc, model_core * target_model, obj_hashtable & seen); + void convert_rm_consts(model_core * mc, model_core * target_model, obj_hashtable & seen); + void convert_min_max_specials(model_core * mc, model_core * target_model, obj_hashtable & seen); + void convert_uf2bvuf(model_core * mc, model_core * target_model, obj_hashtable & seen); + + func_interp * convert_func_interp(model_core * mc, func_decl * f, func_decl * bv_f); + expr_ref rebuild_floats(model_core * mc, sort * s, app * e); + + class array_model { + public: + func_decl * new_float_fd; + func_interp * new_float_fi; + func_decl * bv_fd; + expr_ref result; + array_model(ast_manager & m) : new_float_fd(0), new_float_fi(0), bv_fd(0), result(m) {} + }; + + array_model convert_array_func_interp(model_core * mc, func_decl * f, func_decl * bv_f); +}; + +#endif \ No newline at end of file diff --git a/src/ast/fpa/fpa2bv_converter.cpp b/src/ast/fpa/fpa2bv_converter.cpp index 8db839e24..05c45c925 100644 --- a/src/ast/fpa/fpa2bv_converter.cpp +++ b/src/ast/fpa/fpa2bv_converter.cpp @@ -23,6 +23,7 @@ Notes: #include"th_rewriter.h" #include"fpa2bv_converter.h" +#include"fpa_rewriter.h" #define BVULT(X,Y,R) { expr_ref bvult_eq(m), bvult_not(m); m_simp.mk_eq(X, Y, bvult_eq); m_simp.mk_not(bvult_eq, bvult_not); expr_ref t(m); t = m_bv_util.mk_ule(X,Y); m_simp.mk_and(t, bvult_not, R); } @@ -32,7 +33,6 @@ fpa2bv_converter::fpa2bv_converter(ast_manager & m) : m_util(m), m_bv_util(m), m_arith_util(m), - m_array_util(m), m_dt_util(m), m_seq_util(m), m_mpf_manager(m_util.fm()), @@ -2771,6 +2771,7 @@ void fpa2bv_converter::mk_to_real(func_decl * f, unsigned num, expr * const * ar expr_ref unspec(m); unspec = mk_to_real_unspecified(ebits, sbits); + result = m.mk_ite(x_is_zero, zero, res); result = m.mk_ite(x_is_inf, unspec, result); result = m.mk_ite(x_is_nan, unspec, result); @@ -3073,11 +3074,9 @@ void fpa2bv_converter::mk_to_ieee_bv(func_decl * f, unsigned num, expr * const * m_bv_util.mk_concat(m_bv_util.mk_numeral(0, sbits - 2), m_bv_util.mk_numeral(1, 1)))); else { - expr_ref unspec_bits(m); - unspec_bits = m_util.mk_internal_to_ieee_bv_unspecified(ebits, sbits); - nanv = m_bv_util.mk_concat(m_bv_util.mk_extract(sbits-1, sbits-1, unspec_bits), - m_bv_util.mk_concat(m_bv_util.mk_numeral(-1, ebits), - m_bv_util.mk_extract(sbits-2, 0, unspec_bits))); + app_ref unspec(m); + unspec = m_util.mk_internal_to_ieee_bv_unspecified(ebits, sbits); + mk_to_ieee_bv_unspecified(unspec->get_decl(), 0, 0, nanv); } expr_ref sgn_e_s(m); @@ -3127,39 +3126,42 @@ void fpa2bv_converter::mk_to_ieee_bv_unspecified(func_decl * f, unsigned num, ex } void fpa2bv_converter::mk_to_bv(func_decl * f, unsigned num, expr * const * args, bool is_signed, expr_ref & result) { - TRACE("fpa2bv_to_bv", for (unsigned i = 0; i < num; i++) - tout << "arg" << i << " = " << mk_ismt2_pp(args[i], m) << std::endl;); + TRACE("fpa2bv_to_bv", for (unsigned i = 0; i < num; i++) + tout << "arg" << i << " = " << mk_ismt2_pp(args[i], m) << std::endl;); - SASSERT(num == 2); - SASSERT(m_util.is_bv2rm(args[0])); - SASSERT(m_util.is_float(args[1])); + SASSERT(num == 2); + SASSERT(m_util.is_bv2rm(args[0])); + SASSERT(m_util.is_float(args[1])); - expr * rm = to_app(args[0])->get_arg(0); - expr * x = args[1]; - sort * xs = m.get_sort(x); - sort * bv_srt = f->get_range(); + expr * rm = to_app(args[0])->get_arg(0); + expr * x = args[1]; + sort * xs = m.get_sort(x); + sort * bv_srt = f->get_range(); - unsigned ebits = m_util.get_ebits(xs); - unsigned sbits = m_util.get_sbits(xs); - unsigned bv_sz = (unsigned)f->get_parameter(0).get_int(); + unsigned ebits = m_util.get_ebits(xs); + unsigned sbits = m_util.get_sbits(xs); + unsigned bv_sz = (unsigned)f->get_parameter(0).get_int(); - expr_ref bv0(m), bv1(m); - bv1 = m_bv_util.mk_numeral(1, 1); + expr_ref bv0(m), bv1(m); + bv1 = m_bv_util.mk_numeral(1, 1); - expr_ref x_is_nan(m), x_is_inf(m), x_is_zero(m), x_is_neg(m), x_is_nzero(m); - mk_is_nan(x, x_is_nan); - mk_is_inf(x, x_is_inf); - mk_is_zero(x, x_is_zero); - mk_is_neg(x, x_is_neg); - mk_is_nzero(x, x_is_nzero); + expr_ref x_is_nan(m), x_is_inf(m), x_is_zero(m), x_is_neg(m), x_is_nzero(m); + mk_is_nan(x, x_is_nan); + mk_is_inf(x, x_is_inf); + mk_is_zero(x, x_is_zero); + mk_is_neg(x, x_is_neg); + mk_is_nzero(x, x_is_nzero); - // NaN, Inf, or negative (except -0) -> unspecified - expr_ref c1(m), v1(m); - if (!is_signed) - c1 = m.mk_or(x_is_nan, x_is_inf, m.mk_and(x_is_neg, m.mk_not(x_is_nzero))); - else - c1 = m.mk_or(x_is_nan, x_is_inf); - v1 = mk_to_ubv_unspecified(ebits, sbits, bv_sz); + // NaN, Inf, or negative (except -0) -> unspecified + expr_ref c1(m), v1(m); + if (!is_signed) { + c1 = m.mk_or(x_is_nan, x_is_inf, m.mk_and(x_is_neg, m.mk_not(x_is_nzero))); + v1 = mk_to_ubv_unspecified(ebits, sbits, bv_sz); + } + else { + c1 = m.mk_or(x_is_nan, x_is_inf); + v1 = mk_to_sbv_unspecified(ebits, sbits, bv_sz); + } dbg_decouple("fpa2bv_to_bv_c1", c1); // +-Zero -> 0 @@ -3269,7 +3271,8 @@ void fpa2bv_converter::mk_to_bv(func_decl * f, unsigned num, expr * const * args dbg_decouple("fpa2bv_to_bv_rnd", rnd); expr_ref unspec(m); - unspec = mk_to_ubv_unspecified(ebits, sbits, bv_sz); + unspec = is_signed ? mk_to_sbv_unspecified(ebits, sbits, bv_sz) : + mk_to_ubv_unspecified(ebits, sbits, bv_sz); result = m.mk_ite(rnd_has_overflown, unspec, rnd); result = m.mk_ite(c_in_limits, result, unspec); result = m.mk_ite(c2, v2, result); @@ -3290,70 +3293,89 @@ void fpa2bv_converter::mk_to_sbv(func_decl * f, unsigned num, expr * const * arg mk_to_bv(f, num, args, true, result); } +void fpa2bv_converter::mk_to_ubv_unspecified(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { + SASSERT(num == 0); + unsigned ebits = f->get_parameter(0).get_int(); + unsigned sbits = f->get_parameter(1).get_int(); + unsigned width = m_bv_util.get_bv_size(f->get_range()); + + if (m_hi_fp_unspecified) + result = m_bv_util.mk_numeral(0, width); + else { + func_decl * fd; + if (!m_uf2bvuf.find(f, fd)) { + fd = m.mk_fresh_func_decl(0, 0, 0, f->get_range()); + m_uf2bvuf.insert(f, fd); + m.inc_ref(f); + m.inc_ref(fd); + } + result = m.mk_const(fd); + } + + TRACE("fpa2bv_to_ubv_unspecified", tout << "result=" << mk_ismt2_pp(result, m) << std::endl;); + SASSERT(is_well_sorted(m, result)); +} + expr_ref fpa2bv_converter::mk_to_ubv_unspecified(unsigned ebits, unsigned sbits, unsigned width) { - expr_ref result(m); - if (m_hi_fp_unspecified) - result = m_bv_util.mk_numeral(0, width); - else { - app_ref unspec(m); - unspec = m_util.mk_internal_to_ubv_unspecified(ebits, sbits, width); - func_decl * unspec_fd = unspec->get_decl(); - func_decl * fd; - if (!m_uf2bvuf.find(unspec_fd, fd)) { - app_ref bvc(m); - bvc = m.mk_fresh_const(0, unspec_fd->get_range()); - fd = bvc->get_decl(); - m_uf2bvuf.insert(unspec_fd, fd); - m.inc_ref(unspec_fd); - m.inc_ref(fd); - } - result = m.mk_const(fd); - } - return result; + expr_ref res(m); + app_ref u(m); + u = m_util.mk_internal_to_ubv_unspecified(ebits, sbits, width); + mk_to_sbv_unspecified(u->get_decl(), 0, 0, res); + return res; +} + +void fpa2bv_converter::mk_to_sbv_unspecified(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { + SASSERT(num == 0); + unsigned ebits = f->get_parameter(0).get_int(); + unsigned sbits = f->get_parameter(1).get_int(); + unsigned width = m_bv_util.get_bv_size(f->get_range()); + + if (m_hi_fp_unspecified) + result = m_bv_util.mk_numeral(0, width); + else { + func_decl * fd; + if (!m_uf2bvuf.find(f, fd)) { + fd = m.mk_fresh_func_decl(0, 0, 0, f->get_range()); + m_uf2bvuf.insert(f, fd); + m.inc_ref(f); + m.inc_ref(fd); + } + result = m.mk_const(fd); + } + + TRACE("fpa2bv_to_sbv_unspecified", tout << "result=" << mk_ismt2_pp(result, m) << std::endl;); + SASSERT(is_well_sorted(m, result)); } expr_ref fpa2bv_converter::mk_to_sbv_unspecified(unsigned ebits, unsigned sbits, unsigned width) { - expr_ref result(m); - if (m_hi_fp_unspecified) - result = m_bv_util.mk_numeral(0, width); - else { - app_ref unspec(m); - unspec = m_util.mk_internal_to_sbv_unspecified(ebits, sbits, width); - func_decl * unspec_fd = unspec->get_decl(); - func_decl * fd; - if (!m_uf2bvuf.find(unspec_fd, fd)) { - app_ref bvc(m); - bvc = m.mk_fresh_const(0, unspec_fd->get_range()); - fd = bvc->get_decl(); - m_uf2bvuf.insert(unspec_fd, fd); - m.inc_ref(unspec_fd); - m.inc_ref(fd); - } - result = m.mk_const(fd); - } - return result; + expr_ref res(m); + app_ref u(m); + u = m_util.mk_internal_to_sbv_unspecified(ebits, sbits, width); + mk_to_sbv_unspecified(u->get_decl(), 0, 0, res); + return res; } -expr_ref fpa2bv_converter::mk_to_real_unspecified(unsigned ebits, unsigned sbits) { - expr_ref result(m); +void fpa2bv_converter::mk_to_real_unspecified(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { if (m_hi_fp_unspecified) result = m_arith_util.mk_numeral(rational(0), false); else { - app_ref unspec(m); - unspec = m_util.mk_internal_to_real_unspecified(ebits, sbits); - func_decl * unspec_fd = unspec->get_decl(); func_decl * fd; - if (!m_uf2bvuf.find(unspec_fd, fd)) { - app_ref bvc(m); - bvc = m.mk_fresh_const(0, unspec_fd->get_range()); - fd = bvc->get_decl(); - m_uf2bvuf.insert(unspec_fd, fd); - m.inc_ref(unspec_fd); + if (!m_uf2bvuf.find(f, fd)) { + fd = m.mk_fresh_func_decl(0, 0, 0, f->get_range()); + m_uf2bvuf.insert(f, fd); + m.inc_ref(f); m.inc_ref(fd); } result = m.mk_const(fd); } - return result; +} + +expr_ref fpa2bv_converter::mk_to_real_unspecified(unsigned ebits, unsigned sbits) { + expr_ref res(m); + app_ref u(m); + u = m_util.mk_internal_to_real_unspecified(ebits, sbits); + mk_to_real_unspecified(u->get_decl(), 0, 0, res); + return res; } void fpa2bv_converter::mk_fp(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { diff --git a/src/ast/fpa/fpa2bv_converter.h b/src/ast/fpa/fpa2bv_converter.h index 4fcfe42f6..247cfcacb 100644 --- a/src/ast/fpa/fpa2bv_converter.h +++ b/src/ast/fpa/fpa2bv_converter.h @@ -43,7 +43,6 @@ protected: fpa_util m_util; bv_util m_bv_util; arith_util m_arith_util; - array_util m_array_util; datatype_util m_dt_util; seq_util m_seq_util; mpf_manager & m_mpf_manager; @@ -57,6 +56,7 @@ protected: special_t m_min_max_specials; friend class fpa2bv_model_converter; + friend class bv2fpa_converter; public: fpa2bv_converter(ast_manager & m); @@ -138,8 +138,11 @@ public: void mk_to_fp_real_int(func_decl * f, unsigned num, expr * const * args, expr_ref & result); void mk_to_ubv(func_decl * f, unsigned num, expr * const * args, expr_ref & result); + void mk_to_ubv_unspecified(func_decl * f, unsigned num, expr * const * args, expr_ref & result); void mk_to_sbv(func_decl * f, unsigned num, expr * const * args, expr_ref & result); + void mk_to_sbv_unspecified(func_decl * f, unsigned num, expr * const * args, expr_ref & result); void mk_to_real(func_decl * f, unsigned num, expr * const * args, expr_ref & result); + void mk_to_real_unspecified(func_decl * f, unsigned num, expr * const * args, expr_ref & result); void set_unspecified_fp_hi(bool v) { m_hi_fp_unspecified = v; } @@ -150,10 +153,6 @@ public: void mk_max(func_decl * f, unsigned num, expr * const * args, expr_ref & result); void mk_max_i(func_decl * f, unsigned num, expr * const * args, expr_ref & result); - expr_ref mk_to_ubv_unspecified(unsigned ebits, unsigned sbits, unsigned width); - expr_ref mk_to_sbv_unspecified(unsigned ebits, unsigned sbits, unsigned width); - expr_ref mk_to_real_unspecified(unsigned ebits, unsigned sbits); - void reset(void); void dbg_decouple(const char * prefix, expr_ref & e); @@ -227,6 +226,10 @@ private: void mk_round_to_integral(sort * s, expr_ref & rm, expr_ref & x, expr_ref & result); void mk_to_fp_float(sort * s, expr * rm, expr * x, expr_ref & result); + + expr_ref mk_to_ubv_unspecified(unsigned ebits, unsigned sbits, unsigned width); + expr_ref mk_to_sbv_unspecified(unsigned ebits, unsigned sbits, unsigned width); + expr_ref mk_to_real_unspecified(unsigned ebits, unsigned sbits); }; #endif diff --git a/src/ast/fpa/fpa2bv_rewriter.cpp b/src/ast/fpa/fpa2bv_rewriter.cpp index 6d4f24856..725c0b043 100644 --- a/src/ast/fpa/fpa2bv_rewriter.cpp +++ b/src/ast/fpa/fpa2bv_rewriter.cpp @@ -143,9 +143,12 @@ br_status fpa2bv_rewriter_cfg::reduce_app(func_decl * f, unsigned num, expr * co case OP_FPA_TO_FP_UNSIGNED: m_conv.mk_to_fp_unsigned(f, num, args, result); return BR_DONE; case OP_FPA_FP: m_conv.mk_fp(f, num, args, result); return BR_DONE; case OP_FPA_TO_UBV: m_conv.mk_to_ubv(f, num, args, result); return BR_DONE; + case OP_FPA_INTERNAL_TO_UBV_UNSPECIFIED: m_conv.mk_to_ubv_unspecified(f, num, args, result); return BR_DONE; case OP_FPA_TO_SBV: m_conv.mk_to_sbv(f, num, args, result); return BR_DONE; + case OP_FPA_INTERNAL_TO_SBV_UNSPECIFIED: m_conv.mk_to_sbv_unspecified(f, num, args, result); return BR_DONE; case OP_FPA_TO_REAL: m_conv.mk_to_real(f, num, args, result); return BR_DONE; - case OP_FPA_TO_IEEE_BV: m_conv.mk_to_ieee_bv(f, num, args, result); return BR_REWRITE_FULL; + case OP_FPA_INTERNAL_TO_REAL_UNSPECIFIED: m_conv.mk_to_real_unspecified(f, num, args, result); return BR_DONE; + case OP_FPA_TO_IEEE_BV: m_conv.mk_to_ieee_bv(f, num, args, result); return BR_DONE; case OP_FPA_INTERNAL_TO_IEEE_BV_UNSPECIFIED: m_conv.mk_to_ieee_bv_unspecified(f, num, args, result); return BR_DONE; case OP_FPA_MIN: m_conv.mk_min(f, num, args, result); return BR_REWRITE_FULL; @@ -158,11 +161,8 @@ br_status fpa2bv_rewriter_cfg::reduce_app(func_decl * f, unsigned num, expr * co case OP_FPA_INTERNAL_BVWRAP: case OP_FPA_INTERNAL_BV2RM: - - case OP_FPA_INTERNAL_TO_REAL_UNSPECIFIED: - case OP_FPA_INTERNAL_TO_UBV_UNSPECIFIED: - case OP_FPA_INTERNAL_TO_SBV_UNSPECIFIED: return BR_FAILED; + default: TRACE("fpa2bv", tout << "unsupported operator: " << f->get_name() << "\n"; for (unsigned i = 0; i < num; i++) tout << mk_ismt2_pp(args[i], m()) << std::endl;); diff --git a/src/smt/theory_fpa.cpp b/src/smt/theory_fpa.cpp index 288b61748..248d5b84d 100644 --- a/src/smt/theory_fpa.cpp +++ b/src/smt/theory_fpa.cpp @@ -21,6 +21,7 @@ Revision History: #include"theory_fpa.h" #include"theory_bv.h" #include"smt_model_generator.h" +#include"bv2fpa_converter.h" namespace smt { @@ -83,15 +84,15 @@ namespace smt { } } - theory_fpa::theory_fpa(ast_manager & m) : - theory(m.mk_family_id("fpa")), - m_converter(m, this), - m_rw(m, m_converter, params_ref()), - m_th_rw(m), - m_trail_stack(*this), - m_fpa_util(m_converter.fu()), - m_bv_util(m_converter.bu()), - m_arith_util(m_converter.au()), + theory_fpa::theory_fpa(ast_manager & m) : + theory(m.mk_family_id("fpa")), + m_converter(m, this), + m_rw(m, m_converter, params_ref()), + m_th_rw(m), + m_trail_stack(*this), + m_fpa_util(m_converter.fu()), + m_bv_util(m_converter.bu()), + m_arith_util(m_converter.au()), m_is_initialized(false) { params_ref p; @@ -712,20 +713,6 @@ namespace smt { ast_manager & m = get_manager(); m_factory = alloc(fpa_value_factory, m, get_family_id()); mg.register_factory(m_factory); - - fpa2bv_converter::uf2bvuf_t const & uf2bvuf = m_converter.get_uf2bvuf(); - for (fpa2bv_converter::uf2bvuf_t::iterator it = uf2bvuf.begin(); - it != uf2bvuf.end(); - it++) { - //mg.hide(it->m_value); - } - fpa2bv_converter::special_t const & specials = m_converter.get_min_max_specials(); - for (fpa2bv_converter::special_t::iterator it = specials.begin(); - it != specials.end(); - it++) { - mg.hide(it->m_value.first->get_decl()); - mg.hide(it->m_value.second->get_decl()); - } } model_value_proc * theory_fpa::mk_value(enode * n, model_generator & mg) { @@ -814,21 +801,29 @@ namespace smt { void theory_fpa::finalize_model(model_generator & mg) { ast_manager & m = get_manager(); proto_model & mdl = mg.get_model(); + proto_model new_model(m); - fpa2bv_converter::uf2bvuf_t const & uf2bvuf = m_converter.get_uf2bvuf(); - for (fpa2bv_converter::uf2bvuf_t::iterator it = uf2bvuf.begin(); - it != uf2bvuf.end(); - it++) { - func_decl * bv_fd = it->m_value; - if (bv_fd->get_arity() == 0) { - expr_ref bve(m), v(m); - bve = m.mk_const(bv_fd); - mdl.eval(bve, v, true); - mdl.register_decl(it->m_key, v); - } - else - NOT_IMPLEMENTED_YET(); - } + bv2fpa_converter bv2fp(m, m_converter); + + obj_hashtable seen; + bv2fp.convert_min_max_specials(&mdl, &new_model, seen); + bv2fp.convert_uf2bvuf(&mdl, &new_model, seen); + + for (obj_hashtable::iterator it = seen.begin(); + it != seen.end(); + it++) + mdl.unregister_decl(*it); + + for (unsigned i = 0; i < new_model.get_num_constants(); i++) { + func_decl * f = new_model.get_constant(i); + mdl.register_decl(f, new_model.get_const_interp(f)); + } + + for (unsigned i = 0; i < new_model.get_num_functions(); i++) { + func_decl * f = new_model.get_function(i); + func_interp * fi = new_model.get_func_interp(f)->copy(); + mdl.register_decl(f, fi); + } } void theory_fpa::display(std::ostream & out) const diff --git a/src/tactic/fpa/fpa2bv_model_converter.cpp b/src/tactic/fpa/fpa2bv_model_converter.cpp index 05fedb37f..9b95cf921 100644 --- a/src/tactic/fpa/fpa2bv_model_converter.cpp +++ b/src/tactic/fpa/fpa2bv_model_converter.cpp @@ -22,448 +22,54 @@ Notes: void fpa2bv_model_converter::display(std::ostream & out) { out << "(fpa2bv-model-converter"; - for (obj_map::iterator it = m_const2bv.begin(); - it != m_const2bv.end(); - it++) { - const symbol & n = it->m_key->get_name(); - out << "\n (" << n << " "; - unsigned indent = n.size() + 4; - out << mk_ismt2_pp(it->m_value, m, indent) << ")"; - } - for (obj_map::iterator it = m_rm_const2bv.begin(); - it != m_rm_const2bv.end(); - it++) { - const symbol & n = it->m_key->get_name(); - out << "\n (" << n << " "; - unsigned indent = n.size() + 4; - out << mk_ismt2_pp(it->m_value, m, indent) << ")"; - } - for (obj_map::iterator it = m_uf2bvuf.begin(); - it != m_uf2bvuf.end(); - it++) { - const symbol & n = it->m_key->get_name(); - out << "\n (" << n << " "; - unsigned indent = n.size() + 4; - out << mk_ismt2_pp(it->m_value, m, indent) << ")"; - } - for (obj_map >::iterator it = m_specials.begin(); - it != m_specials.end(); - it++) { - const symbol & n = it->m_key->get_name(); - out << "\n (" << n << " "; - unsigned indent = n.size() + 4; - out << mk_ismt2_pp(it->m_value.first, m, indent) << "; " << - mk_ismt2_pp(it->m_value.second, m, indent) << ")"; - } + m_bv2fp->display(out); out << ")"; } model_converter * fpa2bv_model_converter::translate(ast_translation & translator) { - fpa2bv_model_converter * res = alloc(fpa2bv_model_converter, translator.to()); - for (obj_map::iterator it = m_const2bv.begin(); - it != m_const2bv.end(); - it++) - { - func_decl * k = translator(it->m_key); - expr * v = translator(it->m_value); - res->m_const2bv.insert(k, v); - translator.to().inc_ref(k); - translator.to().inc_ref(v); - } - for (obj_map::iterator it = m_rm_const2bv.begin(); - it != m_rm_const2bv.end(); - it++) - { - func_decl * k = translator(it->m_key); - expr * v = translator(it->m_value); - res->m_rm_const2bv.insert(k, v); - translator.to().inc_ref(k); - translator.to().inc_ref(v); - } - for (obj_map::iterator it = m_uf2bvuf.begin(); - it != m_uf2bvuf.end(); - it++) { - func_decl * k = translator(it->m_key); - func_decl * v = translator(it->m_value); - res->m_uf2bvuf.insert(k, v); - translator.to().inc_ref(k); - translator.to().inc_ref(v); - } - for (obj_map >::iterator it = m_specials.begin(); - it != m_specials.end(); - it++) { - func_decl * k = translator(it->m_key); - app * v1 = translator(it->m_value.first); - app * v2 = translator(it->m_value.second); - res->m_specials.insert(k, std::pair(v1, v2)); - translator.to().inc_ref(k); - translator.to().inc_ref(v1); - translator.to().inc_ref(v2); - } + fpa2bv_model_converter * res = alloc(fpa2bv_model_converter, translator.to()); + res->m_bv2fp = m_bv2fp->translate(translator); return res; } -expr_ref fpa2bv_model_converter::convert_bv2fp(sort * s, expr * sgn, expr * exp, expr * sig) { - unsynch_mpz_manager & mpzm = m_fpa_util.fm().mpz_manager(); - unsynch_mpq_manager & mpqm = m_fpa_util.fm().mpq_manager(); +void fpa2bv_model_converter::convert(model_core * mc, model * float_mdl) { + obj_hashtable seen; + m_bv2fp->convert_consts(mc, float_mdl, seen); + m_bv2fp->convert_rm_consts(mc, float_mdl, seen); + m_bv2fp->convert_min_max_specials(mc, float_mdl, seen); + m_bv2fp->convert_uf2bvuf(mc, float_mdl, seen); - expr_ref res(m); - mpf fp_val; + // Keep all the non-float constants. + unsigned sz = mc->get_num_constants(); + for (unsigned i = 0; i < sz; i++) + { + func_decl * c = mc->get_constant(i); + if (!seen.contains(c)) + float_mdl->register_decl(c, mc->get_const_interp(c)); + } - unsigned ebits = m_fpa_util.get_ebits(s); - unsigned sbits = m_fpa_util.get_sbits(s); + // And keep everything else + sz = mc->get_num_functions(); + for (unsigned i = 0; i < sz; i++) + { + func_decl * f = mc->get_function(i); + if (!seen.contains(f)) + { + TRACE("fpa2bv_mc", tout << "Keeping: " << mk_ismt2_pp(f, m) << std::endl;); + func_interp * val = mc->get_func_interp(f)->copy(); + float_mdl->register_decl(f, val); + } + } - unsigned sgn_sz = 1; - unsigned exp_sz = ebits; - unsigned sig_sz = sbits - 1; - - rational sgn_q(0), sig_q(0), exp_q(0); - - if (sgn) m_bv_util.is_numeral(sgn, sgn_q, sgn_sz); - if (exp) m_bv_util.is_numeral(exp, exp_q, exp_sz); - if (sig) m_bv_util.is_numeral(sig, sig_q, sig_sz); - - // un-bias exponent - rational exp_unbiased_q; - exp_unbiased_q = exp_q - m_fpa_util.fm().m_powers2.m1(ebits - 1); - - mpz sig_z; mpf_exp_t exp_z; - mpzm.set(sig_z, sig_q.to_mpq().numerator()); - exp_z = mpzm.get_int64(exp_unbiased_q.to_mpq().numerator()); - - m_fpa_util.fm().set(fp_val, ebits, sbits, !mpqm.is_zero(sgn_q.to_mpq()), exp_z, sig_z); - - mpzm.del(sig_z); - - res = m_fpa_util.mk_value(fp_val); - - TRACE("fpa2bv_mc", tout << "[" << mk_ismt2_pp(sgn, m) << - " " << mk_ismt2_pp(exp, m) << - " " << mk_ismt2_pp(sig, m) << "] == " << - mk_ismt2_pp(res, m) << std::endl;); - m_fpa_util.fm().del(fp_val); - - return res; + sz = mc->get_num_uninterpreted_sorts(); + for (unsigned i = 0; i < sz; i++) + { + sort * s = mc->get_uninterpreted_sort(i); + ptr_vector u = mc->get_universe(s); + float_mdl->register_usort(s, u.size(), u.c_ptr()); + } } -expr_ref fpa2bv_model_converter::convert_bv2fp(model * bv_mdl, sort * s, expr * bv) { - SASSERT(m_bv_util.is_bv(bv)); - - unsigned ebits = m_fpa_util.get_ebits(s); - unsigned sbits = m_fpa_util.get_sbits(s); - unsigned bv_sz = sbits + ebits; - - expr_ref sgn(m), exp(m), sig(m); - sgn = m_bv_util.mk_extract(bv_sz - 1, bv_sz - 1, bv); - exp = m_bv_util.mk_extract(bv_sz - 2, sbits - 1, bv); - sig = m_bv_util.mk_extract(sbits - 2, 0, bv); - - expr_ref v_sgn(m), v_exp(m), v_sig(m); - bv_mdl->eval(sgn, v_sgn); - bv_mdl->eval(exp, v_exp); - bv_mdl->eval(sig, v_sig); - - return convert_bv2fp(s, v_sgn, v_exp, v_sig); -} - -expr_ref fpa2bv_model_converter::convert_bv2rm(expr * bv_rm) { - expr_ref res(m); - rational bv_val(0); - unsigned sz = 0; - - if (m_bv_util.is_numeral(bv_rm, bv_val, sz)) { - SASSERT(bv_val.is_uint64()); - switch (bv_val.get_uint64()) { - case BV_RM_TIES_TO_AWAY: res = m_fpa_util.mk_round_nearest_ties_to_away(); break; - case BV_RM_TIES_TO_EVEN: res = m_fpa_util.mk_round_nearest_ties_to_even(); break; - case BV_RM_TO_NEGATIVE: res = m_fpa_util.mk_round_toward_negative(); break; - case BV_RM_TO_POSITIVE: res = m_fpa_util.mk_round_toward_positive(); break; - case BV_RM_TO_ZERO: - default: res = m_fpa_util.mk_round_toward_zero(); - } - } - - return res; -} - -expr_ref fpa2bv_model_converter::convert_bv2rm(model * bv_mdl, expr * val) { - expr_ref res(m); - expr_ref eval_v(m); - - if (val && bv_mdl->eval(val, eval_v, true)) - res = convert_bv2rm(eval_v); - - return res; -} - -expr_ref fpa2bv_model_converter::rebuild_floats(model * bv_mdl, sort * s, expr * e) { - expr_ref result(m); - TRACE("fpa2bv_mc", tout << "rebuild floats in " << mk_ismt2_pp(s, m) << " for " << mk_ismt2_pp(e, m) << std::endl;); - - if (m_fpa_util.is_float(s)) { - if (m_fpa_util.is_numeral(e)) { - result = e; - } - else { - SASSERT(m_bv_util.is_bv(e) && m_bv_util.get_bv_size(e) == (m_fpa_util.get_ebits(s) + m_fpa_util.get_sbits(s))); - result = convert_bv2fp(bv_mdl, s, e); - } - } - else if (m_fpa_util.is_rm(s)) { - if (m_fpa_util.is_rm_numeral(e)) { - result = e; - } - else { - SASSERT(m_bv_util.is_bv(e) && m_bv_util.get_bv_size(e) == 3); - result = convert_bv2rm(bv_mdl, e); - } - } - else if (is_app(e)) { - app * a = to_app(e); - expr_ref_vector new_args(m); - for (unsigned i = 0; i < a->get_num_args(); i++) - new_args.push_back(rebuild_floats(bv_mdl, a->get_decl()->get_domain()[i], a->get_arg(i))); - result = m.mk_app(a->get_decl(), new_args.size(), new_args.c_ptr()); - } - - return result; -} - -fpa2bv_model_converter::array_model fpa2bv_model_converter::convert_array_func_interp(func_decl * f, func_decl * bv_f, model * bv_mdl) { - SASSERT(f->get_arity() == 0); - array_util arr_util(m); - - array_model am(m); - sort_ref_vector array_domain(m); - unsigned arity = f->get_range()->get_num_parameters()-1; - - expr_ref as_arr_mdl(m); - as_arr_mdl = bv_mdl->get_const_interp(bv_f); - if (as_arr_mdl == 0) return am; - TRACE("fpa2bv_mc", tout << "arity=0 func_interp for " << mk_ismt2_pp(f, m) << " := " << mk_ismt2_pp(as_arr_mdl, m) << std::endl;); - SASSERT(arr_util.is_as_array(as_arr_mdl)); - for (unsigned i = 0; i < arity; i++) - array_domain.push_back(to_sort(f->get_range()->get_parameter(i).get_ast())); - sort * rng = to_sort(f->get_range()->get_parameter(arity).get_ast()); - - bv_f = arr_util.get_as_array_func_decl(to_app(as_arr_mdl)); - - am.new_float_fd = m.mk_fresh_func_decl(arity, array_domain.c_ptr(), rng); - am.new_float_fi = convert_func_interp(am.new_float_fd, bv_f, bv_mdl); - am.bv_fd = bv_f; - am.result = arr_util.mk_as_array(f->get_range(), am.new_float_fd); - return am; -} - -func_interp * fpa2bv_model_converter::convert_func_interp(func_decl * f, func_decl * bv_f, model * bv_mdl) { - SASSERT(f->get_arity() > 0); - func_interp * result = 0; - sort * rng = f->get_range(); - sort * const * dmn = f->get_domain(); - - unsigned arity = bv_f->get_arity(); - func_interp * bv_fi = bv_mdl->get_func_interp(bv_f); - - if (bv_fi != 0) { - fpa_rewriter rw(m); - expr_ref ai(m); - result = alloc(func_interp, m, arity); - - for (unsigned i = 0; i < bv_fi->num_entries(); i++) { - func_entry const * bv_fe = bv_fi->get_entry(i); - expr * const * bv_args = bv_fe->get_args(); - expr_ref_buffer new_args(m); - - for (unsigned j = 0; j < arity; j++) { - sort * ft_dj = dmn[j]; - expr * bv_aj = bv_args[j]; - ai = rebuild_floats(bv_mdl, ft_dj, bv_aj); - m_th_rw(ai); - new_args.push_back(ai); - } - - expr_ref bv_fres(m), ft_fres(m); - bv_fres = bv_fe->get_result(); - ft_fres = rebuild_floats(bv_mdl, rng, bv_fres); - m_th_rw(ft_fres); - result->insert_new_entry(new_args.c_ptr(), ft_fres); - } - - expr_ref bv_els(m), ft_els(m); - bv_els = bv_fi->get_else(); - ft_els = rebuild_floats(bv_mdl, rng, bv_els); - m_th_rw(ft_els); - result->set_else(ft_els); - } - - return result; -} - -void fpa2bv_model_converter::convert(model * bv_mdl, model * float_mdl) { - TRACE("fpa2bv_mc", tout << "BV Model: " << std::endl; - for (unsigned i = 0; i < bv_mdl->get_num_constants(); i++) - tout << bv_mdl->get_constant(i)->get_name() << " --> " << - mk_ismt2_pp(bv_mdl->get_const_interp(bv_mdl->get_constant(i)), m) << std::endl; - for (unsigned i = 0; i < bv_mdl->get_num_functions(); i++) { - func_decl * f = bv_mdl->get_function(i); - tout << f->get_name() << "(...) := " << std::endl; - func_interp * fi = bv_mdl->get_func_interp(f); - for (unsigned j = 0; j < fi->num_entries(); j++) { - func_entry const * fe = fi->get_entry(j); - for (unsigned k = 0; k < f->get_arity(); k++) { - tout << mk_ismt2_pp(fe->get_arg(k), m) << " "; - } - tout << "--> " << mk_ismt2_pp(fe->get_result(), m) << std::endl; - } - tout << "else " << mk_ismt2_pp(fi->get_else(), m) << std::endl; - }); - - obj_hashtable seen; - - for (obj_map >::iterator it = m_specials.begin(); - it != m_specials.end(); - it++) { - func_decl * f = it->m_key; - expr_ref pzero(m), nzero(m); - pzero = m_fpa_util.mk_pzero(f->get_range()); - nzero = m_fpa_util.mk_nzero(f->get_range()); - - expr_ref pn(m), np(m); - bv_mdl->eval(it->m_value.first, pn, true); - bv_mdl->eval(it->m_value.second, np, true); - seen.insert(it->m_value.first->get_decl()); - seen.insert(it->m_value.second->get_decl()); - - rational pn_num, np_num; - unsigned bv_sz; - m_bv_util.is_numeral(pn, pn_num, bv_sz); - m_bv_util.is_numeral(np, np_num, bv_sz); - - func_interp * flt_fi = alloc(func_interp, m, f->get_arity()); - expr * pn_args[2] = { pzero, nzero }; - if (pn != np) flt_fi->insert_new_entry(pn_args, (pn_num.is_one() ? nzero : pzero)); - flt_fi->set_else(np_num.is_one() ? nzero : pzero); - - float_mdl->register_decl(f, flt_fi); - TRACE("fpa2bv_mc", tout << "fp.min/fp.max special: " << std::endl << - mk_ismt2_pp(f, m) << " == " << mk_ismt2_pp(flt_fi->get_interp(), m) << std::endl;); - } - - for (obj_map::iterator it = m_const2bv.begin(); - it != m_const2bv.end(); - it++) - { - func_decl * var = it->m_key; - app * val = to_app(it->m_value); - SASSERT(m_fpa_util.is_float(var->get_range())); - SASSERT(var->get_range()->get_num_parameters() == 2); - - expr_ref sgn(m), sig(m), exp(m); - bv_mdl->eval(val->get_arg(0), sgn, true); - bv_mdl->eval(val->get_arg(1), exp, true); - bv_mdl->eval(val->get_arg(2), sig, true); - - SASSERT(val->is_app_of(m_fpa_util.get_family_id(), OP_FPA_FP)); - -#ifdef Z3DEBUG - SASSERT(to_app(val->get_arg(0))->get_decl()->get_arity() == 0); - SASSERT(to_app(val->get_arg(1))->get_decl()->get_arity() == 0); - SASSERT(to_app(val->get_arg(2))->get_decl()->get_arity() == 0); - seen.insert(to_app(val->get_arg(0))->get_decl()); - seen.insert(to_app(val->get_arg(1))->get_decl()); - seen.insert(to_app(val->get_arg(2))->get_decl()); -#else - SASSERT(a->get_arg(0)->get_kind() == OP_EXTRACT); - SASSERT(to_app(a->get_arg(0))->get_arg(0)->get_kind() == OP_EXTRACT); - seen.insert(to_app(to_app(val->get_arg(0))->get_arg(0))->get_decl()); -#endif - - if (!sgn && !sig && !exp) - continue; - - expr_ref cv(m); - cv = convert_bv2fp(var->get_range(), sgn, exp, sig); - float_mdl->register_decl(var, cv); - - TRACE("fpa2bv_mc", tout << var->get_name() << " == " << mk_ismt2_pp(cv, m) << std::endl;); - } - - for (obj_map::iterator it = m_rm_const2bv.begin(); - it != m_rm_const2bv.end(); - it++) - { - func_decl * var = it->m_key; - SASSERT(m_fpa_util.is_rm(var->get_range())); - expr * val = it->m_value; - SASSERT(m_fpa_util.is_bv2rm(val)); - expr * bvval = to_app(val)->get_arg(0); - expr_ref fv(m); - fv = convert_bv2rm(bv_mdl, bvval); - TRACE("fpa2bv_mc", tout << var->get_name() << " == " << mk_ismt2_pp(fv, m) << ")" << std::endl;); - float_mdl->register_decl(var, fv); - seen.insert(to_app(bvval)->get_decl()); - } - - for (obj_map::iterator it = m_uf2bvuf.begin(); - it != m_uf2bvuf.end(); - it++) { - seen.insert(it->m_value); - - func_decl * f = it->m_key; - if (f->get_arity() == 0) - { - array_util au(m); - if (au.is_array(f->get_range())) { - array_model am = convert_array_func_interp(f, it->m_value, bv_mdl); - if (am.new_float_fd) float_mdl->register_decl(am.new_float_fd, am.new_float_fi); - if (am.result) float_mdl->register_decl(f, am.result); - if (am.bv_fd) seen.insert(am.bv_fd); - } - else { - // Just keep. - SASSERT(!m_fpa_util.is_float(f->get_range()) && !m_fpa_util.is_rm(f->get_range())); - expr_ref val(m); - bv_mdl->eval(it->m_value, val); - if (val) float_mdl->register_decl(f, val); - } - } - else { - func_interp * fmv = convert_func_interp(f, it->m_value, bv_mdl); - if (fmv) float_mdl->register_decl(f, fmv); - } - } - - // Keep all the non-float constants. - unsigned sz = bv_mdl->get_num_constants(); - for (unsigned i = 0; i < sz; i++) - { - func_decl * c = bv_mdl->get_constant(i); - if (!seen.contains(c)) - float_mdl->register_decl(c, bv_mdl->get_const_interp(c)); - } - - // And keep everything else - sz = bv_mdl->get_num_functions(); - for (unsigned i = 0; i < sz; i++) - { - func_decl * f = bv_mdl->get_function(i); - if (!seen.contains(f)) - { - TRACE("fpa2bv_mc", tout << "Keeping: " << mk_ismt2_pp(f, m) << std::endl;); - func_interp * val = bv_mdl->get_func_interp(f)->copy(); - float_mdl->register_decl(f, val); - } - } - - sz = bv_mdl->get_num_uninterpreted_sorts(); - for (unsigned i = 0; i < sz; i++) - { - sort * s = bv_mdl->get_uninterpreted_sort(i); - ptr_vector u = bv_mdl->get_universe(s); - float_mdl->register_usort(s, u.size(), u.c_ptr()); - } -} - -model_converter * mk_fpa2bv_model_converter(ast_manager & m, fpa2bv_converter const & conv) { +model_converter * mk_fpa2bv_model_converter(ast_manager & m, fpa2bv_converter & conv) { return alloc(fpa2bv_model_converter, m, conv); } diff --git a/src/tactic/fpa/fpa2bv_model_converter.h b/src/tactic/fpa/fpa2bv_model_converter.h index 909a7cb78..7a39c0fba 100644 --- a/src/tactic/fpa/fpa2bv_model_converter.h +++ b/src/tactic/fpa/fpa2bv_model_converter.h @@ -19,79 +19,29 @@ Notes: #ifndef FPA2BV_MODEL_CONVERTER_H_ #define FPA2BV_MODEL_CONVERTER_H_ -#include"th_rewriter.h" #include"fpa2bv_converter.h" #include"model_converter.h" +#include"bv2fpa_converter.h" class fpa2bv_model_converter : public model_converter { ast_manager & m; - fpa_util m_fpa_util; - bv_util m_bv_util; - th_rewriter m_th_rw; + bv2fpa_converter * m_bv2fp; - obj_map m_const2bv; - obj_map m_rm_const2bv; - obj_map m_uf2bvuf; - obj_map > m_specials; - public: - fpa2bv_model_converter(ast_manager & m, fpa2bv_converter const & conv) : - m(m), - m_fpa_util(m), - m_bv_util(m), - m_th_rw(m) { - for (obj_map::iterator it = conv.m_const2bv.begin(); - it != conv.m_const2bv.end(); - it++) - { - m_const2bv.insert(it->m_key, it->m_value); - m.inc_ref(it->m_key); - m.inc_ref(it->m_value); - } - for (obj_map::iterator it = conv.m_rm_const2bv.begin(); - it != conv.m_rm_const2bv.end(); - it++) - { - m_rm_const2bv.insert(it->m_key, it->m_value); - m.inc_ref(it->m_key); - m.inc_ref(it->m_value); - } - for (obj_map::iterator it = conv.m_uf2bvuf.begin(); - it != conv.m_uf2bvuf.end(); - it++) - { - m_uf2bvuf.insert(it->m_key, it->m_value); - m.inc_ref(it->m_key); - m.inc_ref(it->m_value); - } - for (obj_map >::iterator it = conv.m_min_max_specials.begin(); - it != conv.m_min_max_specials.end(); - it++) { - m_specials.insert(it->m_key, it->m_value); - m.inc_ref(it->m_key); - m.inc_ref(it->m_value.first); - m.inc_ref(it->m_value.second); - } + fpa2bv_model_converter(ast_manager & m, fpa2bv_converter & conv) : + m(m) { + m_bv2fp = alloc(bv2fpa_converter, m, conv); } virtual ~fpa2bv_model_converter() { - dec_ref_map_key_values(m, m_const2bv); - dec_ref_map_key_values(m, m_rm_const2bv); - dec_ref_map_key_values(m, m_uf2bvuf); - for (obj_map >::iterator it = m_specials.begin(); - it != m_specials.end(); - it++) { - m.dec_ref(it->m_key); - m.dec_ref(it->m_value.first); - m.dec_ref(it->m_value.second); - } + if (m_bv2fp) dealloc(m_bv2fp); + m_bv2fp = 0; } virtual void operator()(model_ref & md, unsigned goal_idx) { SASSERT(goal_idx == 0); model * new_model = alloc(model, m); - obj_hashtable bits; - convert(md.get(), new_model); + convert(md.get(), new_model); md = new_model; } @@ -106,32 +56,12 @@ public: protected: fpa2bv_model_converter(ast_manager & m) : m(m), - m_fpa_util(m), - m_bv_util(m), - m_th_rw(m) {} + m_bv2fp(0) {} - void convert(model * bv_mdl, model * float_mdl); - expr_ref convert_bv2fp(sort * s, expr * sgn, expr * exp, expr * sig); - expr_ref convert_bv2fp(model * bv_mdl, sort * s, expr * bv); - expr_ref convert_bv2rm(expr * eval_v); - expr_ref convert_bv2rm(model * bv_mdl, expr * val); - - func_interp * convert_func_interp(func_decl * f, func_decl * bv_f, model * bv_mdl); - expr_ref rebuild_floats(model * bv_mdl, sort * s, expr * e); - - class array_model { - public: - func_decl * new_float_fd; - func_interp * new_float_fi; - func_decl * bv_fd; - expr_ref result; - array_model(ast_manager & m) : new_float_fd(0), new_float_fi(0), bv_fd(0), result(m) {} - }; - - array_model convert_array_func_interp(func_decl * f, func_decl * bv_f, model * bv_mdl); + void convert(model_core * mc, model * float_mdl); }; -model_converter * mk_fpa2bv_model_converter(ast_manager & m, fpa2bv_converter const & conv); +model_converter * mk_fpa2bv_model_converter(ast_manager & m, fpa2bv_converter & conv); #endif From b2381acceb345b85f9dd03d2213bc24b08b16ea2 Mon Sep 17 00:00:00 2001 From: Dan Liew Date: Sat, 15 Oct 2016 21:42:20 +0100 Subject: [PATCH 233/536] Unbreak the CMake build broken by 009af4455d60e0affb376e36f48e3ab42fcf67d0 The commit added an additional source file and dependency but the corresponding changes weren't added to the CMake build. --- contrib/cmake/src/ast/fpa/CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/contrib/cmake/src/ast/fpa/CMakeLists.txt b/contrib/cmake/src/ast/fpa/CMakeLists.txt index 7369a9b3d..4a9506d16 100644 --- a/contrib/cmake/src/ast/fpa/CMakeLists.txt +++ b/contrib/cmake/src/ast/fpa/CMakeLists.txt @@ -1,10 +1,12 @@ z3_add_component(fpa SOURCES + bv2fpa_converter.cpp fpa2bv_converter.cpp fpa2bv_rewriter.cpp COMPONENT_DEPENDENCIES ast simplifier + model util PYG_FILES fpa2bv_rewriter_params.pyg From aec59e4ff77b5389e377a5df2336491cd99ed84e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 16 Oct 2016 15:43:28 -0400 Subject: [PATCH 234/536] add consequence finding to inc-sat-solver Signed-off-by: Nikolaj Bjorner --- contrib/cmake/src/test/CMakeLists.txt | 1 + src/ast/pb_decl_plugin.cpp | 50 +++++---- src/ast/pb_decl_plugin.h | 1 + src/ast/rewriter/pb_rewriter.cpp | 16 +++ src/sat/sat_solver.cpp | 46 ++++---- src/sat/sat_solver.h | 3 + src/sat/sat_solver/inc_sat_solver.cpp | 144 +++++++++++++++++++++++++- src/sat/sat_types.h | 12 +++ src/test/get_consequences.cpp | 50 +++++++++ src/test/main.cpp | 1 + 10 files changed, 283 insertions(+), 41 deletions(-) create mode 100644 src/test/get_consequences.cpp diff --git a/contrib/cmake/src/test/CMakeLists.txt b/contrib/cmake/src/test/CMakeLists.txt index 427cedcdb..acaf186ba 100644 --- a/contrib/cmake/src/test/CMakeLists.txt +++ b/contrib/cmake/src/test/CMakeLists.txt @@ -42,6 +42,7 @@ add_executable(test-z3 factor_rewriter.cpp fixed_bit_vector.cpp for_each_file.cpp + get_consequences.cpp get_implied_equalities.cpp "${CMAKE_CURRENT_BINARY_DIR}/gparams_register_modules.cpp" hashtable.cpp diff --git a/src/ast/pb_decl_plugin.cpp b/src/ast/pb_decl_plugin.cpp index e87bc15ac..18a652859 100644 --- a/src/ast/pb_decl_plugin.cpp +++ b/src/ast/pb_decl_plugin.cpp @@ -101,35 +101,47 @@ void pb_decl_plugin::get_op_names(svector & op_names, symbol const } void pb_util::normalize(unsigned num_args, rational const* coeffs, rational const& k) { - rational d(1); - for (unsigned i = 0; i < num_args; ++i) { - d = lcm(d, denominator(coeffs[i])); - } m_coeffs.reset(); - for (unsigned i = 0; i < num_args; ++i) { - m_coeffs.push_back(d*coeffs[i]); + bool all_ones = true; + for (unsigned i = 0; i < num_args && all_ones; ++i) { + all_ones = denominator(coeffs[i]).is_one(); + } + if (all_ones) { + for (unsigned i = 0; i < num_args; ++i) { + m_coeffs.push_back(coeffs[i]); + } + m_k = k; + } + else { + rational d(1); + for (unsigned i = 0; i < num_args; ++i) { + d = lcm(d, denominator(coeffs[i])); + } + for (unsigned i = 0; i < num_args; ++i) { + m_coeffs.push_back(d*coeffs[i]); + } + m_k = d*k; } - m_k = d*k; } app * pb_util::mk_le(unsigned num_args, rational const * coeffs, expr * const * args, rational const& k) { normalize(num_args, coeffs, k); - vector params; - params.push_back(parameter(floor(m_k))); + m_params.reset(); + m_params.push_back(parameter(floor(m_k))); for (unsigned i = 0; i < num_args; ++i) { - params.push_back(parameter(m_coeffs[i])); + m_params.push_back(parameter(m_coeffs[i])); } - return m.mk_app(m_fid, OP_PB_LE, params.size(), params.c_ptr(), num_args, args, m.mk_bool_sort()); + return m.mk_app(m_fid, OP_PB_LE, m_params.size(), m_params.c_ptr(), num_args, args, m.mk_bool_sort()); } app * pb_util::mk_ge(unsigned num_args, rational const * coeffs, expr * const * args, rational const& k) { normalize(num_args, coeffs, k); - vector params; - params.push_back(parameter(ceil(m_k))); + m_params.reset(); + m_params.push_back(parameter(ceil(m_k))); for (unsigned i = 0; i < num_args; ++i) { - params.push_back(parameter(m_coeffs[i])); + m_params.push_back(parameter(m_coeffs[i])); } - return m.mk_app(m_fid, OP_PB_GE, params.size(), params.c_ptr(), num_args, args, m.mk_bool_sort()); + return m.mk_app(m_fid, OP_PB_GE, m_params.size(), m_params.c_ptr(), num_args, args, m.mk_bool_sort()); } app * pb_util::mk_eq(unsigned num_args, rational const * coeffs, expr * const * args, rational const& k) { @@ -137,12 +149,12 @@ app * pb_util::mk_eq(unsigned num_args, rational const * coeffs, expr * const * if (!m_k.is_int()) { return m.mk_false(); } - vector params; - params.push_back(parameter(m_k)); + m_params.reset(); + m_params.push_back(parameter(m_k)); for (unsigned i = 0; i < num_args; ++i) { - params.push_back(parameter(m_coeffs[i])); + m_params.push_back(parameter(m_coeffs[i])); } - return m.mk_app(m_fid, OP_PB_EQ, params.size(), params.c_ptr(), num_args, args, m.mk_bool_sort()); + return m.mk_app(m_fid, OP_PB_EQ, m_params.size(), m_params.c_ptr(), num_args, args, m.mk_bool_sort()); } // ax + by < k diff --git a/src/ast/pb_decl_plugin.h b/src/ast/pb_decl_plugin.h index e1b16f0c9..2ed14a4ce 100644 --- a/src/ast/pb_decl_plugin.h +++ b/src/ast/pb_decl_plugin.h @@ -80,6 +80,7 @@ class pb_util { ast_manager & m; family_id m_fid; vector m_coeffs; + vector m_params; rational m_k; void normalize(unsigned num_args, rational const* coeffs, rational const& k); public: diff --git a/src/ast/rewriter/pb_rewriter.cpp b/src/ast/rewriter/pb_rewriter.cpp index eb85f8ec9..74062fbfa 100644 --- a/src/ast/rewriter/pb_rewriter.cpp +++ b/src/ast/rewriter/pb_rewriter.cpp @@ -277,6 +277,22 @@ br_status pb_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * cons tout << tmp << "\n"; tout << result << "\n"; ); + +#if 0 + static unsigned num_changes = 0; + static unsigned num_calls = 0; + static unsigned inc = 1; + { + expr_ref tmp(m); + tmp = m.mk_app(f, num_args, args); + num_calls++; + if (tmp != result) ++num_changes; + if (num_calls > inc) { + std::cout << num_calls << " " << num_changes << "\n"; + inc *= 2; + } + } +#endif TRACE("pb_validate", validate_rewrite(f, num_args, args, result);); diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index f2279b3c4..915080c4a 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -3075,45 +3075,51 @@ namespace sat { m_binary_clause_graph[l1.index()].push_back(l2); m_binary_clause_graph[l2.index()].push_back(l1); } - while (!ps.empty()) { + bool non_empty = true; + m_seen[0].reset(); + while (non_empty) { literal_vector mutex; - literal_set other(ps); - while (!other.empty()) { - literal_set conseq; - literal p = other.pop(); + bool turn = false; + m_reachable[turn] = ps; + while (!m_reachable[turn].empty()) { + literal p = m_reachable[turn].pop(); + if (m_seen[0].contains(p)) { + continue; + } + m_reachable[turn].remove(p); + m_seen[0].insert(p); mutex.push_back(p); - if (other.empty()) { + if (m_reachable[turn].empty()) { break; } - get_reachable(p, other, conseq); - other = conseq; + m_reachable[!turn].reset(); + get_reachable(p, m_reachable[turn], m_reachable[!turn]); + turn = !turn; } if (mutex.size() > 1) { mutexes.push_back(mutex); } - for (unsigned i = 0; i < mutex.size(); ++i) { - ps.erase(mutex[i]); - } + non_empty = !mutex.empty(); } return l_true; } void solver::get_reachable(literal p, literal_set const& goal, literal_set& reachable) { - literal_set seen; - literal_vector todo; - todo.push_back(p); - while (!todo.empty()) { - p = todo.back(); - todo.pop_back(); - if (seen.contains(p)) { + m_seen[1].reset(); + m_todo.reset(); + m_todo.push_back(p); + while (!m_todo.empty()) { + p = m_todo.back(); + m_todo.pop_back(); + if (m_seen[1].contains(p)) { continue; } - seen.insert(p); + m_seen[1].insert(p); literal np = ~p; if (goal.contains(np)) { reachable.insert(np); } - todo.append(m_binary_clause_graph[np.index()]); + m_todo.append(m_binary_clause_graph[np.index()]); } } diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index 785bc6856..85836b889 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -447,6 +447,9 @@ namespace sat { u_map m_antecedents; vector m_binary_clause_graph; + literal_set m_reachable[2]; + literal_set m_seen[2]; + literal_vector m_todo; void extract_assumptions(literal lit, index_set& s); diff --git a/src/sat/sat_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp index 6139b3e22..83ccfcac4 100644 --- a/src/sat/sat_solver/inc_sat_solver.cpp +++ b/src/sat/sat_solver/inc_sat_solver.cpp @@ -33,6 +33,7 @@ Notes: #include "filter_model_converter.h" #include "bit_blaster_model_converter.h" #include "ast_translation.h" +#include "ast_util.h" // incremental SAT solver. class inc_sat_solver : public solver { @@ -232,6 +233,41 @@ public: return 0; } + virtual lbool get_consequences_core(expr_ref_vector const& assumptions, expr_ref_vector const& vars, expr_ref_vector& conseq) { + TRACE("sat", tout << assumptions << "\n" << vars << "\n";); + sat::literal_vector asms; + sat::bool_var_vector bvars; + vector lconseq; + dep2asm_t dep2asm; + m_solver.pop_to_base_level(); + lbool r = internalize_formulas(); + if (r != l_true) return r; + r = internalize_assumptions(assumptions.size(), assumptions.c_ptr(), dep2asm); + if (r != l_true) return r; + r = internalize_vars(vars, bvars); + + r = m_solver.get_consequences(m_asms, bvars, lconseq); + if (r != l_true) return r; + + // build map from bound variables to + // the consequences that cover them. + u_map bool_var2conseq; + for (unsigned i = 0; i < lconseq.size(); ++i) { + TRACE("sat", tout << lconseq[i] << "\n";); + bool_var2conseq.insert(lconseq[i][0].var(), i); + } + + // extract original fixed variables + for (unsigned i = 0; i < vars.size(); ++i) { + expr_ref cons(m); + if (extract_fixed_variable(dep2asm, vars[i], bool_var2conseq, lconseq, cons)) { + conseq.push_back(cons); + } + } + + return r; + } + virtual lbool find_mutexes(expr_ref_vector const& vars, vector& mutexes) { sat::literal_vector ls; u_map lit2var; @@ -359,6 +395,106 @@ private: return res; } + lbool internalize_vars(expr_ref_vector const& vars, sat::bool_var_vector& bvars) { + for (unsigned i = 0; i < vars.size(); ++i) { + internalize_var(vars[i], bvars); + } + return l_true; + } + + bool internalize_var(expr* v, sat::bool_var_vector& bvars) { + obj_map const& const2bits = m_bb_rewriter->const2bits(); + expr* bv; + bv_util bvutil(m); + bool internalized = false; + if (is_uninterp_const(v) && m.is_bool(v)) { + sat::bool_var b = m_map.to_bool_var(v); + + if (b != sat::null_bool_var) { + bvars.push_back(b); + internalized = true; + } + } + else if (is_uninterp_const(v) && const2bits.find(to_app(v)->get_decl(), bv)) { + SASSERT(bvutil.is_bv(bv)); + app* abv = to_app(bv); + internalized = true; + unsigned sz = abv->get_num_args(); + for (unsigned j = 0; j < sz; ++j) { + SASSERT(is_uninterp_const(abv->get_arg(j))); + sat::bool_var b = m_map.to_bool_var(abv->get_arg(j)); + if (b == sat::null_bool_var) { + internalized = false; + } + else { + bvars.push_back(b); + } + } + CTRACE("sat", internalized, tout << "var: "; for (unsigned j = 0; j < sz; ++j) tout << bvars[bvars.size()-sz+j] << " "; tout << "\n";); + } + else if (is_uninterp_const(v) && bvutil.is_bv(v)) { + // variable does not occur in assertions, so is unconstrained. + } + CTRACE("sat", !internalized, tout << "unhandled variable " << mk_pp(v, m) << "\n";); + return internalized; + } + + bool extract_fixed_variable(dep2asm_t& dep2asm, expr* v, u_map const& bool_var2conseq, vector const& lconseq, expr_ref& conseq) { + u_map asm2dep; + extract_asm2dep(dep2asm, asm2dep); + + sat::bool_var_vector bvars; + if (!internalize_var(v, bvars)) { + return false; + } + sat::literal_vector value; + sat::literal_set premises; + for (unsigned i = 0; i < bvars.size(); ++i) { + unsigned index; + if (bool_var2conseq.find(bvars[i], index)) { + value.push_back(lconseq[index][0]); + for (unsigned j = 1; j < lconseq[index].size(); ++j) { + premises.insert(lconseq[index][j]); + } + } + else { + TRACE("sat", tout << "variable is not bound " << mk_pp(v, m) << "\n";); + return false; + } + } + expr_ref val(m); + expr_ref_vector conj(m); + internalize_value(value, v, val); + while (!premises.empty()) { + expr* e = 0; + VERIFY(asm2dep.find(premises.pop().index(), e)); + conj.push_back(e); + } + conseq = m.mk_implies(mk_and(conj), val); + return true; + } + + void internalize_value(sat::literal_vector const& value, expr* v, expr_ref& val) { + bv_util bvutil(m); + if (is_uninterp_const(v) && m.is_bool(v)) { + SASSERT(value.size() == 1); + val = value[0].sign() ? m.mk_not(v) : v; + } + else if (is_uninterp_const(v) && bvutil.is_bv_sort(m.get_sort(v))) { + SASSERT(value.size() == bvutil.get_bv_size(v)); + rational r(0); + for (unsigned i = 0; i < value.size(); ++i) { + if (!value[i].sign()) { + r += rational(2).expt(i); + } + } + val = m.mk_eq(v, bvutil.mk_numeral(r, value.size())); + } + else { + UNREACHABLE(); + } + } + lbool internalize_formulas() { if (m_fmls_head == m_fmls.size()) { return l_true; @@ -395,13 +531,17 @@ private: SASSERT(dep2asm.size() == m_asms.size()); } - void extract_core(dep2asm_t& dep2asm) { - u_map asm2dep; + void extract_asm2dep(dep2asm_t const& dep2asm, u_map& asm2dep) { dep2asm_t::iterator it = dep2asm.begin(), end = dep2asm.end(); for (; it != end; ++it) { expr* e = it->m_key; asm2dep.insert(it->m_value.index(), e); } + } + + void extract_core(dep2asm_t& dep2asm) { + u_map asm2dep; + extract_asm2dep(dep2asm, asm2dep); sat::literal_vector const& core = m_solver.get_core(); TRACE("sat", dep2asm_t::iterator it2 = dep2asm.begin(); diff --git a/src/sat/sat_types.h b/src/sat/sat_types.h index 697af2e2d..93109a74f 100644 --- a/src/sat/sat_types.h +++ b/src/sat/sat_types.h @@ -239,6 +239,18 @@ namespace sat { } return result; } + literal_set& operator=(literal_vector const& v) { + reset(); + for (unsigned i = 0; i < v.size(); ++i) insert(v[i]); + return *this; + } + literal_set& operator=(literal_set const& other) { + if (this != &other) { + m_set = other.m_set; + } + return *this; + } + void insert(literal l) { m_set.insert(l.index()); } void remove(literal l) { m_set.remove(l.index()); } literal pop() { return to_literal(m_set.erase()); } diff --git a/src/test/get_consequences.cpp b/src/test/get_consequences.cpp new file mode 100644 index 000000000..8bd6bccba --- /dev/null +++ b/src/test/get_consequences.cpp @@ -0,0 +1,50 @@ +/*++ +Copyright (c) 2016 Microsoft Corporation + +--*/ + +#include "inc_sat_solver.h" +#include "bv_decl_plugin.h" +#include "reg_decl_plugins.h" +#include "ast_pp.h" +//include + +static expr_ref mk_const(ast_manager& m, char const* name, sort* s) { + return expr_ref(m.mk_const(symbol(name), s), m); +} + +static expr_ref mk_bool(ast_manager& m, char const* name) { + return expr_ref(m.mk_const(symbol(name), m.mk_bool_sort()), m); +} + +static expr_ref mk_bv(ast_manager& m, char const* name, unsigned sz) { + bv_util bv(m); + return expr_ref(m.mk_const(symbol(name), bv.mk_sort(sz)), m); +} + +void tst_get_consequences() { + ast_manager m; + reg_decl_plugins(m); + bv_util bv(m); + params_ref p; + + ref solver = mk_inc_sat_solver(m, p); + expr_ref a = mk_bool(m, "a"), b = mk_bool(m, "b"), c = mk_bool(m, "c"); + expr_ref ba = mk_bv(m, "ba", 3), bb = mk_bv(m, "bb", 3), bc = mk_bv(m, "bc", 3); + + solver->assert_expr(m.mk_implies(a, b)); + solver->assert_expr(m.mk_implies(b, c)); + expr_ref_vector asms(m), vars(m), conseq(m); + asms.push_back(a); + vars.push_back(b); + vars.push_back(c); + vars.push_back(bb); + vars.push_back(bc); + solver->assert_expr(m.mk_eq(ba, bc)); + solver->assert_expr(m.mk_eq(bv.mk_numeral(2, 3), ba)); + solver->get_consequences(asms, vars, conseq); + + std::cout << conseq << "\n"; + + +} diff --git a/src/test/main.cpp b/src/test/main.cpp index 8fc0a2de6..9c6cdd668 100644 --- a/src/test/main.cpp +++ b/src/test/main.cpp @@ -228,6 +228,7 @@ int main(int argc, char ** argv) { TST(pdr); TST_ARGV(ddnf); TST(model_evaluator); + TST(get_consequences); //TST_ARGV(hs); } From 58198d7cb69df67b0c7974f55109613839975300 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 16 Oct 2016 15:45:39 -0400 Subject: [PATCH 235/536] add consequence finding to inc-sat-solver Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/pb_rewriter.cpp | 15 --------------- src/smt/theory_pb.cpp | 2 +- 2 files changed, 1 insertion(+), 16 deletions(-) diff --git a/src/ast/rewriter/pb_rewriter.cpp b/src/ast/rewriter/pb_rewriter.cpp index 74062fbfa..d233604f9 100644 --- a/src/ast/rewriter/pb_rewriter.cpp +++ b/src/ast/rewriter/pb_rewriter.cpp @@ -278,21 +278,6 @@ br_status pb_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * cons tout << result << "\n"; ); -#if 0 - static unsigned num_changes = 0; - static unsigned num_calls = 0; - static unsigned inc = 1; - { - expr_ref tmp(m); - tmp = m.mk_app(f, num_args, args); - num_calls++; - if (tmp != result) ++num_changes; - if (num_calls > inc) { - std::cout << num_calls << " " << num_changes << "\n"; - inc *= 2; - } - } -#endif TRACE("pb_validate", validate_rewrite(f, num_args, args, result);); diff --git a/src/smt/theory_pb.cpp b/src/smt/theory_pb.cpp index 2461a9db2..90cd020c3 100644 --- a/src/smt/theory_pb.cpp +++ b/src/smt/theory_pb.cpp @@ -519,7 +519,7 @@ namespace smt { c->m_compilation_threshold = th; IF_VERBOSE(2, verbose_stream() << "(smt.pb setting compilation threhshold to " << th << ")\n";); TRACE("pb", tout << "compilation threshold: " << th << "\n";); - compile_ineq(*c); + //compile_ineq(*c); } else { c->m_compilation_threshold = UINT_MAX; From fe14a22baacb8185e701a5d321226ba387cab76e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 16 Oct 2016 22:19:59 -0400 Subject: [PATCH 236/536] adding enumeration tests Signed-off-by: Nikolaj Bjorner --- src/test/get_consequences.cpp | 36 +++++++++++++++++++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/src/test/get_consequences.cpp b/src/test/get_consequences.cpp index 8bd6bccba..9dc0b43f9 100644 --- a/src/test/get_consequences.cpp +++ b/src/test/get_consequences.cpp @@ -5,6 +5,7 @@ Copyright (c) 2016 Microsoft Corporation #include "inc_sat_solver.h" #include "bv_decl_plugin.h" +#include "datatype_decl_plugin.h" #include "reg_decl_plugins.h" #include "ast_pp.h" //include @@ -22,7 +23,7 @@ static expr_ref mk_bv(ast_manager& m, char const* name, unsigned sz) { return expr_ref(m.mk_const(symbol(name), bv.mk_sort(sz)), m); } -void tst_get_consequences() { +static void test1() { ast_manager m; reg_decl_plugins(m); bv_util bv(m); @@ -45,6 +46,37 @@ void tst_get_consequences() { solver->get_consequences(asms, vars, conseq); std::cout << conseq << "\n"; - +} + +static void test2() { + ast_manager m; + reg_decl_plugins(m); + bv_util bv(m); + + datatype_decl_plugin& dt = static_cast(*m.get_plugin(m.get_family_id("datatype"))); + sort_ref_vector new_sorts(m); + constructor_decl* R = mk_constructor_decl(symbol("R"), symbol("is-R"), 0, 0); + constructor_decl* G = mk_constructor_decl(symbol("G"), symbol("is-G"), 0, 0); + constructor_decl* B = mk_constructor_decl(symbol("B"), symbol("is-B"), 0, 0); + constructor_decl* constrs[3] = { R, G, B }; + datatype_decl const* enum_sort = mk_datatype_decl(symbol("RGB"), 3, constrs); + VERIFY(dt.mk_datatypes(1, &enum_sort, new_sorts)); + del_constructor_decls(3, constrs); + sort* rgb = new_sorts[0].get(); + + expr_ref x = mk_const(m, "x", rgb), y = mk_const(m, "y", rgb), z = mk_const(m, "z", rgb); + ptr_vector const& enums = dt.geet_datatype_constructors(rgb); + expr_ref r = expr_ref(m.mk_const(enums[0], m), m), g = expr_ref(m.mk_const(enums[1], m), m), b = expr_ref(m.mk_const(enums[2], m), m); + + goal_ref g = alloc(goal, m); + g->assert_expr(m.mk_not(m.mk_eq(x, r))); + g->assert_expr(m.mk_not(m.mk_eq(x, b))); + g->display(std::cout); +} + +void tst_get_consequences() { + test1(); + test2(); + } From 4cae91b0965954b1e495b3b3e641381b45578069 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 17 Oct 2016 08:07:23 -0400 Subject: [PATCH 237/536] spacing, unit test Signed-off-by: Nikolaj Bjorner --- src/ast/fpa/fpa2bv_converter.h | 14 ++--- src/smt/theory_fpa.cpp | 68 ++++++++++----------- src/tactic/fpa/fpa2bv_model_converter.cpp | 72 +++++++++++------------ src/tactic/fpa/fpa2bv_model_converter.h | 19 +++--- src/test/get_consequences.cpp | 13 ++++ 5 files changed, 98 insertions(+), 88 deletions(-) diff --git a/src/ast/fpa/fpa2bv_converter.h b/src/ast/fpa/fpa2bv_converter.h index 247cfcacb..34417b7fc 100644 --- a/src/ast/fpa/fpa2bv_converter.h +++ b/src/ast/fpa/fpa2bv_converter.h @@ -56,7 +56,7 @@ protected: special_t m_min_max_specials; friend class fpa2bv_model_converter; - friend class bv2fpa_converter; + friend class bv2fpa_converter; public: fpa2bv_converter(ast_manager & m); @@ -138,11 +138,11 @@ public: void mk_to_fp_real_int(func_decl * f, unsigned num, expr * const * args, expr_ref & result); void mk_to_ubv(func_decl * f, unsigned num, expr * const * args, expr_ref & result); - void mk_to_ubv_unspecified(func_decl * f, unsigned num, expr * const * args, expr_ref & result); + void mk_to_ubv_unspecified(func_decl * f, unsigned num, expr * const * args, expr_ref & result); void mk_to_sbv(func_decl * f, unsigned num, expr * const * args, expr_ref & result); - void mk_to_sbv_unspecified(func_decl * f, unsigned num, expr * const * args, expr_ref & result); + void mk_to_sbv_unspecified(func_decl * f, unsigned num, expr * const * args, expr_ref & result); void mk_to_real(func_decl * f, unsigned num, expr * const * args, expr_ref & result); - void mk_to_real_unspecified(func_decl * f, unsigned num, expr * const * args, expr_ref & result); + void mk_to_real_unspecified(func_decl * f, unsigned num, expr * const * args, expr_ref & result); void set_unspecified_fp_hi(bool v) { m_hi_fp_unspecified = v; } @@ -227,9 +227,9 @@ private: void mk_to_fp_float(sort * s, expr * rm, expr * x, expr_ref & result); - expr_ref mk_to_ubv_unspecified(unsigned ebits, unsigned sbits, unsigned width); - expr_ref mk_to_sbv_unspecified(unsigned ebits, unsigned sbits, unsigned width); - expr_ref mk_to_real_unspecified(unsigned ebits, unsigned sbits); + expr_ref mk_to_ubv_unspecified(unsigned ebits, unsigned sbits, unsigned width); + expr_ref mk_to_sbv_unspecified(unsigned ebits, unsigned sbits, unsigned width); + expr_ref mk_to_real_unspecified(unsigned ebits, unsigned sbits); }; #endif diff --git a/src/smt/theory_fpa.cpp b/src/smt/theory_fpa.cpp index 248d5b84d..3a45e1876 100644 --- a/src/smt/theory_fpa.cpp +++ b/src/smt/theory_fpa.cpp @@ -84,15 +84,15 @@ namespace smt { } } - theory_fpa::theory_fpa(ast_manager & m) : - theory(m.mk_family_id("fpa")), - m_converter(m, this), - m_rw(m, m_converter, params_ref()), - m_th_rw(m), - m_trail_stack(*this), - m_fpa_util(m_converter.fu()), - m_bv_util(m_converter.bu()), - m_arith_util(m_converter.au()), + theory_fpa::theory_fpa(ast_manager & m) : + theory(m.mk_family_id("fpa")), + m_converter(m, this), + m_rw(m, m_converter, params_ref()), + m_th_rw(m), + m_trail_stack(*this), + m_fpa_util(m_converter.fu()), + m_bv_util(m_converter.bu()), + m_arith_util(m_converter.au()), m_is_initialized(false) { params_ref p; @@ -799,33 +799,35 @@ namespace smt { } void theory_fpa::finalize_model(model_generator & mg) { +#if 0 ast_manager & m = get_manager(); proto_model & mdl = mg.get_model(); - proto_model new_model(m); - - bv2fpa_converter bv2fp(m, m_converter); - - obj_hashtable seen; - bv2fp.convert_min_max_specials(&mdl, &new_model, seen); - bv2fp.convert_uf2bvuf(&mdl, &new_model, seen); - - for (obj_hashtable::iterator it = seen.begin(); - it != seen.end(); - it++) - mdl.unregister_decl(*it); - - for (unsigned i = 0; i < new_model.get_num_constants(); i++) { - func_decl * f = new_model.get_constant(i); - mdl.register_decl(f, new_model.get_const_interp(f)); - } - - for (unsigned i = 0; i < new_model.get_num_functions(); i++) { - func_decl * f = new_model.get_function(i); - func_interp * fi = new_model.get_func_interp(f)->copy(); - mdl.register_decl(f, fi); - } + proto_model new_model(m); + + bv2fpa_converter bv2fp(m, m_converter); + + obj_hashtable seen; + bv2fp.convert_min_max_specials(&mdl, &new_model, seen); + bv2fp.convert_uf2bvuf(&mdl, &new_model, seen); + + for (obj_hashtable::iterator it = seen.begin(); + it != seen.end(); + it++) + mdl.unregister_decl(*it); + + for (unsigned i = 0; i < new_model.get_num_constants(); i++) { + func_decl * f = new_model.get_constant(i); + mdl.register_decl(f, new_model.get_const_interp(f)); + } + + for (unsigned i = 0; i < new_model.get_num_functions(); i++) { + func_decl * f = new_model.get_function(i); + func_interp * fi = new_model.get_func_interp(f)->copy(); + mdl.register_decl(f, fi); + } +#endif } - + void theory_fpa::display(std::ostream & out) const { ast_manager & m = get_manager(); diff --git a/src/tactic/fpa/fpa2bv_model_converter.cpp b/src/tactic/fpa/fpa2bv_model_converter.cpp index 9b95cf921..88224d2f2 100644 --- a/src/tactic/fpa/fpa2bv_model_converter.cpp +++ b/src/tactic/fpa/fpa2bv_model_converter.cpp @@ -22,52 +22,48 @@ Notes: void fpa2bv_model_converter::display(std::ostream & out) { out << "(fpa2bv-model-converter"; - m_bv2fp->display(out); + m_bv2fp->display(out); out << ")"; } model_converter * fpa2bv_model_converter::translate(ast_translation & translator) { - fpa2bv_model_converter * res = alloc(fpa2bv_model_converter, translator.to()); - res->m_bv2fp = m_bv2fp->translate(translator); + fpa2bv_model_converter * res = alloc(fpa2bv_model_converter, translator.to()); + res->m_bv2fp = m_bv2fp->translate(translator); return res; } void fpa2bv_model_converter::convert(model_core * mc, model * float_mdl) { - obj_hashtable seen; - m_bv2fp->convert_consts(mc, float_mdl, seen); - m_bv2fp->convert_rm_consts(mc, float_mdl, seen); - m_bv2fp->convert_min_max_specials(mc, float_mdl, seen); - m_bv2fp->convert_uf2bvuf(mc, float_mdl, seen); - - // Keep all the non-float constants. - unsigned sz = mc->get_num_constants(); - for (unsigned i = 0; i < sz; i++) - { - func_decl * c = mc->get_constant(i); - if (!seen.contains(c)) - float_mdl->register_decl(c, mc->get_const_interp(c)); - } - - // And keep everything else - sz = mc->get_num_functions(); - for (unsigned i = 0; i < sz; i++) - { - func_decl * f = mc->get_function(i); - if (!seen.contains(f)) - { - TRACE("fpa2bv_mc", tout << "Keeping: " << mk_ismt2_pp(f, m) << std::endl;); - func_interp * val = mc->get_func_interp(f)->copy(); - float_mdl->register_decl(f, val); - } - } - - sz = mc->get_num_uninterpreted_sorts(); - for (unsigned i = 0; i < sz; i++) - { - sort * s = mc->get_uninterpreted_sort(i); - ptr_vector u = mc->get_universe(s); - float_mdl->register_usort(s, u.size(), u.c_ptr()); - } + obj_hashtable seen; + m_bv2fp->convert_consts(mc, float_mdl, seen); + m_bv2fp->convert_rm_consts(mc, float_mdl, seen); + m_bv2fp->convert_min_max_specials(mc, float_mdl, seen); + m_bv2fp->convert_uf2bvuf(mc, float_mdl, seen); + + // Keep all the non-float constants. + unsigned sz = mc->get_num_constants(); + for (unsigned i = 0; i < sz; i++) { + func_decl * c = mc->get_constant(i); + if (!seen.contains(c)) + float_mdl->register_decl(c, mc->get_const_interp(c)); + } + + // And keep everything else + sz = mc->get_num_functions(); + for (unsigned i = 0; i < sz; i++) { + func_decl * f = mc->get_function(i); + if (!seen.contains(f)) { + TRACE("fpa2bv_mc", tout << "Keeping: " << mk_ismt2_pp(f, m) << std::endl;); + func_interp * val = mc->get_func_interp(f)->copy(); + float_mdl->register_decl(f, val); + } + } + + sz = mc->get_num_uninterpreted_sorts(); + for (unsigned i = 0; i < sz; i++) { + sort * s = mc->get_uninterpreted_sort(i); + ptr_vector u = mc->get_universe(s); + float_mdl->register_usort(s, u.size(), u.c_ptr()); + } } model_converter * mk_fpa2bv_model_converter(ast_manager & m, fpa2bv_converter & conv) { diff --git a/src/tactic/fpa/fpa2bv_model_converter.h b/src/tactic/fpa/fpa2bv_model_converter.h index 7a39c0fba..1f482478b 100644 --- a/src/tactic/fpa/fpa2bv_model_converter.h +++ b/src/tactic/fpa/fpa2bv_model_converter.h @@ -25,23 +25,22 @@ Notes: class fpa2bv_model_converter : public model_converter { ast_manager & m; - bv2fpa_converter * m_bv2fp; + bv2fpa_converter * m_bv2fp; public: - fpa2bv_model_converter(ast_manager & m, fpa2bv_converter & conv) : - m(m) { - m_bv2fp = alloc(bv2fpa_converter, m, conv); + fpa2bv_model_converter(ast_manager & m, fpa2bv_converter & conv): + m(m), + m_bv2fp(alloc(bv2fpa_converter, m, conv)) { } virtual ~fpa2bv_model_converter() { - if (m_bv2fp) dealloc(m_bv2fp); - m_bv2fp = 0; + dealloc(m_bv2fp); } virtual void operator()(model_ref & md, unsigned goal_idx) { SASSERT(goal_idx == 0); model * new_model = alloc(model, m); - convert(md.get(), new_model); + convert(md.get(), new_model); md = new_model; } @@ -56,9 +55,9 @@ public: protected: fpa2bv_model_converter(ast_manager & m) : m(m), - m_bv2fp(0) {} - - void convert(model_core * mc, model * float_mdl); + m_bv2fp(0) {} + + void convert(model_core * mc, model * float_mdl); }; diff --git a/src/test/get_consequences.cpp b/src/test/get_consequences.cpp index 9dc0b43f9..f35a12ede 100644 --- a/src/test/get_consequences.cpp +++ b/src/test/get_consequences.cpp @@ -8,6 +8,7 @@ Copyright (c) 2016 Microsoft Corporation #include "datatype_decl_plugin.h" #include "reg_decl_plugins.h" #include "ast_pp.h" +#include "dt2bv.h" //include static expr_ref mk_const(ast_manager& m, char const* name, sort* s) { @@ -72,6 +73,18 @@ static void test2() { g->assert_expr(m.mk_not(m.mk_eq(x, r))); g->assert_expr(m.mk_not(m.mk_eq(x, b))); g->display(std::cout); + tactic_ref dt2bv = mk_dt2bv_tactic(m); + goal_ref_buffer result; + model_converter_ref mc; + proof_converter_ref pc; + expr_dependency_ref core; + (*dt2bv)(g, result, mc, pc, core); + model_ref mdl1 = alloc(model, m); + model_ref mdl2 = (*mc)(*mdl1); + expr_ref val(m); + mdl2->eval(x, val); + std::cout << val << "\n"; + } void tst_get_consequences() { From 707dbd4173a6dff25d4b4212df64240406c01824 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Mon, 17 Oct 2016 16:19:27 +0100 Subject: [PATCH 238/536] Bugfix for bv2fpa (model) conversion. Relates to #740 --- src/ast/fpa/bv2fpa_converter.cpp | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/ast/fpa/bv2fpa_converter.cpp b/src/ast/fpa/bv2fpa_converter.cpp index fb3af396c..50f13aeee 100644 --- a/src/ast/fpa/bv2fpa_converter.cpp +++ b/src/ast/fpa/bv2fpa_converter.cpp @@ -316,13 +316,21 @@ void bv2fpa_converter::convert_consts(model_core * mc, model_core * target_model app * a2 = to_app(val->get_arg(2)); expr_ref v0(m), v1(m), v2(m); +#ifdef Z3DEBUG v0 = mc->get_const_interp(a0->get_decl()); v1 = mc->get_const_interp(a1->get_decl()); v2 = mc->get_const_interp(a2->get_decl()); +#else + expr * bv = mc->get_const_interp(to_app(to_app(a0)->get_arg(0))->get_decl()); + unsigned bv_sz = m_bv_util.get_bv_size(bv); + v0 = m_bv_util.mk_extract(bv_sz-1, bv_sz-1, bv); + v1 = m_bv_util.mk_extract(bv_sz-2, sbits-1, bv); + v2 = m_bv_util.mk_extract(sbits-2, 0, bv); +#endif - if (!v0) v0 = m_bv_util.mk_numeral(0, 1); - if (!v1) v1 = m_bv_util.mk_numeral(0, ebits); - if (!v2) v2 = m_bv_util.mk_numeral(0, sbits-1); + if (!v0) v0 = m_bv_util.mk_numeral(0, 1); + if (!v1) v1 = m_bv_util.mk_numeral(0, ebits); + if (!v2) v2 = m_bv_util.mk_numeral(0, sbits-1); expr_ref sgn(m), exp(m), sig(m); m_th_rw(v0, sgn); From 2f6ef0f3be4ba96dd09c7f1c7c13d88bc77f19c7 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Mon, 17 Oct 2016 16:33:09 +0100 Subject: [PATCH 239/536] Removed unnecessary variables. --- src/ast/fpa/fpa2bv_converter.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/ast/fpa/fpa2bv_converter.cpp b/src/ast/fpa/fpa2bv_converter.cpp index 05c45c925..da473f993 100644 --- a/src/ast/fpa/fpa2bv_converter.cpp +++ b/src/ast/fpa/fpa2bv_converter.cpp @@ -3295,8 +3295,6 @@ void fpa2bv_converter::mk_to_sbv(func_decl * f, unsigned num, expr * const * arg void fpa2bv_converter::mk_to_ubv_unspecified(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { SASSERT(num == 0); - unsigned ebits = f->get_parameter(0).get_int(); - unsigned sbits = f->get_parameter(1).get_int(); unsigned width = m_bv_util.get_bv_size(f->get_range()); if (m_hi_fp_unspecified) @@ -3326,8 +3324,6 @@ expr_ref fpa2bv_converter::mk_to_ubv_unspecified(unsigned ebits, unsigned sbits, void fpa2bv_converter::mk_to_sbv_unspecified(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { SASSERT(num == 0); - unsigned ebits = f->get_parameter(0).get_int(); - unsigned sbits = f->get_parameter(1).get_int(); unsigned width = m_bv_util.get_bv_size(f->get_range()); if (m_hi_fp_unspecified) @@ -3339,7 +3335,7 @@ void fpa2bv_converter::mk_to_sbv_unspecified(func_decl * f, unsigned num, expr * m_uf2bvuf.insert(f, fd); m.inc_ref(f); m.inc_ref(fd); - } + } result = m.mk_const(fd); } From 4ef55505e7f8ca5b35b88ec1c2e1a2c331460d40 Mon Sep 17 00:00:00 2001 From: Dan Liew Date: Mon, 17 Oct 2016 17:12:04 +0100 Subject: [PATCH 240/536] [CMake] Fix #763 reported by @jirislaby. `INTERFACE` was the not appropriate usage requirement to use. However it only caused a problem when USE_LIB_GMP was enabled. With `INTERFACE` `-lgmp` was not specified on the link line so `libz3.so` did not have a reference to the library and linking against `libz3.so` by clients would fail with missing references to symbols in `libgmp`. --- contrib/cmake/src/CMakeLists.txt | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/contrib/cmake/src/CMakeLists.txt b/contrib/cmake/src/CMakeLists.txt index cba30c46f..f12c56f8e 100644 --- a/contrib/cmake/src/CMakeLists.txt +++ b/contrib/cmake/src/CMakeLists.txt @@ -136,9 +136,10 @@ if (NOT MSVC) set_target_properties(libz3 PROPERTIES OUTPUT_NAME z3) endif() -# Using INTERFACE means that targets that try link against libz3 will -# automatically link against the libs in Z3_DEPENDENT_LIBS -target_link_libraries(libz3 INTERFACE ${Z3_DEPENDENT_LIBS}) +# The `PRIVATE` usage requirement is specified so that when building Z3 as a +# shared library the dependent libraries are specified on the link command line +# so that if those are also shared libraries they are referenced by `libz3.so`. +target_link_libraries(libz3 PRIVATE ${Z3_DEPENDENT_LIBS}) z3_append_linker_flag_list_to_target(libz3 ${Z3_DEPENDENT_EXTRA_CXX_LINK_FLAGS}) From 03071db3eda047743442f1160af28f223ddb6608 Mon Sep 17 00:00:00 2001 From: Dan Liew Date: Mon, 17 Oct 2016 18:00:08 +0100 Subject: [PATCH 241/536] [CMake] Fix building the examples when libz3 is built as a static library. --- contrib/cmake/examples/c++/CMakeLists.txt | 5 +++++ contrib/cmake/examples/c/CMakeLists.txt | 6 ++++++ 2 files changed, 11 insertions(+) diff --git a/contrib/cmake/examples/c++/CMakeLists.txt b/contrib/cmake/examples/c++/CMakeLists.txt index 85bbd77c7..fdc5cf387 100644 --- a/contrib/cmake/examples/c++/CMakeLists.txt +++ b/contrib/cmake/examples/c++/CMakeLists.txt @@ -1,4 +1,9 @@ +# FIXME: We should build this as an external project and consume +# Z3 as `find_package(z3 CONFIG)`. add_executable(cpp_example EXCLUDE_FROM_ALL example.cpp) target_link_libraries(cpp_example PRIVATE libz3) target_include_directories(cpp_example PRIVATE "${CMAKE_SOURCE_DIR}/src/api") target_include_directories(cpp_example PRIVATE "${CMAKE_SOURCE_DIR}/src/api/c++") +if (NOT BUILD_LIBZ3_SHARED) + z3_append_linker_flag_list_to_target(cpp_example ${Z3_DEPENDENT_EXTRA_CXX_LINK_FLAGS}) +endif() diff --git a/contrib/cmake/examples/c/CMakeLists.txt b/contrib/cmake/examples/c/CMakeLists.txt index 1a14573ac..fc6eaee18 100644 --- a/contrib/cmake/examples/c/CMakeLists.txt +++ b/contrib/cmake/examples/c/CMakeLists.txt @@ -1,3 +1,9 @@ +# FIXME: We should build this as an external project and consume +# Z3 as `find_package(z3 CONFIG)`. add_executable(c_example EXCLUDE_FROM_ALL test_capi.c) target_link_libraries(c_example PRIVATE libz3) target_include_directories(c_example PRIVATE "${CMAKE_SOURCE_DIR}/src/api") +# This is needed for when libz3 is built as a static library +if (NOT BUILD_LIBZ3_SHARED) + z3_append_linker_flag_list_to_target(c_example ${Z3_DEPENDENT_EXTRA_C_LINK_FLAGS}) +endif() From 462d3e8e8b6ac0f8319bd0f8e73aa82e85d02e1a Mon Sep 17 00:00:00 2001 From: Dan Liew Date: Mon, 17 Oct 2016 18:15:31 +0100 Subject: [PATCH 242/536] [CMake] Unbreak building the .NET bindings. 7fefe40f210300dc073c93b2889be274bd92da62 broke building the .NET bindings by renaming the signing key without updating the CMake build. --- contrib/cmake/src/api/dotnet/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/cmake/src/api/dotnet/CMakeLists.txt b/contrib/cmake/src/api/dotnet/CMakeLists.txt index 7440f021b..93f5929d9 100644 --- a/contrib/cmake/src/api/dotnet/CMakeLists.txt +++ b/contrib/cmake/src/api/dotnet/CMakeLists.txt @@ -156,7 +156,7 @@ elseif (DOTNET_TOOLCHAIN_IS_MONO) # We need to give the assembly a strong name so that it can be installed # into the GAC. list(APPEND CSC_FLAGS - "/keyfile:${CMAKE_CURRENT_SOURCE_DIR}/Microsoft.Z3.mono.snk" + "/keyfile:${CMAKE_CURRENT_SOURCE_DIR}/Microsoft.Z3.snk" ) else() message(FATAL_ERROR "Unknown .NET toolchain") From 289e51f4557baebb08ea37f951bf92fc01b3c1ef Mon Sep 17 00:00:00 2001 From: Dan Liew Date: Mon, 17 Oct 2016 18:30:49 +0100 Subject: [PATCH 243/536] [CMake] Fix building the Java bindings. This was broken due to 495ef0f055f300089ec57f7aa71c2cc48d0fd402 and a914822346179531cf36c79809e5f01842267c84 adding and removing source files without updating the CMake build. --- contrib/cmake/src/api/java/CMakeLists.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/contrib/cmake/src/api/java/CMakeLists.txt b/contrib/cmake/src/api/java/CMakeLists.txt index 6e16ddb74..b34277266 100644 --- a/contrib/cmake/src/api/java/CMakeLists.txt +++ b/contrib/cmake/src/api/java/CMakeLists.txt @@ -110,7 +110,9 @@ set(Z3_JAVA_JAR_SOURCE_FILES BitVecSort.java BoolExpr.java BoolSort.java + ConstructorDecRefQueue.java Constructor.java + ConstructorListDecRefQueue.java ConstructorList.java Context.java DatatypeExpr.java @@ -136,7 +138,6 @@ set(Z3_JAVA_JAR_SOURCE_FILES GoalDecRefQueue.java Goal.java IDecRefQueue.java - IDisposable.java InterpolationContext.java IntExpr.java IntNum.java From 9e4450228eb4537e7cf87192c53ba4bcb69107bb Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 17 Oct 2016 14:52:37 -0400 Subject: [PATCH 244/536] adding unit test for enumeration types Signed-off-by: Nikolaj Bjorner --- src/ast/ast_smt2_pp.cpp | 5 ++- src/tactic/bv/dt2bv_tactic.cpp | 16 +++++--- src/tactic/bv/dt2bv_tactic.h | 3 +- src/test/get_consequences.cpp | 74 ++++++++++++++++++++++++++-------- 4 files changed, 74 insertions(+), 24 deletions(-) diff --git a/src/ast/ast_smt2_pp.cpp b/src/ast/ast_smt2_pp.cpp index 2e2d99a38..98c3b7962 100644 --- a/src/ast/ast_smt2_pp.cpp +++ b/src/ast/ast_smt2_pp.cpp @@ -1205,13 +1205,16 @@ mk_ismt2_pp::mk_ismt2_pp(ast * t, ast_manager & m, unsigned indent, unsigned num } std::ostream& operator<<(std::ostream& out, mk_ismt2_pp const & p) { - smt2_pp_environment_dbg env(p.m_manager); + smt2_pp_environment_dbg env(p.m_manager); if (is_expr(p.m_ast)) { ast_smt2_pp(out, to_expr(p.m_ast), env, p.m_params, p.m_indent, p.m_num_vars, p.m_var_prefix); } else if (is_sort(p.m_ast)) { ast_smt2_pp(out, to_sort(p.m_ast), env, p.m_params, p.m_indent); } + else if (p.m_ast == 0) { + out << "null"; + } else { SASSERT(is_func_decl(p.m_ast)); ast_smt2_pp(out, to_func_decl(p.m_ast), env, p.m_params, p.m_indent); diff --git a/src/tactic/bv/dt2bv_tactic.cpp b/src/tactic/bv/dt2bv_tactic.cpp index e8763475b..ab9df78ad 100644 --- a/src/tactic/bv/dt2bv_tactic.cpp +++ b/src/tactic/bv/dt2bv_tactic.cpp @@ -43,6 +43,7 @@ class dt2bv_tactic : public tactic { ref m_ext; ref m_filter; unsigned m_num_translated; + obj_map* m_translate; struct rw_cfg : public default_rewriter_cfg { dt2bv_tactic& m_t; @@ -117,7 +118,7 @@ class dt2bv_tactic : public tactic { unsigned nc = m_t.m_dt.get_datatype_num_constructors(s); result = m.mk_fresh_const(f->get_name().str().c_str(), m_t.m_bv.mk_sort(bv_size)); if (!is_power_of_two(nc)) { - m_t.m_bounds.push_back(m_t.m_bv.mk_ule(result, m_t.m_bv.mk_numeral(nc, bv_size))); + m_t.m_bounds.push_back(m_t.m_bv.mk_ule(result, m_t.m_bv.mk_numeral(nc-1, bv_size))); } expr_ref f_def(m); ptr_vector const& cs = *m_t.m_dt.get_datatype_constructors(s); @@ -129,6 +130,9 @@ class dt2bv_tactic : public tactic { // update model converters. m_t.m_ext->insert(f, f_def); m_t.m_filter->insert(to_app(result)->get_decl()); + if (m_t.m_translate) { + m_t.m_translate->insert(f, result); + } } else { return false; @@ -253,11 +257,11 @@ class dt2bv_tactic : public tactic { public: - dt2bv_tactic(ast_manager& m, params_ref const& p): - m(m), m_params(p), m_dt(m), m_bv(m), m_bounds(m) {} + dt2bv_tactic(ast_manager& m, params_ref const& p, obj_map* tr): + m(m), m_params(p), m_dt(m), m_bv(m), m_bounds(m), m_translate(tr) {} virtual tactic * translate(ast_manager & m) { - return alloc(dt2bv_tactic, m, m_params); + return alloc(dt2bv_tactic, m, m_params, 0); } virtual void updt_params(params_ref const & p) { @@ -320,6 +324,6 @@ public: }; -tactic * mk_dt2bv_tactic(ast_manager & m, params_ref const & p) { - return alloc(dt2bv_tactic, m, p); +tactic * mk_dt2bv_tactic(ast_manager & m, params_ref const & p, obj_map* tr) { + return alloc(dt2bv_tactic, m, p, tr); } diff --git a/src/tactic/bv/dt2bv_tactic.h b/src/tactic/bv/dt2bv_tactic.h index 64d1d5497..a8fb33fe8 100644 --- a/src/tactic/bv/dt2bv_tactic.h +++ b/src/tactic/bv/dt2bv_tactic.h @@ -20,10 +20,11 @@ Revision History: #define DT2BV_TACTIC_H_ #include"params.h" +#include"obj_hashtable.h" class ast_manager; class tactic; -tactic * mk_dt2bv_tactic(ast_manager & m, params_ref const & p = params_ref()); +tactic * mk_dt2bv_tactic(ast_manager & m, params_ref const & p = params_ref(), obj_map* tr = 0); /* ADD_TACTIC("dt2bv", "eliminate finite domain data-types. Replace by bit-vectors.", "mk_dt2bv_tactic(m, p)") diff --git a/src/test/get_consequences.cpp b/src/test/get_consequences.cpp index f35a12ede..24f3a5d38 100644 --- a/src/test/get_consequences.cpp +++ b/src/test/get_consequences.cpp @@ -8,7 +8,9 @@ Copyright (c) 2016 Microsoft Corporation #include "datatype_decl_plugin.h" #include "reg_decl_plugins.h" #include "ast_pp.h" -#include "dt2bv.h" +#include "dt2bv_tactic.h" +#include "tactic.h" +#include "model_smt2_pp.h" //include static expr_ref mk_const(ast_manager& m, char const* name, sort* s) { @@ -53,38 +55,78 @@ static void test2() { ast_manager m; reg_decl_plugins(m); bv_util bv(m); + datatype_util dtutil(m); + params_ref p; - datatype_decl_plugin& dt = static_cast(*m.get_plugin(m.get_family_id("datatype"))); + datatype_decl_plugin & dt = *(static_cast(m.get_plugin(m.get_family_id("datatype")))); sort_ref_vector new_sorts(m); constructor_decl* R = mk_constructor_decl(symbol("R"), symbol("is-R"), 0, 0); constructor_decl* G = mk_constructor_decl(symbol("G"), symbol("is-G"), 0, 0); constructor_decl* B = mk_constructor_decl(symbol("B"), symbol("is-B"), 0, 0); constructor_decl* constrs[3] = { R, G, B }; - datatype_decl const* enum_sort = mk_datatype_decl(symbol("RGB"), 3, constrs); + datatype_decl * enum_sort = mk_datatype_decl(symbol("RGB"), 3, constrs); VERIFY(dt.mk_datatypes(1, &enum_sort, new_sorts)); del_constructor_decls(3, constrs); sort* rgb = new_sorts[0].get(); expr_ref x = mk_const(m, "x", rgb), y = mk_const(m, "y", rgb), z = mk_const(m, "z", rgb); - ptr_vector const& enums = dt.geet_datatype_constructors(rgb); - expr_ref r = expr_ref(m.mk_const(enums[0], m), m), g = expr_ref(m.mk_const(enums[1], m), m), b = expr_ref(m.mk_const(enums[2], m), m); + ptr_vector const& enums = *dtutil.get_datatype_constructors(rgb); + expr_ref r = expr_ref(m.mk_const(enums[0]), m); + expr_ref g = expr_ref(m.mk_const(enums[1]), m); + expr_ref b = expr_ref(m.mk_const(enums[2]), m); + expr_ref val(m); - goal_ref g = alloc(goal, m); - g->assert_expr(m.mk_not(m.mk_eq(x, r))); - g->assert_expr(m.mk_not(m.mk_eq(x, b))); - g->display(std::cout); - tactic_ref dt2bv = mk_dt2bv_tactic(m); + // Eliminate enumeration data-types: + goal_ref gl = alloc(goal, m); + gl->assert_expr(m.mk_not(m.mk_eq(x, r))); + gl->assert_expr(m.mk_not(m.mk_eq(x, b))); + gl->display(std::cout); + obj_map tr; + obj_map rev_tr; + ref dt2bv = mk_dt2bv_tactic(m, p, &tr); goal_ref_buffer result; model_converter_ref mc; proof_converter_ref pc; - expr_dependency_ref core; - (*dt2bv)(g, result, mc, pc, core); - model_ref mdl1 = alloc(model, m); - model_ref mdl2 = (*mc)(*mdl1); - expr_ref val(m); - mdl2->eval(x, val); + expr_dependency_ref core(m); + (*dt2bv)(gl, result, mc, pc, core); + + // Collect translations from enumerations to bit-vectors + obj_map::iterator it = tr.begin(), end = tr.end(); + for (; it != end; ++it) { + rev_tr.insert(it->m_value, it->m_key); + } + + // Create bit-vector implication problem + val = tr.find(to_app(x)->get_decl()); std::cout << val << "\n"; + ptr_vector fmls; + result[0]->get_formulas(fmls); + ref solver = mk_inc_sat_solver(m, p); + for (unsigned i = 0; i < fmls.size(); ++i) { + solver->assert_expr(fmls[i]); + } + expr_ref_vector asms(m), vars(m), conseq(m); + vars.push_back(val); + + // retrieve consequences + solver->get_consequences(asms, vars, conseq); + // Convert consequences over bit-vectors to enumeration types. + std::cout << conseq << "\n"; + for (unsigned i = 0; i < conseq.size(); ++i) { + expr* a, *b, *u, *v; + func_decl* f; + rational num; + unsigned bvsize; + VERIFY(m.is_implies(conseq[i].get(), a, b)); + if (m.is_eq(b, u, v) && rev_tr.find(u, f) && bv.is_numeral(v, num, bvsize)) { + SASSERT(num.is_unsigned()); + expr_ref head(m); + head = m.mk_eq(m.mk_const(f), m.mk_const(enums[num.get_unsigned()])); + conseq[i] = m.mk_implies(a, head); + } + } + std::cout << conseq << "\n"; } void tst_get_consequences() { From 5ac3bb04eef80de3edf9d495612228055e02857e Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Tue, 18 Oct 2016 13:18:59 +0100 Subject: [PATCH 245/536] Tabs --- src/ast/fpa/bv2fpa_converter.cpp | 826 +++++++++++++++---------------- src/ast/fpa/bv2fpa_converter.h | 74 +-- src/ast/fpa/fpa2bv_converter.cpp | 162 +++--- 3 files changed, 531 insertions(+), 531 deletions(-) diff --git a/src/ast/fpa/bv2fpa_converter.cpp b/src/ast/fpa/bv2fpa_converter.cpp index 50f13aeee..07a24e40a 100644 --- a/src/ast/fpa/bv2fpa_converter.cpp +++ b/src/ast/fpa/bv2fpa_converter.cpp @@ -1,17 +1,17 @@ /*++ - Copyright (c) 2012 Microsoft Corporation + Copyright (c) 2012 Microsoft Corporation Module Name: - bv2fpa_converter.cpp + bv2fpa_converter.cpp Abstract: - Model conversion for fpa2bv_converter + Model conversion for fpa2bv_converter Author: - Christoph (cwinter) 2016-10-15 + Christoph (cwinter) 2016-10-15 Notes: @@ -27,299 +27,299 @@ Notes: bv2fpa_converter::bv2fpa_converter(ast_manager & m) : - m(m), - m_fpa_util(m), - m_bv_util(m), - m_th_rw(m) { + m(m), + m_fpa_util(m), + m_bv_util(m), + m_th_rw(m) { } bv2fpa_converter::bv2fpa_converter(ast_manager & m, fpa2bv_converter & conv) : - m(m), - m_fpa_util(m), - m_bv_util(m), - m_th_rw(m) { - for (obj_map::iterator it = conv.m_const2bv.begin(); - it != conv.m_const2bv.end(); - it++) - { - m_const2bv.insert(it->m_key, it->m_value); - m.inc_ref(it->m_key); - m.inc_ref(it->m_value); - } - for (obj_map::iterator it = conv.m_rm_const2bv.begin(); - it != conv.m_rm_const2bv.end(); - it++) - { - m_rm_const2bv.insert(it->m_key, it->m_value); - m.inc_ref(it->m_key); - m.inc_ref(it->m_value); - } - for (obj_map::iterator it = conv.m_uf2bvuf.begin(); - it != conv.m_uf2bvuf.end(); - it++) - { - m_uf2bvuf.insert(it->m_key, it->m_value); - m.inc_ref(it->m_key); - m.inc_ref(it->m_value); - } - for (obj_map >::iterator it = conv.m_min_max_specials.begin(); - it != conv.m_min_max_specials.end(); - it++) { - m_specials.insert(it->m_key, it->m_value); - m.inc_ref(it->m_key); - m.inc_ref(it->m_value.first); - m.inc_ref(it->m_value.second); - } + m(m), + m_fpa_util(m), + m_bv_util(m), + m_th_rw(m) { + for (obj_map::iterator it = conv.m_const2bv.begin(); + it != conv.m_const2bv.end(); + it++) + { + m_const2bv.insert(it->m_key, it->m_value); + m.inc_ref(it->m_key); + m.inc_ref(it->m_value); + } + for (obj_map::iterator it = conv.m_rm_const2bv.begin(); + it != conv.m_rm_const2bv.end(); + it++) + { + m_rm_const2bv.insert(it->m_key, it->m_value); + m.inc_ref(it->m_key); + m.inc_ref(it->m_value); + } + for (obj_map::iterator it = conv.m_uf2bvuf.begin(); + it != conv.m_uf2bvuf.end(); + it++) + { + m_uf2bvuf.insert(it->m_key, it->m_value); + m.inc_ref(it->m_key); + m.inc_ref(it->m_value); + } + for (obj_map >::iterator it = conv.m_min_max_specials.begin(); + it != conv.m_min_max_specials.end(); + it++) { + m_specials.insert(it->m_key, it->m_value); + m.inc_ref(it->m_key); + m.inc_ref(it->m_value.first); + m.inc_ref(it->m_value.second); + } } bv2fpa_converter::~bv2fpa_converter() { - dec_ref_map_key_values(m, m_const2bv); - dec_ref_map_key_values(m, m_rm_const2bv); - dec_ref_map_key_values(m, m_uf2bvuf); - for (obj_map >::iterator it = m_specials.begin(); - it != m_specials.end(); - it++) { - m.dec_ref(it->m_key); - m.dec_ref(it->m_value.first); - m.dec_ref(it->m_value.second); - } + dec_ref_map_key_values(m, m_const2bv); + dec_ref_map_key_values(m, m_rm_const2bv); + dec_ref_map_key_values(m, m_uf2bvuf); + for (obj_map >::iterator it = m_specials.begin(); + it != m_specials.end(); + it++) { + m.dec_ref(it->m_key); + m.dec_ref(it->m_value.first); + m.dec_ref(it->m_value.second); + } } expr_ref bv2fpa_converter::convert_bv2fp(sort * s, expr * sgn, expr * exp, expr * sig) { - unsynch_mpz_manager & mpzm = m_fpa_util.fm().mpz_manager(); - unsynch_mpq_manager & mpqm = m_fpa_util.fm().mpq_manager(); + unsynch_mpz_manager & mpzm = m_fpa_util.fm().mpz_manager(); + unsynch_mpq_manager & mpqm = m_fpa_util.fm().mpq_manager(); - expr_ref res(m); - mpf fp_val; + expr_ref res(m); + mpf fp_val; - unsigned ebits = m_fpa_util.get_ebits(s); - unsigned sbits = m_fpa_util.get_sbits(s); + unsigned ebits = m_fpa_util.get_ebits(s); + unsigned sbits = m_fpa_util.get_sbits(s); - unsigned sgn_sz = 1; - unsigned exp_sz = ebits; - unsigned sig_sz = sbits - 1; + unsigned sgn_sz = 1; + unsigned exp_sz = ebits; + unsigned sig_sz = sbits - 1; - rational sgn_q(0), sig_q(0), exp_q(0); + rational sgn_q(0), sig_q(0), exp_q(0); - if (sgn) m_bv_util.is_numeral(sgn, sgn_q, sgn_sz); - if (exp) m_bv_util.is_numeral(exp, exp_q, exp_sz); - if (sig) m_bv_util.is_numeral(sig, sig_q, sig_sz); + if (sgn) m_bv_util.is_numeral(sgn, sgn_q, sgn_sz); + if (exp) m_bv_util.is_numeral(exp, exp_q, exp_sz); + if (sig) m_bv_util.is_numeral(sig, sig_q, sig_sz); - // un-bias exponent - rational exp_unbiased_q; - exp_unbiased_q = exp_q - m_fpa_util.fm().m_powers2.m1(ebits - 1); + // un-bias exponent + rational exp_unbiased_q; + exp_unbiased_q = exp_q - m_fpa_util.fm().m_powers2.m1(ebits - 1); - mpz sig_z; mpf_exp_t exp_z; - mpzm.set(sig_z, sig_q.to_mpq().numerator()); - exp_z = mpzm.get_int64(exp_unbiased_q.to_mpq().numerator()); + mpz sig_z; mpf_exp_t exp_z; + mpzm.set(sig_z, sig_q.to_mpq().numerator()); + exp_z = mpzm.get_int64(exp_unbiased_q.to_mpq().numerator()); - m_fpa_util.fm().set(fp_val, ebits, sbits, !mpqm.is_zero(sgn_q.to_mpq()), exp_z, sig_z); + m_fpa_util.fm().set(fp_val, ebits, sbits, !mpqm.is_zero(sgn_q.to_mpq()), exp_z, sig_z); - mpzm.del(sig_z); + mpzm.del(sig_z); - res = m_fpa_util.mk_value(fp_val); + res = m_fpa_util.mk_value(fp_val); - TRACE("bv2fpa", tout << "[" << mk_ismt2_pp(sgn, m) << - " " << mk_ismt2_pp(exp, m) << - " " << mk_ismt2_pp(sig, m) << "] == " << - mk_ismt2_pp(res, m) << std::endl;); - m_fpa_util.fm().del(fp_val); + TRACE("bv2fpa", tout << "[" << mk_ismt2_pp(sgn, m) << + " " << mk_ismt2_pp(exp, m) << + " " << mk_ismt2_pp(sig, m) << "] == " << + mk_ismt2_pp(res, m) << std::endl;); + m_fpa_util.fm().del(fp_val); - return res; + return res; } expr_ref bv2fpa_converter::convert_bv2fp(model_core * mc, sort * s, app * bv) { - SASSERT(m_bv_util.is_bv(bv)); + SASSERT(m_bv_util.is_bv(bv)); - unsigned ebits = m_fpa_util.get_ebits(s); - unsigned sbits = m_fpa_util.get_sbits(s); - unsigned bv_sz = sbits + ebits; + unsigned ebits = m_fpa_util.get_ebits(s); + unsigned sbits = m_fpa_util.get_sbits(s); + unsigned bv_sz = sbits + ebits; - expr_ref bv_num(m); - if (m_bv_util.is_numeral(bv)) - bv_num = bv; - else if (!mc->eval(bv->get_decl(), bv_num)) - bv_num = m_bv_util.mk_numeral(0, m_bv_util.get_bv_size(bv)); + expr_ref bv_num(m); + if (m_bv_util.is_numeral(bv)) + bv_num = bv; + else if (!mc->eval(bv->get_decl(), bv_num)) + bv_num = m_bv_util.mk_numeral(0, m_bv_util.get_bv_size(bv)); - expr_ref sgn(m), exp(m), sig(m); - sgn = m_bv_util.mk_extract(bv_sz - 1, bv_sz - 1, bv_num); - exp = m_bv_util.mk_extract(bv_sz - 2, sbits - 1, bv_num); - sig = m_bv_util.mk_extract(sbits - 2, 0, bv_num); + expr_ref sgn(m), exp(m), sig(m); + sgn = m_bv_util.mk_extract(bv_sz - 1, bv_sz - 1, bv_num); + exp = m_bv_util.mk_extract(bv_sz - 2, sbits - 1, bv_num); + sig = m_bv_util.mk_extract(sbits - 2, 0, bv_num); - expr_ref v_sgn(m), v_exp(m), v_sig(m); - m_th_rw(sgn, v_sgn); - m_th_rw(exp, v_exp); - m_th_rw(sig, v_sig); + expr_ref v_sgn(m), v_exp(m), v_sig(m); + m_th_rw(sgn, v_sgn); + m_th_rw(exp, v_exp); + m_th_rw(sig, v_sig); - return convert_bv2fp(s, v_sgn, v_exp, v_sig); + return convert_bv2fp(s, v_sgn, v_exp, v_sig); } expr_ref bv2fpa_converter::convert_bv2rm(expr * bv_rm) { - expr_ref res(m); - rational bv_val(0); - unsigned sz = 0; + expr_ref res(m); + rational bv_val(0); + unsigned sz = 0; - if (m_bv_util.is_numeral(bv_rm, bv_val, sz)) { - SASSERT(bv_val.is_uint64()); - switch (bv_val.get_uint64()) { - case BV_RM_TIES_TO_AWAY: res = m_fpa_util.mk_round_nearest_ties_to_away(); break; - case BV_RM_TIES_TO_EVEN: res = m_fpa_util.mk_round_nearest_ties_to_even(); break; - case BV_RM_TO_NEGATIVE: res = m_fpa_util.mk_round_toward_negative(); break; - case BV_RM_TO_POSITIVE: res = m_fpa_util.mk_round_toward_positive(); break; - case BV_RM_TO_ZERO: - default: res = m_fpa_util.mk_round_toward_zero(); - } - } + if (m_bv_util.is_numeral(bv_rm, bv_val, sz)) { + SASSERT(bv_val.is_uint64()); + switch (bv_val.get_uint64()) { + case BV_RM_TIES_TO_AWAY: res = m_fpa_util.mk_round_nearest_ties_to_away(); break; + case BV_RM_TIES_TO_EVEN: res = m_fpa_util.mk_round_nearest_ties_to_even(); break; + case BV_RM_TO_NEGATIVE: res = m_fpa_util.mk_round_toward_negative(); break; + case BV_RM_TO_POSITIVE: res = m_fpa_util.mk_round_toward_positive(); break; + case BV_RM_TO_ZERO: + default: res = m_fpa_util.mk_round_toward_zero(); + } + } - return res; + return res; } expr_ref bv2fpa_converter::convert_bv2rm(model_core * mc, app * val) { - expr_ref res(m); + expr_ref res(m); - if (val) { - expr_ref eval_v(m); - if (m_bv_util.is_numeral(val)) - res = convert_bv2rm(val); - else if (mc->eval(val->get_decl(), eval_v)) - res = convert_bv2rm(eval_v); - else - res = m_fpa_util.mk_round_toward_zero(); - } + if (val) { + expr_ref eval_v(m); + if (m_bv_util.is_numeral(val)) + res = convert_bv2rm(val); + else if (mc->eval(val->get_decl(), eval_v)) + res = convert_bv2rm(eval_v); + else + res = m_fpa_util.mk_round_toward_zero(); + } - return res; + return res; } expr_ref bv2fpa_converter::rebuild_floats(model_core * mc, sort * s, app * e) { - expr_ref result(m); - TRACE("bv2fpa", tout << "rebuild floats in " << mk_ismt2_pp(s, m) << " for "; - if (e) tout << mk_ismt2_pp(e, m); - else tout << "nil"; - tout << std::endl; ); + expr_ref result(m); + TRACE("bv2fpa", tout << "rebuild floats in " << mk_ismt2_pp(s, m) << " for "; + if (e) tout << mk_ismt2_pp(e, m); + else tout << "nil"; + tout << std::endl; ); - if (m_fpa_util.is_float(s)) { - if (e == 0) - result = m_fpa_util.mk_pzero(s); - else if (m_fpa_util.is_numeral(e)) - result = e; - else { - SASSERT(m_bv_util.is_bv(e) && m_bv_util.get_bv_size(e) == (m_fpa_util.get_ebits(s) + m_fpa_util.get_sbits(s))); - result = convert_bv2fp(mc, s, e); - } - } - else if (m_fpa_util.is_rm(s)) { - if (e == 0) - result = m_fpa_util.mk_round_toward_zero(); - else if (m_fpa_util.is_rm_numeral(e)) - result = e; - else { - SASSERT(m_bv_util.is_bv(e) && m_bv_util.get_bv_size(e) == 3); - result = convert_bv2rm(mc, e); - } - } - else if (is_app(e)) { - app * a = to_app(e); - expr_ref_vector new_args(m); - for (unsigned i = 0; i < a->get_num_args(); i++) - new_args.push_back(rebuild_floats(mc, a->get_decl()->get_domain()[i], to_app(a->get_arg(i)))); - result = m.mk_app(a->get_decl(), new_args.size(), new_args.c_ptr()); - } + if (m_fpa_util.is_float(s)) { + if (e == 0) + result = m_fpa_util.mk_pzero(s); + else if (m_fpa_util.is_numeral(e)) + result = e; + else { + SASSERT(m_bv_util.is_bv(e) && m_bv_util.get_bv_size(e) == (m_fpa_util.get_ebits(s) + m_fpa_util.get_sbits(s))); + result = convert_bv2fp(mc, s, e); + } + } + else if (m_fpa_util.is_rm(s)) { + if (e == 0) + result = m_fpa_util.mk_round_toward_zero(); + else if (m_fpa_util.is_rm_numeral(e)) + result = e; + else { + SASSERT(m_bv_util.is_bv(e) && m_bv_util.get_bv_size(e) == 3); + result = convert_bv2rm(mc, e); + } + } + else if (is_app(e)) { + app * a = to_app(e); + expr_ref_vector new_args(m); + for (unsigned i = 0; i < a->get_num_args(); i++) + new_args.push_back(rebuild_floats(mc, a->get_decl()->get_domain()[i], to_app(a->get_arg(i)))); + result = m.mk_app(a->get_decl(), new_args.size(), new_args.c_ptr()); + } - return result; + return result; } bv2fpa_converter::array_model bv2fpa_converter::convert_array_func_interp(model_core * mc, func_decl * f, func_decl * bv_f) { - SASSERT(f->get_arity() == 0); - array_util arr_util(m); + SASSERT(f->get_arity() == 0); + array_util arr_util(m); - array_model am(m); - sort_ref_vector array_domain(m); - unsigned arity = f->get_range()->get_num_parameters()-1; + array_model am(m); + sort_ref_vector array_domain(m); + unsigned arity = f->get_range()->get_num_parameters()-1; - expr_ref as_arr_mdl(m); - as_arr_mdl = mc->get_const_interp(bv_f); - if (as_arr_mdl == 0) return am; - TRACE("bv2fpa", tout << "arity=0 func_interp for " << mk_ismt2_pp(f, m) << " := " << mk_ismt2_pp(as_arr_mdl, m) << std::endl;); - SASSERT(arr_util.is_as_array(as_arr_mdl)); - for (unsigned i = 0; i < arity; i++) - array_domain.push_back(to_sort(f->get_range()->get_parameter(i).get_ast())); - sort * rng = to_sort(f->get_range()->get_parameter(arity).get_ast()); + expr_ref as_arr_mdl(m); + as_arr_mdl = mc->get_const_interp(bv_f); + if (as_arr_mdl == 0) return am; + TRACE("bv2fpa", tout << "arity=0 func_interp for " << mk_ismt2_pp(f, m) << " := " << mk_ismt2_pp(as_arr_mdl, m) << std::endl;); + SASSERT(arr_util.is_as_array(as_arr_mdl)); + for (unsigned i = 0; i < arity; i++) + array_domain.push_back(to_sort(f->get_range()->get_parameter(i).get_ast())); + sort * rng = to_sort(f->get_range()->get_parameter(arity).get_ast()); - bv_f = arr_util.get_as_array_func_decl(to_app(as_arr_mdl)); + bv_f = arr_util.get_as_array_func_decl(to_app(as_arr_mdl)); - am.new_float_fd = m.mk_fresh_func_decl(arity, array_domain.c_ptr(), rng); - am.new_float_fi = convert_func_interp(mc, am.new_float_fd, bv_f); - am.bv_fd = bv_f; - am.result = arr_util.mk_as_array(f->get_range(), am.new_float_fd); - return am; + am.new_float_fd = m.mk_fresh_func_decl(arity, array_domain.c_ptr(), rng); + am.new_float_fi = convert_func_interp(mc, am.new_float_fd, bv_f); + am.bv_fd = bv_f; + am.result = arr_util.mk_as_array(f->get_range(), am.new_float_fd); + return am; } func_interp * bv2fpa_converter::convert_func_interp(model_core * mc, func_decl * f, func_decl * bv_f) { - SASSERT(f->get_arity() > 0); - func_interp * result = 0; - sort * rng = f->get_range(); - sort * const * dmn = f->get_domain(); + SASSERT(f->get_arity() > 0); + func_interp * result = 0; + sort * rng = f->get_range(); + sort * const * dmn = f->get_domain(); - unsigned arity = bv_f->get_arity(); - func_interp * bv_fi = mc->get_func_interp(bv_f); + unsigned arity = bv_f->get_arity(); + func_interp * bv_fi = mc->get_func_interp(bv_f); - if (bv_fi != 0) { - fpa_rewriter rw(m); - expr_ref ai(m); - result = alloc(func_interp, m, arity); + if (bv_fi != 0) { + fpa_rewriter rw(m); + expr_ref ai(m); + result = alloc(func_interp, m, arity); - for (unsigned i = 0; i < bv_fi->num_entries(); i++) { - func_entry const * bv_fe = bv_fi->get_entry(i); - expr * const * bv_args = bv_fe->get_args(); - expr_ref_buffer new_args(m); + for (unsigned i = 0; i < bv_fi->num_entries(); i++) { + func_entry const * bv_fe = bv_fi->get_entry(i); + expr * const * bv_args = bv_fe->get_args(); + expr_ref_buffer new_args(m); - for (unsigned j = 0; j < arity; j++) { - sort * ft_dj = dmn[j]; - expr * bv_aj = bv_args[j]; - ai = rebuild_floats(mc, ft_dj, to_app(bv_aj)); - m_th_rw(ai); - new_args.push_back(ai); - } + for (unsigned j = 0; j < arity; j++) { + sort * ft_dj = dmn[j]; + expr * bv_aj = bv_args[j]; + ai = rebuild_floats(mc, ft_dj, to_app(bv_aj)); + m_th_rw(ai); + new_args.push_back(ai); + } - expr_ref bv_fres(m), ft_fres(m); - bv_fres = bv_fe->get_result(); - ft_fres = rebuild_floats(mc, rng, to_app(bv_fres)); - m_th_rw(ft_fres); - result->insert_new_entry(new_args.c_ptr(), ft_fres); - } + expr_ref bv_fres(m), ft_fres(m); + bv_fres = bv_fe->get_result(); + ft_fres = rebuild_floats(mc, rng, to_app(bv_fres)); + m_th_rw(ft_fres); + result->insert_new_entry(new_args.c_ptr(), ft_fres); + } - app_ref bv_els(m); - expr_ref ft_els(m); - bv_els = (app*)bv_fi->get_else(); - ft_els = rebuild_floats(mc, rng, bv_els); - m_th_rw(ft_els); - result->set_else(ft_els); - } + app_ref bv_els(m); + expr_ref ft_els(m); + bv_els = (app*)bv_fi->get_else(); + ft_els = rebuild_floats(mc, rng, bv_els); + m_th_rw(ft_els); + result->set_else(ft_els); + } - return result; + return result; } void bv2fpa_converter::convert_consts(model_core * mc, model_core * target_model, obj_hashtable & seen) { - for (obj_map::iterator it = m_const2bv.begin(); - it != m_const2bv.end(); - it++) - { - func_decl * var = it->m_key; - app * val = to_app(it->m_value); - SASSERT(m_fpa_util.is_float(var->get_range())); - SASSERT(var->get_range()->get_num_parameters() == 2); - unsigned ebits = m_fpa_util.get_ebits(var->get_range()); - unsigned sbits = m_fpa_util.get_sbits(var->get_range()); + for (obj_map::iterator it = m_const2bv.begin(); + it != m_const2bv.end(); + it++) + { + func_decl * var = it->m_key; + app * val = to_app(it->m_value); + SASSERT(m_fpa_util.is_float(var->get_range())); + SASSERT(var->get_range()->get_num_parameters() == 2); + unsigned ebits = m_fpa_util.get_ebits(var->get_range()); + unsigned sbits = m_fpa_util.get_sbits(var->get_range()); - app * a0 = to_app(val->get_arg(0)); - app * a1 = to_app(val->get_arg(1)); - app * a2 = to_app(val->get_arg(2)); + app * a0 = to_app(val->get_arg(0)); + app * a1 = to_app(val->get_arg(1)); + app * a2 = to_app(val->get_arg(2)); - expr_ref v0(m), v1(m), v2(m); + expr_ref v0(m), v1(m), v2(m); #ifdef Z3DEBUG - v0 = mc->get_const_interp(a0->get_decl()); - v1 = mc->get_const_interp(a1->get_decl()); - v2 = mc->get_const_interp(a2->get_decl()); + v0 = mc->get_const_interp(a0->get_decl()); + v1 = mc->get_const_interp(a1->get_decl()); + v2 = mc->get_const_interp(a2->get_decl()); #else expr * bv = mc->get_const_interp(to_app(to_app(a0)->get_arg(0))->get_decl()); unsigned bv_sz = m_bv_util.get_bv_size(bv); @@ -332,220 +332,220 @@ void bv2fpa_converter::convert_consts(model_core * mc, model_core * target_model if (!v1) v1 = m_bv_util.mk_numeral(0, ebits); if (!v2) v2 = m_bv_util.mk_numeral(0, sbits-1); - expr_ref sgn(m), exp(m), sig(m); - m_th_rw(v0, sgn); - m_th_rw(v1, exp); - m_th_rw(v2, sig); + expr_ref sgn(m), exp(m), sig(m); + m_th_rw(v0, sgn); + m_th_rw(v1, exp); + m_th_rw(v2, sig); - SASSERT(val->is_app_of(m_fpa_util.get_family_id(), OP_FPA_FP)); + SASSERT(val->is_app_of(m_fpa_util.get_family_id(), OP_FPA_FP)); #ifdef Z3DEBUG - SASSERT(to_app(val->get_arg(0))->get_decl()->get_arity() == 0); - SASSERT(to_app(val->get_arg(1))->get_decl()->get_arity() == 0); - SASSERT(to_app(val->get_arg(2))->get_decl()->get_arity() == 0); - seen.insert(to_app(val->get_arg(0))->get_decl()); - seen.insert(to_app(val->get_arg(1))->get_decl()); - seen.insert(to_app(val->get_arg(2))->get_decl()); + SASSERT(to_app(val->get_arg(0))->get_decl()->get_arity() == 0); + SASSERT(to_app(val->get_arg(1))->get_decl()->get_arity() == 0); + SASSERT(to_app(val->get_arg(2))->get_decl()->get_arity() == 0); + seen.insert(to_app(val->get_arg(0))->get_decl()); + seen.insert(to_app(val->get_arg(1))->get_decl()); + seen.insert(to_app(val->get_arg(2))->get_decl()); #else - SASSERT(a->get_arg(0)->get_kind() == OP_EXTRACT); - SASSERT(to_app(a->get_arg(0))->get_arg(0)->get_kind() == OP_EXTRACT); - seen.insert(to_app(to_app(val->get_arg(0))->get_arg(0))->get_decl()); + SASSERT(a->get_arg(0)->get_kind() == OP_EXTRACT); + SASSERT(to_app(a->get_arg(0))->get_arg(0)->get_kind() == OP_EXTRACT); + seen.insert(to_app(to_app(val->get_arg(0))->get_arg(0))->get_decl()); #endif - if (!sgn && !sig && !exp) - continue; + if (!sgn && !sig && !exp) + continue; - expr_ref cv(m); - cv = convert_bv2fp(var->get_range(), sgn, exp, sig); - target_model->register_decl(var, cv); + expr_ref cv(m); + cv = convert_bv2fp(var->get_range(), sgn, exp, sig); + target_model->register_decl(var, cv); - TRACE("bv2fpa", tout << var->get_name() << " == " << mk_ismt2_pp(cv, m) << std::endl;); - } + TRACE("bv2fpa", tout << var->get_name() << " == " << mk_ismt2_pp(cv, m) << std::endl;); + } } void bv2fpa_converter::convert_rm_consts(model_core * mc, model_core * target_model, obj_hashtable & seen) { - for (obj_map::iterator it = m_rm_const2bv.begin(); - it != m_rm_const2bv.end(); - it++) - { - func_decl * var = it->m_key; - SASSERT(m_fpa_util.is_rm(var->get_range())); - expr * val = it->m_value; - SASSERT(m_fpa_util.is_bv2rm(val)); - expr * bvval = to_app(val)->get_arg(0); - expr_ref fv(m); - fv = convert_bv2rm(mc, to_app(bvval)); - TRACE("bv2fpa", tout << var->get_name() << " == " << mk_ismt2_pp(fv, m) << ")" << std::endl;); - target_model->register_decl(var, fv); - seen.insert(to_app(bvval)->get_decl()); - } + for (obj_map::iterator it = m_rm_const2bv.begin(); + it != m_rm_const2bv.end(); + it++) + { + func_decl * var = it->m_key; + SASSERT(m_fpa_util.is_rm(var->get_range())); + expr * val = it->m_value; + SASSERT(m_fpa_util.is_bv2rm(val)); + expr * bvval = to_app(val)->get_arg(0); + expr_ref fv(m); + fv = convert_bv2rm(mc, to_app(bvval)); + TRACE("bv2fpa", tout << var->get_name() << " == " << mk_ismt2_pp(fv, m) << ")" << std::endl;); + target_model->register_decl(var, fv); + seen.insert(to_app(bvval)->get_decl()); + } } void bv2fpa_converter::convert_min_max_specials(model_core * mc, model_core * target_model, obj_hashtable & seen) { - for (obj_map >::iterator it = m_specials.begin(); - it != m_specials.end(); - it++) { - func_decl * f = it->m_key; - app * pn_cnst = it->m_value.first; - app * np_cnst = it->m_value.second; + for (obj_map >::iterator it = m_specials.begin(); + it != m_specials.end(); + it++) { + func_decl * f = it->m_key; + app * pn_cnst = it->m_value.first; + app * np_cnst = it->m_value.second; - expr_ref pzero(m), nzero(m); - pzero = m_fpa_util.mk_pzero(f->get_range()); - nzero = m_fpa_util.mk_nzero(f->get_range()); + expr_ref pzero(m), nzero(m); + pzero = m_fpa_util.mk_pzero(f->get_range()); + nzero = m_fpa_util.mk_nzero(f->get_range()); - expr_ref pn(m), np(m); - if (!mc->eval(pn_cnst->get_decl(), pn)) pn = pzero; - if (!mc->eval(np_cnst->get_decl(), np)) np = pzero; - seen.insert(pn_cnst->get_decl()); - seen.insert(np_cnst->get_decl()); + expr_ref pn(m), np(m); + if (!mc->eval(pn_cnst->get_decl(), pn)) pn = pzero; + if (!mc->eval(np_cnst->get_decl(), np)) np = pzero; + seen.insert(pn_cnst->get_decl()); + seen.insert(np_cnst->get_decl()); - rational pn_num, np_num; - unsigned bv_sz; - m_bv_util.is_numeral(pn, pn_num, bv_sz); - m_bv_util.is_numeral(np, np_num, bv_sz); + rational pn_num, np_num; + unsigned bv_sz; + m_bv_util.is_numeral(pn, pn_num, bv_sz); + m_bv_util.is_numeral(np, np_num, bv_sz); - func_interp * flt_fi = alloc(func_interp, m, f->get_arity()); - expr * pn_args[2] = { pzero, nzero }; - if (pn != np) flt_fi->insert_new_entry(pn_args, (pn_num.is_one() ? nzero : pzero)); - flt_fi->set_else(np_num.is_one() ? nzero : pzero); + func_interp * flt_fi = alloc(func_interp, m, f->get_arity()); + expr * pn_args[2] = { pzero, nzero }; + if (pn != np) flt_fi->insert_new_entry(pn_args, (pn_num.is_one() ? nzero : pzero)); + flt_fi->set_else(np_num.is_one() ? nzero : pzero); - target_model->register_decl(f, flt_fi); - TRACE("bv2fpa", tout << "fp.min/fp.max special: " << std::endl << - mk_ismt2_pp(f, m) << " == " << mk_ismt2_pp(flt_fi->get_interp(), m) << std::endl;); - } + target_model->register_decl(f, flt_fi); + TRACE("bv2fpa", tout << "fp.min/fp.max special: " << std::endl << + mk_ismt2_pp(f, m) << " == " << mk_ismt2_pp(flt_fi->get_interp(), m) << std::endl;); + } } void bv2fpa_converter::convert_uf2bvuf(model_core * mc, model_core * target_model, obj_hashtable & seen) { - for (obj_map::iterator it = m_uf2bvuf.begin(); - it != m_uf2bvuf.end(); - it++) { - seen.insert(it->m_value); + for (obj_map::iterator it = m_uf2bvuf.begin(); + it != m_uf2bvuf.end(); + it++) { + seen.insert(it->m_value); - func_decl * f = it->m_key; - if (f->get_arity() == 0) - { - array_util au(m); - if (au.is_array(f->get_range())) { - array_model am = convert_array_func_interp(mc, f, it->m_value); - if (am.new_float_fd) target_model->register_decl(am.new_float_fd, am.new_float_fi); - if (am.result) target_model->register_decl(f, am.result); - if (am.bv_fd) seen.insert(am.bv_fd); - } - else { - // Just keep. - SASSERT(!m_fpa_util.is_float(f->get_range()) && !m_fpa_util.is_rm(f->get_range())); - expr_ref var(m), val(m); - if (mc->eval(it->m_value, val)) - target_model->register_decl(f, val); - } - } - else { - func_interp * fmv = convert_func_interp(mc, f, it->m_value); - if (fmv) target_model->register_decl(f, fmv); - } - } + func_decl * f = it->m_key; + if (f->get_arity() == 0) + { + array_util au(m); + if (au.is_array(f->get_range())) { + array_model am = convert_array_func_interp(mc, f, it->m_value); + if (am.new_float_fd) target_model->register_decl(am.new_float_fd, am.new_float_fi); + if (am.result) target_model->register_decl(f, am.result); + if (am.bv_fd) seen.insert(am.bv_fd); + } + else { + // Just keep. + SASSERT(!m_fpa_util.is_float(f->get_range()) && !m_fpa_util.is_rm(f->get_range())); + expr_ref var(m), val(m); + if (mc->eval(it->m_value, val)) + target_model->register_decl(f, val); + } + } + else { + func_interp * fmv = convert_func_interp(mc, f, it->m_value); + if (fmv) target_model->register_decl(f, fmv); + } + } } void bv2fpa_converter::display(std::ostream & out) { - out << "(fpa2bv-model-converter"; - for (obj_map::iterator it = m_const2bv.begin(); - it != m_const2bv.end(); - it++) { - const symbol & n = it->m_key->get_name(); - out << "\n (" << n << " "; - unsigned indent = n.size() + 4; - out << mk_ismt2_pp(it->m_value, m, indent) << ")"; - } - for (obj_map::iterator it = m_rm_const2bv.begin(); - it != m_rm_const2bv.end(); - it++) { - const symbol & n = it->m_key->get_name(); - out << "\n (" << n << " "; - unsigned indent = n.size() + 4; - out << mk_ismt2_pp(it->m_value, m, indent) << ")"; - } - for (obj_map::iterator it = m_uf2bvuf.begin(); - it != m_uf2bvuf.end(); - it++) { - const symbol & n = it->m_key->get_name(); - out << "\n (" << n << " "; - unsigned indent = n.size() + 4; - out << mk_ismt2_pp(it->m_value, m, indent) << ")"; - } - for (obj_map >::iterator it = m_specials.begin(); - it != m_specials.end(); - it++) { - const symbol & n = it->m_key->get_name(); - out << "\n (" << n << " "; - unsigned indent = n.size() + 4; - out << mk_ismt2_pp(it->m_value.first, m, indent) << "; " << - mk_ismt2_pp(it->m_value.second, m, indent) << ")"; - } - out << ")"; + out << "(fpa2bv-model-converter"; + for (obj_map::iterator it = m_const2bv.begin(); + it != m_const2bv.end(); + it++) { + const symbol & n = it->m_key->get_name(); + out << "\n (" << n << " "; + unsigned indent = n.size() + 4; + out << mk_ismt2_pp(it->m_value, m, indent) << ")"; + } + for (obj_map::iterator it = m_rm_const2bv.begin(); + it != m_rm_const2bv.end(); + it++) { + const symbol & n = it->m_key->get_name(); + out << "\n (" << n << " "; + unsigned indent = n.size() + 4; + out << mk_ismt2_pp(it->m_value, m, indent) << ")"; + } + for (obj_map::iterator it = m_uf2bvuf.begin(); + it != m_uf2bvuf.end(); + it++) { + const symbol & n = it->m_key->get_name(); + out << "\n (" << n << " "; + unsigned indent = n.size() + 4; + out << mk_ismt2_pp(it->m_value, m, indent) << ")"; + } + for (obj_map >::iterator it = m_specials.begin(); + it != m_specials.end(); + it++) { + const symbol & n = it->m_key->get_name(); + out << "\n (" << n << " "; + unsigned indent = n.size() + 4; + out << mk_ismt2_pp(it->m_value.first, m, indent) << "; " << + mk_ismt2_pp(it->m_value.second, m, indent) << ")"; + } + out << ")"; } bv2fpa_converter * bv2fpa_converter::translate(ast_translation & translator) { - bv2fpa_converter * res = alloc(bv2fpa_converter, translator.to()); - for (obj_map::iterator it = m_const2bv.begin(); - it != m_const2bv.end(); - it++) - { - func_decl * k = translator(it->m_key); - expr * v = translator(it->m_value); - res->m_const2bv.insert(k, v); - translator.to().inc_ref(k); - translator.to().inc_ref(v); - } - for (obj_map::iterator it = m_rm_const2bv.begin(); - it != m_rm_const2bv.end(); - it++) - { - func_decl * k = translator(it->m_key); - expr * v = translator(it->m_value); - res->m_rm_const2bv.insert(k, v); - translator.to().inc_ref(k); - translator.to().inc_ref(v); - } - for (obj_map::iterator it = m_uf2bvuf.begin(); - it != m_uf2bvuf.end(); - it++) { - func_decl * k = translator(it->m_key); - func_decl * v = translator(it->m_value); - res->m_uf2bvuf.insert(k, v); - translator.to().inc_ref(k); - translator.to().inc_ref(v); - } - for (obj_map >::iterator it = m_specials.begin(); - it != m_specials.end(); - it++) { - func_decl * k = translator(it->m_key); - app * v1 = translator(it->m_value.first); - app * v2 = translator(it->m_value.second); - res->m_specials.insert(k, std::pair(v1, v2)); - translator.to().inc_ref(k); - translator.to().inc_ref(v1); - translator.to().inc_ref(v2); - } - return res; + bv2fpa_converter * res = alloc(bv2fpa_converter, translator.to()); + for (obj_map::iterator it = m_const2bv.begin(); + it != m_const2bv.end(); + it++) + { + func_decl * k = translator(it->m_key); + expr * v = translator(it->m_value); + res->m_const2bv.insert(k, v); + translator.to().inc_ref(k); + translator.to().inc_ref(v); + } + for (obj_map::iterator it = m_rm_const2bv.begin(); + it != m_rm_const2bv.end(); + it++) + { + func_decl * k = translator(it->m_key); + expr * v = translator(it->m_value); + res->m_rm_const2bv.insert(k, v); + translator.to().inc_ref(k); + translator.to().inc_ref(v); + } + for (obj_map::iterator it = m_uf2bvuf.begin(); + it != m_uf2bvuf.end(); + it++) { + func_decl * k = translator(it->m_key); + func_decl * v = translator(it->m_value); + res->m_uf2bvuf.insert(k, v); + translator.to().inc_ref(k); + translator.to().inc_ref(v); + } + for (obj_map >::iterator it = m_specials.begin(); + it != m_specials.end(); + it++) { + func_decl * k = translator(it->m_key); + app * v1 = translator(it->m_value.first); + app * v2 = translator(it->m_value.second); + res->m_specials.insert(k, std::pair(v1, v2)); + translator.to().inc_ref(k); + translator.to().inc_ref(v1); + translator.to().inc_ref(v2); + } + return res; } void bv2fpa_converter::convert(model_core * mc, model_core * float_mdl) { - TRACE("bv2fpa", tout << "BV Model: " << std::endl; - for (unsigned i = 0; i < mc->get_num_constants(); i++) - tout << mc->get_constant(i)->get_name() << " --> " << - mk_ismt2_pp(mc->get_const_interp(mc->get_constant(i)), m) << std::endl; - for (unsigned i = 0; i < mc->get_num_functions(); i++) { - func_decl * f = mc->get_function(i); - tout << f->get_name() << "(...) := " << std::endl; - func_interp * fi = mc->get_func_interp(f); - for (unsigned j = 0; j < fi->num_entries(); j++) { - func_entry const * fe = fi->get_entry(j); - for (unsigned k = 0; k < f->get_arity(); k++) { - tout << mk_ismt2_pp(fe->get_arg(k), m) << " "; - } - tout << "--> " << mk_ismt2_pp(fe->get_result(), m) << std::endl; - } - tout << "else " << mk_ismt2_pp(fi->get_else(), m) << std::endl; - }); + TRACE("bv2fpa", tout << "BV Model: " << std::endl; + for (unsigned i = 0; i < mc->get_num_constants(); i++) + tout << mc->get_constant(i)->get_name() << " --> " << + mk_ismt2_pp(mc->get_const_interp(mc->get_constant(i)), m) << std::endl; + for (unsigned i = 0; i < mc->get_num_functions(); i++) { + func_decl * f = mc->get_function(i); + tout << f->get_name() << "(...) := " << std::endl; + func_interp * fi = mc->get_func_interp(f); + for (unsigned j = 0; j < fi->num_entries(); j++) { + func_entry const * fe = fi->get_entry(j); + for (unsigned k = 0; k < f->get_arity(); k++) { + tout << mk_ismt2_pp(fe->get_arg(k), m) << " "; + } + tout << "--> " << mk_ismt2_pp(fe->get_result(), m) << std::endl; + } + tout << "else " << mk_ismt2_pp(fi->get_else(), m) << std::endl; + }); } \ No newline at end of file diff --git a/src/ast/fpa/bv2fpa_converter.h b/src/ast/fpa/bv2fpa_converter.h index c441ea6ff..5150056c4 100644 --- a/src/ast/fpa/bv2fpa_converter.h +++ b/src/ast/fpa/bv2fpa_converter.h @@ -1,17 +1,17 @@ /*++ - Copyright (c) 2016 Microsoft Corporation + Copyright (c) 2016 Microsoft Corporation Module Name: - bv2fpa_converter.h + bv2fpa_converter.h Abstract: - Model conversion for fpa2bv_converter + Model conversion for fpa2bv_converter Author: - Christoph (cwinter) 2016-10-15 + Christoph (cwinter) 2016-10-15 Notes: @@ -27,48 +27,48 @@ Notes: class bv2fpa_converter { - ast_manager & m; - fpa_util m_fpa_util; - bv_util m_bv_util; - th_rewriter m_th_rw; + ast_manager & m; + fpa_util m_fpa_util; + bv_util m_bv_util; + th_rewriter m_th_rw; - obj_map m_const2bv; - obj_map m_rm_const2bv; - obj_map m_uf2bvuf; - obj_map > m_specials; + obj_map m_const2bv; + obj_map m_rm_const2bv; + obj_map m_uf2bvuf; + obj_map > m_specials; public: - bv2fpa_converter(ast_manager & m); - bv2fpa_converter(ast_manager & m, fpa2bv_converter & conv); - virtual ~bv2fpa_converter(); + bv2fpa_converter(ast_manager & m); + bv2fpa_converter(ast_manager & m, fpa2bv_converter & conv); + virtual ~bv2fpa_converter(); - void display(std::ostream & out); - bv2fpa_converter * translate(ast_translation & translator); + void display(std::ostream & out); + bv2fpa_converter * translate(ast_translation & translator); - expr_ref convert_bv2fp(sort * s, expr * sgn, expr * exp, expr * sig); - expr_ref convert_bv2fp(model_core * mc, sort * s, app * bv); - expr_ref convert_bv2rm(expr * eval_v); - expr_ref convert_bv2rm(model_core * mc, app * val); + expr_ref convert_bv2fp(sort * s, expr * sgn, expr * exp, expr * sig); + expr_ref convert_bv2fp(model_core * mc, sort * s, app * bv); + expr_ref convert_bv2rm(expr * eval_v); + expr_ref convert_bv2rm(model_core * mc, app * val); - void convert(model_core * mc, model_core * float_mdl); - void convert_consts(model_core * mc, model_core * target_model, obj_hashtable & seen); - void convert_rm_consts(model_core * mc, model_core * target_model, obj_hashtable & seen); - void convert_min_max_specials(model_core * mc, model_core * target_model, obj_hashtable & seen); - void convert_uf2bvuf(model_core * mc, model_core * target_model, obj_hashtable & seen); + void convert(model_core * mc, model_core * float_mdl); + void convert_consts(model_core * mc, model_core * target_model, obj_hashtable & seen); + void convert_rm_consts(model_core * mc, model_core * target_model, obj_hashtable & seen); + void convert_min_max_specials(model_core * mc, model_core * target_model, obj_hashtable & seen); + void convert_uf2bvuf(model_core * mc, model_core * target_model, obj_hashtable & seen); - func_interp * convert_func_interp(model_core * mc, func_decl * f, func_decl * bv_f); - expr_ref rebuild_floats(model_core * mc, sort * s, app * e); + func_interp * convert_func_interp(model_core * mc, func_decl * f, func_decl * bv_f); + expr_ref rebuild_floats(model_core * mc, sort * s, app * e); - class array_model { - public: - func_decl * new_float_fd; - func_interp * new_float_fi; - func_decl * bv_fd; - expr_ref result; - array_model(ast_manager & m) : new_float_fd(0), new_float_fi(0), bv_fd(0), result(m) {} - }; + class array_model { + public: + func_decl * new_float_fd; + func_interp * new_float_fi; + func_decl * bv_fd; + expr_ref result; + array_model(ast_manager & m) : new_float_fd(0), new_float_fi(0), bv_fd(0), result(m) {} + }; - array_model convert_array_func_interp(model_core * mc, func_decl * f, func_decl * bv_f); + array_model convert_array_func_interp(model_core * mc, func_decl * f, func_decl * bv_f); }; #endif \ No newline at end of file diff --git a/src/ast/fpa/fpa2bv_converter.cpp b/src/ast/fpa/fpa2bv_converter.cpp index da473f993..ba6d436cc 100644 --- a/src/ast/fpa/fpa2bv_converter.cpp +++ b/src/ast/fpa/fpa2bv_converter.cpp @@ -3074,9 +3074,9 @@ void fpa2bv_converter::mk_to_ieee_bv(func_decl * f, unsigned num, expr * const * m_bv_util.mk_concat(m_bv_util.mk_numeral(0, sbits - 2), m_bv_util.mk_numeral(1, 1)))); else { - app_ref unspec(m); - unspec = m_util.mk_internal_to_ieee_bv_unspecified(ebits, sbits); - mk_to_ieee_bv_unspecified(unspec->get_decl(), 0, 0, nanv); + app_ref unspec(m); + unspec = m_util.mk_internal_to_ieee_bv_unspecified(ebits, sbits); + mk_to_ieee_bv_unspecified(unspec->get_decl(), 0, 0, nanv); } expr_ref sgn_e_s(m); @@ -3126,42 +3126,42 @@ void fpa2bv_converter::mk_to_ieee_bv_unspecified(func_decl * f, unsigned num, ex } void fpa2bv_converter::mk_to_bv(func_decl * f, unsigned num, expr * const * args, bool is_signed, expr_ref & result) { - TRACE("fpa2bv_to_bv", for (unsigned i = 0; i < num; i++) - tout << "arg" << i << " = " << mk_ismt2_pp(args[i], m) << std::endl;); + TRACE("fpa2bv_to_bv", for (unsigned i = 0; i < num; i++) + tout << "arg" << i << " = " << mk_ismt2_pp(args[i], m) << std::endl;); - SASSERT(num == 2); - SASSERT(m_util.is_bv2rm(args[0])); - SASSERT(m_util.is_float(args[1])); + SASSERT(num == 2); + SASSERT(m_util.is_bv2rm(args[0])); + SASSERT(m_util.is_float(args[1])); - expr * rm = to_app(args[0])->get_arg(0); - expr * x = args[1]; - sort * xs = m.get_sort(x); - sort * bv_srt = f->get_range(); + expr * rm = to_app(args[0])->get_arg(0); + expr * x = args[1]; + sort * xs = m.get_sort(x); + sort * bv_srt = f->get_range(); - unsigned ebits = m_util.get_ebits(xs); - unsigned sbits = m_util.get_sbits(xs); - unsigned bv_sz = (unsigned)f->get_parameter(0).get_int(); + unsigned ebits = m_util.get_ebits(xs); + unsigned sbits = m_util.get_sbits(xs); + unsigned bv_sz = (unsigned)f->get_parameter(0).get_int(); - expr_ref bv0(m), bv1(m); - bv1 = m_bv_util.mk_numeral(1, 1); + expr_ref bv0(m), bv1(m); + bv1 = m_bv_util.mk_numeral(1, 1); - expr_ref x_is_nan(m), x_is_inf(m), x_is_zero(m), x_is_neg(m), x_is_nzero(m); - mk_is_nan(x, x_is_nan); - mk_is_inf(x, x_is_inf); - mk_is_zero(x, x_is_zero); - mk_is_neg(x, x_is_neg); - mk_is_nzero(x, x_is_nzero); + expr_ref x_is_nan(m), x_is_inf(m), x_is_zero(m), x_is_neg(m), x_is_nzero(m); + mk_is_nan(x, x_is_nan); + mk_is_inf(x, x_is_inf); + mk_is_zero(x, x_is_zero); + mk_is_neg(x, x_is_neg); + mk_is_nzero(x, x_is_nzero); - // NaN, Inf, or negative (except -0) -> unspecified - expr_ref c1(m), v1(m); - if (!is_signed) { - c1 = m.mk_or(x_is_nan, x_is_inf, m.mk_and(x_is_neg, m.mk_not(x_is_nzero))); - v1 = mk_to_ubv_unspecified(ebits, sbits, bv_sz); - } - else { - c1 = m.mk_or(x_is_nan, x_is_inf); - v1 = mk_to_sbv_unspecified(ebits, sbits, bv_sz); - } + // NaN, Inf, or negative (except -0) -> unspecified + expr_ref c1(m), v1(m); + if (!is_signed) { + c1 = m.mk_or(x_is_nan, x_is_inf, m.mk_and(x_is_neg, m.mk_not(x_is_nzero))); + v1 = mk_to_ubv_unspecified(ebits, sbits, bv_sz); + } + else { + c1 = m.mk_or(x_is_nan, x_is_inf); + v1 = mk_to_sbv_unspecified(ebits, sbits, bv_sz); + } dbg_decouple("fpa2bv_to_bv_c1", c1); // +-Zero -> 0 @@ -3272,7 +3272,7 @@ void fpa2bv_converter::mk_to_bv(func_decl * f, unsigned num, expr * const * args expr_ref unspec(m); unspec = is_signed ? mk_to_sbv_unspecified(ebits, sbits, bv_sz) : - mk_to_ubv_unspecified(ebits, sbits, bv_sz); + mk_to_ubv_unspecified(ebits, sbits, bv_sz); result = m.mk_ite(rnd_has_overflown, unspec, rnd); result = m.mk_ite(c_in_limits, result, unspec); result = m.mk_ite(c2, v2, result); @@ -3294,61 +3294,61 @@ void fpa2bv_converter::mk_to_sbv(func_decl * f, unsigned num, expr * const * arg } void fpa2bv_converter::mk_to_ubv_unspecified(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { - SASSERT(num == 0); - unsigned width = m_bv_util.get_bv_size(f->get_range()); + SASSERT(num == 0); + unsigned width = m_bv_util.get_bv_size(f->get_range()); - if (m_hi_fp_unspecified) - result = m_bv_util.mk_numeral(0, width); - else { - func_decl * fd; - if (!m_uf2bvuf.find(f, fd)) { - fd = m.mk_fresh_func_decl(0, 0, 0, f->get_range()); - m_uf2bvuf.insert(f, fd); - m.inc_ref(f); - m.inc_ref(fd); - } - result = m.mk_const(fd); - } + if (m_hi_fp_unspecified) + result = m_bv_util.mk_numeral(0, width); + else { + func_decl * fd; + if (!m_uf2bvuf.find(f, fd)) { + fd = m.mk_fresh_func_decl(0, 0, 0, f->get_range()); + m_uf2bvuf.insert(f, fd); + m.inc_ref(f); + m.inc_ref(fd); + } + result = m.mk_const(fd); + } - TRACE("fpa2bv_to_ubv_unspecified", tout << "result=" << mk_ismt2_pp(result, m) << std::endl;); - SASSERT(is_well_sorted(m, result)); + TRACE("fpa2bv_to_ubv_unspecified", tout << "result=" << mk_ismt2_pp(result, m) << std::endl;); + SASSERT(is_well_sorted(m, result)); } expr_ref fpa2bv_converter::mk_to_ubv_unspecified(unsigned ebits, unsigned sbits, unsigned width) { - expr_ref res(m); - app_ref u(m); - u = m_util.mk_internal_to_ubv_unspecified(ebits, sbits, width); - mk_to_sbv_unspecified(u->get_decl(), 0, 0, res); - return res; + expr_ref res(m); + app_ref u(m); + u = m_util.mk_internal_to_ubv_unspecified(ebits, sbits, width); + mk_to_sbv_unspecified(u->get_decl(), 0, 0, res); + return res; } void fpa2bv_converter::mk_to_sbv_unspecified(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { - SASSERT(num == 0); - unsigned width = m_bv_util.get_bv_size(f->get_range()); + SASSERT(num == 0); + unsigned width = m_bv_util.get_bv_size(f->get_range()); - if (m_hi_fp_unspecified) - result = m_bv_util.mk_numeral(0, width); - else { - func_decl * fd; - if (!m_uf2bvuf.find(f, fd)) { - fd = m.mk_fresh_func_decl(0, 0, 0, f->get_range()); - m_uf2bvuf.insert(f, fd); - m.inc_ref(f); - m.inc_ref(fd); - } - result = m.mk_const(fd); - } + if (m_hi_fp_unspecified) + result = m_bv_util.mk_numeral(0, width); + else { + func_decl * fd; + if (!m_uf2bvuf.find(f, fd)) { + fd = m.mk_fresh_func_decl(0, 0, 0, f->get_range()); + m_uf2bvuf.insert(f, fd); + m.inc_ref(f); + m.inc_ref(fd); + } + result = m.mk_const(fd); + } - TRACE("fpa2bv_to_sbv_unspecified", tout << "result=" << mk_ismt2_pp(result, m) << std::endl;); - SASSERT(is_well_sorted(m, result)); + TRACE("fpa2bv_to_sbv_unspecified", tout << "result=" << mk_ismt2_pp(result, m) << std::endl;); + SASSERT(is_well_sorted(m, result)); } expr_ref fpa2bv_converter::mk_to_sbv_unspecified(unsigned ebits, unsigned sbits, unsigned width) { - expr_ref res(m); - app_ref u(m); - u = m_util.mk_internal_to_sbv_unspecified(ebits, sbits, width); - mk_to_sbv_unspecified(u->get_decl(), 0, 0, res); - return res; + expr_ref res(m); + app_ref u(m); + u = m_util.mk_internal_to_sbv_unspecified(ebits, sbits, width); + mk_to_sbv_unspecified(u->get_decl(), 0, 0, res); + return res; } void fpa2bv_converter::mk_to_real_unspecified(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { @@ -3367,11 +3367,11 @@ void fpa2bv_converter::mk_to_real_unspecified(func_decl * f, unsigned num, expr } expr_ref fpa2bv_converter::mk_to_real_unspecified(unsigned ebits, unsigned sbits) { - expr_ref res(m); - app_ref u(m); - u = m_util.mk_internal_to_real_unspecified(ebits, sbits); - mk_to_real_unspecified(u->get_decl(), 0, 0, res); - return res; + expr_ref res(m); + app_ref u(m); + u = m_util.mk_internal_to_real_unspecified(ebits, sbits); + mk_to_real_unspecified(u->get_decl(), 0, 0, res); + return res; } void fpa2bv_converter::mk_fp(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { From 948a1e600e453a76f5293d54a807d630650da5b9 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 18 Oct 2016 10:27:47 -0400 Subject: [PATCH 246/536] undo breaking commit Signed-off-by: Nikolaj Bjorner --- src/smt/theory_fpa.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/smt/theory_fpa.cpp b/src/smt/theory_fpa.cpp index 3a45e1876..b0b8ffff5 100644 --- a/src/smt/theory_fpa.cpp +++ b/src/smt/theory_fpa.cpp @@ -799,7 +799,6 @@ namespace smt { } void theory_fpa::finalize_model(model_generator & mg) { -#if 0 ast_manager & m = get_manager(); proto_model & mdl = mg.get_model(); proto_model new_model(m); @@ -825,7 +824,6 @@ namespace smt { func_interp * fi = new_model.get_func_interp(f)->copy(); mdl.register_decl(f, fi); } -#endif } void theory_fpa::display(std::ostream & out) const From 9fef51553c728b02b0de2f17f4be588608ee1e44 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Tue, 18 Oct 2016 17:15:43 +0100 Subject: [PATCH 247/536] Whitespace --- src/smt/theory_arith_nl.h | 390 +++++++++++++++++++------------------- 1 file changed, 195 insertions(+), 195 deletions(-) diff --git a/src/smt/theory_arith_nl.h b/src/smt/theory_arith_nl.h index 311a62a38..c3ae8c99b 100644 --- a/src/smt/theory_arith_nl.h +++ b/src/smt/theory_arith_nl.h @@ -23,9 +23,9 @@ Revision History: namespace smt { - template + template expr * theory_arith::mk_nary_mul(unsigned sz, expr * const * args, bool is_int) { - if (sz == 0) + if (sz == 0) return m_util.mk_numeral(rational(1), is_int); if (sz == 1) return args[0]; @@ -36,21 +36,21 @@ namespace smt { return m_util.mk_mul(sz, args); } - template + template expr * theory_arith::mk_nary_add(unsigned sz, expr * const * args, bool is_int) { - if (sz == 0) + if (sz == 0) return m_util.mk_numeral(rational(0), is_int); if (sz == 1) return args[0]; return m_util.mk_add(sz, args); } - template + template expr * theory_arith::mk_nary_add(unsigned sz, expr * const * args) { SASSERT(sz != 0); return mk_nary_add(sz, args, false); } - + /** \brief Insert v into vars and already_found if v is not already in already_found. */ @@ -92,21 +92,21 @@ namespace smt { theory_var s = r.get_base_var(); // ignore quasi base vars... actually they should not be used if the problem is non linear... if (is_quasi_base(s)) - continue; + continue; // If s is a base variable different from v and it is free, then this row can be ignored. // It doesn't need to be part of the non linear cluster. For all purposes, this variable // was eliminated by substitution. if (is_free(s) && s != v) - continue; + continue; typename vector::const_iterator it2 = r.begin_entries(); typename vector::const_iterator end2 = r.end_entries(); - for (; it2 != end2; ++it2) { - if (!it2->is_dead() && !is_fixed(it2->m_var)) + for (; it2 != end2; ++it2) { + if (!it2->is_dead() && !is_fixed(it2->m_var)) mark_var(it2->m_var, vars, already_found); } } } - + /** \brief Store in vars the variables that are in the non linear cluster of constraints, and are not satisfied by the current assignment. @@ -123,7 +123,7 @@ namespace smt { for (; it != end; ++it) { theory_var v = *it; expr * n = var2expr(v); - if (ctx.is_relevant(n)) + if (ctx.is_relevant(n)) mark_var(v, vars, already_found); } for (unsigned idx = 0; idx < vars.size(); idx++) { @@ -134,7 +134,7 @@ namespace smt { svector::const_iterator it = vars.begin(); svector::const_iterator end = vars.end(); for (; it != end; ++it) tout << "v" << *it << " "; - tout << "\n";); + tout << "\n";); } /** @@ -148,7 +148,7 @@ namespace smt { \remark if a variables has an even number of occurrences, then I consider that it has a bound associated with it. - + Examples: 1) Assume x1, x4 have bounds: analyze_monomial(x1 * x2 * x2 * x3 * x3 * x3 * x4) @@ -168,24 +168,24 @@ namespace smt { int idx = 0; for (unsigned i = 0; i < to_app(m)->get_num_args(); i++) { expr * arg = to_app(m)->get_arg(i); - if (var == 0) { - var = arg; - power = 1; - } - else if (arg == var) { - power++; - } - else { - if (power % 2 == 1 && is_free(var)) { - c++; - free_var_idx = idx; - if (c > 1) - return std::make_pair(2, free_var_idx); - } - var = arg; - power = 1; - idx++; - } + if (var == 0) { + var = arg; + power = 1; + } + else if (arg == var) { + power++; + } + else { + if (power % 2 == 1 && is_free(var)) { + c++; + free_var_idx = idx; + if (c > 1) + return std::make_pair(2, free_var_idx); + } + var = arg; + power = 1; + idx++; + } } if (power % 2 == 1 && is_free(var)) { c++; @@ -257,17 +257,17 @@ namespace smt { unsigned j; for (j = 0; j < to_app(m)->get_num_args(); j++) { expr * arg = to_app(m)->get_arg(j); - if (var == 0) { - var = arg; - power = 1; - } - else if (var == arg) { - power++; - } - else { - if (curr_idx == i) - return var_power_pair(var, power); - curr_idx++; + if (var == 0) { + var = arg; + power = 1; + } + else if (var == arg) { + power++; + } + else { + if (curr_idx == i) + return var_power_pair(var, power); + curr_idx++; var = arg; power = 1; } @@ -289,24 +289,24 @@ namespace smt { bound * l = lower(v); bound * u = upper(v); if (l && u) { - return interval(m_dep_manager, - l->get_value().get_rational().to_rational(), + return interval(m_dep_manager, + l->get_value().get_rational().to_rational(), !l->get_value().get_infinitesimal().to_rational().is_zero(), m_dep_manager.mk_leaf(l), - u->get_value().get_rational().to_rational(), + u->get_value().get_rational().to_rational(), !u->get_value().get_infinitesimal().to_rational().is_zero(), m_dep_manager.mk_leaf(u)); } else if (l) { return interval(m_dep_manager, - l->get_value().get_rational().to_rational(), + l->get_value().get_rational().to_rational(), !l->get_value().get_infinitesimal().to_rational().is_zero(), true, m_dep_manager.mk_leaf(l)); } else if (u) { return interval(m_dep_manager, - u->get_value().get_rational().to_rational(), + u->get_value().get_rational().to_rational(), !u->get_value().get_infinitesimal().to_rational().is_zero(), false, m_dep_manager.mk_leaf(u)); @@ -333,12 +333,12 @@ namespace smt { void theory_arith::mul_bound_of(expr * var, unsigned power, interval & target) { theory_var v = expr2var(var); interval i = mk_interval_for(v); - - TRACE("non_linear", + + TRACE("non_linear", display_interval(tout << "bound: ",i); tout << i << "\n"; tout << mk_pp(var, get_manager()) << "\n"; tout << "power " << power << ": " << expt(i, power) << "\n"; - display_interval(tout << "target before: ", target); tout << "\n";); + display_interval(tout << "target before: ", target); tout << "\n";); i.expt(power); target *= i; TRACE("non_linear", display_interval(tout << "target after: ", target); tout << "\n";); @@ -348,7 +348,7 @@ namespace smt { \brief Evaluate the given expression using interval arithmetic. - If a subexpression is internalized, then mk_interval_for is used to - compute its interval. + compute its interval. - Only +, *, and numerals are handled. */ @@ -382,7 +382,7 @@ namespace smt { interval it = evaluate_as_interval(var); it.expt(power); r *= it; - } + } TRACE("cross_nested_eval_bug", display_nested_form(tout, n); tout << "\ninterval: " << r << "\n";); return r; } @@ -424,7 +424,7 @@ namespace smt { ptr_vector::const_iterator end = bounds.end(); for (; it != end; ++it) { bound * b = static_cast(*it); - accumulate_justification(*b, new_bound, numeral::zero(), m_tmp_lit_set, m_tmp_eq_set); + accumulate_justification(*b, new_bound, numeral::zero(), m_tmp_lit_set, m_tmp_eq_set); } } @@ -476,7 +476,7 @@ namespace smt { } return r; } - + template bool theory_arith::update_bounds_using_interval(expr * n, interval const & i) { SASSERT(expr2var(n) != null_theory_var); @@ -510,7 +510,7 @@ namespace smt { } /** - \brief Propagate a bound to the i-th variable of the given monomial + \brief Propagate a bound to the i-th variable of the given monomial using the bounds of m and other variables in m. \remark We do not support roots in interval... so, if the i-th var has power != 1 @@ -523,7 +523,7 @@ namespace smt { var_power_pair p = get_var_and_degree(m, i); expr * v = p.first; unsigned power = p.second; - TRACE("propagate_nl_downward", tout << "m: " << mk_ismt2_pp(m, get_manager()) << "\nv: " << mk_ismt2_pp(v, get_manager()) << + TRACE("propagate_nl_downward", tout << "m: " << mk_ismt2_pp(m, get_manager()) << "\nv: " << mk_ismt2_pp(v, get_manager()) << "\npower: " << power << "\n";); if (power != 1) return false; // TODO: remove, when the n-th root is implemented in interval. @@ -556,7 +556,7 @@ namespace smt { template bool theory_arith::propagate_nl_bound(expr * m, int i) { TRACE("propagate_nl_bound", tout << "propagate using i: " << i << "\n"; display_monomial(tout, m); tout << "\n";); - if (i == -1) + if (i == -1) return propagate_nl_upward(m); else return propagate_nl_downward(m, i); @@ -657,13 +657,13 @@ namespace smt { rational val(1); for (unsigned i = 0; i < to_app(m)->get_num_args(); i++) { expr * arg = to_app(m)->get_arg(i); - theory_var curr = expr2var(arg); - SASSERT(curr != null_theory_var); - val *= get_value(curr, computed_epsilon); + theory_var curr = expr2var(arg); + SASSERT(curr != null_theory_var); + val *= get_value(curr, computed_epsilon); } return get_value(v, computed_epsilon) == val; } - + /** \brief Return true if for every monomial x_1 * ... * x_n, @@ -691,11 +691,11 @@ namespace smt { /** \brief Try to find an integer variable for performing branching in the non linear cluster. - + The idea is select a variable in a monomial with an invalid assignment. I give preference to variables with small ranges. If no variable is bounded, then select a random one. - + Free variables are not considered. */ template @@ -705,44 +705,44 @@ namespace smt { theory_var target = null_theory_var; bool bounded = false; unsigned n = 0; - numeral range; + numeral range; svector::const_iterator it = m_nl_monomials.begin(); svector::const_iterator end = m_nl_monomials.end(); for (; it != end; ++it) { theory_var v = *it; - if (is_real(v)) + if (is_real(v)) continue; bool computed_epsilon = false; - bool r = check_monomial_assignment(v, computed_epsilon); + bool r = check_monomial_assignment(v, computed_epsilon); SASSERT(!computed_epsilon); // integer variables do not use epsilon if (!r) { expr * m = get_enode(v)->get_owner(); SASSERT(is_pure_monomial(m)); for (unsigned i = 0; i < to_app(m)->get_num_args(); i++) { expr * arg = to_app(m)->get_arg(i); - theory_var curr = ctx.get_enode(arg)->get_th_var(get_id()); - TRACE("nl_branching", tout << "target: v" << target << ", curr: v" << curr << "\n";); - if (!is_fixed(curr) && is_int(curr)) { - if (is_bounded(curr)) { - numeral new_range; - new_range = upper_bound(curr).get_rational(); - new_range -= lower_bound(curr).get_rational(); - if (!bounded || new_range < range) { - target = curr; - range = new_range; - bounded = true; - } - } - else if (!bounded) { - n++; - TRACE("nl_branching", tout << "n: " << n << "\n";); - if (m_random()%n == 0) - target = curr; - SASSERT(target != null_theory_var); - } - SASSERT(target != null_theory_var); - } - TRACE("nl_branching", tout << "after target: v" << target << "\n";); + theory_var curr = ctx.get_enode(arg)->get_th_var(get_id()); + TRACE("nl_branching", tout << "target: v" << target << ", curr: v" << curr << "\n";); + if (!is_fixed(curr) && is_int(curr)) { + if (is_bounded(curr)) { + numeral new_range; + new_range = upper_bound(curr).get_rational(); + new_range -= lower_bound(curr).get_rational(); + if (!bounded || new_range < range) { + target = curr; + range = new_range; + bounded = true; + } + } + else if (!bounded) { + n++; + TRACE("nl_branching", tout << "n: " << n << "\n";); + if (m_random()%n == 0) + target = curr; + SASSERT(target != null_theory_var); + } + SASSERT(target != null_theory_var); + } + TRACE("nl_branching", tout << "after target: v" << target << "\n";); } } } @@ -762,7 +762,7 @@ namespace smt { m_stats.m_nl_branching++; SASSERT(is_int(v)); expr * bound = 0; - if (lower(v)) + if (lower(v)) bound = m_util.mk_le(var2expr(v), m_util.mk_numeral(lower_bound(v).get_rational().to_rational(), true)); else if (upper(v)) bound = m_util.mk_ge(var2expr(v), m_util.mk_numeral(upper_bound(v).get_rational().to_rational(), true)); @@ -787,14 +787,14 @@ namespace smt { unsigned num_nl_vars = 0; for (unsigned i = 0; i < to_app(m)->get_num_args(); i++) { expr * arg = to_app(m)->get_arg(i); - theory_var _var = expr2var(arg); - if (!is_fixed(_var)) { - num_nl_vars++; - } - else { - if (lower_bound(_var).is_zero()) - return true; - } + theory_var _var = expr2var(arg); + if (!is_fixed(_var)) { + num_nl_vars++; + } + else { + if (lower_bound(_var).is_zero()) + return true; + } } return num_nl_vars <= 1; } @@ -809,9 +809,9 @@ namespace smt { numeral r(1); for (unsigned i = 0; i < to_app(m)->get_num_args(); i++) { expr * arg = to_app(m)->get_arg(i); - theory_var _var = expr2var(arg); - if (is_fixed(_var)) - r *= lower_bound(_var).get_rational(); + theory_var _var = expr2var(arg); + if (is_fixed(_var)) + r *= lower_bound(_var).get_rational(); } return r; } @@ -825,9 +825,9 @@ namespace smt { SASSERT(is_pure_monomial(m)); for (unsigned i = 0; i < to_app(m)->get_num_args(); i++) { expr * arg = to_app(m)->get_arg(i); - theory_var _var = expr2var(arg); - if (!is_fixed(_var)) - return arg; + theory_var _var = expr2var(arg); + if (!is_fixed(_var)) + return arg; } return 0; } @@ -886,7 +886,7 @@ namespace smt { } else { // One of the x_i variables is zero, - // or all of them are assigned. + // or all of them are assigned. // Assert the equality // (= (* x_1 ... x_n) k) @@ -908,45 +908,45 @@ namespace smt { SASSERT(is_pure_monomial(m)); bool found_zero = false; - for (unsigned i = 0; !found_zero && i < to_app(m)->get_num_args(); i++) { - expr * arg = to_app(m)->get_arg(i); - theory_var _var = expr2var(arg); - if (is_fixed(_var)) { - bound * l = lower(_var); - bound * u = upper(_var); - if (l->get_value().is_zero()) { - /* if zero was found, then it is the explanation */ - SASSERT(k.is_zero()); - found_zero = true; - m_tmp_lit_set.reset(); - m_tmp_eq_set.reset(); - new_lower->m_lits.reset(); - new_lower->m_eqs.reset(); - } + for (unsigned i = 0; !found_zero && i < to_app(m)->get_num_args(); i++) { + expr * arg = to_app(m)->get_arg(i); + theory_var _var = expr2var(arg); + if (is_fixed(_var)) { + bound * l = lower(_var); + bound * u = upper(_var); + if (l->get_value().is_zero()) { + /* if zero was found, then it is the explanation */ + SASSERT(k.is_zero()); + found_zero = true; + m_tmp_lit_set.reset(); + m_tmp_eq_set.reset(); + new_lower->m_lits.reset(); + new_lower->m_eqs.reset(); + } accumulate_justification(*l, *new_lower, numeral::zero(), m_tmp_lit_set, m_tmp_eq_set); - - TRACE("non_linear", + + TRACE("non_linear", for (unsigned j = 0; j < new_lower->m_lits.size(); ++j) { ctx.display_detailed_literal(tout, new_lower->m_lits[j]); tout << " "; } tout << "\n";); - + accumulate_justification(*u, *new_lower, numeral::zero(), m_tmp_lit_set, m_tmp_eq_set); - - TRACE("non_linear", + + TRACE("non_linear", for (unsigned j = 0; j < new_lower->m_lits.size(); ++j) { ctx.display_detailed_literal(tout, new_lower->m_lits[j]); tout << " "; } tout << "\n";); - - } - } + + } + } new_upper->m_lits.append(new_lower->m_lits); new_upper->m_eqs.append(new_lower->m_eqs); - TRACE("non_linear", + TRACE("non_linear", tout << "lower: " << new_lower << " upper: " << new_upper << "\n"; for (unsigned j = 0; j < new_upper->m_lits.size(); ++j) { ctx.display_detailed_literal(tout, new_upper->m_lits[j]); @@ -979,9 +979,9 @@ namespace smt { /* Interval arithmetic does not satisfy distributivity. Actually, it satisfies the sub-distributivity property: - + x*(y + z) \subseteq x*y + x*z - + The sub-distributivity property only holds if condensation is not used. For example: @@ -995,11 +995,11 @@ namespace smt { x*(x^3+1) = [-7, 14] x^4 + x = [-2, 17] - + This weakness of AI is known as the "dependency problem", which comes from the decorrelation of the multiple occurrences of one variable during interval evaluation. - + Given a polynomial: p(x) = a_0 + a_1 * x + ... + a_n * x^n The horner extension is: @@ -1009,13 +1009,13 @@ namespace smt { h_p(x) = x(2 + x^3(1 + x)) The horner extension evaluates tighter intervals when - condensation is not used. + condensation is not used. Remark: there is no guarantee that horner extension will provide a tighter interval than a sum of monomials when condensation is used. - For multivariate polynomials nested (or cross nested) forms + For multivariate polynomials nested (or cross nested) forms are used. The idea is to select one variable, and pretend the other are parameters. The horner form is computed for the selected variable, and the computation continues for the polynomials on the @@ -1027,13 +1027,13 @@ namespace smt { p(x) = a*x^n + b*x^{n+m} for n >= m is equivalent to - + b*x^{n-m}*[(x^{m} + a/(2b))^2 - (a/2b)^2] - + This polynomial provides tight bound when n and m have the same parity and: 1) a*b > 0 and (lower(x) >= 0 or upper(x)^m <= -a/b) 2) a*b < 0 and (upper(x) <= 0 or lower(x)^m >= a/b) - + This polynomial also provides tight bounds when n = m, and the polynomial is simplified to, and n and m may have arbitrary parities: @@ -1047,7 +1047,7 @@ namespace smt { If we compute the bounds for x^2 - x we obtain (-oo, oo). - On the other hand, if we compute the bounds for + On the other hand, if we compute the bounds for (x - 1/2)^2 - 1/4 we obtain the bounds (0, oo), and the inconsistency is detected. @@ -1055,8 +1055,8 @@ namespace smt { Remark: In Z3, I condensate multiple occurrences of a variable when evaluating monomials. So, the interval for a monomial is always tight. - - Remark: M1*(M2 + M3) is more precise than M1 * M2 + M1 * M3, + + Remark: M1*(M2 + M3) is more precise than M1 * M2 + M1 * M3, if intersection(Vars(M1), union(Vars(M2), Vars(M3))) = empty-set, Remark: A trivial consequence of Moore's theorem for interval @@ -1066,7 +1066,7 @@ namespace smt { /** \brief Check whether the same variable occurs in two different monomials. - + \remark Fixed variables are ignored. \remark A trivial consequence of Moore's theorem for interval @@ -1208,7 +1208,7 @@ namespace smt { UNREACHABLE(); } } - + // Update the number of occurrences in the result vector. typename var2num_occs::iterator it2 = m_var2num_occs.begin(); typename var2num_occs::iterator end2 = m_var2num_occs.end(); @@ -1263,14 +1263,14 @@ namespace smt { m_nl_new_exprs.push_back(r); return r; } - + /** \brief Return true if var only occurs in two monovariate monomials, and return its power and coefficients and these monomials. The arguments i1 and i2 contain the position in p of the two monomials. */ template - bool theory_arith::in_monovariate_monomials(sbuffer & p, expr * var, + bool theory_arith::in_monovariate_monomials(sbuffer & p, expr * var, unsigned & i1, rational & c1, unsigned & n1, unsigned & i2, rational & c2, unsigned & n2) { int idx = 0; #define SET_RESULT(POWER) { \ @@ -1289,7 +1289,7 @@ namespace smt { else \ return false; \ } - + typename sbuffer::const_iterator it = p.begin(); typename sbuffer::const_iterator end = p.end(); for (unsigned i = 0; it != end; ++it, ++i) { @@ -1396,7 +1396,7 @@ namespace smt { SASSERT(d != UINT_MAX); return d; } - + /** \brief Divide m by var^d. */ @@ -1416,19 +1416,19 @@ namespace smt { ptr_buffer new_args; for (unsigned i = 0; i < to_app(m)->get_num_args(); i++) { expr * arg = to_app(m)->get_arg(i); - if (arg == var) { - if (idx < d) - idx++; - else - new_args.push_back(arg); - } - else { - new_args.push_back(arg); - } + if (arg == var) { + if (idx < d) + idx++; + else + new_args.push_back(arg); + } + else { + new_args.push_back(arg); + } } SASSERT(idx == d); TRACE("factor_bug", tout << "new_args:\n"; for(unsigned i = 0; i < new_args.size(); i++) tout << mk_pp(new_args[i], get_manager()) << "\n";); - expr * result = mk_nary_mul(new_args.size(), new_args.c_ptr(), m_util.is_int(var)); + expr * result = mk_nary_mul(new_args.size(), new_args.c_ptr(), m_util.is_int(var)); m_nl_new_exprs.push_back(result); TRACE("factor", tout << "result: " << mk_pp(result, get_manager()) << "\n";); return result; @@ -1442,7 +1442,7 @@ namespace smt { SASSERT(!p.empty()); SASSERT(var != 0); unsigned d = get_min_degree(p, var); - TRACE("horner_bug", tout << "poly:\n"; + TRACE("horner_bug", tout << "poly:\n"; for (unsigned i = 0; i < p.size(); i++) { if (i > 0) tout << " + "; tout << p[i].first << "*" << mk_pp(p[i].second, get_manager()); } tout << "\n"; tout << "var: " << mk_pp(var, get_manager()) << "\n"; tout << "min_degree: " << d << "\n";); @@ -1467,7 +1467,7 @@ namespace smt { // TODO: improve here s = m_util.mk_add(q, s); } - + expr * result = s; if (d != 0) { expr * xd = power(var, d); @@ -1513,9 +1513,9 @@ namespace smt { unsigned nm = UINT_MAX; if (in_monovariate_monomials(p, var, i1, a, n, i2, b, nm)) { CTRACE("in_monovariate_monomials", n == nm, - for (unsigned i = 0; i < p.size(); i++) { - if (i > 0) tout << " + "; tout << p[i].first << "*" << mk_pp(p[i].second, get_manager()); - } + for (unsigned i = 0; i < p.size(); i++) { + if (i > 0) tout << " + "; tout << p[i].first << "*" << mk_pp(p[i].second, get_manager()); + } tout << "\n"; tout << "var: " << mk_pp(var, get_manager()) << "\n"; tout << "i1: " << i1 << "\n"; @@ -1556,7 +1556,7 @@ namespace smt { sbuffer rest; unsigned sz = p.size(); for (unsigned i = 0; i < sz; i++) { - if (i != i1 && i != i2) + if (i != i1 && i != i2) rest.push_back(p[i]); } if (rest.empty()) @@ -1620,7 +1620,7 @@ namespace smt { /** \brief Check whether the polynomial represented by the current row is - consistent with respect to the known bound when converted into a + consistent with respect to the known bound when converted into a equivalent cross nested form. */ template @@ -1630,17 +1630,17 @@ namespace smt { return true; TRACE("cross_nested", tout << "problematic...\n";); - + /* The method is_cross_nested converts rows back to expressions. The conversion back to expressions may create sort incorrect expressions. - This is in some sense ok, since these expressions are temporary, but + This is in some sense ok, since these expressions are temporary, but the sort incorrect expressions may generate assertion violations. - + Sort incorrect expressions may be created in the following cases: - + 1) mixed real int rows. - + 2) int rows that contain non integer coefficients. 3) int rows that when converted to cross nested form use non integer coefficients. @@ -1654,10 +1654,10 @@ namespace smt { c) Disable the assertions temporally. This sounds like a big HACK. d) Use a different data-structure to represent polynomials in cross-nested form. Disadvantage: code duplication, the data-structure - is essentially identical to the ASTs we are using right now. + is essentially identical to the ASTs we are using right now. e) Disable the test when we cannot create a well-sorted expression. - I'm temporally using this solution. + I'm temporally using this solution. I implemented the following logic: 1) (mixed real int) Disable the test. Most benchmarks do not contain mixed int real variables. 2) (int coeffs) I multiply the row by a constant to force it to have only integer coefficients. @@ -1696,7 +1696,7 @@ namespace smt { svector::const_iterator end = nl_cluster.end(); for (; it != end; ++it) { theory_var v = *it; - if (!is_base(v)) + if (!is_base(v)) continue; m_stats.m_nl_cross_nested++; row const & r = m_rows[get_var_row(v)]; @@ -1719,8 +1719,8 @@ namespace smt { /** \brief Initialize variable order for grobner basis computation. Make: - "quoted free vars" > "free vars" > "quoted variables with lower or upper bounds" > - "variables with lower or upper bounds" > "quoted bounded variables" > + "quoted free vars" > "free vars" > "quoted variables with lower or upper bounds" > + "variables with lower or upper bounds" > "quoted bounded variables" > "bounded variables" > "quoted fixed variables" > "fixed variables" */ template @@ -1801,7 +1801,7 @@ namespace smt { } if (!coeff.is_zero()) return gb.mk_monomial(coeff, vars.size(), vars.c_ptr()); - else + else return 0; } @@ -1918,7 +1918,7 @@ namespace smt { derived_bound b(null_theory_var, inf_numeral(0), B_LOWER); dependency2new_bound(d, b); set_conflict(b, ante, "arith_nl"); - TRACE("non_linear", + TRACE("non_linear", for (unsigned i = 0; i < b.m_lits.size(); ++i) { tout << b.m_lits[i] << " "; }); @@ -2027,7 +2027,7 @@ namespace smt { unsigned num1 = m1_sq->get_degree(); unsigned num2 = m2_sq->get_degree(); unsigned num12 = m1m2->get_degree(); - if (num1 + num2 != num12 * 2) + if (num1 + num2 != num12 * 2) return false; unsigned i1, i2, i12; i1 = i2 = i12 = 0; @@ -2072,8 +2072,8 @@ namespace smt { */ template bool theory_arith::is_inconsistent2(grobner::equation const * eq, grobner & gb) { - // TODO: a possible improvement: create a quotation for (M1 - M2)^2 - // instead of trying to find it in a specific equation. + // TODO: a possible improvement: create a quotation for (M1 - M2)^2 + // instead of trying to find it in a specific equation. // This approach is more precise, but more expensive // since a new row must be created. buffer intervals; @@ -2117,7 +2117,7 @@ namespace smt { continue; // m1, m2, and m1m2 form a perfect square. // check if [0, oo) provides a better lowerbound than adding the intervals of m1, m2 and m1m2; - TRACE("non_linear", tout << "found perfect square (M1-M2)^2:\n"; + TRACE("non_linear", tout << "found perfect square (M1-M2)^2:\n"; gb.display_monomial(tout, *m1); tout << "\n"; gb.display_monomial(tout, *m2); tout << "\n"; gb.display_monomial(tout, *m1m2); tout << "\n";); @@ -2131,7 +2131,7 @@ namespace smt { deleted[i] = true; deleted[j] = true; deleted[k] = true; - break; + break; } } if (k < num) @@ -2184,7 +2184,7 @@ namespace smt { grobner::monomial const * m = eq->get_monomial(i); if (m->get_degree() == 0) k -= m->get_coeff(); - else + else args.push_back(monomial2expr(eq->get_monomial(i), is_int)); } context & ctx = get_context(); @@ -2213,7 +2213,7 @@ namespace smt { TRACE("non_linear", tout << "inserted new equation into the tableau\n"; display_var(tout, v);); return true; } - + /** \brief Compute Grobner basis, return true if a conflict or new fixed variables were detected. */ @@ -2227,7 +2227,7 @@ namespace smt { bool warn = false; unsigned next_weight = MAX_DEFAULT_WEIGHT + 1; // next weight using during perturbation phase. ptr_vector eqs; - + while (true) { TRACE("non_linear_gb", tout << "before:\n"; gb.display(tout);); bool r = false; @@ -2267,7 +2267,7 @@ namespace smt { if (is_inconsistent2(eq, gb)) return GB_PROGRESS; } - // Scan the grobner basis eqs for equations of the form x - k = 0 or x = 0 is found, and x is not fixed, + // Scan the grobner basis eqs for equations of the form x - k = 0 or x = 0 is found, and x is not fixed, // then assert bounds for x, and continue gb_result result = GB_FAIL; if (m_params.m_nl_arith_gb_eqs) { @@ -2277,7 +2277,7 @@ namespace smt { if (!eq->is_linear_combination()) { TRACE("non_linear", tout << "processing new equality:\n"; gb.display_equation(tout, *eq);); TRACE("non_linear_bug", tout << "processing new equality:\n"; gb.display_equation(tout, *eq);); - if (internalize_gb_eq(eq)) + if (internalize_gb_eq(eq)) result = GB_NEW_EQ; } } @@ -2372,10 +2372,10 @@ namespace smt { IF_VERBOSE(3, verbose_stream() << "Max. non linear arithmetic rounds. Increase threshold using NL_ARITH_ROUNDS=\n";); return FC_GIVEUP; } - + get_context().push_trail(value_trail(m_nl_rounds)); m_nl_rounds++; - + elim_quasi_base_rows(); move_non_base_vars_to_bounds(); TRACE("non_linear", tout << "processing non linear constraints...\n"; get_context().display(tout);); @@ -2384,8 +2384,8 @@ namespace smt { failed(); return FC_CONTINUE; } - - if (!max_min_nl_vars()) + + if (!max_min_nl_vars()) return FC_CONTINUE; if (check_monomial_assignments()) { @@ -2409,20 +2409,20 @@ namespace smt { } break; case 1: - if (!is_cross_nested_consistent(vars)) + if (!is_cross_nested_consistent(vars)) progress = true; break; case 2: if (m_params.m_nl_arith_gb) { switch(compute_grobner(vars)) { - case GB_PROGRESS: + case GB_PROGRESS: progress = true; break; - case GB_NEW_EQ: + case GB_NEW_EQ: progress = true; propagate_core(); break; - case GB_FAIL: + case GB_FAIL: break; } } From 45469152387b8f89ba386c770bd8a7028fc152af Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Tue, 18 Oct 2016 17:17:19 +0100 Subject: [PATCH 248/536] Fixed iterator invalidation bug in theory_arith_nl. Indirectly relates to #740 --- src/smt/theory_arith_nl.h | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/smt/theory_arith_nl.h b/src/smt/theory_arith_nl.h index c3ae8c99b..04b974d6e 100644 --- a/src/smt/theory_arith_nl.h +++ b/src/smt/theory_arith_nl.h @@ -965,10 +965,19 @@ namespace smt { bool theory_arith::propagate_linear_monomials() { TRACE("non_linear", tout << "propagating linear monomials...\n";); bool p = false; - svector::const_iterator it = m_nl_monomials.begin(); - svector::const_iterator end = m_nl_monomials.end(); - for (; it != end; ++it) { - theory_var v = *it; + // CMW: m_nl_monomials is sometimes modified while executing + // propagate_linear_monomial(...), invalidating the iterator `it'. + // (Via the relevancy propagation that internalizes a new axiom + // in mk_div_axiom and possibly others.) I'm replacing the iterator + // with an index `i'. + + // Was previously: + // svector::const_iterator it = m_nl_monomials.begin(); + // svector::const_iterator end = m_nl_monomials.end(); + // for (; it != end; ++it) { + // theory_var v = *it; + for (unsigned i = 0; i < m_nl_monomials.size(); i++) { + theory_var v = m_nl_monomials[i]; if (propagate_linear_monomial(v)) p = true; } From d060359f01b06c19bd4d65c4ba73d0f5c2393fc7 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 18 Oct 2016 22:34:34 -0400 Subject: [PATCH 249/536] add fd solver for finite domain queries Signed-off-by: Nikolaj Bjorner --- contrib/cmake/src/ast/rewriter/CMakeLists.txt | 1 + .../cmake/src/tactic/portfolio/CMakeLists.txt | 1 + src/ast/expr_functors.h | 8 + src/ast/rewriter/fd_rewriter.cpp | 292 ++++++++++++++++++ src/ast/rewriter/fd_rewriter.h | 48 +++ src/cmd_context/check_logic.cpp | 17 +- src/cmd_context/cmd_context.cpp | 5 +- src/sat/sat_solver.cpp | 9 +- src/sat/sat_solver/inc_sat_solver.cpp | 2 +- src/tactic/bv/dt2bv_tactic.cpp | 228 +++----------- src/tactic/bv/dt2bv_tactic.h | 2 +- src/tactic/extension_model_converter.cpp | 2 +- src/tactic/portfolio/fd_solver.cpp | 161 ++++++++++ src/tactic/portfolio/fd_solver.h | 29 ++ src/tactic/portfolio/smt_strategic_solver.cpp | 4 +- src/test/get_consequences.cpp | 71 ++++- 16 files changed, 676 insertions(+), 204 deletions(-) create mode 100644 src/ast/rewriter/fd_rewriter.cpp create mode 100644 src/ast/rewriter/fd_rewriter.h create mode 100644 src/tactic/portfolio/fd_solver.cpp create mode 100644 src/tactic/portfolio/fd_solver.h diff --git a/contrib/cmake/src/ast/rewriter/CMakeLists.txt b/contrib/cmake/src/ast/rewriter/CMakeLists.txt index 47323d821..b01a0e016 100644 --- a/contrib/cmake/src/ast/rewriter/CMakeLists.txt +++ b/contrib/cmake/src/ast/rewriter/CMakeLists.txt @@ -12,6 +12,7 @@ z3_add_component(rewriter expr_replacer.cpp expr_safe_replace.cpp factor_rewriter.cpp + fd_rewriter.cpp fpa_rewriter.cpp label_rewriter.cpp mk_simplified_app.cpp diff --git a/contrib/cmake/src/tactic/portfolio/CMakeLists.txt b/contrib/cmake/src/tactic/portfolio/CMakeLists.txt index d20af772b..201cdcf0f 100644 --- a/contrib/cmake/src/tactic/portfolio/CMakeLists.txt +++ b/contrib/cmake/src/tactic/portfolio/CMakeLists.txt @@ -1,6 +1,7 @@ z3_add_component(portfolio SOURCES default_tactic.cpp + fd_solver.cpp smt_strategic_solver.cpp COMPONENT_DEPENDENCIES aig_tactic diff --git a/src/ast/expr_functors.h b/src/ast/expr_functors.h index 32560e139..da2b43dea 100644 --- a/src/ast/expr_functors.h +++ b/src/ast/expr_functors.h @@ -31,6 +31,14 @@ public: virtual ~i_expr_pred() {} }; + +class i_sort_pred { +public: + virtual bool operator()(sort* s) = 0; + virtual ~i_sort_pred() {} +}; + + /** \brief Memoizing predicate functor on sub-expressions. diff --git a/src/ast/rewriter/fd_rewriter.cpp b/src/ast/rewriter/fd_rewriter.cpp new file mode 100644 index 000000000..026387e22 --- /dev/null +++ b/src/ast/rewriter/fd_rewriter.cpp @@ -0,0 +1,292 @@ +/*++ +Copyright (c) 2016 Microsoft Corporation + +Module Name: + + fd_rewriter.cpp + +Abstract: + + Conversion from enumeration types to bit-vectors. + +Author: + + Nikolaj Bjorner (nbjorner) 2016-10-18 + +Notes: + +--*/ + +#include"rewriter.h" +#include"rewriter_def.h" +#include"fd_rewriter.h" +#include"ast_util.h" +#include"ast_pp.h" + +struct fd_rewriter::imp { + ast_manager& m; + params_ref m_params; + obj_map m_enum2bv; + obj_map m_bv2enum; + obj_map m_enum2def; + expr_ref_vector m_bounds; + datatype_util m_dt; + func_decl_ref_vector m_enum_consts; + func_decl_ref_vector m_enum_bvs; + expr_ref_vector m_enum_defs; + unsigned_vector m_enum_consts_lim; + unsigned m_num_translated; + i_sort_pred* m_sort_pred; + + struct rw_cfg : public default_rewriter_cfg { + imp& m_imp; + ast_manager& m; + datatype_util m_dt; + bv_util m_bv; + + rw_cfg(imp& i, ast_manager & m) : + m_imp(i), + m(m), + m_dt(m), + m_bv(m) + {} + + br_status reduce_app(func_decl * f, unsigned num, expr * const * args, expr_ref & result, proof_ref & result_pr) { + expr_ref a0(m), a1(m); + expr_ref_vector _args(m); + if (m.is_eq(f) && reduce_arg(args[0], a0) && reduce_arg(args[1], a1)) { + result = m.mk_eq(a0, a1); + return BR_DONE; + } + else if (m.is_distinct(f) && reduce_args(num, args, _args)) { + result = m.mk_distinct(_args.size(), _args.c_ptr()); + return BR_DONE; + } + else if (m_dt.is_recognizer(f) && reduce_arg(args[0], a0)) { + unsigned idx = m_dt.get_recognizer_constructor_idx(f); + a1 = m_bv.mk_numeral(rational(idx), get_sort(a0)); + result = m.mk_eq(a0, a1); + return BR_DONE; + } + else { + check_for_fd(num, args); + return BR_FAILED; + } + } + + bool reduce_args(unsigned sz, expr*const* as, expr_ref_vector& result) { + expr_ref tmp(m); + for (unsigned i = 0; i < sz; ++i) { + if (!reduce_arg(as[i], tmp)) return false; + result.push_back(tmp); + } + return true; + } + + void throw_non_fd(expr* e) { + std::stringstream strm; + strm << "unabled nested data-type expression " << mk_pp(e, m); + throw rewriter_exception(strm.str().c_str()); + } + + void check_for_fd(unsigned n, expr* const* args) { + for (unsigned i = 0; i < n; ++i) { + if (m_imp.is_fd(get_sort(args[i]))) { + throw_non_fd(args[i]); + } + } + } + + bool reduce_arg(expr* a, expr_ref& result) { + + sort* s = get_sort(a); + if (!m_imp.is_fd(s)) { + return false; + } + unsigned bv_size = get_bv_size(s); + + if (is_var(a)) { + result = m.mk_var(to_var(a)->get_idx(), m_bv.mk_sort(bv_size)); + return true; + } + SASSERT(is_app(a)); + func_decl* f = to_app(a)->get_decl(); + if (m_dt.is_constructor(f)) { + unsigned idx = m_dt.get_constructor_idx(f); + result = m_bv.mk_numeral(idx, bv_size); + } + else if (is_uninterp_const(a)) { + func_decl* f_fresh; + if (m_imp.m_enum2bv.find(f, f_fresh)) { + result = m.mk_const(f_fresh); + return true; + } + + // create a fresh variable, add bounds constraints for it. + unsigned nc = m_dt.get_datatype_num_constructors(s); + result = m.mk_fresh_const(f->get_name().str().c_str(), m_bv.mk_sort(bv_size)); + f_fresh = to_app(result)->get_decl(); + if (!is_power_of_two(nc)) { + m_imp.m_bounds.push_back(m_bv.mk_ule(result, m_bv.mk_numeral(nc-1, bv_size))); + } + expr_ref f_def(m); + ptr_vector const& cs = *m_dt.get_datatype_constructors(s); + f_def = m.mk_const(cs[nc-1]); + for (unsigned i = nc - 1; i > 0; ) { + --i; + f_def = m.mk_ite(m.mk_eq(result, m_bv.mk_numeral(i,bv_size)), m.mk_const(cs[i]), f_def); + } + m_imp.m_enum2def.insert(f, f_def); + m_imp.m_enum2bv.insert(f, f_fresh); + m_imp.m_bv2enum.insert(f_fresh, f); + m_imp.m_enum_consts.push_back(f); + m_imp.m_enum_bvs.push_back(f_fresh); + m_imp.m_enum_defs.push_back(f_def); + } + else { + throw_non_fd(a); + } + ++m_imp.m_num_translated; + return true; + } + + ptr_buffer m_sorts; + + bool reduce_quantifier( + quantifier * q, + expr * old_body, + expr * const * new_patterns, + expr * const * new_no_patterns, + expr_ref & result, + proof_ref & result_pr) { + m_sorts.reset(); + expr_ref_vector bounds(m); + bool found = false; + for (unsigned i = 0; i < q->get_num_decls(); ++i) { + sort* s = q->get_decl_sort(i); + if (m_imp.is_fd(s)) { + unsigned bv_size = get_bv_size(s); + m_sorts.push_back(m_bv.mk_sort(bv_size)); + unsigned nc = m_dt.get_datatype_num_constructors(s); + if (!is_power_of_two(nc)) { + bounds.push_back(m_bv.mk_ule(m.mk_var(q->get_num_decls()-i-1, m_sorts[i]), m_bv.mk_numeral(nc-1, bv_size))); + } + found = true; + } + else { + m_sorts.push_back(s); + } + } + if (!found) { + return false; + } + expr_ref new_body_ref(old_body, m), tmp(m); + if (!bounds.empty()) { + if (q->is_forall()) { + new_body_ref = m.mk_implies(mk_and(bounds), new_body_ref); + } + else { + bounds.push_back(new_body_ref); + new_body_ref = mk_and(bounds); + } + } + result = m.mk_quantifier(q->is_forall(), q->get_num_decls(), m_sorts.c_ptr(), q->get_decl_names(), new_body_ref, + q->get_weight(), q->get_qid(), q->get_skid(), + q->get_num_patterns(), new_patterns, + q->get_num_no_patterns(), new_no_patterns); + result_pr = 0; + return true; + } + + unsigned get_bv_size(sort* s) { + unsigned nc = m_dt.get_datatype_num_constructors(s); + unsigned bv_size = 1; + while ((unsigned)(1 << bv_size) < nc) { + ++bv_size; + } + return bv_size; + } + }; + + struct rw : public rewriter_tpl { + rw_cfg m_cfg; + + rw(imp& t, ast_manager & m, params_ref const & p) : + rewriter_tpl(m, m.proofs_enabled(), m_cfg), + m_cfg(t, m) { + } + }; + + rw m_rw; + + imp(ast_manager& m, params_ref const& p): + m(m), m_params(p), m_bounds(m), + m_dt(m), + m_enum_consts(m), + m_enum_bvs(m), + m_enum_defs(m), + m_num_translated(0), + m_sort_pred(0), + m_rw(*this, m, p) { + } + + void updt_params(params_ref const & p) {} + unsigned get_num_steps() const { return m_rw.get_num_steps(); } + void cleanup() { m_rw.cleanup(); } + void operator()(expr * e, expr_ref & result, proof_ref & result_proof) { + m_rw(e, result, result_proof); + } + void push() { + m_enum_consts_lim.push_back(m_enum_consts.size()); + } + void pop(unsigned num_scopes) { + SASSERT(m_bounds.empty()); // bounds must be flushed before pop. + if (num_scopes > 0) { + SASSERT(num_scopes <= m_enum_consts_lim.size()); + unsigned new_sz = m_enum_consts_lim.size() - num_scopes; + unsigned lim = m_enum_consts_lim[new_sz]; + for (unsigned i = m_enum_consts.size(); i > lim; ) { + --i; + func_decl* f = m_enum_consts[i].get(); + func_decl* f_fresh = m_enum2bv.find(f); + m_bv2enum.erase(f_fresh); + m_enum2bv.erase(f); + m_enum2def.erase(f); + } + m_enum_consts_lim.resize(new_sz); + m_enum_consts.resize(lim); + m_enum_defs.resize(lim); + m_enum_bvs.resize(lim); + } + } + + void flush_side_constraints(expr_ref_vector& side_constraints) { + side_constraints.append(m_bounds); + m_bounds.reset(); + } + + bool is_fd(sort* s) { + return m_dt.is_enum_sort(s) && (!m_sort_pred || (*m_sort_pred)(s)); + } + + void set_is_fd(i_sort_pred* sp) { + m_sort_pred = sp; + } +}; + + +fd_rewriter::fd_rewriter(ast_manager & m, params_ref const& p) { m_imp = alloc(imp, m, p); } +fd_rewriter::~fd_rewriter() { dealloc(m_imp); } +void fd_rewriter::updt_params(params_ref const & p) { m_imp->updt_params(p); } +ast_manager & fd_rewriter::m() const { return m_imp->m; } +unsigned fd_rewriter::get_num_steps() const { return m_imp->get_num_steps(); } +void fd_rewriter::cleanup() { ast_manager& mgr = m(); params_ref p = m_imp->m_params; dealloc(m_imp); m_imp = alloc(imp, mgr, p); } +obj_map const& fd_rewriter::enum2bv() const { return m_imp->m_enum2bv; } +obj_map const& fd_rewriter::bv2enum() const { return m_imp->m_bv2enum; } +obj_map const& fd_rewriter::enum2def() const { return m_imp->m_enum2def; } +void fd_rewriter::operator()(expr * e, expr_ref & result, proof_ref & result_proof) { (*m_imp)(e, result, result_proof); } +void fd_rewriter::push() { m_imp->push(); } +void fd_rewriter::pop(unsigned num_scopes) { m_imp->pop(num_scopes); } +void fd_rewriter::flush_side_constraints(expr_ref_vector& side_constraints) { m_imp->flush_side_constraints(side_constraints); } +unsigned fd_rewriter::num_translated() const { return m_imp->m_num_translated; } +void fd_rewriter::set_is_fd(i_sort_pred* sp) const { m_imp->set_is_fd(sp); } diff --git a/src/ast/rewriter/fd_rewriter.h b/src/ast/rewriter/fd_rewriter.h new file mode 100644 index 000000000..3d4ecae9c --- /dev/null +++ b/src/ast/rewriter/fd_rewriter.h @@ -0,0 +1,48 @@ +/*++ +Copyright (c) 2016 Microsoft Corporation + +Module Name: + + fd_rewriter.h + +Abstract: + + Conversion from enumeration types to bit-vectors. + +Author: + + Nikolaj Bjorner (nbjorner) 2016-10-18 + +Notes: + +--*/ +#ifndef ENUM_REWRITER_H_ +#define ENUM_REWRITER_H_ + +#include"datatype_decl_plugin.h" +#include"rewriter_types.h" +#include"expr_functors.h" + +class fd_rewriter { + struct imp; + imp* m_imp; +public: + fd_rewriter(ast_manager & m, params_ref const& p); + ~fd_rewriter(); + + void updt_params(params_ref const & p); + ast_manager & m() const; + unsigned get_num_steps() const; + void cleanup(); + obj_map const& enum2bv() const; + obj_map const& bv2enum() const; + obj_map const& enum2def() const; + void operator()(expr * e, expr_ref & result, proof_ref & result_proof); + void push(); + void pop(unsigned num_scopes); + void flush_side_constraints(expr_ref_vector& side_constraints); + unsigned num_translated() const; + void set_is_fd(i_sort_pred* sp) const; +}; + +#endif diff --git a/src/cmd_context/check_logic.cpp b/src/cmd_context/check_logic.cpp index 733689ac9..7a49f8fd0 100644 --- a/src/cmd_context/check_logic.cpp +++ b/src/cmd_context/check_logic.cpp @@ -21,8 +21,10 @@ Revision History: #include"array_decl_plugin.h" #include"bv_decl_plugin.h" #include"seq_decl_plugin.h" +#include"datatype_decl_plugin.h" #include"ast_pp.h" #include"for_each_expr.h" +#include struct check_logic::imp { ast_manager & m; @@ -31,6 +33,7 @@ struct check_logic::imp { bv_util m_bv_util; array_util m_ar_util; seq_util m_seq_util; + datatype_util m_dt_util; bool m_uf; // true if the logic supports uninterpreted functions bool m_arrays; // true if the logic supports arbitrary arrays bool m_bv_arrays; // true if the logic supports only bv arrays @@ -42,7 +45,7 @@ struct check_logic::imp { bool m_quantifiers; // true if the logic supports quantifiers bool m_unknown_logic; - imp(ast_manager & _m):m(_m), m_a_util(m), m_bv_util(m), m_ar_util(m), m_seq_util(m) { + imp(ast_manager & _m):m(_m), m_a_util(m), m_bv_util(m), m_ar_util(m), m_seq_util(m), m_dt_util(m) { reset(); } @@ -178,6 +181,11 @@ struct check_logic::imp { m_reals = true; m_quantifiers = false; } + else if (logic == "QF_FD") { + m_bvs = true; + m_uf = true; + m_ints = true; + } else { m_unknown_logic = true; } @@ -432,8 +440,13 @@ struct check_logic::imp { else if (fid == m_seq_util.get_family_id()) { // nothing to check } + else if (fid == m_dt_util.get_family_id() && m_logic == "QF_FD") { + // nothing to check + } else { - fail("logic does not support theory"); + std::stringstream strm; + strm << "logic does not support theory " << m.get_family_name(fid); + fail(strm.str().c_str()); } } diff --git a/src/cmd_context/cmd_context.cpp b/src/cmd_context/cmd_context.cpp index 3260f02b0..1df28b8e5 100644 --- a/src/cmd_context/cmd_context.cpp +++ b/src/cmd_context/cmd_context.cpp @@ -568,6 +568,7 @@ bool cmd_context::logic_has_bv_core(symbol const & s) const { s == "QF_FPBV" || s == "QF_BVFP" || s == "ALL" || + s == "QF_FD" || s == "HORN"; } @@ -622,7 +623,7 @@ bool cmd_context::logic_has_array() const { } bool cmd_context::logic_has_datatype() const { - return !has_logic(); + return !has_logic() || m_logic == "QF_FD"; } void cmd_context::init_manager_core(bool new_manager) { @@ -705,7 +706,7 @@ void cmd_context::init_external_manager() { } bool cmd_context::supported_logic(symbol const & s) const { - return s == "QF_UF" || s == "UF" || s == "ALL" || + return s == "QF_UF" || s == "UF" || s == "ALL" || s == "QF_FD" || logic_has_arith_core(s) || logic_has_bv_core(s) || logic_has_array_core(s) || logic_has_seq_core(s) || logic_has_horn(s) || logic_has_fpa_core(s); diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 915080c4a..1e667eccc 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -3135,6 +3135,7 @@ namespace sat { if (is_sat != l_true) { return is_sat; } + model mdl = get_model(); for (unsigned i = 0; i < vars.size(); ++i) { bool_var v = vars[i]; switch (get_model()[v]) { @@ -3143,7 +3144,9 @@ namespace sat { default: break; } } - return get_consequences(asms, lits, conseq); + is_sat = get_consequences(asms, lits, conseq); + set_model(mdl); + return is_sat; } lbool solver::get_consequences(literal_vector const& asms, literal_vector const& lits, vector& conseq) { @@ -3164,13 +3167,11 @@ namespace sat { while (!unfixed.empty()) { checkpoint(); literal_set::iterator it = unfixed.begin(), end = unfixed.end(); - unsigned chunk_size = 100; - for (; it != end && chunk_size > 0; ++it) { + for (; it != end; ++it) { literal lit = *it; if (value(lit) != l_undef) { continue; } - --chunk_size; push(); assign(~lit, justification()); propagate(false); diff --git a/src/sat/sat_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp index 83ccfcac4..349b60f55 100644 --- a/src/sat/sat_solver/inc_sat_solver.cpp +++ b/src/sat/sat_solver/inc_sat_solver.cpp @@ -580,7 +580,7 @@ private: } void extract_model() { - TRACE("sat", tout << "retrieve model\n";); + TRACE("sat", tout << "retrieve model " << (m_solver.model_is_current()?"present":"absent") << "\n";); if (!m_solver.model_is_current()) { m_model = 0; return; diff --git a/src/tactic/bv/dt2bv_tactic.cpp b/src/tactic/bv/dt2bv_tactic.cpp index ab9df78ad..d7d6c9811 100644 --- a/src/tactic/bv/dt2bv_tactic.cpp +++ b/src/tactic/bv/dt2bv_tactic.cpp @@ -29,6 +29,7 @@ Revision History: #include "extension_model_converter.h" #include "var_subst.h" #include "ast_util.h" +#include "fd_rewriter.h" class dt2bv_tactic : public tactic { @@ -39,177 +40,8 @@ class dt2bv_tactic : public tactic { bv_util m_bv; obj_hashtable m_fd_sorts; obj_hashtable m_non_fd_sorts; - expr_ref_vector m_bounds; - ref m_ext; - ref m_filter; - unsigned m_num_translated; - obj_map* m_translate; - - struct rw_cfg : public default_rewriter_cfg { - dt2bv_tactic& m_t; - ast_manager& m; - params_ref m_params; - obj_map m_cache; - expr_ref_vector m_trail; - - rw_cfg(dt2bv_tactic& t, ast_manager & m, params_ref const & p) : - m_t(t), - m(m), - m_params(p), - m_trail(m) - {} - - br_status reduce_app(func_decl * f, unsigned num, expr * const * args, expr_ref & result, proof_ref & result_pr) { - expr_ref a0(m), a1(m); - expr_ref_vector _args(m); - if (m.is_eq(f) && reduce_arg(args[0], a0) && reduce_arg(args[1], a1)) { - result = m.mk_eq(a0, a1); - return BR_DONE; - } - else if (m.is_distinct(f) && reduce_args(num, args, _args)) { - result = m.mk_distinct(_args.size(), _args.c_ptr()); - return BR_DONE; - } - else if (m_t.m_dt.is_recognizer(f) && reduce_arg(args[0], a0)) { - unsigned idx = m_t.m_dt.get_recognizer_constructor_idx(f); - a1 = m_t.m_bv.mk_numeral(rational(idx), get_sort(a0)); - result = m.mk_eq(a0, a1); - return BR_DONE; - } - else { - return BR_FAILED; - } - } - - bool reduce_args(unsigned sz, expr*const* as, expr_ref_vector& result) { - expr_ref tmp(m); - for (unsigned i = 0; i < sz; ++i) { - if (!reduce_arg(as[i], tmp)) return false; - result.push_back(tmp); - } - return true; - } - - bool reduce_arg(expr* a, expr_ref& result) { - expr* b; - if (m_cache.find(a, b)) { - result = b; - return true; - } - - sort* s = get_sort(a); - if (!m_t.m_fd_sorts.contains(s)) { - return false; - } - unsigned bv_size = get_bv_size(s); - - if (is_var(a)) { - result = m.mk_var(to_var(a)->get_idx(), m_t.m_bv.mk_sort(bv_size)); - return true; - } - SASSERT(is_app(a)); - func_decl* f = to_app(a)->get_decl(); - if (m_t.m_dt.is_constructor(f)) { - unsigned idx = m_t.m_dt.get_constructor_idx(f); - result = m_t.m_bv.mk_numeral(idx, bv_size); - } - else if (is_uninterp_const(a)) { - // create a fresh variable, add bounds constraints for it. - unsigned nc = m_t.m_dt.get_datatype_num_constructors(s); - result = m.mk_fresh_const(f->get_name().str().c_str(), m_t.m_bv.mk_sort(bv_size)); - if (!is_power_of_two(nc)) { - m_t.m_bounds.push_back(m_t.m_bv.mk_ule(result, m_t.m_bv.mk_numeral(nc-1, bv_size))); - } - expr_ref f_def(m); - ptr_vector const& cs = *m_t.m_dt.get_datatype_constructors(s); - f_def = m.mk_const(cs[nc-1]); - for (unsigned i = nc - 1; i > 0; ) { - --i; - f_def = m.mk_ite(m.mk_eq(result, m_t.m_bv.mk_numeral(i,bv_size)), m.mk_const(cs[i]), f_def); - } - // update model converters. - m_t.m_ext->insert(f, f_def); - m_t.m_filter->insert(to_app(result)->get_decl()); - if (m_t.m_translate) { - m_t.m_translate->insert(f, result); - } - } - else { - return false; - } - m_cache.insert(a, result); - ++m_t.m_num_translated; - return true; - } - - ptr_buffer m_sorts; - - bool reduce_quantifier( - quantifier * q, - expr * old_body, - expr * const * new_patterns, - expr * const * new_no_patterns, - expr_ref & result, - proof_ref & result_pr) { - m_sorts.reset(); - expr_ref_vector bounds(m); - bool found = false; - for (unsigned i = 0; i < q->get_num_decls(); ++i) { - sort* s = q->get_decl_sort(i); - if (m_t.m_fd_sorts.contains(s)) { - unsigned bv_size = get_bv_size(s); - m_sorts.push_back(m_t.m_bv.mk_sort(bv_size)); - unsigned nc = m_t.m_dt.get_datatype_num_constructors(s); - if (!is_power_of_two(nc)) { - bounds.push_back(m_t.m_bv.mk_ule(m.mk_var(q->get_num_decls()-i-1, m_sorts[i]), m_t.m_bv.mk_numeral(nc, bv_size))); - } - found = true; - } - else { - m_sorts.push_back(s); - } - } - if (!found) { - return false; - } - expr_ref new_body_ref(old_body, m), tmp(m); - if (!bounds.empty()) { - if (q->is_forall()) { - new_body_ref = m.mk_implies(mk_and(bounds), new_body_ref); - } - else { - bounds.push_back(new_body_ref); - new_body_ref = mk_and(bounds); - } - } - result = m.mk_quantifier(q->is_forall(), q->get_num_decls(), m_sorts.c_ptr(), q->get_decl_names(), new_body_ref, - q->get_weight(), q->get_qid(), q->get_skid(), - q->get_num_patterns(), new_patterns, - q->get_num_no_patterns(), new_no_patterns); - result_pr = 0; - return true; - } - - unsigned get_bv_size(sort* s) { - unsigned nc = m_t.m_dt.get_datatype_num_constructors(s); - unsigned bv_size = 1; - while ((unsigned)(1 << bv_size) < nc) { - ++bv_size; - } - return bv_size; - } - }; - - struct rw : public rewriter_tpl { - rw_cfg m_cfg; - - rw(dt2bv_tactic& t, ast_manager & m, params_ref const & p) : - rewriter_tpl(m, m.proofs_enabled(), m_cfg), - m_cfg(t, m, p) { - } - }; - - + obj_map* m_translate; + bool is_fd(expr* a) { return is_fd(get_sort(a)); } bool is_fd(sort* a) { return m_dt.is_enum_sort(a); } @@ -255,10 +87,20 @@ class dt2bv_tactic : public tactic { void operator()(quantifier* q) {} }; + struct sort_pred : public i_sort_pred { + dt2bv_tactic& m_t; + sort_pred(dt2bv_tactic& t): m_t(t) {} + virtual ~sort_pred() {} + virtual bool operator()(sort* s) { + return m_t.m_fd_sorts.contains(s); + } + }; + + sort_pred m_is_fd; public: - dt2bv_tactic(ast_manager& m, params_ref const& p, obj_map* tr): - m(m), m_params(p), m_dt(m), m_bv(m), m_bounds(m), m_translate(tr) {} + dt2bv_tactic(ast_manager& m, params_ref const& p, obj_map* tr): + m(m), m_params(p), m_dt(m), m_bv(m), m_translate(tr), m_is_fd(*this) {} virtual tactic * translate(ast_manager & m) { return alloc(dt2bv_tactic, m, m_params, 0); @@ -289,26 +131,43 @@ public: m_fd_sorts.remove(*it); } if (!m_fd_sorts.empty()) { - m_bounds.reset(); - m_num_translated = 0; - m_ext = alloc(extension_model_converter, m); - m_filter = alloc(filter_model_converter, m); - scoped_ptr r = alloc(rw, *this, m, m_params); + ref ext = alloc(extension_model_converter, m); + ref filter = alloc(filter_model_converter, m); + fd_rewriter rw(m, m_params); + rw.set_is_fd(&m_is_fd); expr_ref new_curr(m); proof_ref new_pr(m); for (unsigned idx = 0; idx < size; idx++) { - (*r)(g->form(idx), new_curr, new_pr); + rw(g->form(idx), new_curr, new_pr); if (produce_proofs) { proof * pr = g->pr(idx); new_pr = m.mk_modus_ponens(pr, new_pr); } g->update(idx, new_curr, new_pr, g->dep(idx)); } - for (unsigned i = 0; i < m_bounds.size(); ++i) { - g->assert_expr(m_bounds[i].get()); + expr_ref_vector bounds(m); + rw.flush_side_constraints(bounds); + for (unsigned i = 0; i < bounds.size(); ++i) { + g->assert_expr(bounds[i].get()); } - mc = concat(m_filter.get(), m_ext.get()); - report_tactic_progress(":fd-num-translated", m_num_translated); + { + obj_map::iterator it = rw.enum2bv().begin(), end = rw.enum2bv().end(); + for (; it != end; ++it) { + filter->insert(it->m_value); + if (m_translate) { + m_translate->insert(it->m_key, it->m_value); + } + } + } + { + obj_map::iterator it = rw.enum2def().begin(), end = rw.enum2def().end(); + for (; it != end; ++it) { + ext->insert(it->m_key, it->m_value); + } + } + + mc = concat(filter.get(), ext.get()); + report_tactic_progress(":fd-num-translated", rw.num_translated()); } g->inc_depth(); result.push_back(g.get()); @@ -319,11 +178,10 @@ public: virtual void cleanup() { m_fd_sorts.reset(); m_non_fd_sorts.reset(); - m_bounds.reset(); } }; -tactic * mk_dt2bv_tactic(ast_manager & m, params_ref const & p, obj_map* tr) { +tactic * mk_dt2bv_tactic(ast_manager & m, params_ref const & p, obj_map* tr) { return alloc(dt2bv_tactic, m, p, tr); } diff --git a/src/tactic/bv/dt2bv_tactic.h b/src/tactic/bv/dt2bv_tactic.h index a8fb33fe8..fd5aacda6 100644 --- a/src/tactic/bv/dt2bv_tactic.h +++ b/src/tactic/bv/dt2bv_tactic.h @@ -24,7 +24,7 @@ Revision History: class ast_manager; class tactic; -tactic * mk_dt2bv_tactic(ast_manager & m, params_ref const & p = params_ref(), obj_map* tr = 0); +tactic * mk_dt2bv_tactic(ast_manager & m, params_ref const & p = params_ref(), obj_map* tr = 0); /* ADD_TACTIC("dt2bv", "eliminate finite domain data-types. Replace by bit-vectors.", "mk_dt2bv_tactic(m, p)") diff --git a/src/tactic/extension_model_converter.cpp b/src/tactic/extension_model_converter.cpp index cdd096455..345ea5cc9 100644 --- a/src/tactic/extension_model_converter.cpp +++ b/src/tactic/extension_model_converter.cpp @@ -71,7 +71,7 @@ void extension_model_converter::operator()(model_ref & md, unsigned goal_idx) { void extension_model_converter::insert(func_decl * v, expr * def) { m_vars.push_back(v); - m_defs.push_back(def); + m_defs.push_back(def); } diff --git a/src/tactic/portfolio/fd_solver.cpp b/src/tactic/portfolio/fd_solver.cpp new file mode 100644 index 000000000..9447c158c --- /dev/null +++ b/src/tactic/portfolio/fd_solver.cpp @@ -0,0 +1,161 @@ +/*++ +Copyright (c) 2016 Microsoft Corporation + +Module Name: + + fd_solver.cpp + +Abstract: + + Finite domain solver. + + Enumeration data-types are translated into bit-vectors, and then + the incremental sat-solver is applied to the resulting assertions. + +Author: + + Nikolaj Bjorner (nbjorner) 2016-10-17 + +Notes: + +--*/ + +#include "fd_solver.h" +#include "solver_na2as.h" +#include "tactic.h" +#include "inc_sat_solver.h" +#include "bv_decl_plugin.h" +#include "datatype_decl_plugin.h" +#include "fd_rewriter.h" +#include "extension_model_converter.h" +#include "filter_model_converter.h" +#include "ast_pp.h" +#include "model_smt2_pp.h" + +class fd_solver : public solver_na2as { + ast_manager& m; + params_ref m_params; + ref m_solver; + fd_rewriter m_rewriter; + +public: + + fd_solver(ast_manager& m, params_ref const& p): + solver_na2as(m), + m(m), + m_params(p), + m_solver(mk_inc_sat_solver(m, p)), + m_rewriter(m, p) + { + } + + virtual ~fd_solver() {} + + virtual solver* translate(ast_manager& m, params_ref const& p) { + return alloc(fd_solver, m, p); + } + + virtual void assert_expr(expr * t) { + expr_ref tmp(t, m); + expr_ref_vector bounds(m); + proof_ref tmp_proof(m); + m_rewriter(t, tmp, tmp_proof); + m_solver->assert_expr(tmp); + m_rewriter.flush_side_constraints(bounds); + m_solver->assert_expr(bounds); + } + + virtual void push_core() { + m_rewriter.push(); + m_solver->push(); + } + + virtual void pop_core(unsigned n) { + m_solver->pop(n); + m_rewriter.pop(n); + } + + virtual lbool check_sat_core(unsigned num_assumptions, expr * const * assumptions) { + return m_solver->check_sat(num_assumptions, assumptions); + } + + virtual void updt_params(params_ref const & p) { m_solver->updt_params(p); } + virtual void collect_param_descrs(param_descrs & r) { m_solver->collect_param_descrs(r); } + virtual void set_produce_models(bool f) { m_solver->set_produce_models(f); } + virtual void set_progress_callback(progress_callback * callback) { m_solver->set_progress_callback(callback); } + virtual void collect_statistics(statistics & st) const { m_solver->collect_statistics(st); } + virtual void get_unsat_core(ptr_vector & r) { m_solver->get_unsat_core(r); } + virtual void get_model(model_ref & mdl) { + m_solver->get_model(mdl); + if (mdl) { + extend_model(mdl); + filter_model(mdl); + } + } + virtual proof * get_proof() { return m_solver->get_proof(); } + virtual std::string reason_unknown() const { return m_solver->reason_unknown(); } + virtual void set_reason_unknown(char const* msg) { m_solver->set_reason_unknown(msg); } + virtual void get_labels(svector & r) { m_solver->get_labels(r); } + virtual ast_manager& get_manager() const { return m; } + virtual lbool find_mutexes(expr_ref_vector const& vars, vector& mutexes) { return m_solver->find_mutexes(vars, mutexes); } + + virtual lbool get_consequences_core(expr_ref_vector const& asms, expr_ref_vector const& vars, expr_ref_vector& consequences) { + + datatype_util dt(m); + bv_util bv(m); + + // translate enumeration constants to bit-vectors. + expr_ref_vector bvars(m), conseq(m); + for (unsigned i = 0; i < vars.size(); ++i) { + func_decl* f; + if (is_app(vars[i]) && is_uninterp_const(vars[i]) && m_rewriter.enum2bv().find(to_app(vars[i])->get_decl(), f)) { + bvars.push_back(m.mk_const(f)); + } + else { + bvars.push_back(vars[i]); + } + } + lbool r = m_solver->get_consequences(asms, bvars, consequences); + + // translate bit-vector consequences back to enumeration types + for (unsigned i = 0; i < consequences.size(); ++i) { + expr* a, *b, *u, *v; + func_decl* f; + rational num; + unsigned bvsize; + VERIFY(m.is_implies(consequences[i].get(), a, b)); + if (m.is_eq(b, u, v) && is_uninterp_const(u) && m_rewriter.bv2enum().find(to_app(u)->get_decl(), f) && bv.is_numeral(v, num, bvsize)) { + SASSERT(num.is_unsigned()); + expr_ref head(m); + ptr_vector const& enums = *dt.get_datatype_constructors(f->get_range()); + head = m.mk_eq(m.mk_const(f), m.mk_const(enums[num.get_unsigned()])); + consequences[i] = m.mk_implies(a, head); + } + } + return r; + } + + void filter_model(model_ref& mdl) { + filter_model_converter filter(m); + obj_map::iterator it = m_rewriter.enum2bv().begin(), end = m_rewriter.enum2bv().end(); + for (; it != end; ++it) { + filter.insert(it->m_value); + } + filter(mdl, 0); + } + + void extend_model(model_ref& mdl) { + extension_model_converter ext(m); + obj_map::iterator it = m_rewriter.enum2def().begin(), end = m_rewriter.enum2def().end(); + for (; it != end; ++it) { + ext.insert(it->m_key, it->m_value); + + } + ext(mdl, 0); + } + +}; + +solver * mk_fd_solver(ast_manager & m, params_ref const & p) { + return alloc(fd_solver, m, p); +} diff --git a/src/tactic/portfolio/fd_solver.h b/src/tactic/portfolio/fd_solver.h new file mode 100644 index 000000000..51abb087f --- /dev/null +++ b/src/tactic/portfolio/fd_solver.h @@ -0,0 +1,29 @@ +/*++ +Copyright (c) 2016 Microsoft Corporation + +Module Name: + + fd_solver.h + +Abstract: + + Finite domain solver. + +Author: + + Nikolaj Bjorner (nbjorner) 2016-10-17 + +Notes: + +--*/ +#ifndef FD_SOLVER_H_ +#define FD_SOLVER_H_ + +#include"ast.h" +#include"params.h" + +class solver; + +solver * mk_fd_solver(ast_manager & m, params_ref const & p); + +#endif diff --git a/src/tactic/portfolio/smt_strategic_solver.cpp b/src/tactic/portfolio/smt_strategic_solver.cpp index f9334bcb2..81825221e 100644 --- a/src/tactic/portfolio/smt_strategic_solver.cpp +++ b/src/tactic/portfolio/smt_strategic_solver.cpp @@ -38,6 +38,7 @@ Notes: #include"horn_tactic.h" #include"smt_solver.h" #include"inc_sat_solver.h" +#include"fd_solver.h" #include"bv_rewriter.h" @@ -98,6 +99,8 @@ static solver* mk_solver_for_logic(ast_manager & m, params_ref const & p, symbol bv_rewriter rw(m); if (logic == "QF_BV" && rw.hi_div0()) return mk_inc_sat_solver(m, p); + if (logic == "QF_FD") + return mk_fd_solver(m, p); return mk_smt_solver(m, p, logic); } @@ -116,7 +119,6 @@ public: tactic * t = mk_tactic_for_logic(m, p, l); return mk_combined_solver(mk_tactic2solver(m, t, p, proofs_enabled, models_enabled, unsat_core_enabled, l), mk_solver_for_logic(m, p, l), - //mk_smt_solver(m, p, l), p); } }; diff --git a/src/test/get_consequences.cpp b/src/test/get_consequences.cpp index 24f3a5d38..8c35bcfb1 100644 --- a/src/test/get_consequences.cpp +++ b/src/test/get_consequences.cpp @@ -11,7 +11,7 @@ Copyright (c) 2016 Microsoft Corporation #include "dt2bv_tactic.h" #include "tactic.h" #include "model_smt2_pp.h" -//include +#include "fd_solver.h" static expr_ref mk_const(ast_manager& m, char const* name, sort* s) { return expr_ref(m.mk_const(symbol(name), s), m); @@ -81,8 +81,8 @@ static void test2() { gl->assert_expr(m.mk_not(m.mk_eq(x, r))); gl->assert_expr(m.mk_not(m.mk_eq(x, b))); gl->display(std::cout); - obj_map tr; - obj_map rev_tr; + obj_map tr; + obj_map rev_tr; ref dt2bv = mk_dt2bv_tactic(m, p, &tr); goal_ref_buffer result; model_converter_ref mc; @@ -91,13 +91,13 @@ static void test2() { (*dt2bv)(gl, result, mc, pc, core); // Collect translations from enumerations to bit-vectors - obj_map::iterator it = tr.begin(), end = tr.end(); + obj_map::iterator it = tr.begin(), end = tr.end(); for (; it != end; ++it) { rev_tr.insert(it->m_value, it->m_key); } // Create bit-vector implication problem - val = tr.find(to_app(x)->get_decl()); + val = m.mk_const(tr.find(to_app(x)->get_decl())); std::cout << val << "\n"; ptr_vector fmls; result[0]->get_formulas(fmls); @@ -119,7 +119,7 @@ static void test2() { rational num; unsigned bvsize; VERIFY(m.is_implies(conseq[i].get(), a, b)); - if (m.is_eq(b, u, v) && rev_tr.find(u, f) && bv.is_numeral(v, num, bvsize)) { + if (m.is_eq(b, u, v) && rev_tr.find(to_app(u)->get_decl(), f) && bv.is_numeral(v, num, bvsize)) { SASSERT(num.is_unsigned()); expr_ref head(m); head = m.mk_eq(m.mk_const(f), m.mk_const(enums[num.get_unsigned()])); @@ -129,9 +129,66 @@ static void test2() { std::cout << conseq << "\n"; } +void test3() { + ast_manager m; + reg_decl_plugins(m); + bv_util bv(m); + datatype_util dtutil(m); + params_ref p; + + datatype_decl_plugin & dt = *(static_cast(m.get_plugin(m.get_family_id("datatype")))); + sort_ref_vector new_sorts(m); + constructor_decl* R = mk_constructor_decl(symbol("R"), symbol("is-R"), 0, 0); + constructor_decl* G = mk_constructor_decl(symbol("G"), symbol("is-G"), 0, 0); + constructor_decl* B = mk_constructor_decl(symbol("B"), symbol("is-B"), 0, 0); + constructor_decl* constrs[3] = { R, G, B }; + datatype_decl * enum_sort = mk_datatype_decl(symbol("RGB"), 3, constrs); + VERIFY(dt.mk_datatypes(1, &enum_sort, new_sorts)); + del_constructor_decls(3, constrs); + sort* rgb = new_sorts[0].get(); + + expr_ref x = mk_const(m, "x", rgb), y = mk_const(m, "y", rgb), z = mk_const(m, "z", rgb); + ptr_vector const& enums = *dtutil.get_datatype_constructors(rgb); + expr_ref r = expr_ref(m.mk_const(enums[0]), m); + expr_ref g = expr_ref(m.mk_const(enums[1]), m); + expr_ref b = expr_ref(m.mk_const(enums[2]), m); + + ref fd_solver = mk_fd_solver(m, p); + fd_solver->assert_expr(m.mk_not(m.mk_eq(x, r))); + fd_solver->assert_expr(m.mk_not(m.mk_eq(x, b))); + + expr_ref_vector asms(m), vars(m), conseq(m); + vars.push_back(x); + vars.push_back(y); + + VERIFY(l_true == fd_solver->get_consequences(asms, vars, conseq)); + std::cout << conseq << "\n"; + conseq.reset(); + + fd_solver->push(); + fd_solver->assert_expr(m.mk_not(m.mk_eq(x, g))); + VERIFY(l_false == fd_solver->check_sat(0,0)); + fd_solver->pop(1); + + VERIFY(l_true == fd_solver->get_consequences(asms, vars, conseq)); + + std::cout << conseq << "\n"; + conseq.reset(); + + model_ref mr; + fd_solver->get_model(mr); + model_smt2_pp(std::cout << "model:\n", m, *mr.get(), 0); + + VERIFY(l_true == fd_solver->check_sat(0,0)); + fd_solver->get_model(mr); + SASSERT(mr.get()); + model_smt2_pp(std::cout, m, *mr.get(), 0); + +} + void tst_get_consequences() { test1(); test2(); - + test3(); } From 881e82e3fa76c92b69f46dcf92f031c0a871545d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 18 Oct 2016 23:04:17 -0400 Subject: [PATCH 250/536] remove legacy interface to dt2bv tactic Signed-off-by: Nikolaj Bjorner --- src/smt/theory_arith_nl.h | 18 +++----- src/tactic/bv/dt2bv_tactic.cpp | 14 +++--- src/tactic/bv/dt2bv_tactic.h | 2 +- src/test/get_consequences.cpp | 81 +--------------------------------- 4 files changed, 13 insertions(+), 102 deletions(-) diff --git a/src/smt/theory_arith_nl.h b/src/smt/theory_arith_nl.h index 04b974d6e..7af736a53 100644 --- a/src/smt/theory_arith_nl.h +++ b/src/smt/theory_arith_nl.h @@ -589,10 +589,8 @@ namespace smt { m_dep_manager.reset(); bool propagated = false; context & ctx = get_context(); - svector::const_iterator it = m_nl_monomials.begin(); - svector::const_iterator end = m_nl_monomials.end(); - for (; it != end; ++it) { - theory_var v = *it; + for (unsigned j = 0; j < m_nl_monomials.size(); ++j) { + theory_var v = m_nl_monomials[j]; expr * m = var2expr(v); if (!ctx.is_relevant(m)) continue; @@ -706,10 +704,8 @@ namespace smt { bool bounded = false; unsigned n = 0; numeral range; - svector::const_iterator it = m_nl_monomials.begin(); - svector::const_iterator end = m_nl_monomials.end(); - for (; it != end; ++it) { - theory_var v = *it; + for (unsigned j = 0; j < m_nl_monomials.size(); ++j) { + theory_var v = m_nl_monomials[j]; if (is_real(v)) continue; bool computed_epsilon = false; @@ -2340,10 +2336,8 @@ namespace smt { bool theory_arith::max_min_nl_vars() { var_set already_found; svector vars; - svector::const_iterator it = m_nl_monomials.begin(); - svector::const_iterator end = m_nl_monomials.end(); - for (; it != end; ++it) { - theory_var v = *it; + for (unsigned j = 0; j < m_nl_monomials.size(); ++j) { + theory_var v = m_nl_monomials[j]; mark_var(v, vars, already_found); expr * n = var2expr(v); SASSERT(is_pure_monomial(n)); diff --git a/src/tactic/bv/dt2bv_tactic.cpp b/src/tactic/bv/dt2bv_tactic.cpp index d7d6c9811..2ecc80980 100644 --- a/src/tactic/bv/dt2bv_tactic.cpp +++ b/src/tactic/bv/dt2bv_tactic.cpp @@ -40,7 +40,6 @@ class dt2bv_tactic : public tactic { bv_util m_bv; obj_hashtable m_fd_sorts; obj_hashtable m_non_fd_sorts; - obj_map* m_translate; bool is_fd(expr* a) { return is_fd(get_sort(a)); } @@ -99,11 +98,11 @@ class dt2bv_tactic : public tactic { sort_pred m_is_fd; public: - dt2bv_tactic(ast_manager& m, params_ref const& p, obj_map* tr): - m(m), m_params(p), m_dt(m), m_bv(m), m_translate(tr), m_is_fd(*this) {} + dt2bv_tactic(ast_manager& m, params_ref const& p): + m(m), m_params(p), m_dt(m), m_bv(m), m_is_fd(*this) {} virtual tactic * translate(ast_manager & m) { - return alloc(dt2bv_tactic, m, m_params, 0); + return alloc(dt2bv_tactic, m, m_params); } virtual void updt_params(params_ref const & p) { @@ -154,9 +153,6 @@ public: obj_map::iterator it = rw.enum2bv().begin(), end = rw.enum2bv().end(); for (; it != end; ++it) { filter->insert(it->m_value); - if (m_translate) { - m_translate->insert(it->m_key, it->m_value); - } } } { @@ -182,6 +178,6 @@ public: }; -tactic * mk_dt2bv_tactic(ast_manager & m, params_ref const & p, obj_map* tr) { - return alloc(dt2bv_tactic, m, p, tr); +tactic * mk_dt2bv_tactic(ast_manager & m, params_ref const & p) { + return alloc(dt2bv_tactic, m, p); } diff --git a/src/tactic/bv/dt2bv_tactic.h b/src/tactic/bv/dt2bv_tactic.h index fd5aacda6..10ce0724f 100644 --- a/src/tactic/bv/dt2bv_tactic.h +++ b/src/tactic/bv/dt2bv_tactic.h @@ -24,7 +24,7 @@ Revision History: class ast_manager; class tactic; -tactic * mk_dt2bv_tactic(ast_manager & m, params_ref const & p = params_ref(), obj_map* tr = 0); +tactic * mk_dt2bv_tactic(ast_manager & m, params_ref const & p = params_ref()); /* ADD_TACTIC("dt2bv", "eliminate finite domain data-types. Replace by bit-vectors.", "mk_dt2bv_tactic(m, p)") diff --git a/src/test/get_consequences.cpp b/src/test/get_consequences.cpp index 8c35bcfb1..febff0151 100644 --- a/src/test/get_consequences.cpp +++ b/src/test/get_consequences.cpp @@ -51,85 +51,8 @@ static void test1() { std::cout << conseq << "\n"; } -static void test2() { - ast_manager m; - reg_decl_plugins(m); - bv_util bv(m); - datatype_util dtutil(m); - params_ref p; - datatype_decl_plugin & dt = *(static_cast(m.get_plugin(m.get_family_id("datatype")))); - sort_ref_vector new_sorts(m); - constructor_decl* R = mk_constructor_decl(symbol("R"), symbol("is-R"), 0, 0); - constructor_decl* G = mk_constructor_decl(symbol("G"), symbol("is-G"), 0, 0); - constructor_decl* B = mk_constructor_decl(symbol("B"), symbol("is-B"), 0, 0); - constructor_decl* constrs[3] = { R, G, B }; - datatype_decl * enum_sort = mk_datatype_decl(symbol("RGB"), 3, constrs); - VERIFY(dt.mk_datatypes(1, &enum_sort, new_sorts)); - del_constructor_decls(3, constrs); - sort* rgb = new_sorts[0].get(); - - expr_ref x = mk_const(m, "x", rgb), y = mk_const(m, "y", rgb), z = mk_const(m, "z", rgb); - ptr_vector const& enums = *dtutil.get_datatype_constructors(rgb); - expr_ref r = expr_ref(m.mk_const(enums[0]), m); - expr_ref g = expr_ref(m.mk_const(enums[1]), m); - expr_ref b = expr_ref(m.mk_const(enums[2]), m); - expr_ref val(m); - - // Eliminate enumeration data-types: - goal_ref gl = alloc(goal, m); - gl->assert_expr(m.mk_not(m.mk_eq(x, r))); - gl->assert_expr(m.mk_not(m.mk_eq(x, b))); - gl->display(std::cout); - obj_map tr; - obj_map rev_tr; - ref dt2bv = mk_dt2bv_tactic(m, p, &tr); - goal_ref_buffer result; - model_converter_ref mc; - proof_converter_ref pc; - expr_dependency_ref core(m); - (*dt2bv)(gl, result, mc, pc, core); - - // Collect translations from enumerations to bit-vectors - obj_map::iterator it = tr.begin(), end = tr.end(); - for (; it != end; ++it) { - rev_tr.insert(it->m_value, it->m_key); - } - - // Create bit-vector implication problem - val = m.mk_const(tr.find(to_app(x)->get_decl())); - std::cout << val << "\n"; - ptr_vector fmls; - result[0]->get_formulas(fmls); - ref solver = mk_inc_sat_solver(m, p); - for (unsigned i = 0; i < fmls.size(); ++i) { - solver->assert_expr(fmls[i]); - } - expr_ref_vector asms(m), vars(m), conseq(m); - vars.push_back(val); - - // retrieve consequences - solver->get_consequences(asms, vars, conseq); - - // Convert consequences over bit-vectors to enumeration types. - std::cout << conseq << "\n"; - for (unsigned i = 0; i < conseq.size(); ++i) { - expr* a, *b, *u, *v; - func_decl* f; - rational num; - unsigned bvsize; - VERIFY(m.is_implies(conseq[i].get(), a, b)); - if (m.is_eq(b, u, v) && rev_tr.find(to_app(u)->get_decl(), f) && bv.is_numeral(v, num, bvsize)) { - SASSERT(num.is_unsigned()); - expr_ref head(m); - head = m.mk_eq(m.mk_const(f), m.mk_const(enums[num.get_unsigned()])); - conseq[i] = m.mk_implies(a, head); - } - } - std::cout << conseq << "\n"; -} - -void test3() { +void test2() { ast_manager m; reg_decl_plugins(m); bv_util bv(m); @@ -189,6 +112,4 @@ void test3() { void tst_get_consequences() { test1(); test2(); - test3(); - } From 11997afb5d1c0dd816bcd43dfa8298031e4ee743 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Wed, 19 Oct 2016 12:00:34 +0100 Subject: [PATCH 251/536] Fixed potential problems with invalidated iterators. --- src/smt/theory_arith_nl.h | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/src/smt/theory_arith_nl.h b/src/smt/theory_arith_nl.h index 04b974d6e..df9a71aaa 100644 --- a/src/smt/theory_arith_nl.h +++ b/src/smt/theory_arith_nl.h @@ -589,10 +589,8 @@ namespace smt { m_dep_manager.reset(); bool propagated = false; context & ctx = get_context(); - svector::const_iterator it = m_nl_monomials.begin(); - svector::const_iterator end = m_nl_monomials.end(); - for (; it != end; ++it) { - theory_var v = *it; + for (unsigned i = 0; i < m_nl_monomials.size(); i++) { + theory_var v = m_nl_monomials.size(); expr * m = var2expr(v); if (!ctx.is_relevant(m)) continue; @@ -706,10 +704,8 @@ namespace smt { bool bounded = false; unsigned n = 0; numeral range; - svector::const_iterator it = m_nl_monomials.begin(); - svector::const_iterator end = m_nl_monomials.end(); - for (; it != end; ++it) { - theory_var v = *it; + for (unsigned i = 0; i < m_nl_monomials.size(); i++) { + theory_var v = m_nl_monomials.size(); if (is_real(v)) continue; bool computed_epsilon = false; @@ -2340,10 +2336,8 @@ namespace smt { bool theory_arith::max_min_nl_vars() { var_set already_found; svector vars; - svector::const_iterator it = m_nl_monomials.begin(); - svector::const_iterator end = m_nl_monomials.end(); - for (; it != end; ++it) { - theory_var v = *it; + for (unsigned i = 0; i < m_nl_monomials.size(); i++) { + theory_var v = m_nl_monomials.size(); mark_var(v, vars, already_found); expr * n = var2expr(v); SASSERT(is_pure_monomial(n)); From 948bf9540f92a32da1450360a0e33e10dabbd7d2 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Wed, 19 Oct 2016 12:07:33 +0100 Subject: [PATCH 252/536] Fix for previous commit. --- src/smt/theory_arith_nl.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/smt/theory_arith_nl.h b/src/smt/theory_arith_nl.h index df9a71aaa..d47ecaa4e 100644 --- a/src/smt/theory_arith_nl.h +++ b/src/smt/theory_arith_nl.h @@ -590,7 +590,7 @@ namespace smt { bool propagated = false; context & ctx = get_context(); for (unsigned i = 0; i < m_nl_monomials.size(); i++) { - theory_var v = m_nl_monomials.size(); + theory_var v = m_nl_monomials[i]; expr * m = var2expr(v); if (!ctx.is_relevant(m)) continue; @@ -705,7 +705,7 @@ namespace smt { unsigned n = 0; numeral range; for (unsigned i = 0; i < m_nl_monomials.size(); i++) { - theory_var v = m_nl_monomials.size(); + theory_var v = m_nl_monomials[i]; if (is_real(v)) continue; bool computed_epsilon = false; @@ -2337,7 +2337,7 @@ namespace smt { var_set already_found; svector vars; for (unsigned i = 0; i < m_nl_monomials.size(); i++) { - theory_var v = m_nl_monomials.size(); + theory_var v = m_nl_monomials[i]; mark_var(v, vars, already_found); expr * n = var2expr(v); SASSERT(is_pure_monomial(n)); From f9bd8f674dd9d1783cee13c96d8caecbd0d72a55 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Wed, 19 Oct 2016 12:31:06 +0100 Subject: [PATCH 253/536] whitespace --- src/sat/sat_types.h | 66 ++++++++++++++++++++++----------------------- 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/src/sat/sat_types.h b/src/sat/sat_types.h index 93109a74f..8e3460179 100644 --- a/src/sat/sat_types.h +++ b/src/sat/sat_types.h @@ -40,9 +40,9 @@ namespace sat { typedef unsigned bool_var; typedef svector bool_var_vector; - + const bool_var null_bool_var = UINT_MAX >> 1; - + /** \brief The literal b is represented by the value 2*b, and the literal (not b) by the value 2*b + 1 @@ -54,33 +54,33 @@ namespace sat { literal():m_val(null_bool_var << 1) { SASSERT(var() == null_bool_var && !sign()); } - + literal(bool_var v, bool _sign): m_val((v << 1) + static_cast(_sign)) { SASSERT(var() == v); SASSERT(sign() == _sign); } - - bool_var var() const { - return m_val >> 1; + + bool_var var() const { + return m_val >> 1; } - + bool sign() const { - return m_val & 1; + return m_val & 1; } literal unsign() const { return literal(m_val & ~1); } - + unsigned index() const { return m_val; } - + void neg() { m_val = m_val ^ 1; } - + friend literal operator~(literal l) { return literal(l.m_val ^ 1); } @@ -116,7 +116,7 @@ namespace sat { typedef approx_set_tpl literal_approx_set; typedef approx_set_tpl var_approx_set; - + enum phase { POS_PHASE, NEG_PHASE, PHASE_NOT_AVAILABLE }; @@ -128,7 +128,7 @@ namespace sat { typedef ptr_vector clause_vector; class solver_exception : public default_exception { - public: + public: solver_exception(char const * msg):default_exception(msg) {} }; @@ -138,7 +138,7 @@ namespace sat { inline lbool value_at(bool_var v, model const & m) { return m[v]; } inline lbool value_at(literal l, model const & m) { lbool r = value_at(l.var(), m); return l.sign() ? ~r : r; } - + inline std::ostream & operator<<(std::ostream & out, model const & m) { bool first = true; for (bool_var v = 0; v < m.size(); v++) { @@ -154,12 +154,12 @@ namespace sat { svector m_set; public: typedef svector::const_iterator iterator; - void insert(unsigned v) { + void insert(unsigned v) { m_in_set.reserve(v+1, false); - if (m_in_set[v]) - return; - m_in_set[v] = true; - m_set.push_back(v); + if (m_in_set[v]) + return; + m_in_set[v] = true; + m_set.push_back(v); } void remove(unsigned v) { @@ -178,22 +178,22 @@ namespace sat { m_set = other.m_set; return *this; } - - bool contains(unsigned v) const { - return v < m_in_set.size() && m_in_set[v] != 0; + + bool contains(unsigned v) const { + return v < m_in_set.size() && m_in_set[v] != 0; } - - bool empty() const { - return m_set.empty(); + + bool empty() const { + return m_set.empty(); } // erase some variable from the set - unsigned erase() { - SASSERT(!empty()); - unsigned v = m_set.back(); - m_set.pop_back(); - m_in_set[v] = false; - return v; + unsigned erase() { + SASSERT(!empty()); + unsigned v = m_set.back(); + m_set.pop_back(); + m_in_set[v] = false; + return v; } unsigned size() const { return m_set.size(); } iterator begin() const { return m_set.begin(); } @@ -280,10 +280,10 @@ namespace sat { return *this; } }; - + struct mem_stat { }; - + inline std::ostream & operator<<(std::ostream & out, mem_stat const & m) { double mem = static_cast(memory::get_allocation_size())/static_cast(1024*1024); out << " :memory " << std::fixed << std::setprecision(2) << mem; From f97ffce479e3283e59f5352d001e9ab4cd1dafc9 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Wed, 19 Oct 2016 12:31:35 +0100 Subject: [PATCH 254/536] Silenced GCC warning about empty loop body. --- src/sat/sat_types.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sat/sat_types.h b/src/sat/sat_types.h index 8e3460179..00edaa593 100644 --- a/src/sat/sat_types.h +++ b/src/sat/sat_types.h @@ -166,7 +166,8 @@ namespace sat { if (contains(v)) { m_in_set[v] = false; unsigned i = 0; - for (i = 0; i < m_set.size() && m_set[i] != v; ++i); + for (i = 0; i < m_set.size() && m_set[i] != v; ++i) + ; SASSERT(i < m_set.size()); m_set[i] = m_set.back(); m_set.pop_back(); From 527980e44064b213453e5b08a96b5f521d924a5e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 19 Oct 2016 08:57:10 -0700 Subject: [PATCH 255/536] local Signed-off-by: Nikolaj Bjorner --- src/smt/theory_pb.cpp | 15 ++++++++++----- src/util/sorting_network.h | 4 ++-- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/src/smt/theory_pb.cpp b/src/smt/theory_pb.cpp index 2461a9db2..973586bcd 100644 --- a/src/smt/theory_pb.cpp +++ b/src/smt/theory_pb.cpp @@ -1265,6 +1265,7 @@ namespace smt { } } + unsigned num_compiled_vars, num_compiled_clauses; if (ctx.get_assignment(thl) == l_true && ctx.get_assign_level(thl) == ctx.get_base_level()) { @@ -1273,8 +1274,8 @@ namespace smt { sortnw.m_stats.reset(); at_least_k = sortnw.ge(false, k, in.size(), in.c_ptr()); ctx.mk_clause(~thl, at_least_k, justify(~thl, at_least_k)); - m_stats.m_num_compiled_vars += sortnw.m_stats.m_num_compiled_vars; - m_stats.m_num_compiled_clauses += sortnw.m_stats.m_num_compiled_clauses; + num_compiled_vars = sortnw.m_stats.m_num_compiled_vars; + num_compiled_clauses = sortnw.m_stats.m_num_compiled_clauses; } else { psort_expr ps(ctx, *this); @@ -1283,12 +1284,16 @@ namespace smt { literal at_least_k = sortnw.ge(true, k, in.size(), in.c_ptr()); ctx.mk_clause(~thl, at_least_k, justify(~thl, at_least_k)); ctx.mk_clause(~at_least_k, thl, justify(thl, ~at_least_k)); - m_stats.m_num_compiled_vars += sortnw.m_stats.m_num_compiled_vars; - m_stats.m_num_compiled_clauses += sortnw.m_stats.m_num_compiled_clauses; + num_compiled_vars = sortnw.m_stats.m_num_compiled_vars; + num_compiled_clauses = sortnw.m_stats.m_num_compiled_clauses; } + m_stats.m_num_compiled_vars += num_compiled_vars; + m_stats.m_num_compiled_clauses += num_compiled_clauses; IF_VERBOSE(1, verbose_stream() << "(smt.pb compile sorting network bound: " - << k << " literals: " << in.size() << ")\n";); + << k << " literals: " << in.size() + << " clauses: " << num_compiled_clauses + << " vars: " << num_compiled_vars << ")\n";); TRACE("pb", tout << thl << "\n";); // auxiliary clauses get removed when popping scopes. diff --git a/src/util/sorting_network.h b/src/util/sorting_network.h index 242d4f43e..0a1c0ad55 100644 --- a/src/util/sorting_network.h +++ b/src/util/sorting_network.h @@ -235,7 +235,7 @@ Notes: literal mk_at_most_1(bool full, unsigned n, literal const* xs) { literal_vector in(n, xs); - literal result = ctx.fresh(); + literal result = fresh(); unsigned inc_size = 4; while (!in.empty()) { literal_vector ors; @@ -260,7 +260,7 @@ Notes: void mk_at_most_1_small(bool full, bool last, unsigned n, literal const* xs, literal result, literal_vector& ors) { if (!last) { - literal ex = ctx.fresh(); + literal ex = fresh(); for (unsigned j = 0; j < n; ++j) { add_clause(ctx.mk_not(xs[j]), ex); } From 9cd7b9b4f657b15b4eaf80c45284a696647697c1 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 20 Oct 2016 22:13:23 -0700 Subject: [PATCH 256/536] fix mutex finding for smt-core: it was returning mutexes for negations of literals Signed-off-by: Nikolaj Bjorner --- src/smt/smt_consequences.cpp | 2 +- src/tactic/arith/pb2bv_tactic.cpp | 21 ++++++++++++++------- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/src/smt/smt_consequences.cpp b/src/smt/smt_consequences.cpp index e44782a31..ef90aac4c 100644 --- a/src/smt/smt_consequences.cpp +++ b/src/smt/smt_consequences.cpp @@ -373,7 +373,7 @@ namespace smt { expr* n = vars[i]; bool neg = m_manager.is_not(n, n); if (b_internalized(n)) { - lits.insert(literal(get_bool_var(n), !neg).index()); + lits.insert(literal(get_bool_var(n), neg).index()); } } while (!lits.empty()) { diff --git a/src/tactic/arith/pb2bv_tactic.cpp b/src/tactic/arith/pb2bv_tactic.cpp index 4c3790af3..6348ddd74 100644 --- a/src/tactic/arith/pb2bv_tactic.cpp +++ b/src/tactic/arith/pb2bv_tactic.cpp @@ -29,10 +29,11 @@ Notes: #include"filter_model_converter.h" #include"pb2bv_model_converter.h" #include"pb2bv_tactic.h" +#include"ast_pp.h" class pb2bv_tactic : public tactic { public: - struct non_pb {}; + struct non_pb { expr* e; non_pb(expr* e) : e(e) {}}; struct only_01_visitor { typedef rational numeral; @@ -48,7 +49,7 @@ public: void throw_non_pb(expr * n) { TRACE("pb2bv", tout << "Not pseudo-Boolean: " << mk_ismt2_pp(n, m) << "\n";); - throw non_pb(); + throw non_pb(n); } void operator()(var * n) { @@ -575,7 +576,7 @@ private: void throw_non_pb(expr * n) { TRACE("pb2bv", tout << "Not pseudo-Boolean: " << mk_ismt2_pp(n, m) << "\n";); - throw non_pb(); + throw non_pb(n); } // check if polynomial is encoding @@ -910,8 +911,8 @@ private: try { quick_pb_check(g); } - catch (non_pb) { - throw tactic_exception("goal is in a fragment unsupported by pb2bv"); + catch (non_pb& p) { + throw_tactic(p.e); } unsigned size = g->size(); @@ -940,8 +941,8 @@ private: new_exprs.push_back(new_f); } } - catch (non_pb) { - throw tactic_exception("goal is in a fragment unsupported by pb2bv"); + catch (non_pb& p) { + throw_tactic(p.e); } for (unsigned idx = 0; idx < size; idx++) @@ -966,6 +967,12 @@ private: TRACE("pb2bv", g->display(tout);); SASSERT(g->is_well_sorted()); } + + void throw_tactic(expr* e) { + std::stringstream strm; + strm << "goal is in a fragment unsupported by pb2bv. Offending expression: " << mk_pp(e, m); + throw tactic_exception(strm.str().c_str()); + } }; imp * m_imp; From 5bd00d3f8350e1930741318ef9d4e72791926dc8 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Fri, 21 Oct 2016 15:39:02 +0100 Subject: [PATCH 257/536] Bugfixes for the FPA API --- src/api/api_fpa.cpp | 25 ++++++++----------------- src/api/python/z3/z3.py | 6 +++--- 2 files changed, 11 insertions(+), 20 deletions(-) diff --git a/src/api/api_fpa.cpp b/src/api/api_fpa.cpp index 37197e730..5d423c725 100644 --- a/src/api/api_fpa.cpp +++ b/src/api/api_fpa.cpp @@ -914,7 +914,7 @@ extern "C" { fpa_decl_plugin * plugin = (fpa_decl_plugin*)m.get_plugin(mk_c(c)->get_fpa_fid()); family_id fid = mk_c(c)->get_fpa_fid(); expr * e = to_expr(t); - if (!is_app(e) || is_app_of(e, fid, OP_FPA_NAN)) { + if (!is_app(e) || is_app_of(e, fid, OP_FPA_NAN) || !is_fp(c, t)) { SET_ERROR_CODE(Z3_INVALID_ARG); return 0; } @@ -933,6 +933,8 @@ extern "C" { Z3_TRY; LOG_Z3_fpa_get_numeral_significand_string(c, t); RESET_ERROR_CODE(); + CHECK_NON_NULL(t, 0); + CHECK_VALID_AST(t, 0); ast_manager & m = mk_c(c)->m(); mpf_manager & mpfm = mk_c(c)->fpautil().fm(); unsynch_mpq_manager & mpqm = mpfm.mpq_manager(); @@ -940,10 +942,7 @@ extern "C" { fpa_decl_plugin * plugin = (fpa_decl_plugin*)m.get_plugin(fid); SASSERT(plugin != 0); expr * e = to_expr(t); - if (!is_app(e) || - is_app_of(e, fid, OP_FPA_NAN) || - is_app_of(e, fid, OP_FPA_PLUS_INF) || - is_app_of(e, fid, OP_FPA_MINUS_INF)) { + if (!is_app(e) || is_app_of(e, fid, OP_FPA_NAN) || !is_fp(c, t)) { SET_ERROR_CODE(Z3_INVALID_ARG); return ""; } @@ -958,6 +957,7 @@ extern "C" { mpqm.set(q, mpfm.sig(val)); if (!mpfm.is_denormal(val)) mpqm.add(q, mpfm.m_powers2(sbits - 1), q); mpqm.div(q, mpfm.m_powers2(sbits - 1), q); + if (mpfm.is_inf(val)) mpqm.set(q, 0); std::stringstream ss; mpqm.display_decimal(ss, q, sbits); return mk_c(c)->mk_external_string(ss.str()); @@ -975,10 +975,7 @@ extern "C" { fpa_decl_plugin * plugin = (fpa_decl_plugin*)m.get_plugin(fid); SASSERT(plugin != 0); expr * e = to_expr(t); - if (!is_app(e) || - is_app_of(e, fid, OP_FPA_NAN) || - is_app_of(e, fid, OP_FPA_PLUS_INF) || - is_app_of(e, fid, OP_FPA_MINUS_INF)) { + if (!is_app(e) || is_app_of(e, fid, OP_FPA_NAN) || !is_fp(c, t)) { SET_ERROR_CODE(Z3_INVALID_ARG); *n = 0; return 0; @@ -1008,10 +1005,7 @@ extern "C" { fpa_decl_plugin * plugin = (fpa_decl_plugin*)m.get_plugin(mk_c(c)->get_fpa_fid()); SASSERT(plugin != 0); expr * e = to_expr(t); - if (!is_app(e) || - is_app_of(e, fid, OP_FPA_NAN) || - is_app_of(e, fid, OP_FPA_PLUS_INF) || - is_app_of(e, fid, OP_FPA_MINUS_INF)) { + if (!is_app(e) || is_app_of(e, fid, OP_FPA_NAN) || !is_fp(c, t)) { SET_ERROR_CODE(Z3_INVALID_ARG); return ""; } @@ -1040,10 +1034,7 @@ extern "C" { fpa_decl_plugin * plugin = (fpa_decl_plugin*)m.get_plugin(mk_c(c)->get_fpa_fid()); SASSERT(plugin != 0); expr * e = to_expr(t); - if (!is_app(e) || - is_app_of(e, fid, OP_FPA_NAN) || - is_app_of(e, fid, OP_FPA_PLUS_INF) || - is_app_of(e, fid, OP_FPA_MINUS_INF)) { + if (!is_app(e) || is_app_of(e, fid, OP_FPA_NAN) || !is_fp(c, t)) { SET_ERROR_CODE(Z3_INVALID_ARG); *n = 0; return 0; diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index c360a9bdc..361171b56 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -8496,7 +8496,7 @@ class FPNumRef(FPRef): """ def as_string(self): s = Z3_fpa_get_numeral_string(self.ctx.ref(), self.as_ast()) - return ("FPVal(%s, %s)" % (s, FPSortRef(self.sort()).as_string())) + return ("FPVal(%s, %s)" % (s, self.sort())) def is_fp(a): """Return `True` if `a` is a Z3 floating-point expression. @@ -8536,7 +8536,7 @@ def FPSort(ebits, sbits, ctx=None): >>> eq(x, FP('x', FPSort(8, 24))) True """ - ctx = z3._get_ctx(ctx) + ctx = _get_ctx(ctx) return FPSortRef(Z3_mk_fpa_sort(ctx.ref(), ebits, sbits), ctx) def _to_float_str(val, exp=0): @@ -8722,7 +8722,7 @@ def FPs(names, fpsort, ctx=None): >>> fpMul(RNE(), fpAdd(RNE(), x, y), z) fpMul(RNE(), fpAdd(RNE(), x, y), z) """ - ctx = z3._get_ctx(ctx) + ctx = _get_ctx(ctx) if isinstance(names, str): names = names.split(" ") return [FP(name, fpsort, ctx) for name in names] From 23b9d3ef5572e2cb0dede71974690876cc5d67ef Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 22 Oct 2016 18:50:16 -0700 Subject: [PATCH 258/536] fix at-most-1 constraint compiler bug Signed-off-by: Nikolaj Bjorner --- src/api/api_opt.cpp | 31 ++++++++++ src/api/python/z3/z3.py | 9 +++ src/api/z3_api.h | 2 +- src/api/z3_optimization.h | 27 ++++++++ src/ast/rewriter/arith_rewriter.cpp | 43 ++++++++++++- src/opt/maxres.cpp | 11 ++-- src/opt/opt_context.cpp | 79 ++++++++++++++++++------ src/opt/opt_context.h | 7 ++- src/smt/smt_internalizer.cpp | 2 +- src/smt/theory_arith_aux.h | 2 +- src/smt/theory_arith_int.h | 2 +- src/smt/theory_pb.cpp | 25 +++++--- src/test/sorting_network.cpp | 95 ++++++++++++++++++++++++++--- src/util/mpq.cpp | 4 +- src/util/mpq.h | 2 +- src/util/rational.h | 2 +- src/util/sorting_network.h | 88 ++++++++++++++++++++++---- 17 files changed, 369 insertions(+), 62 deletions(-) diff --git a/src/api/api_opt.cpp b/src/api/api_opt.cpp index 58d8902c3..20eb6d1d4 100644 --- a/src/api/api_opt.cpp +++ b/src/api/api_opt.cpp @@ -27,6 +27,7 @@ Revision History: #include"cancel_eh.h" #include"scoped_timer.h" #include"smt2parser.h" +#include"api_ast_vector.h" extern "C" { @@ -296,6 +297,36 @@ extern "C" { } + Z3_ast_vector Z3_API Z3_optimize_get_assertions(Z3_context c, Z3_optimize o) { + Z3_TRY; + LOG_Z3_optimize_get_assertions(c, o); + RESET_ERROR_CODE(); + Z3_ast_vector_ref * v = alloc(Z3_ast_vector_ref, *mk_c(c), mk_c(c)->m()); + mk_c(c)->save_object(v); + expr_ref_vector hard(mk_c(c)->m()); + to_optimize_ptr(o)->get_hard_constraints(hard); + for (unsigned i = 0; i < hard.size(); i++) { + v->m_ast_vector.push_back(hard[i].get()); + } + RETURN_Z3(of_ast_vector(v)); + Z3_CATCH_RETURN(0); + } + + unsigned Z3_API Z3_optimize_get_num_objectives(Z3_context c, Z3_optimize o) { + RESET_ERROR_CODE(); + return to_optimize_ptr(o)->num_objectives(); + } + + Z3_ast Z3_API Z3_optimize_get_objective(Z3_context c, Z3_optimize o, unsigned index) { + Z3_TRY; + LOG_Z3_optimize_get_objective(c, o, index); + RESET_ERROR_CODE(); + expr_ref result = to_optimize_ptr(o)->get_objective(index); + mk_c(c)->save_ast_trail(result); + RETURN_Z3(of_expr(result)); + Z3_CATCH_RETURN(0); + } + }; diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index c360a9bdc..bc5bd8153 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -6796,6 +6796,15 @@ class Optimize(Z3PPObject): """Parse assertions and objectives from a string""" Z3_optimize_from_string(self.ctx.ref(), self.optimize, s) + def assertions(self): + """Return an AST vector containing all added constraints.""" + return AstVector(Z3_optimize_get_assertions(self.ctx.ref(), self.optimize), self.ctx) + + def objectives(self): + """returns set of objective functions""" + num = Z3_optimize_get_num_objectives(self.ctx.ref(), self.optimize) + return [_to_expr_ref(Z3_optimize_get_objective(self.ctx.ref(), self.optimize, i), self.ctx) for i in range(num)] + def __repr__(self): """Return a formatted string with all added rules and constraints.""" return self.sexpr() diff --git a/src/api/z3_api.h b/src/api/z3_api.h index cd889b3be..9e9771884 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -5832,7 +5832,7 @@ extern "C" { void Z3_API Z3_solver_assert_and_track(Z3_context c, Z3_solver s, Z3_ast a, Z3_ast p); /** - \brief Return the set of asserted formulas as a goal object. + \brief Return the set of asserted formulas on the solver. def_API('Z3_solver_get_assertions', AST_VECTOR, (_in(CONTEXT), _in(SOLVER))) */ diff --git a/src/api/z3_optimization.h b/src/api/z3_optimization.h index 15a6dff16..e78be7881 100644 --- a/src/api/z3_optimization.h +++ b/src/api/z3_optimization.h @@ -239,6 +239,33 @@ extern "C" { def_API('Z3_optimize_get_statistics', STATS, (_in(CONTEXT), _in(OPTIMIZE))) */ Z3_stats Z3_API Z3_optimize_get_statistics(Z3_context c, Z3_optimize d); + + + /** + \brief Return the set of asserted formulas on the optimization context. + + def_API('Z3_optimize_get_assertions', AST_VECTOR, (_in(CONTEXT), _in(OPTIMIZE))) + */ + Z3_ast_vector Z3_API Z3_optimize_get_assertions(Z3_context c, Z3_optimize o); + + /** + \brief Return number of objectives on the optimization context. + + def_API('Z3_optimize_get_num_objectives', UINT, (_in(CONTEXT), _in(OPTIMIZE))) + */ + unsigned Z3_API Z3_optimize_get_num_objectives(Z3_context c, Z3_optimize o); + + /** + \brief Return i'th objective function. If the objective function is a max-sat objective it is returned + as a Pseudo-Boolean (minimization) sum of the form (+ (if f1 w1 0) (if f2 w2 0) ...) + If the objective function is entered as a maximization objective, then return the corresponding minimizaiton + objective. In this way the resulting objective function is always returned as a minimization objective. + + def_API('Z3_optimize_get_objective', AST, (_in(CONTEXT), _in(OPTIMIZE), _in(UINT))) + */ + Z3_ast Z3_API Z3_optimize_get_objective(Z3_context c, Z3_optimize o, unsigned index); + + /*@}*/ /*@}*/ diff --git a/src/ast/rewriter/arith_rewriter.cpp b/src/ast/rewriter/arith_rewriter.cpp index 368476b8e..81385c2af 100644 --- a/src/ast/rewriter/arith_rewriter.cpp +++ b/src/ast/rewriter/arith_rewriter.cpp @@ -162,8 +162,8 @@ bool arith_rewriter::div_polynomial(expr * t, numeral const & g, const_treatment } bool arith_rewriter::is_bound(expr * arg1, expr * arg2, op_kind kind, expr_ref & result) { - numeral c; - if (!is_add(arg1) && is_numeral(arg2, c)) { + numeral b, c; + if (!is_add(arg1) && !m_util.is_mod(arg1) && is_numeral(arg2, c)) { numeral a; bool r = false; expr * pp = get_power_product(arg1, a); @@ -193,6 +193,45 @@ bool arith_rewriter::is_bound(expr * arg1, expr * arg2, op_kind kind, expr_ref & case EQ: result = m_util.mk_eq(pp, k); return true; } } + expr* t1, *t2; + bool is_int; + if (m_util.is_mod(arg2)) { + std::swap(arg1, arg2); + switch (kind) { + case LE: kind = GE; break; + case GE: kind = LE; break; + case EQ: break; + } + } + + if (m_util.is_numeral(arg2, c, is_int) && is_int && + m_util.is_mod(arg1, t1, t2) && m_util.is_numeral(t2, b, is_int) && !b.is_zero()) { + // mod x b <= c = false if c < 0, b != 0, true if c >= b, b != 0 + if (c.is_neg()) { + switch (kind) { + case EQ: + case LE: result = m().mk_false(); return true; + case GE: result = m().mk_true(); return true; + } + } + if (c.is_zero() && kind == GE) { + result = m().mk_true(); + return true; + } + if (c.is_pos() && c >= abs(b)) { + switch (kind) { + case LE: result = m().mk_true(); return true; + case EQ: + case GE: result = m().mk_false(); return true; + } + } + // mod x b <= b - 1 + if (c + rational::one() == abs(b) && kind == LE) { + result = m().mk_true(); + return true; + } + } + return false; } diff --git a/src/opt/maxres.cpp b/src/opt/maxres.cpp index d9f060784..d8b166924 100644 --- a/src/opt/maxres.cpp +++ b/src/opt/maxres.cpp @@ -297,12 +297,16 @@ public: sort_assumptions(mutex); ptr_vector core(mutex.size(), mutex.c_ptr()); remove_soft(core, m_asms); - rational weight(0); + rational weight(0), sum1(0), sum2(0); + for (unsigned i = 0; i < mutex.size(); ++i) { + sum1 += get_weight(mutex[i].get()); + } while (!mutex.empty()) { expr_ref soft = mk_or(mutex); rational w = get_weight(mutex.back()); weight = w - weight; m_lower += weight*rational(mutex.size()-1); + sum2 += weight*rational(mutex.size()); add_soft(soft, weight); mutex.pop_back(); while (!mutex.empty() && get_weight(mutex.back()) == w) { @@ -310,6 +314,7 @@ public: } weight = w; } + SASSERT(sum1 == sum2); } lbool check_sat_hill_climb(expr_ref_vector& asms1) { @@ -398,7 +403,7 @@ public: while (is_sat == l_false) { core.reset(); s().get_unsat_core(core); - //verify_core(core); + // verify_core(core); model_ref mdl; get_mus_model(mdl); is_sat = minimize_core(core); @@ -772,8 +777,6 @@ public: for (unsigned i = 0; i < m_soft.size(); ++i) { m_assignment[i] = is_true(m_soft[i]); } - - DEBUG_CODE(verify_assignment();); diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 07bb8385b..1335685ff 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -181,6 +181,43 @@ namespace opt { clear_state(); } + void context::get_hard_constraints(expr_ref_vector& hard) { + hard.append(m_scoped_state.m_hard); + } + + expr_ref context::get_objective(unsigned i) { + SASSERT(i < num_objectives()); + objective const& o = m_scoped_state.m_objectives[i]; + expr_ref result(m), zero(m); + expr_ref_vector args(m); + switch (o.m_type) { + case O_MAXSMT: + zero = m_arith.mk_numeral(rational(0), false); + for (unsigned i = 0; i < o.m_terms.size(); ++i) { + args.push_back(m.mk_ite(o.m_terms[i], zero, m_arith.mk_numeral(o.m_weights[i], false))); + } + result = m_arith.mk_add(args.size(), args.c_ptr()); + break; + case O_MAXIMIZE: + result = o.m_term; + if (m_arith.is_arith_expr(result)) { + result = m_arith.mk_uminus(result); + } + else if (m_bv.is_bv(result)) { + result = m_bv.mk_bv_neg(result); + } + else { + UNREACHABLE(); + } + break; + case O_MINIMIZE: + result = o.m_term; + break; + } + return result; + } + + unsigned context::add_soft_constraint(expr* f, rational const& w, symbol const& id) { clear_state(); return m_scoped_state.add(f, w, id); @@ -1328,14 +1365,21 @@ namespace opt { } std::string context::to_string() const { + return to_string(m_scoped_state.m_hard, m_scoped_state.m_objectives); + } + + std::string context::to_string_internal() const { + return to_string(m_hard_constraints, m_objectives); + } + + std::string context::to_string(expr_ref_vector const& hard, vector const& objectives) const { smt2_pp_environment_dbg env(m); ast_pp_util visitor(m); std::ostringstream out; -#define PP(_e_) ast_smt2_pp(out, _e_, env); - visitor.collect(m_scoped_state.m_hard); + visitor.collect(hard); - for (unsigned i = 0; i < m_scoped_state.m_objectives.size(); ++i) { - objective const& obj = m_scoped_state.m_objectives[i]; + for (unsigned i = 0; i < objectives.size(); ++i) { + objective const& obj = objectives[i]; switch(obj.m_type) { case O_MAXIMIZE: case O_MINIMIZE: @@ -1351,33 +1395,34 @@ namespace opt { } visitor.display_decls(out); - visitor.display_asserts(out, m_scoped_state.m_hard, m_pp_neat); - for (unsigned i = 0; i < m_scoped_state.m_objectives.size(); ++i) { - objective const& obj = m_scoped_state.m_objectives[i]; + visitor.display_asserts(out, hard, m_pp_neat); + for (unsigned i = 0; i < objectives.size(); ++i) { + objective const& obj = objectives[i]; switch(obj.m_type) { case O_MAXIMIZE: out << "(maximize "; - PP(obj.m_term); + ast_smt2_pp(out, obj.m_term, env); out << ")\n"; break; case O_MINIMIZE: out << "(minimize "; - PP(obj.m_term); + ast_smt2_pp(out, obj.m_term, env); out << ")\n"; break; case O_MAXSMT: for (unsigned j = 0; j < obj.m_terms.size(); ++j) { out << "(assert-soft "; - PP(obj.m_terms[j]); + ast_smt2_pp(out, obj.m_terms[j], env); rational w = obj.m_weights[j]; - if (w.is_int()) { - out << " :weight " << w; - } - else { - out << " :dweight " << w; - } + + w.display_decimal(out << " :weight ", 3, true); if (obj.m_id != symbol::null) { - out << " :id " << obj.m_id; + if (is_smt2_quoted_symbol(obj.m_id)) { + out << " :id " << mk_smt2_quoted_symbol(obj.m_id); + } + else { + out << " :id " << obj.m_id; + } } out << ")\n"; } diff --git a/src/opt/opt_context.h b/src/opt/opt_context.h index ac1fe8e7a..18af756bf 100644 --- a/src/opt/opt_context.h +++ b/src/opt/opt_context.h @@ -175,6 +175,8 @@ namespace opt { unsigned add_objective(app* t, bool is_max); void add_hard_constraint(expr* f); + void get_hard_constraints(expr_ref_vector& hard); + expr_ref get_objective(unsigned i); virtual void push(); virtual void pop(unsigned n); @@ -208,7 +210,7 @@ namespace opt { std::string to_string() const; - virtual unsigned num_objectives() { return m_objectives.size(); } + virtual unsigned num_objectives() { return m_scoped_state.m_objectives.size(); } virtual expr_ref mk_gt(unsigned i, model_ref& model); virtual expr_ref mk_ge(unsigned i, model_ref& model); virtual expr_ref mk_le(unsigned i, model_ref& model); @@ -284,6 +286,9 @@ namespace opt { void display_objective(std::ostream& out, objective const& obj) const; void display_bounds(std::ostream& out, bounds_t const& b) const; + std::string to_string(expr_ref_vector const& hard, vector const& objectives) const; + std::string to_string_internal() const; + void validate_lex(); diff --git a/src/smt/smt_internalizer.cpp b/src/smt/smt_internalizer.cpp index d4880f7d7..94ce453b4 100644 --- a/src/smt/smt_internalizer.cpp +++ b/src/smt/smt_internalizer.cpp @@ -1281,7 +1281,7 @@ namespace smt { The deletion event handler is ignored if binary clause optimization is applicable. */ clause * context::mk_clause(unsigned num_lits, literal * lits, justification * j, clause_kind k, clause_del_eh * del_eh) { - TRACE("mk_clause", tout << "creating clause:\n"; display_literals(tout, num_lits, lits); tout << "\n";); + TRACE("mk_clause", tout << "creating clause:\n"; display_literals_verbose(tout, num_lits, lits); tout << "\n";); switch (k) { case CLS_AUX: { literal_buffer simp_lits; diff --git a/src/smt/theory_arith_aux.h b/src/smt/theory_arith_aux.h index 163452d47..d2db3a603 100644 --- a/src/smt/theory_arith_aux.h +++ b/src/smt/theory_arith_aux.h @@ -1709,7 +1709,7 @@ namespace smt { SASSERT(!maintain_integrality || valid_assignment()); SASSERT(satisfy_bounds()); } - TRACE("opt", display(tout);); + TRACE("opt_verbose", display(tout);); return (best_efforts>0 || ctx.get_cancel_flag())?BEST_EFFORT:result; } diff --git a/src/smt/theory_arith_int.h b/src/smt/theory_arith_int.h index d3b1f0f10..c06f82c8b 100644 --- a/src/smt/theory_arith_int.h +++ b/src/smt/theory_arith_int.h @@ -1385,7 +1385,7 @@ namespace smt { m_branch_cut_counter++; // TODO: add giveup code if (m_branch_cut_counter % m_params.m_arith_branch_cut_ratio == 0) { - TRACE("opt", display(tout);); + TRACE("opt_verbose", display(tout);); move_non_base_vars_to_bounds(); if (!make_feasible()) { TRACE("arith_int", tout << "failed to move variables to bounds.\n";); diff --git a/src/smt/theory_pb.cpp b/src/smt/theory_pb.cpp index 90cd020c3..384c58d73 100644 --- a/src/smt/theory_pb.cpp +++ b/src/smt/theory_pb.cpp @@ -321,7 +321,8 @@ namespace smt { if (m_simplex.upper_valid(v)) { m_simplex.get_upper(v, last_bound); if (m_mpq_inf_mgr.gt(bound, last_bound)) { - literal lit = m_explain_upper.get(v, null_literal); + literal lit = m_explain_upper.get(v, null_literal); + TRACE("pb", tout << ~lit << " " << ~explain << "\n";); get_context().mk_clause(~lit, ~explain, justify(~lit, ~explain)); return false; } @@ -342,6 +343,7 @@ namespace smt { m_simplex.get_lower(v, last_bound); if (m_mpq_inf_mgr.gt(last_bound, bound)) { literal lit = m_explain_lower.get(v, null_literal); + TRACE("pb", tout << ~lit << " " << ~explain << "\n";); get_context().mk_clause(~lit, ~explain, justify(~lit, ~explain)); return false; } @@ -405,6 +407,7 @@ namespace smt { if (proofs_enabled()) { js = alloc(theory_lemma_justification, get_id(), ctx, lits.size(), lits.c_ptr()); } + TRACE("pb", tout << lits << "\n";); ctx.mk_clause(lits.size(), lits.c_ptr(), js, CLS_AUX_LEMMA, 0); return false; @@ -515,11 +518,10 @@ namespace smt { ++log; n *= 2; } - unsigned th = args.size()*log; // 10* + unsigned th = args.size()*log; c->m_compilation_threshold = th; - IF_VERBOSE(2, verbose_stream() << "(smt.pb setting compilation threhshold to " << th << ")\n";); + IF_VERBOSE(2, verbose_stream() << "(smt.pb setting compilation threshold to " << th << " " << c->k() << ")\n";); TRACE("pb", tout << "compilation threshold: " << th << "\n";); - //compile_ineq(*c); } else { c->m_compilation_threshold = UINT_MAX; @@ -1247,9 +1249,9 @@ namespace smt { literal_vector in; for (unsigned i = 0; i < num_args; ++i) { rational n = c.coeff(i); - lbool val = ctx.get_assignment(c.lit()); - if (val != l_undef && - ctx.get_assign_level(thl) == ctx.get_base_level()) { + literal lit = c.lit(i); + lbool val = ctx.get_assignment(lit); + if (val != l_undef && ctx.get_assign_level(lit) == ctx.get_base_level()) { if (val == l_true) { unsigned m = n.get_unsigned(); if (k < m) { @@ -1264,6 +1266,8 @@ namespace smt { n -= rational::one(); } } + + TRACE("pb", tout << in << " >= " << k << "\n";); if (ctx.get_assignment(thl) == l_true && @@ -1272,6 +1276,7 @@ namespace smt { psort_nw sortnw(ps); sortnw.m_stats.reset(); at_least_k = sortnw.ge(false, k, in.size(), in.c_ptr()); + TRACE("pb", tout << ~thl << " " << at_least_k << "\n";); ctx.mk_clause(~thl, at_least_k, justify(~thl, at_least_k)); m_stats.m_num_compiled_vars += sortnw.m_stats.m_num_compiled_vars; m_stats.m_num_compiled_clauses += sortnw.m_stats.m_num_compiled_clauses; @@ -1281,6 +1286,7 @@ namespace smt { psort_nw sortnw(ps); sortnw.m_stats.reset(); literal at_least_k = sortnw.ge(true, k, in.size(), in.c_ptr()); + TRACE("pb", tout << ~thl << " " << at_least_k << "\n";); ctx.mk_clause(~thl, at_least_k, justify(~thl, at_least_k)); ctx.mk_clause(~at_least_k, thl, justify(thl, ~at_least_k)); m_stats.m_num_compiled_vars += sortnw.m_stats.m_num_compiled_vars; @@ -1290,7 +1296,6 @@ namespace smt { << "(smt.pb compile sorting network bound: " << k << " literals: " << in.size() << ")\n";); - TRACE("pb", tout << thl << "\n";); // auxiliary clauses get removed when popping scopes. // we have to recompile the circuit after back-tracking. c.m_compiled = l_false; @@ -1300,7 +1305,6 @@ namespace smt { void theory_pb::init_search_eh() { - m_to_compile.reset(); } void theory_pb::push_scope_eh() { @@ -1329,6 +1333,7 @@ namespace smt { m_ineq_rep.erase(r_info.m_rep); } } + m_to_compile.erase(c); dealloc(c); } m_ineqs_lim.resize(new_lim); @@ -1454,6 +1459,7 @@ namespace smt { if (proofs_enabled()) { js = alloc(theory_lemma_justification, get_id(), ctx, lits.size(), lits.c_ptr()); } + TRACE("pb", tout << lits << "\n";); ctx.mk_clause(lits.size(), lits.c_ptr(), js, CLS_AUX_LEMMA, 0); } @@ -1760,6 +1766,7 @@ namespace smt { for (unsigned i = 0; i < m_ineq_literals.size(); ++i) { m_ineq_literals[i].neg(); } + TRACE("pb", tout << m_ineq_literals << "\n";); ctx.mk_clause(m_ineq_literals.size(), m_ineq_literals.c_ptr(), justify(m_ineq_literals), CLS_AUX_LEMMA, 0); break; default: { diff --git a/src/test/sorting_network.cpp b/src/test/sorting_network.cpp index 57e818542..8b2aadee3 100644 --- a/src/test/sorting_network.cpp +++ b/src/test/sorting_network.cpp @@ -332,31 +332,106 @@ void test_sorting5(unsigned n, unsigned k) { test_sorting_ge(n, k); } -void test_at_most_1(unsigned n) { +expr_ref naive_at_most1(expr_ref_vector const& xs) { + ast_manager& m = xs.get_manager(); + expr_ref_vector clauses(m); + for (unsigned i = 0; i < xs.size(); ++i) { + for (unsigned j = i + 1; j < xs.size(); ++j) { + clauses.push_back(m.mk_not(m.mk_and(xs[i], xs[j]))); + } + } + return mk_and(clauses); +} + +void test_at_most_1(unsigned n, bool full) { ast_manager m; reg_decl_plugins(m); expr_ref_vector in(m), out(m); for (unsigned i = 0; i < n; ++i) { in.push_back(m.mk_fresh_const("a",m.mk_bool_sort())); } - + ast_ext2 ext(m); + psort_nw sn(ext); + expr_ref result1(m), result2(m); + result1 = sn.le(full, 1, in.size(), in.c_ptr()); + result2 = naive_at_most1(in); + + std::cout << "clauses: " << ext.m_clauses << "\n-----\n"; + + smt_params fp; + smt::kernel solver(m, fp); + for (unsigned i = 0; i < ext.m_clauses.size(); ++i) { + solver.assert_expr(ext.m_clauses[i].get()); + } + lbool res; + if (full) { + solver.push(); + solver.assert_expr(m.mk_not(m.mk_eq(result1, result2))); + + std::cout << result1 << "\n"; + + res = solver.check(); + SASSERT(res == l_false); + + solver.pop(1); + } + + if (n >= 9) return; + for (unsigned i = 0; i < static_cast(1 << n); ++i) { + std::cout << "checking: " << n << ": " << i << "\n"; + solver.push(); + unsigned k = 0; + for (unsigned j = 0; j < n; ++j) { + bool is_true = (i & (1 << j)) != 0; + expr_ref atom(m); + atom = is_true ? in[j].get() : m.mk_not(in[j].get()); + solver.assert_expr(atom); + std::cout << atom << "\n"; + if (is_true) ++k; + } + res = solver.check(); + SASSERT(res == l_true); + if (k > 1) { + solver.assert_expr(result1); + } + else if (!full) { + solver.pop(1); + continue; + } + else { + solver.assert_expr(m.mk_not(result1)); + } + res = solver.check(); + SASSERT(res == l_false); + solver.pop(1); + } +} + + +static void test_at_most1() { + ast_manager m; + reg_decl_plugins(m); + expr_ref_vector in(m), out(m); + for (unsigned i = 0; i < 5; ++i) { + in.push_back(m.mk_fresh_const("a",m.mk_bool_sort())); + } + in[4] = in[3]; + ast_ext2 ext(m); psort_nw sn(ext); expr_ref result(m); - result = sn.le(false, 1, in.size(), in.c_ptr()); + result = sn.le(true, 1, in.size(), in.c_ptr()); std::cout << result << "\n"; std::cout << ext.m_clauses << "\n"; } void tst_sorting_network() { - test_at_most_1(1); - test_at_most_1(2); - test_at_most_1(3); - test_at_most_1(4); - test_at_most_1(5); - test_at_most_1(10); - return; + for (unsigned i = 1; i < 17; ++i) { + test_at_most_1(i, true); + test_at_most_1(i, false); + } + test_at_most1(); test_sorting_eq(11,7); for (unsigned n = 3; n < 20; n += 2) { diff --git a/src/util/mpq.cpp b/src/util/mpq.cpp index df4d207a6..feb051033 100644 --- a/src/util/mpq.cpp +++ b/src/util/mpq.cpp @@ -153,7 +153,7 @@ void mpq_manager::display_smt2(std::ostream & out, mpq const & a, bool de } template -void mpq_manager::display_decimal(std::ostream & out, mpq const & a, unsigned prec) { +void mpq_manager::display_decimal(std::ostream & out, mpq const & a, unsigned prec, bool truncate) { mpz n1, d1, v1; get_numerator(a, n1); get_denominator(a, d1); @@ -177,7 +177,7 @@ void mpq_manager::display_decimal(std::ostream & out, mpq const & a, unsi if (is_zero(n1)) goto end; // number is precise } - out << "?"; + if (!truncate) out << "?"; end: del(ten); del(n1); del(d1); del(v1); } diff --git a/src/util/mpq.h b/src/util/mpq.h index 0a643c650..093cc0a44 100644 --- a/src/util/mpq.h +++ b/src/util/mpq.h @@ -265,7 +265,7 @@ public: void display_smt2(std::ostream & out, mpq const & a, bool decimal) const; - void display_decimal(std::ostream & out, mpq const & a, unsigned prec); + void display_decimal(std::ostream & out, mpq const & a, unsigned prec, bool truncate = false); void add(mpz const & a, mpz const & b, mpz & c) { mpz_manager::add(a, b, c); } diff --git a/src/util/rational.h b/src/util/rational.h index fc25837c6..ba447fca6 100644 --- a/src/util/rational.h +++ b/src/util/rational.h @@ -86,7 +86,7 @@ public: void display(std::ostream & out) const { return m().display(out, m_val); } - void display_decimal(std::ostream & out, unsigned prec) const { return m().display_decimal(out, m_val, prec); } + void display_decimal(std::ostream & out, unsigned prec, bool truncate = false) const { return m().display_decimal(out, m_val, prec, truncate); } bool is_uint64() const { return m().is_uint64(m_val); } diff --git a/src/util/sorting_network.h b/src/util/sorting_network.h index 242d4f43e..31ad8a452 100644 --- a/src/util/sorting_network.h +++ b/src/util/sorting_network.h @@ -234,19 +234,28 @@ Notes: private: literal mk_at_most_1(bool full, unsigned n, literal const* xs) { + TRACE("pb", tout << (full?"full":"partial") << " "; + for (unsigned i = 0; i < n; ++i) tout << xs[i] << " "; + tout << "\n";); + + if (!full && n >= 4) { + return mk_at_most_1_bimander(n, xs); + } literal_vector in(n, xs); - literal result = ctx.fresh(); + literal result = fresh(); unsigned inc_size = 4; + literal_vector ands; + ands.push_back(result); while (!in.empty()) { literal_vector ors; unsigned i = 0; unsigned n = in.size(); bool last = n <= inc_size; for (; i + inc_size < n; i += inc_size) { - mk_at_most_1_small(full, last, inc_size, in.c_ptr() + i, result, ors); + mk_at_most_1_small(full, last, inc_size, in.c_ptr() + i, result, ands, ors); } if (i < n) { - mk_at_most_1_small(full, last, n - i, in.c_ptr() + i, result, ors); + mk_at_most_1_small(full, last, n - i, in.c_ptr() + i, result, ands, ors); } if (last) { break; @@ -255,12 +264,22 @@ Notes: in.append(ors); ors.reset(); } + if (full) { + add_clause(ands); + } return result; } - void mk_at_most_1_small(bool full, bool last, unsigned n, literal const* xs, literal result, literal_vector& ors) { + void mk_at_most_1_small(bool full, bool last, unsigned n, literal const* xs, literal result, literal_vector& ands, literal_vector& ors) { + SASSERT(n > 0); + if (n == 1) { + if (!last) { + ors.push_back(xs[0]); + } + return; + } if (!last) { - literal ex = ctx.fresh(); + literal ex = fresh(); for (unsigned j = 0; j < n; ++j) { add_clause(ctx.mk_not(xs[j]), ex); } @@ -271,16 +290,59 @@ Notes: } ors.push_back(ex); } + // result => xs[0] + ... + xs[n-1] <= 1 for (unsigned i = 0; i < n; ++i) { for (unsigned j = i + 1; j < n; ++j) { add_clause(ctx.mk_not(result), ctx.mk_not(xs[i]), ctx.mk_not(xs[j])); } - if (full) { - add_clause(result, xs[i]); + } + // xs[0] + ... + xs[n-1] <= 1 => and_x + if (full) { + literal and_i = fresh(); + for (unsigned i = 0; i < n; ++i) { + literal_vector lits; + lits.push_back(and_i); + for (unsigned j = 0; j < n; ++j) { + if (j != i) lits.push_back(xs[j]); + } + add_clause(lits); } + ands.push_back(ctx.mk_not(and_i)); } } + literal mk_at_most_1_bimander(unsigned n, literal const* xs) { + literal_vector in(n, xs); + literal result = fresh(); + unsigned inc_size = 2; + bool last = false; + bool full = false; + literal_vector ors, ands; + unsigned i = 0; + for (; i + inc_size < n; i += inc_size) { + mk_at_most_1_small(full, last, inc_size, in.c_ptr() + i, result, ands, ors); + } + if (i < n) { + mk_at_most_1_small(full, last, n - i, in.c_ptr() + i, result, ands, ors); + } + + unsigned nbits = 0; + while (static_cast(1 << nbits) < ors.size()) { + ++nbits; + } + literal_vector bits; + for (unsigned k = 0; k < nbits; ++k) { + bits.push_back(fresh()); + } + for (i = 0; i < ors.size(); ++i) { + for (unsigned k = 0; k < nbits; ++k) { + bool bit_set = (i & (static_cast(1 << k))) != 0; + add_clause(ctx.mk_not(result), ctx.mk_not(ors[i]), bit_set ? bits[k] : ctx.mk_not(bits[k])); + } + } + return result; + } + std::ostream& pp(std::ostream& out, unsigned n, literal const* lits) { for (unsigned i = 0; i < n; ++i) ctx.pp(out, lits[i]) << " "; return out; @@ -344,9 +406,13 @@ Notes: literal lits[2] = { l1, l2 }; add_clause(2, lits); } + void add_clause(literal_vector const& lits) { + add_clause(lits.size(), lits.c_ptr()); + } void add_clause(unsigned n, literal const* ls) { m_stats.m_num_compiled_clauses++; literal_vector tmp(n, ls); + TRACE("pb", for (unsigned i = 0; i < n; ++i) tout << ls[i] << " "; tout << "\n";); ctx.mk_clause(n, tmp.c_ptr()); } @@ -383,7 +449,7 @@ Notes: } void card(unsigned k, unsigned n, literal const* xs, literal_vector& out) { - TRACE("pb", tout << "card k:" << k << " n: " << n << "\n";); + TRACE("pb", tout << "card k: " << k << " n: " << n << "\n";); if (n <= k) { psort_nw::sorting(n, xs, out); } @@ -397,7 +463,7 @@ Notes: card(k, n-l, xs + l, out2); smerge(k, out1.size(), out1.c_ptr(), out2.size(), out2.c_ptr(), out); } - TRACE("pb", tout << "card k:" << k << " n: " << n << "\n"; + TRACE("pb", tout << "card k: " << k << " n: " << n << "\n"; pp(tout << "in:", n, xs) << "\n"; pp(tout << "out:", out) << "\n";); @@ -743,7 +809,7 @@ Notes: if (j < b) { ls.push_back(as[i]); ls.push_back(bs[j]); - add_clause(ls.size(), ls.c_ptr()); + add_clause(ls); ls.pop_back(); ls.pop_back(); } @@ -804,7 +870,7 @@ Notes: pp(tout, lits) << "\n";); SASSERT(k + offset <= n); if (k == 0) { - add_clause(lits.size(), lits.c_ptr()); + add_clause(lits); return; } for (unsigned i = offset; i < n - k + 1; ++i) { From e32e0d460d8f7e393f28ade7b10f9bac6a13033c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 22 Oct 2016 21:50:45 -0700 Subject: [PATCH 259/536] fix at-most-1 constraint compiler bug Signed-off-by: Nikolaj Bjorner --- src/api/api_opt.cpp | 19 +++++++++---------- src/api/c++/z3++.h | 2 ++ src/api/dotnet/Optimize.cs | 27 +++++++++++++++++++++++++++ src/api/python/z3/z3.py | 3 +-- src/api/z3_optimization.h | 17 ++++++----------- src/smt/theory_pb.cpp | 2 +- 6 files changed, 46 insertions(+), 24 deletions(-) diff --git a/src/api/api_opt.cpp b/src/api/api_opt.cpp index 20eb6d1d4..308db4081 100644 --- a/src/api/api_opt.cpp +++ b/src/api/api_opt.cpp @@ -311,19 +311,18 @@ extern "C" { RETURN_Z3(of_ast_vector(v)); Z3_CATCH_RETURN(0); } - - unsigned Z3_API Z3_optimize_get_num_objectives(Z3_context c, Z3_optimize o) { - RESET_ERROR_CODE(); - return to_optimize_ptr(o)->num_objectives(); - } - Z3_ast Z3_API Z3_optimize_get_objective(Z3_context c, Z3_optimize o, unsigned index) { + Z3_ast_vector Z3_API Z3_optimize_get_objectives(Z3_context c, Z3_optimize o) { Z3_TRY; - LOG_Z3_optimize_get_objective(c, o, index); + LOG_Z3_optimize_get_objectives(c, o); RESET_ERROR_CODE(); - expr_ref result = to_optimize_ptr(o)->get_objective(index); - mk_c(c)->save_ast_trail(result); - RETURN_Z3(of_expr(result)); + unsigned n = to_optimize_ptr(o)->num_objectives(); + Z3_ast_vector_ref * v = alloc(Z3_ast_vector_ref, *mk_c(c), mk_c(c)->m()); + mk_c(c)->save_object(v); + for (unsigned i = 0; i < n; i++) { + v->m_ast_vector.push_back(to_optimize_ptr(o)->get_objective(i)); + } + RETURN_Z3(of_ast_vector(v)); Z3_CATCH_RETURN(0); } diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index b03e38b7e..2a9c771a1 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -2053,6 +2053,8 @@ namespace z3 { check_error(); return expr(ctx(), r); } + expr_vector assertions() const { Z3_ast_vector r = Z3_optimize_get_assertions(ctx(), m_opt); check_error(); return expr_vector(ctx(), r); } + expr_vector objectives() const { Z3_ast_vector r = Z3_optimize_get_objectives(ctx(), m_opt); check_error(); return expr_vector(ctx(), r); } stats statistics() const { Z3_stats r = Z3_optimize_get_statistics(ctx(), m_opt); check_error(); return stats(ctx(), r); } friend std::ostream & operator<<(std::ostream & out, optimize const & s); void from_file(char const* filename) { Z3_optimize_from_file(ctx(), m_opt, filename); check_error(); } diff --git a/src/api/dotnet/Optimize.cs b/src/api/dotnet/Optimize.cs index e5982e4fc..036aaf2f2 100644 --- a/src/api/dotnet/Optimize.cs +++ b/src/api/dotnet/Optimize.cs @@ -290,6 +290,33 @@ namespace Microsoft.Z3 Native.Z3_optimize_from_string(Context.nCtx, NativeObject, s); } + /// + /// The set of asserted formulas. + /// + public BoolExpr[] Assertions + { + get + { + Contract.Ensures(Contract.Result() != null); + + ASTVector assertions = new ASTVector(Context, Native.Z3_optimize_get_assertions(Context.nCtx, NativeObject)); + return assertions.ToBoolExprArray(); + } + } + + /// + /// The set of asserted formulas. + /// + public Expr[] Objectives + { + get + { + Contract.Ensures(Contract.Result() != null); + + ASTVector objectives = new ASTVector(Context, Native.Z3_optimize_get_objectives(Context.nCtx, NativeObject)); + return objectives.ToExprArray(); + } + } /// diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index bc5bd8153..abeee5ba3 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -6802,8 +6802,7 @@ class Optimize(Z3PPObject): def objectives(self): """returns set of objective functions""" - num = Z3_optimize_get_num_objectives(self.ctx.ref(), self.optimize) - return [_to_expr_ref(Z3_optimize_get_objective(self.ctx.ref(), self.optimize, i), self.ctx) for i in range(num)] + return AstVector(Z3_optimize_get_objectives(self.ctx.ref(), self.optimize), self.ctx) def __repr__(self): """Return a formatted string with all added rules and constraints.""" diff --git a/src/api/z3_optimization.h b/src/api/z3_optimization.h index e78be7881..219f3ede8 100644 --- a/src/api/z3_optimization.h +++ b/src/api/z3_optimization.h @@ -249,21 +249,16 @@ extern "C" { Z3_ast_vector Z3_API Z3_optimize_get_assertions(Z3_context c, Z3_optimize o); /** - \brief Return number of objectives on the optimization context. - - def_API('Z3_optimize_get_num_objectives', UINT, (_in(CONTEXT), _in(OPTIMIZE))) - */ - unsigned Z3_API Z3_optimize_get_num_objectives(Z3_context c, Z3_optimize o); - - /** - \brief Return i'th objective function. If the objective function is a max-sat objective it is returned + \brief Return objectives on the optimization context. + If the objective function is a max-sat objective it is returned as a Pseudo-Boolean (minimization) sum of the form (+ (if f1 w1 0) (if f2 w2 0) ...) If the objective function is entered as a maximization objective, then return the corresponding minimizaiton objective. In this way the resulting objective function is always returned as a minimization objective. - - def_API('Z3_optimize_get_objective', AST, (_in(CONTEXT), _in(OPTIMIZE), _in(UINT))) + + def_API('Z3_optimize_get_objectives', AST_VECTOR, (_in(CONTEXT), _in(OPTIMIZE))) */ - Z3_ast Z3_API Z3_optimize_get_objective(Z3_context c, Z3_optimize o, unsigned index); + Z3_ast_vector Z3_API Z3_optimize_get_objectives(Z3_context c, Z3_optimize o); + /*@}*/ diff --git a/src/smt/theory_pb.cpp b/src/smt/theory_pb.cpp index 384c58d73..7b032dce9 100644 --- a/src/smt/theory_pb.cpp +++ b/src/smt/theory_pb.cpp @@ -520,7 +520,7 @@ namespace smt { } unsigned th = args.size()*log; c->m_compilation_threshold = th; - IF_VERBOSE(2, verbose_stream() << "(smt.pb setting compilation threshold to " << th << " " << c->k() << ")\n";); + IF_VERBOSE(2, verbose_stream() << "(smt.pb setting compilation threshold to " << th << ")\n";); TRACE("pb", tout << "compilation threshold: " << th << "\n";); } else { From 3778048eb48296a4a7655f646ff83868e1c57a1d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 23 Oct 2016 20:31:59 -0700 Subject: [PATCH 260/536] add bounded-int and pb2bv solvers to fd_solver, use sorting networks for pb2bv rewriter when applicable, hoist to pb2bv_rewriter module and remove it from the pb2bv_tactic Signed-off-by: Nikolaj Bjorner --- contrib/cmake/src/ast/rewriter/CMakeLists.txt | 3 +- .../cmake/src/tactic/portfolio/CMakeLists.txt | 3 + contrib/cmake/src/test/CMakeLists.txt | 1 + .../{fd_rewriter.cpp => enum2bv_rewriter.cpp} | 37 +- src/ast/rewriter/pb2bv_rewriter.cpp | 453 ++++++++++++++++ .../{fd_rewriter.h => pb2bv_rewriter.h} | 24 +- src/ast/rewriter/pb_rewriter.cpp | 7 +- src/cmd_context/check_logic.cpp | 4 +- src/cmd_context/cmd_context.cpp | 1 + src/opt/opt_sls_solver.h | 31 +- src/smt/smt_kernel.cpp | 6 + src/smt/smt_kernel.h | 3 +- src/smt/theory_pb.cpp | 17 +- src/tactic/arith/bv2int_rewriter.h | 2 +- src/tactic/arith/card2bv_tactic.cpp | 509 +----------------- src/tactic/bv/dt2bv_tactic.cpp | 4 +- .../portfolio/bounded_int2bv_solver.cpp | 296 ++++++++++ src/tactic/portfolio/bounded_int2bv_solver.h | 29 + src/tactic/portfolio/enum2bv_solver.cpp | 162 ++++++ src/tactic/portfolio/enum2bv_solver.h | 29 + src/tactic/portfolio/fd_solver.cpp | 144 +---- src/tactic/portfolio/pb2bv_solver.cpp | 127 +++++ src/tactic/portfolio/pb2bv_solver.h | 29 + src/test/main.cpp | 1 + src/test/pb2bv.cpp | 195 +++++++ src/util/sorting_network.h | 7 +- 26 files changed, 1424 insertions(+), 700 deletions(-) rename src/ast/rewriter/{fd_rewriter.cpp => enum2bv_rewriter.cpp} (86%) create mode 100644 src/ast/rewriter/pb2bv_rewriter.cpp rename src/ast/rewriter/{fd_rewriter.h => pb2bv_rewriter.h} (52%) create mode 100644 src/tactic/portfolio/bounded_int2bv_solver.cpp create mode 100644 src/tactic/portfolio/bounded_int2bv_solver.h create mode 100644 src/tactic/portfolio/enum2bv_solver.cpp create mode 100644 src/tactic/portfolio/enum2bv_solver.h create mode 100644 src/tactic/portfolio/pb2bv_solver.cpp create mode 100644 src/tactic/portfolio/pb2bv_solver.h create mode 100644 src/test/pb2bv.cpp diff --git a/contrib/cmake/src/ast/rewriter/CMakeLists.txt b/contrib/cmake/src/ast/rewriter/CMakeLists.txt index b01a0e016..74fddd2bb 100644 --- a/contrib/cmake/src/ast/rewriter/CMakeLists.txt +++ b/contrib/cmake/src/ast/rewriter/CMakeLists.txt @@ -9,14 +9,15 @@ z3_add_component(rewriter datatype_rewriter.cpp der.cpp dl_rewriter.cpp + enum2bv_rewriter.cpp expr_replacer.cpp expr_safe_replace.cpp factor_rewriter.cpp - fd_rewriter.cpp fpa_rewriter.cpp label_rewriter.cpp mk_simplified_app.cpp pb_rewriter.cpp + pb2bv_rewriter.cpp quant_hoist.cpp rewriter.cpp seq_rewriter.cpp diff --git a/contrib/cmake/src/tactic/portfolio/CMakeLists.txt b/contrib/cmake/src/tactic/portfolio/CMakeLists.txt index 201cdcf0f..c6f621f25 100644 --- a/contrib/cmake/src/tactic/portfolio/CMakeLists.txt +++ b/contrib/cmake/src/tactic/portfolio/CMakeLists.txt @@ -1,6 +1,9 @@ z3_add_component(portfolio SOURCES default_tactic.cpp + enum2bv_solver.cpp + pb2bv_solver.cpp + bounded_int2bv_solver.cpp fd_solver.cpp smt_strategic_solver.cpp COMPONENT_DEPENDENCIES diff --git a/contrib/cmake/src/test/CMakeLists.txt b/contrib/cmake/src/test/CMakeLists.txt index acaf186ba..6f6615e0c 100644 --- a/contrib/cmake/src/test/CMakeLists.txt +++ b/contrib/cmake/src/test/CMakeLists.txt @@ -78,6 +78,7 @@ add_executable(test-z3 old_interval.cpp optional.cpp parray.cpp + pb2bv.cpp pdr.cpp permutation.cpp polynomial.cpp diff --git a/src/ast/rewriter/fd_rewriter.cpp b/src/ast/rewriter/enum2bv_rewriter.cpp similarity index 86% rename from src/ast/rewriter/fd_rewriter.cpp rename to src/ast/rewriter/enum2bv_rewriter.cpp index 026387e22..bbe07f625 100644 --- a/src/ast/rewriter/fd_rewriter.cpp +++ b/src/ast/rewriter/enum2bv_rewriter.cpp @@ -3,7 +3,7 @@ Copyright (c) 2016 Microsoft Corporation Module Name: - fd_rewriter.cpp + enum2bv_rewriter.cpp Abstract: @@ -19,11 +19,11 @@ Notes: #include"rewriter.h" #include"rewriter_def.h" -#include"fd_rewriter.h" +#include"enum2bv_rewriter.h" #include"ast_util.h" #include"ast_pp.h" -struct fd_rewriter::imp { +struct enum2bv_rewriter::imp { ast_manager& m; params_ref m_params; obj_map m_enum2bv; @@ -258,6 +258,7 @@ struct fd_rewriter::imp { m_enum_defs.resize(lim); m_enum_bvs.resize(lim); } + m_rw.reset(); } void flush_side_constraints(expr_ref_vector& side_constraints) { @@ -275,18 +276,18 @@ struct fd_rewriter::imp { }; -fd_rewriter::fd_rewriter(ast_manager & m, params_ref const& p) { m_imp = alloc(imp, m, p); } -fd_rewriter::~fd_rewriter() { dealloc(m_imp); } -void fd_rewriter::updt_params(params_ref const & p) { m_imp->updt_params(p); } -ast_manager & fd_rewriter::m() const { return m_imp->m; } -unsigned fd_rewriter::get_num_steps() const { return m_imp->get_num_steps(); } -void fd_rewriter::cleanup() { ast_manager& mgr = m(); params_ref p = m_imp->m_params; dealloc(m_imp); m_imp = alloc(imp, mgr, p); } -obj_map const& fd_rewriter::enum2bv() const { return m_imp->m_enum2bv; } -obj_map const& fd_rewriter::bv2enum() const { return m_imp->m_bv2enum; } -obj_map const& fd_rewriter::enum2def() const { return m_imp->m_enum2def; } -void fd_rewriter::operator()(expr * e, expr_ref & result, proof_ref & result_proof) { (*m_imp)(e, result, result_proof); } -void fd_rewriter::push() { m_imp->push(); } -void fd_rewriter::pop(unsigned num_scopes) { m_imp->pop(num_scopes); } -void fd_rewriter::flush_side_constraints(expr_ref_vector& side_constraints) { m_imp->flush_side_constraints(side_constraints); } -unsigned fd_rewriter::num_translated() const { return m_imp->m_num_translated; } -void fd_rewriter::set_is_fd(i_sort_pred* sp) const { m_imp->set_is_fd(sp); } +enum2bv_rewriter::enum2bv_rewriter(ast_manager & m, params_ref const& p) { m_imp = alloc(imp, m, p); } +enum2bv_rewriter::~enum2bv_rewriter() { dealloc(m_imp); } +void enum2bv_rewriter::updt_params(params_ref const & p) { m_imp->updt_params(p); } +ast_manager & enum2bv_rewriter::m() const { return m_imp->m; } +unsigned enum2bv_rewriter::get_num_steps() const { return m_imp->get_num_steps(); } +void enum2bv_rewriter::cleanup() { ast_manager& mgr = m(); params_ref p = m_imp->m_params; dealloc(m_imp); m_imp = alloc(imp, mgr, p); } +obj_map const& enum2bv_rewriter::enum2bv() const { return m_imp->m_enum2bv; } +obj_map const& enum2bv_rewriter::bv2enum() const { return m_imp->m_bv2enum; } +obj_map const& enum2bv_rewriter::enum2def() const { return m_imp->m_enum2def; } +void enum2bv_rewriter::operator()(expr * e, expr_ref & result, proof_ref & result_proof) { (*m_imp)(e, result, result_proof); } +void enum2bv_rewriter::push() { m_imp->push(); } +void enum2bv_rewriter::pop(unsigned num_scopes) { m_imp->pop(num_scopes); } +void enum2bv_rewriter::flush_side_constraints(expr_ref_vector& side_constraints) { m_imp->flush_side_constraints(side_constraints); } +unsigned enum2bv_rewriter::num_translated() const { return m_imp->m_num_translated; } +void enum2bv_rewriter::set_is_fd(i_sort_pred* sp) const { m_imp->set_is_fd(sp); } diff --git a/src/ast/rewriter/pb2bv_rewriter.cpp b/src/ast/rewriter/pb2bv_rewriter.cpp new file mode 100644 index 000000000..0aeeea81a --- /dev/null +++ b/src/ast/rewriter/pb2bv_rewriter.cpp @@ -0,0 +1,453 @@ +/*++ +Copyright (c) 2016 Microsoft Corporation + +Module Name: + + pb2bv_rewriter.cpp + +Abstract: + + Conversion from pseudo-booleans to bit-vectors. + +Author: + + Nikolaj Bjorner (nbjorner) 2016-10-23 + +Notes: + +--*/ + +#include"rewriter.h" +#include"rewriter_def.h" +#include"statistics.h" +#include"pb2bv_rewriter.h" +#include"sorting_network.h" +#include"ast_util.h" +#include"ast_pp.h" + + +struct pb2bv_rewriter::imp { + + struct argc_t { + expr* m_arg; + rational m_coeff; + argc_t():m_arg(0), m_coeff(0) {} + argc_t(expr* arg, rational const& r): m_arg(arg), m_coeff(r) {} + }; + + struct argc_gt { + bool operator()(argc_t const& a, argc_t const& b) const { + return a.m_coeff > b.m_coeff; + } + }; + + struct argc_entry { + unsigned m_index; + rational m_k; + expr* m_value; + argc_entry(unsigned i, rational const& k): m_index(i), m_k(k), m_value(0) {} + argc_entry():m_index(0), m_k(0), m_value(0) {} + + struct eq { + bool operator()(argc_entry const& a, argc_entry const& b) const { + return a.m_index == b.m_index && a.m_k == b.m_k; + } + }; + struct hash { + unsigned operator()(argc_entry const& a) const { + return a.m_index ^ a.m_k.hash(); + } + }; + }; + typedef hashtable argc_cache; + + ast_manager& m; + params_ref m_params; + expr_ref_vector m_lemmas; + func_decl_ref_vector m_fresh; // all fresh variables + unsigned_vector m_fresh_lim; + unsigned m_num_translated; + + struct card2bv_rewriter { + typedef expr* literal; + typedef ptr_vector literal_vector; + psort_nw m_sort; + ast_manager& m; + imp& m_imp; + arith_util au; + pb_util pb; + bv_util bv; + expr_ref_vector m_trail; + + unsigned get_num_bits(func_decl* f) { + rational r(0); + unsigned sz = f->get_arity(); + for (unsigned i = 0; i < sz; ++i) { + r += pb.get_coeff(f, i); + } + r = r > pb.get_k(f)? r : pb.get_k(f); + return r.get_num_bits(); + } + + void mk_bv(func_decl * f, unsigned sz, expr * const* args, expr_ref & result) { + + expr_ref zero(m), a(m), b(m); + expr_ref_vector es(m); + unsigned bw = get_num_bits(f); + zero = bv.mk_numeral(rational(0), bw); + for (unsigned i = 0; i < sz; ++i) { + es.push_back(mk_ite(args[i], bv.mk_numeral(pb.get_coeff(f, i), bw), zero)); + } + switch (es.size()) { + case 0: a = zero; break; + case 1: a = es[0].get(); break; + default: + a = es[0].get(); + for (unsigned i = 1; i < es.size(); ++i) { + a = bv.mk_bv_add(a, es[i].get()); + } + break; + } + b = bv.mk_numeral(pb.get_k(f), bw); + + switch (f->get_decl_kind()) { + case OP_AT_MOST_K: + case OP_PB_LE: + result = bv.mk_ule(a, b); + break; + case OP_AT_LEAST_K: + case OP_PB_GE: + result = bv.mk_ule(b, a); + break; + case OP_PB_EQ: + result = m.mk_eq(a, b); + break; + default: + UNREACHABLE(); + } + TRACE("pb", tout << result << "\n";); + } + + bool mk_shannon(func_decl * f, unsigned sz, expr * const* args, expr_ref & result) { + decl_kind kind = f->get_decl_kind(); + if (kind != OP_PB_GE && kind != OP_AT_LEAST_K) { + return false; + } + unsigned max_clauses = sz*10; + vector argcs; + for (unsigned i = 0; i < sz; ++i) { + argcs.push_back(argc_t(args[i], pb.get_coeff(f, i))); + } + std::sort(argcs.begin(), argcs.end(), argc_gt()); + DEBUG_CODE( + for (unsigned i = 0; i + 1 < sz; ++i) { + SASSERT(argcs[i].m_coeff >= argcs[i+1].m_coeff); + }); + result = m.mk_app(f, sz, args); + TRACE("pb", tout << result << "\n";); + argc_cache cache; + expr_ref_vector trail(m); + vector todo_k; + unsigned_vector todo_i; + todo_k.push_back(pb.get_k(f)); + todo_i.push_back(0); + argc_entry entry1; + while (!todo_i.empty()) { + SASSERT(todo_i.size() == todo_k.size()); + if (cache.size() > max_clauses) { + return false; + } + unsigned i = todo_i.back(); + rational k = todo_k.back(); + argc_entry entry(i, k); + if (cache.contains(entry)) { + todo_i.pop_back(); + todo_k.pop_back(); + continue; + } + SASSERT(i < sz); + SASSERT(!k.is_neg()); + rational const& coeff = argcs[i].m_coeff; + expr* arg = argcs[i].m_arg; + if (i + 1 == sz) { + if (k.is_zero()) { + entry.m_value = m.mk_true(); + } + else if (coeff < k) { + entry.m_value = m.mk_false(); + } + else if (coeff.is_zero()) { + entry.m_value = m.mk_true(); + } + else { + SASSERT(coeff >= k && k.is_pos()); + entry.m_value = arg; + } + todo_i.pop_back(); + todo_k.pop_back(); + cache.insert(entry); + continue; + } + entry.m_index++; + expr* lo = 0, *hi = 0; + if (cache.find(entry, entry1)) { + lo = entry1.m_value; + } + else { + todo_i.push_back(i+1); + todo_k.push_back(k); + } + entry.m_k -= coeff; + if (!entry.m_k.is_pos()) { + hi = m.mk_true(); + } + else if (cache.find(entry, entry1)) { + hi = entry1.m_value; + } + else { + todo_i.push_back(i+1); + todo_k.push_back(entry.m_k); + } + if (hi && lo) { + todo_i.pop_back(); + todo_k.pop_back(); + entry.m_index = i; + entry.m_k = k; + entry.m_value = mk_ite(arg, hi, lo); + trail.push_back(entry.m_value); + cache.insert(entry); + } + } + argc_entry entry(0, pb.get_k(f)); + VERIFY(cache.find(entry, entry)); + result = entry.m_value; + TRACE("pb", tout << result << "\n";); + return true; + } + + expr* negate(expr* e) { + if (m.is_not(e, e)) return e; + return m.mk_not(e); + } + expr* mk_ite(expr* c, expr* hi, expr* lo) { + while (m.is_not(c, c)) { + std::swap(hi, lo); + } + if (hi == lo) return hi; + if (m.is_true(hi) && m.is_false(lo)) return c; + if (m.is_false(hi) && m.is_true(lo)) return negate(c); + if (m.is_true(hi)) return m.mk_or(c, lo); + if (m.is_false(lo)) return m.mk_and(c, hi); + if (m.is_false(hi)) return m.mk_and(negate(c), lo); + if (m.is_true(lo)) return m.mk_implies(c, hi); + return m.mk_ite(c, hi, lo); + } + + bool is_or(func_decl* f) { + switch (f->get_decl_kind()) { + case OP_AT_MOST_K: + case OP_PB_LE: + return false; + case OP_AT_LEAST_K: + case OP_PB_GE: + return pb.get_k(f).is_one(); + case OP_PB_EQ: + return false; + default: + UNREACHABLE(); + return false; + } + } + + + public: + + card2bv_rewriter(imp& i, ast_manager& m): + m(m), + m_imp(i), + au(m), + pb(m), + bv(m), + m_sort(*this), + m_trail(m) + {} + + br_status mk_app_core(func_decl * f, unsigned sz, expr * const* args, expr_ref & result) { + if (f->get_family_id() == pb.get_family_id()) { + mk_pb(f, sz, args, result); + ++m_imp.m_num_translated; + return BR_DONE; + } + else if (f->get_family_id() == au.get_family_id() && mk_arith(f, sz, args, result)) { + ++m_imp.m_num_translated; + return BR_DONE; + } + else { + return BR_FAILED; + } + } + + // + // NSB: review + // we should remove this code and rely on a layer above to deal with + // whatever it accomplishes. It seems to break types. + // + bool mk_arith(func_decl * f, unsigned sz, expr * const* args, expr_ref & result) { + if (f->get_decl_kind() == OP_ADD) { + unsigned bits = 0; + for (unsigned i = 0; i < sz; i++) { + rational val1, val2; + if (au.is_int(args[i]) && au.is_numeral(args[i], val1)) { + bits += val1.get_num_bits(); + } + else if (m.is_ite(args[i]) && + au.is_numeral(to_app(args[i])->get_arg(1), val1) && val1.is_one() && + au.is_numeral(to_app(args[i])->get_arg(2), val2) && val2.is_zero()) { + bits++; + } + else + return false; + } + + result = 0; + for (unsigned i = 0; i < sz; i++) { + rational val1, val2; + expr * q; + if (au.is_int(args[i]) && au.is_numeral(args[i], val1)) + q = bv.mk_numeral(val1, bits); + else + q = mk_ite(to_app(args[i])->get_arg(0), bv.mk_numeral(1, bits), bv.mk_numeral(0, bits)); + result = (i == 0) ? q : bv.mk_bv_add(result.get(), q); + } + return true; + } + else { + return false; + } + } + + void mk_pb(func_decl * f, unsigned sz, expr * const* args, expr_ref & result) { + SASSERT(f->get_family_id() == pb.get_family_id()); + if (is_or(f)) { + result = m.mk_or(sz, args); + } + else if (pb.is_at_most_k(f) && pb.get_k(f).is_unsigned()) { + result = m_sort.le(true, pb.get_k(f).get_unsigned(), sz, args); + } + else if (pb.is_at_least_k(f) && pb.get_k(f).is_unsigned()) { + result = m_sort.ge(true, pb.get_k(f).get_unsigned(), sz, args); + } + else if (pb.is_eq(f) && pb.get_k(f).is_unsigned() && pb.has_unit_coefficients(f)) { + result = m_sort.eq(pb.get_k(f).get_unsigned(), sz, args); + } + else if (pb.is_le(f) && pb.get_k(f).is_unsigned() && pb.has_unit_coefficients(f)) { + result = m_sort.le(true, pb.get_k(f).get_unsigned(), sz, args); + } + else if (pb.is_ge(f) && pb.get_k(f).is_unsigned() && pb.has_unit_coefficients(f)) { + result = m_sort.ge(true, pb.get_k(f).get_unsigned(), sz, args); + } + else if (!mk_shannon(f, sz, args, result)) { + mk_bv(f, sz, args, result); + } + } + + // definitions used for sorting network + literal mk_false() { return m.mk_false(); } + literal mk_true() { return m.mk_true(); } + literal mk_max(literal a, literal b) { return trail(m.mk_or(a, b)); } + literal mk_min(literal a, literal b) { return trail(m.mk_and(a, b)); } + literal mk_not(literal a) { if (m.is_not(a,a)) return a; return trail(m.mk_not(a)); } + + std::ostream& pp(std::ostream& out, literal lit) { return out << mk_ismt2_pp(lit, m); } + + literal trail(literal l) { + m_trail.push_back(l); + return l; + } + literal fresh() { + expr_ref fr(m.mk_fresh_const("sn", m.mk_bool_sort()), m); + m_imp.m_fresh.push_back(to_app(fr)->get_decl()); + return trail(fr); + } + + void mk_clause(unsigned n, literal const* lits) { + m_imp.m_lemmas.push_back(mk_or(m, n, lits)); + } + }; + + struct card2bv_rewriter_cfg : public default_rewriter_cfg { + card2bv_rewriter m_r; + bool rewrite_patterns() const { return false; } + bool flat_assoc(func_decl * f) const { return false; } + br_status reduce_app(func_decl * f, unsigned num, expr * const * args, expr_ref & result, proof_ref & result_pr) { + result_pr = 0; + return m_r.mk_app_core(f, num, args, result); + } + card2bv_rewriter_cfg(imp& i, ast_manager & m):m_r(i, m) {} + }; + + class card_pb_rewriter : public rewriter_tpl { + public: + card2bv_rewriter_cfg m_cfg; + card_pb_rewriter(imp& i, ast_manager & m): + rewriter_tpl(m, false, m_cfg), + m_cfg(i, m) {} + }; + + card_pb_rewriter m_rw; + + imp(ast_manager& m, params_ref const& p): + m(m), m_params(p), m_lemmas(m), + m_fresh(m), + m_num_translated(0), + m_rw(*this, m) { + } + + void updt_params(params_ref const & p) {} + unsigned get_num_steps() const { return m_rw.get_num_steps(); } + void cleanup() { m_rw.cleanup(); } + void operator()(expr * e, expr_ref & result, proof_ref & result_proof) { + m_rw(e, result, result_proof); + } + void push() { + m_fresh_lim.push_back(m_fresh.size()); + } + void pop(unsigned num_scopes) { + SASSERT(m_lemmas.empty()); // lemmas must be flushed before pop. + if (num_scopes > 0) { + SASSERT(num_scopes <= m_fresh_lim.size()); + unsigned new_sz = m_fresh_lim.size() - num_scopes; + unsigned lim = m_fresh_lim[new_sz]; + m_fresh.resize(lim); + m_fresh_lim.resize(new_sz); + } + m_rw.reset(); + } + + void flush_side_constraints(expr_ref_vector& side_constraints) { + side_constraints.append(m_lemmas); + m_lemmas.reset(); + } + + void collect_statistics(statistics & st) const { + st.update("pb-aux-variables", m_fresh.size()); + st.update("pb-aux-clauses", m_rw.m_cfg.m_r.m_sort.m_stats.m_num_compiled_clauses); + } + +}; + + +pb2bv_rewriter::pb2bv_rewriter(ast_manager & m, params_ref const& p) { m_imp = alloc(imp, m, p); } +pb2bv_rewriter::~pb2bv_rewriter() { dealloc(m_imp); } +void pb2bv_rewriter::updt_params(params_ref const & p) { m_imp->updt_params(p); } +ast_manager & pb2bv_rewriter::m() const { return m_imp->m; } +unsigned pb2bv_rewriter::get_num_steps() const { return m_imp->get_num_steps(); } +void pb2bv_rewriter::cleanup() { ast_manager& mgr = m(); params_ref p = m_imp->m_params; dealloc(m_imp); m_imp = alloc(imp, mgr, p); } +func_decl_ref_vector const& pb2bv_rewriter::fresh_constants() const { return m_imp->m_fresh; } +void pb2bv_rewriter::operator()(expr * e, expr_ref & result, proof_ref & result_proof) { (*m_imp)(e, result, result_proof); } +void pb2bv_rewriter::push() { m_imp->push(); } +void pb2bv_rewriter::pop(unsigned num_scopes) { m_imp->pop(num_scopes); } +void pb2bv_rewriter::flush_side_constraints(expr_ref_vector& side_constraints) { m_imp->flush_side_constraints(side_constraints); } +unsigned pb2bv_rewriter::num_translated() const { return m_imp->m_num_translated; } + +void pb2bv_rewriter::collect_statistics(statistics & st) const { m_imp->collect_statistics(st); } diff --git a/src/ast/rewriter/fd_rewriter.h b/src/ast/rewriter/pb2bv_rewriter.h similarity index 52% rename from src/ast/rewriter/fd_rewriter.h rename to src/ast/rewriter/pb2bv_rewriter.h index 3d4ecae9c..47d8361cb 100644 --- a/src/ast/rewriter/fd_rewriter.h +++ b/src/ast/rewriter/pb2bv_rewriter.h @@ -3,46 +3,44 @@ Copyright (c) 2016 Microsoft Corporation Module Name: - fd_rewriter.h + pb2bv_rewriter.h Abstract: - Conversion from enumeration types to bit-vectors. + Conversion from pseudo-booleans to bit-vectors. Author: - Nikolaj Bjorner (nbjorner) 2016-10-18 + Nikolaj Bjorner (nbjorner) 2016-10-23 Notes: --*/ -#ifndef ENUM_REWRITER_H_ -#define ENUM_REWRITER_H_ +#ifndef PB2BV_REWRITER_H_ +#define PB2BV_REWRITER_H_ -#include"datatype_decl_plugin.h" +#include"pb_decl_plugin.h" #include"rewriter_types.h" #include"expr_functors.h" -class fd_rewriter { +class pb2bv_rewriter { struct imp; imp* m_imp; public: - fd_rewriter(ast_manager & m, params_ref const& p); - ~fd_rewriter(); + pb2bv_rewriter(ast_manager & m, params_ref const& p); + ~pb2bv_rewriter(); void updt_params(params_ref const & p); ast_manager & m() const; unsigned get_num_steps() const; void cleanup(); - obj_map const& enum2bv() const; - obj_map const& bv2enum() const; - obj_map const& enum2def() const; + func_decl_ref_vector const& fresh_constants() const; void operator()(expr * e, expr_ref & result, proof_ref & result_proof); void push(); void pop(unsigned num_scopes); void flush_side_constraints(expr_ref_vector& side_constraints); unsigned num_translated() const; - void set_is_fd(i_sort_pred* sp) const; + void collect_statistics(statistics & st) const; }; #endif diff --git a/src/ast/rewriter/pb_rewriter.cpp b/src/ast/rewriter/pb_rewriter.cpp index d233604f9..0fdbc858d 100644 --- a/src/ast/rewriter/pb_rewriter.cpp +++ b/src/ast/rewriter/pb_rewriter.cpp @@ -257,7 +257,12 @@ br_status pb_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * cons all_unit &= m_coeffs.back().is_one(); } if (is_eq) { - result = m_util.mk_eq(sz, m_coeffs.c_ptr(), m_args.c_ptr(), k); + if (sz == 0) { + result = k.is_zero()?m.mk_true():m.mk_false(); + } + else { + result = m_util.mk_eq(sz, m_coeffs.c_ptr(), m_args.c_ptr(), k); + } } else if (all_unit && k.is_one()) { result = mk_or(m, sz, m_args.c_ptr()); diff --git a/src/cmd_context/check_logic.cpp b/src/cmd_context/check_logic.cpp index 7a49f8fd0..d9fe9ab72 100644 --- a/src/cmd_context/check_logic.cpp +++ b/src/cmd_context/check_logic.cpp @@ -182,8 +182,8 @@ struct check_logic::imp { m_quantifiers = false; } else if (logic == "QF_FD") { - m_bvs = true; - m_uf = true; + m_bvs = true; + m_uf = true; m_ints = true; } else { diff --git a/src/cmd_context/cmd_context.cpp b/src/cmd_context/cmd_context.cpp index 1df28b8e5..b7c80f65a 100644 --- a/src/cmd_context/cmd_context.cpp +++ b/src/cmd_context/cmd_context.cpp @@ -547,6 +547,7 @@ bool cmd_context::logic_has_arith_core(symbol const & s) const { s == "QF_BVFP" || s == "QF_S" || s == "ALL" || + s == "QF_FD" || s == "HORN"; } diff --git a/src/opt/opt_sls_solver.h b/src/opt/opt_sls_solver.h index 17c5a51bf..5b7f630b4 100644 --- a/src/opt/opt_sls_solver.h +++ b/src/opt/opt_sls_solver.h @@ -90,19 +90,6 @@ namespace opt { virtual void get_labels(svector & r) { m_solver->get_labels(r); } - virtual void set_cancel(bool f) { - m_solver->set_cancel(f); - m_pb2bv.set_cancel(f); - #pragma omp critical (sls_solver) - { - if (m_bvsls) { - m_bvsls->set_cancel(f); - } - if (m_pbsls) { - m_pbsls->set_cancel(f); - } - } - } virtual void set_progress_callback(progress_callback * callback) { m_solver->set_progress_callback(callback); } @@ -203,14 +190,11 @@ namespace opt { } void pbsls_opt(model_ref& mdl) { - #pragma omp critical (sls_solver) - { - if (m_pbsls) { - m_pbsls->reset(); - } - else { - m_pbsls = alloc(smt::pb_sls, m); - } + if (m_pbsls) { + m_pbsls->reset(); + } + else { + m_pbsls = alloc(smt::pb_sls, m); } m_pbsls->set_model(mdl); m_pbsls->updt_params(m_params); @@ -226,10 +210,7 @@ namespace opt { } void bvsls_opt(model_ref& mdl) { - #pragma omp critical (sls_solver) - { - m_bvsls = alloc(bvsls_opt_engine, m, m_params); - } + m_bvsls = alloc(bvsls_opt_engine, m, m_params); assertions2sls(); expr_ref objective = soft2bv(m_soft, m_weights); TRACE("opt", tout << objective << "\n";); diff --git a/src/smt/smt_kernel.cpp b/src/smt/smt_kernel.cpp index 3819f05cb..df39b4186 100644 --- a/src/smt/smt_kernel.cpp +++ b/src/smt/smt_kernel.cpp @@ -222,6 +222,12 @@ namespace smt { m_imp->assert_expr(e); } + void kernel::assert_expr(expr_ref_vector const& es) { + for (unsigned i = 0; i < es.size(); ++i) { + m_imp->assert_expr(es[i]); + } + } + void kernel::assert_expr(expr * e, proof * pr) { m_imp->assert_expr(e, pr); } diff --git a/src/smt/smt_kernel.h b/src/smt/smt_kernel.h index 0fec4a21b..ea09081ec 100644 --- a/src/smt/smt_kernel.h +++ b/src/smt/smt_kernel.h @@ -70,7 +70,8 @@ namespace smt { This method uses the "asserted" proof as a justification for e. */ void assert_expr(expr * e); - + + void assert_expr(expr_ref_vector const& es); /** \brief Assert the given assertion with the given proof as a justification. */ diff --git a/src/smt/theory_pb.cpp b/src/smt/theory_pb.cpp index 7b032dce9..d53371c3c 100644 --- a/src/smt/theory_pb.cpp +++ b/src/smt/theory_pb.cpp @@ -1270,28 +1270,25 @@ namespace smt { TRACE("pb", tout << in << " >= " << k << "\n";); + psort_expr ps(ctx, *this); + psort_nw sortnw(ps); + sortnw.m_stats.reset(); + if (ctx.get_assignment(thl) == l_true && ctx.get_assign_level(thl) == ctx.get_base_level()) { - psort_expr ps(ctx, *this); - psort_nw sortnw(ps); - sortnw.m_stats.reset(); at_least_k = sortnw.ge(false, k, in.size(), in.c_ptr()); TRACE("pb", tout << ~thl << " " << at_least_k << "\n";); ctx.mk_clause(~thl, at_least_k, justify(~thl, at_least_k)); - m_stats.m_num_compiled_vars += sortnw.m_stats.m_num_compiled_vars; - m_stats.m_num_compiled_clauses += sortnw.m_stats.m_num_compiled_clauses; } else { - psort_expr ps(ctx, *this); - psort_nw sortnw(ps); - sortnw.m_stats.reset(); literal at_least_k = sortnw.ge(true, k, in.size(), in.c_ptr()); TRACE("pb", tout << ~thl << " " << at_least_k << "\n";); ctx.mk_clause(~thl, at_least_k, justify(~thl, at_least_k)); ctx.mk_clause(~at_least_k, thl, justify(thl, ~at_least_k)); - m_stats.m_num_compiled_vars += sortnw.m_stats.m_num_compiled_vars; - m_stats.m_num_compiled_clauses += sortnw.m_stats.m_num_compiled_clauses; } + m_stats.m_num_compiled_vars += sortnw.m_stats.m_num_compiled_vars; + m_stats.m_num_compiled_clauses += sortnw.m_stats.m_num_compiled_clauses; + IF_VERBOSE(1, verbose_stream() << "(smt.pb compile sorting network bound: " << k << " literals: " << in.size() << ")\n";); diff --git a/src/tactic/arith/bv2int_rewriter.h b/src/tactic/arith/bv2int_rewriter.h index 0f68257f1..15a425857 100644 --- a/src/tactic/arith/bv2int_rewriter.h +++ b/src/tactic/arith/bv2int_rewriter.h @@ -34,7 +34,7 @@ class bv2int_rewriter_ctx { public: bv2int_rewriter_ctx(ast_manager& m, params_ref const& p) : - m_side_conditions(m), m_trail(m) { update_params(p); } + m_max_size(UINT_MAX), m_side_conditions(m), m_trail(m) { update_params(p); } void reset() { m_side_conditions.reset(); m_trail.reset(); m_power2.reset(); } void add_side_condition(expr* e) { m_side_conditions.push_back(e); } diff --git a/src/tactic/arith/card2bv_tactic.cpp b/src/tactic/arith/card2bv_tactic.cpp index 5019b6550..096e52981 100644 --- a/src/tactic/arith/card2bv_tactic.cpp +++ b/src/tactic/arith/card2bv_tactic.cpp @@ -18,500 +18,22 @@ Notes: --*/ #include"tactical.h" #include"cooperate.h" -#include"rewriter_def.h" #include"ast_smt2_pp.h" -#include"expr_substitution.h" #include"card2bv_tactic.h" -#include"pb_rewriter.h" +#include"pb2bv_rewriter.h" #include"ast_util.h" #include"ast_pp.h" - -namespace pb { - unsigned card2bv_rewriter::get_num_bits(func_decl* f) { - rational r(0); - unsigned sz = f->get_arity(); - for (unsigned i = 0; i < sz; ++i) { - r += pb.get_coeff(f, i); - } - r = r > pb.get_k(f)? r : pb.get_k(f); - return r.get_num_bits(); - } - - card2bv_rewriter::card2bv_rewriter(ast_manager& m): - m(m), - au(m), - pb(m), - bv(m), - m_sort(*this), - m_lemmas(m), - m_trail(m) - {} - - void card2bv_rewriter::mk_assert(func_decl * f, unsigned sz, expr * const* args, expr_ref & result, expr_ref_vector& lemmas) { - m_lemmas.reset(); - SASSERT(f->get_family_id() == pb.get_family_id()); - if (is_or(f)) { - result = m.mk_or(sz, args); - } - else if (is_and(f)) { - result = m.mk_and(sz, args); - } - else if (pb.is_eq(f) && pb.get_k(f).is_unsigned() && pb.has_unit_coefficients(f)) { - result = m_sort.eq(pb.get_k(f).get_unsigned(), sz, args); - } - else if (pb.is_le(f) && pb.get_k(f).is_unsigned() && pb.has_unit_coefficients(f)) { - result = m_sort.le(false, pb.get_k(f).get_unsigned(), sz, args); - } - else if (pb.is_ge(f) && pb.get_k(f).is_unsigned() && pb.has_unit_coefficients(f)) { - result = m_sort.ge(false, pb.get_k(f).get_unsigned(), sz, args); - } - else { - br_status st = mk_shannon(f, sz, args, result); - if (st == BR_FAILED) { - mk_bv(f, sz, args, result); - } - } - lemmas.append(m_lemmas); - } - - std::ostream& card2bv_rewriter::pp(std::ostream& out, literal lit) { - return out << mk_ismt2_pp(lit, m); - } - - card2bv_rewriter::literal card2bv_rewriter::trail(literal l) { - m_trail.push_back(l); - return l; - } - card2bv_rewriter::literal card2bv_rewriter::fresh() { - return trail(m.mk_fresh_const("sn", m.mk_bool_sort())); - } - - void card2bv_rewriter::mk_clause(unsigned n, literal const* lits) { - m_lemmas.push_back(mk_or(m, n, lits)); - } - - - br_status card2bv_rewriter::mk_app_core(func_decl * f, unsigned sz, expr * const* args, expr_ref & result) { - if (f->get_family_id() == null_family_id) { - if (sz == 1) { - // Expecting minimize/maximize. - func_decl_ref fd(m); - fd = m.mk_func_decl(f->get_name(), m.get_sort(args[0]), f->get_range()); - result = m.mk_app(fd.get(), args[0]); - return BR_DONE; - } - else - return BR_FAILED; - } - else if (f->get_family_id() == m.get_basic_family_id()) { - result = m.mk_app(f, sz, args); - return BR_DONE; - } - else if (f->get_family_id() == pb.get_family_id()) { - if (is_or(f)) { - result = m.mk_or(sz, args); - return BR_DONE; - } - if (is_and(f)) { - result = m.mk_and(sz, args); - return BR_DONE; - } - if (is_atmost1(f, sz, args, result)) { - return BR_DONE; - } - br_status st = mk_shannon(f, sz, args, result); - if (st == BR_FAILED) { - mk_bv(f, sz, args, result); - return BR_DONE; - } - else { - return st; - } - } - // NSB: review - // we should remove this code and rely on a layer above to deal with - // whatever it accomplishes. It seems to break types. - // - else if (f->get_family_id() == au.get_family_id()) { - if (f->get_decl_kind() == OP_ADD) { - unsigned bits = 0; - for (unsigned i = 0; i < sz; i++) { - rational val1, val2; - if (au.is_int(args[i]) && au.is_numeral(args[i], val1)) { - bits += val1.get_num_bits(); - } - else if (m.is_ite(args[i]) && - au.is_numeral(to_app(args[i])->get_arg(1), val1) && val1.is_one() && - au.is_numeral(to_app(args[i])->get_arg(2), val2) && val2.is_zero()) { - bits++; - } - else - return BR_FAILED; - } - - result = 0; - for (unsigned i = 0; i < sz; i++) { - rational val1, val2; - expr * q; - if (au.is_int(args[i]) && au.is_numeral(args[i], val1)) - q = bv.mk_numeral(val1, bits); - else - q = mk_ite(to_app(args[i])->get_arg(0), bv.mk_numeral(1, bits), bv.mk_numeral(0, bits)); - result = (i == 0) ? q : bv.mk_bv_add(result.get(), q); - } - return BR_DONE; - } - else - return BR_FAILED; - } - else - return BR_FAILED; - } - - expr_ref card2bv_rewriter::mk_atmost1(unsigned n, expr * const* xs) { - expr_ref_vector result(m), in(m); - in.append(n, xs); - unsigned inc_size = 4; - while (!in.empty()) { - expr_ref_vector ors(m); - unsigned i = 0; - unsigned n = in.size(); - bool last = n <= inc_size; - for (; i + inc_size < n; i += inc_size) { - mk_at_most_1_small(last, inc_size, in.c_ptr() + i, result, ors); - } - if (i < n) { - mk_at_most_1_small(last, n - i, in.c_ptr() + i, result, ors); - } - if (last) { - break; - } - in.reset(); - in.append(ors); - } - return mk_and(result); - } - - void card2bv_rewriter::mk_at_most_1_small(bool last, unsigned n, literal const* xs, expr_ref_vector& result, expr_ref_vector& ors) { - if (!last) { - ors.push_back(m.mk_or(n, xs)); - } - for (unsigned i = 0; i < n; ++i) { - for (unsigned j = i + 1; j < n; ++j) { - result.push_back(m.mk_not(m.mk_and(xs[i], xs[j]))); - } - } - } - - bool card2bv_rewriter::is_atmost1(func_decl* f, unsigned sz, expr * const* args, expr_ref& result) { - switch (f->get_decl_kind()) { - case OP_AT_MOST_K: - case OP_PB_LE: - if (pb.get_k(f).is_one() && pb.has_unit_coefficients(f)) { - result = mk_atmost1(sz, args); - return true; - } - return false; - case OP_AT_LEAST_K: - case OP_PB_GE: - if (pb.get_k(f) == rational(sz-1) && pb.has_unit_coefficients(f)) { - expr_ref_vector nargs(m); - for (unsigned i = 0; i < sz; ++i) { - nargs.push_back(mk_not(args[i])); - } - result = mk_atmost1(nargs.size(), nargs.c_ptr()); - return true; - } - return false; - case OP_PB_EQ: - return false; - default: - UNREACHABLE(); - return false; - } - } - - bool card2bv_rewriter::is_or(func_decl* f) { - switch (f->get_decl_kind()) { - case OP_AT_MOST_K: - case OP_PB_LE: - return false; - case OP_AT_LEAST_K: - case OP_PB_GE: - return pb.get_k(f).is_one(); - case OP_PB_EQ: - return false; - default: - UNREACHABLE(); - return false; - } - } - - bool card2bv_rewriter::is_and(func_decl* f) { - return false; - } - - void card2bv_rewriter::mk_bv(func_decl * f, unsigned sz, expr * const* args, expr_ref & result) { - expr_ref zero(m), a(m), b(m); - expr_ref_vector es(m); - unsigned bw = get_num_bits(f); - zero = bv.mk_numeral(rational(0), bw); - for (unsigned i = 0; i < sz; ++i) { - es.push_back(mk_ite(args[i], bv.mk_numeral(pb.get_coeff(f, i), bw), zero)); - } - switch (es.size()) { - case 0: a = zero; break; - case 1: a = es[0].get(); break; - default: - a = es[0].get(); - for (unsigned i = 1; i < es.size(); ++i) { - a = bv.mk_bv_add(a, es[i].get()); - } - break; - } - b = bv.mk_numeral(pb.get_k(f), bw); - - switch (f->get_decl_kind()) { - case OP_AT_MOST_K: - case OP_PB_LE: - UNREACHABLE(); - result = bv.mk_ule(a, b); - break; - case OP_AT_LEAST_K: - UNREACHABLE(); - case OP_PB_GE: - result = bv.mk_ule(b, a); - break; - case OP_PB_EQ: - result = m.mk_eq(a, b); - break; - default: - UNREACHABLE(); - } - TRACE("card2bv", tout << result << "\n";); - } - - struct argc_t { - expr* m_arg; - rational m_coeff; - argc_t():m_arg(0), m_coeff(0) {} - argc_t(expr* arg, rational const& r): m_arg(arg), m_coeff(r) {} - }; - struct argc_gt { - bool operator()(argc_t const& a, argc_t const& b) const { - return a.m_coeff > b.m_coeff; - } - }; - struct argc_entry { - unsigned m_index; - rational m_k; - expr* m_value; - argc_entry(unsigned i, rational const& k): m_index(i), m_k(k), m_value(0) {} - argc_entry():m_index(0), m_k(0), m_value(0) {} - - struct eq { - bool operator()(argc_entry const& a, argc_entry const& b) const { - return a.m_index == b.m_index && a.m_k == b.m_k; - } - }; - struct hash { - unsigned operator()(argc_entry const& a) const { - return a.m_index ^ a.m_k.hash(); - } - }; - }; - typedef hashtable argc_cache; - - br_status card2bv_rewriter::mk_shannon( - func_decl * f, unsigned sz, expr * const* args, expr_ref & result) { - - unsigned max_clauses = sz*10; - vector argcs; - for (unsigned i = 0; i < sz; ++i) { - argcs.push_back(argc_t(args[i], pb.get_coeff(f, i))); - } - std::sort(argcs.begin(), argcs.end(), argc_gt()); - DEBUG_CODE( - for (unsigned i = 0; i + 1 < sz; ++i) { - SASSERT(argcs[i].m_coeff >= argcs[i+1].m_coeff); - } - ); - result = m.mk_app(f, sz, args); - TRACE("card2bv", tout << result << "\n";); - argc_cache cache; - expr_ref_vector trail(m); - vector todo_k; - unsigned_vector todo_i; - todo_k.push_back(pb.get_k(f)); - todo_i.push_back(0); - decl_kind kind = f->get_decl_kind(); - argc_entry entry1; - while (!todo_i.empty()) { - SASSERT(todo_i.size() == todo_k.size()); - if (cache.size() > max_clauses) { - return BR_FAILED; - } - unsigned i = todo_i.back(); - rational k = todo_k.back(); - argc_entry entry(i, k); - if (cache.contains(entry)) { - todo_i.pop_back(); - todo_k.pop_back(); - continue; - } - SASSERT(i < sz); - SASSERT(!k.is_neg()); - rational const& coeff = argcs[i].m_coeff; - expr* arg = argcs[i].m_arg; - if (i + 1 == sz) { - switch(kind) { - case OP_AT_MOST_K: - case OP_PB_LE: - if (coeff <= k) { - entry.m_value = m.mk_true(); - } - else { - entry.m_value = negate(arg); - trail.push_back(entry.m_value); - } - break; - case OP_AT_LEAST_K: - case OP_PB_GE: - if (k.is_zero()) { - entry.m_value = m.mk_true(); - } - else if (coeff < k) { - entry.m_value = m.mk_false(); - } - else if (coeff.is_zero()) { - entry.m_value = m.mk_true(); - } - else { - SASSERT(coeff >= k && k.is_pos()); - entry.m_value = arg; - } - break; - case OP_PB_EQ: - if (coeff == k) { - entry.m_value = arg; - } - else if (k.is_zero()) { - entry.m_value = negate(arg); - trail.push_back(entry.m_value); - } - else { - entry.m_value = m.mk_false(); - } - break; - } - todo_i.pop_back(); - todo_k.pop_back(); - cache.insert(entry); - continue; - } - entry.m_index++; - expr* lo = 0, *hi = 0; - if (cache.find(entry, entry1)) { - lo = entry1.m_value; - } - else { - todo_i.push_back(i+1); - todo_k.push_back(k); - } - entry.m_k -= coeff; - if (kind != OP_PB_EQ && !entry.m_k.is_pos()) { - switch (kind) { - case OP_AT_MOST_K: - case OP_PB_LE: - hi = m.mk_false(); - break; - case OP_AT_LEAST_K: - case OP_PB_GE: - hi = m.mk_true(); - break; - default: - UNREACHABLE(); - } - } - else if (cache.find(entry, entry1)) { - hi = entry1.m_value; - } - else { - todo_i.push_back(i+1); - todo_k.push_back(entry.m_k); - } - if (hi && lo) { - todo_i.pop_back(); - todo_k.pop_back(); - entry.m_index = i; - entry.m_k = k; - entry.m_value = mk_ite(arg, hi, lo); - trail.push_back(entry.m_value); - cache.insert(entry); - } - } - argc_entry entry(0, pb.get_k(f)); - VERIFY(cache.find(entry, entry)); - result = entry.m_value; - TRACE("card2bv", tout << result << "\n";); - return BR_DONE; - } - - expr* card2bv_rewriter::negate(expr* e) { - if (m.is_not(e, e)) return e; - return m.mk_not(e); - } - - expr* card2bv_rewriter::mk_ite(expr* c, expr* hi, expr* lo) { - while (m.is_not(c, c)) { - std::swap(hi, lo); - } - if (hi == lo) return hi; - if (m.is_true(hi) && m.is_false(lo)) return c; - if (m.is_false(hi) && m.is_true(lo)) return negate(c); - if (m.is_true(hi)) return m.mk_or(c, lo); - if (m.is_false(lo)) return m.mk_and(c, hi); - if (m.is_false(hi)) return m.mk_and(negate(c), lo); - if (m.is_true(lo)) return m.mk_implies(c, hi); - return m.mk_ite(c, hi, lo); - } - - void card_pb_rewriter::rewrite(expr* e, expr_ref& result) { - if (pb.is_eq(e)) { - app* a = to_app(e); - ast_manager& m = m_lemmas.get_manager(); - unsigned sz = a->get_num_args(); - expr_ref_vector args(m); - expr_ref tmp(m); - for (unsigned i = 0; i < sz; ++i) { - (*this)(a->get_arg(i), tmp); - args.push_back(tmp); - } - m_cfg.m_r.mk_assert(a->get_decl(), sz, args.c_ptr(), result, m_lemmas); - } - else { - (*this)(e, result); - } - } - -}; - -template class rewriter_tpl; - +#include"filter_model_converter.h" class card2bv_tactic : public tactic { ast_manager & m; params_ref m_params; - th_rewriter m_rw1; - pb::card_pb_rewriter m_rw2; public: card2bv_tactic(ast_manager & m, params_ref const & p): m(m), - m_params(p), - m_rw1(m), - m_rw2(m) { + m_params(p) { } virtual tactic * translate(ast_manager & m) { @@ -538,9 +60,8 @@ public: SASSERT(g->is_well_sorted()); mc = 0; pc = 0; core = 0; result.reset(); tactic_report report("card2bv", *g); - m_rw1.reset(); - m_rw2.reset(); - m_rw2.lemmas().reset(); + th_rewriter rw1(m, m_params); + pb2bv_rewriter rw2(m, m_params); if (g->inconsistent()) { result.push_back(g.get()); @@ -550,18 +71,28 @@ public: expr_ref new_f1(m), new_f2(m); proof_ref new_pr1(m), new_pr2(m); for (unsigned idx = 0; !g->inconsistent() && idx < g->size(); idx++) { - m_rw1(g->form(idx), new_f1, new_pr1); + rw1(g->form(idx), new_f1, new_pr1); TRACE("card2bv", tout << "Rewriting " << mk_ismt2_pp(new_f1.get(), m) << std::endl;); - m_rw2.rewrite(new_f1, new_f2); + rw2(new_f1, new_f2, new_pr2); if (m.proofs_enabled()) { new_pr1 = m.mk_modus_ponens(g->pr(idx), new_pr1); - new_pr2 = m.mk_rewrite(new_f1, new_f2); new_pr1 = m.mk_modus_ponens(new_pr1, new_pr2); } g->update(idx, new_f2, new_pr1, g->dep(idx)); } - for (unsigned i = 0; i < m_rw2.lemmas().size(); ++i) { - g->assert_expr(m_rw2.lemmas()[i].get()); + expr_ref_vector fmls(m); + rw2.flush_side_constraints(fmls); + for (unsigned i = 0; !g->inconsistent() && i < fmls.size(); ++i) { + g->assert_expr(fmls[i].get()); + } + + func_decl_ref_vector const& fns = rw2.fresh_constants(); + if (!fns.empty()) { + filter_model_converter* filter = alloc(filter_model_converter, m); + for (unsigned i = 0; i < fns.size(); ++i) { + filter->insert(fns[i]); + } + mc = filter; } g->inc_depth(); diff --git a/src/tactic/bv/dt2bv_tactic.cpp b/src/tactic/bv/dt2bv_tactic.cpp index 2ecc80980..2ccbe9712 100644 --- a/src/tactic/bv/dt2bv_tactic.cpp +++ b/src/tactic/bv/dt2bv_tactic.cpp @@ -29,7 +29,7 @@ Revision History: #include "extension_model_converter.h" #include "var_subst.h" #include "ast_util.h" -#include "fd_rewriter.h" +#include "enum2bv_rewriter.h" class dt2bv_tactic : public tactic { @@ -132,7 +132,7 @@ public: if (!m_fd_sorts.empty()) { ref ext = alloc(extension_model_converter, m); ref filter = alloc(filter_model_converter, m); - fd_rewriter rw(m, m_params); + enum2bv_rewriter rw(m, m_params); rw.set_is_fd(&m_is_fd); expr_ref new_curr(m); proof_ref new_pr(m); diff --git a/src/tactic/portfolio/bounded_int2bv_solver.cpp b/src/tactic/portfolio/bounded_int2bv_solver.cpp new file mode 100644 index 000000000..f7236351c --- /dev/null +++ b/src/tactic/portfolio/bounded_int2bv_solver.cpp @@ -0,0 +1,296 @@ +/*++ +Copyright (c) 2016 Microsoft Corporation + +Module Name: + + bounded_int2bv_solver.cpp + +Abstract: + + This solver identifies bounded integers and rewrites them to bit-vectors. + +Author: + + Nikolaj Bjorner (nbjorner) 2016-10-23 + +Notes: + +--*/ + +#include "bounded_int2bv_solver.h" +#include "solver_na2as.h" +#include "tactic.h" +#include "pb2bv_rewriter.h" +#include "filter_model_converter.h" +#include "extension_model_converter.h" +#include "ast_pp.h" +#include "model_smt2_pp.h" +#include "bound_manager.h" +#include "bv2int_rewriter.h" +#include "expr_safe_replace.h" +#include "bv_decl_plugin.h" +#include "arith_decl_plugin.h" + +class bounded_int2bv_solver : public solver_na2as { + ast_manager& m; + params_ref m_params; + bv_util m_bv; + arith_util m_arith; + expr_ref_vector m_assertions; + ref m_solver; + ptr_vector m_bounds; + func_decl_ref_vector m_bv_fns; + func_decl_ref_vector m_int_fns; + unsigned_vector m_bv_fns_lim; + obj_map m_int2bv; + obj_map m_bv2int; + obj_map m_bv2offset; + bv2int_rewriter_ctx m_rewriter_ctx; + bv2int_rewriter_star m_rewriter; + +public: + + bounded_int2bv_solver(ast_manager& m, params_ref const& p, solver* s): + solver_na2as(m), + m(m), + m_params(p), + m_bv(m), + m_arith(m), + m_assertions(m), + m_solver(s), + m_bv_fns(m), + m_int_fns(m), + m_rewriter_ctx(m, p), + m_rewriter(m, m_rewriter_ctx) + { + m_bounds.push_back(alloc(bound_manager, m)); + } + + virtual ~bounded_int2bv_solver() { + while (!m_bounds.empty()) { + dealloc(m_bounds.back()); + m_bounds.pop_back(); + } + } + + virtual solver* translate(ast_manager& m, params_ref const& p) { + return alloc(bounded_int2bv_solver, m, p, m_solver->translate(m, p)); + } + + virtual void assert_expr(expr * t) { + m_assertions.push_back(t); + } + + virtual void push_core() { + flush_assertions(); + m_solver->push(); + m_bv_fns_lim.push_back(m_bv_fns.size()); + m_bounds.push_back(alloc(bound_manager, m)); + } + + virtual void pop_core(unsigned n) { + m_assertions.reset(); + m_solver->pop(n); + + if (n > 0) { + SASSERT(n <= m_bv_fns_lim.size()); + unsigned new_sz = m_bv_fns_lim.size() - n; + unsigned lim = m_bv_fns_lim[new_sz]; + for (unsigned i = m_int_fns.size(); i > lim; ) { + --i; + m_int2bv.erase(m_int_fns[i].get()); + m_bv2int.erase(m_bv_fns[i].get()); + m_bv2offset.erase(m_bv_fns[i].get()); + } + m_bv_fns_lim.resize(new_sz); + m_bv_fns.resize(lim); + m_int_fns.resize(lim); + } + + while (n > 0) { + dealloc(m_bounds.back()); + m_bounds.pop_back(); + --n; + } + } + + virtual lbool check_sat_core(unsigned num_assumptions, expr * const * assumptions) { + flush_assertions(); + return m_solver->check_sat(num_assumptions, assumptions); + } + + virtual void updt_params(params_ref const & p) { m_solver->updt_params(p); } + virtual void collect_param_descrs(param_descrs & r) { m_solver->collect_param_descrs(r); } + virtual void set_produce_models(bool f) { m_solver->set_produce_models(f); } + virtual void set_progress_callback(progress_callback * callback) { m_solver->set_progress_callback(callback); } + virtual void collect_statistics(statistics & st) const { m_solver->collect_statistics(st); } + virtual void get_unsat_core(ptr_vector & r) { m_solver->get_unsat_core(r); } + virtual void get_model(model_ref & mdl) { + m_solver->get_model(mdl); + if (mdl) { + extend_model(mdl); + filter_model(mdl); + } + } + virtual proof * get_proof() { return m_solver->get_proof(); } + virtual std::string reason_unknown() const { return m_solver->reason_unknown(); } + virtual void set_reason_unknown(char const* msg) { m_solver->set_reason_unknown(msg); } + virtual void get_labels(svector & r) { m_solver->get_labels(r); } + virtual ast_manager& get_manager() const { return m; } + virtual lbool find_mutexes(expr_ref_vector const& vars, vector& mutexes) { return m_solver->find_mutexes(vars, mutexes); } + virtual lbool get_consequences_core(expr_ref_vector const& asms, expr_ref_vector const& vars, expr_ref_vector& consequences) { + flush_assertions(); + expr_ref_vector bvars(m); + for (unsigned i = 0; i < vars.size(); ++i) { + expr* v = vars[i]; + func_decl* f; + rational offset; + if (is_app(v) && is_uninterp_const(v) && m_int2bv.find(to_app(v)->get_decl(), f)) { + bvars.push_back(m.mk_const(f)); + } + else { + bvars.push_back(v); + } + } + lbool r = m_solver->get_consequences(asms, bvars, consequences); + + // translate bit-vector consequences back to integer values + for (unsigned i = 0; i < consequences.size(); ++i) { + expr* a, *b, *u, *v; + func_decl* f; + rational num; + unsigned bvsize; + rational offset; + VERIFY(m.is_implies(consequences[i].get(), a, b)); + if (m.is_eq(b, u, v) && is_uninterp_const(u) && m_bv2int.find(to_app(u)->get_decl(), f) && m_bv.is_numeral(v, num, bvsize)) { + SASSERT(num.is_unsigned()); + expr_ref head(m); + VERIFY (m_bv2offset.find(to_app(u)->get_decl(), offset)); + // f + offset == num + // f == num - offset + head = m.mk_eq(m.mk_const(f), m_arith.mk_numeral(num + offset, true)); + consequences[i] = m.mk_implies(a, head); + } + } + return r; + + } + +private: + + void filter_model(model_ref& mdl) const { + if (m_bv_fns.empty()) { + return; + } + filter_model_converter filter(m); + func_decl_ref_vector const& fns = m_bv_fns; + for (unsigned i = 0; i < m_bv_fns.size(); ++i) { + filter.insert(m_bv_fns[i]); + } + filter(mdl, 0); + } + + void extend_model(model_ref& mdl) { + extension_model_converter ext(m); + obj_map::iterator it = m_int2bv.begin(), end = m_int2bv.end(); + for (; it != end; ++it) { + rational offset; + VERIFY (m_bv2offset.find(it->m_value, offset)); + expr_ref value(m_bv.mk_bv2int(m.mk_const(it->m_value)), m); + if (!offset.is_zero()) { + value = m_arith.mk_add(value, m_arith.mk_numeral(offset, true)); + } + TRACE("int2bv", tout << mk_pp(it->m_key, m) << " " << value << "\n";); + ext.insert(it->m_key, value); + } + ext(mdl, 0); + } + + void accumulate_sub(expr_safe_replace& sub) { + for (unsigned i = 0; i < m_bounds.size(); ++i) { + accumulate_sub(sub, *m_bounds[i]); + } + } + + void accumulate_sub(expr_safe_replace& sub, bound_manager& bm) { + bound_manager::iterator it = bm.begin(), end = bm.end(); + for (; it != end; ++it) { + expr* e = *it; + rational lo, hi; + bool s1, s2; + SASSERT(is_uninterp_const(e)); + func_decl* f = to_app(e)->get_decl(); + + if (bm.has_lower(e, lo, s1) && bm.has_upper(e, hi, s2) && lo <= hi && !s1 && !s2) { + func_decl* fbv; + rational offset; + if (!m_int2bv.find(f, fbv)) { + rational n = hi - lo + rational::one(); + unsigned num_bits = get_num_bits(n); + expr_ref b(m); + b = m.mk_fresh_const("b", m_bv.mk_sort(num_bits)); + fbv = to_app(b)->get_decl(); + offset = lo; + m_int2bv.insert(f, fbv); + m_bv2int.insert(fbv, f); + m_bv2offset.insert(fbv, offset); + m_bv_fns.push_back(fbv); + m_int_fns.push_back(f); + unsigned shift; + if (!offset.is_zero() && !n.is_power_of_two(shift)) { + m_assertions.push_back(m_bv.mk_ule(b, m_bv.mk_numeral(n-rational::one(), num_bits))); + } + } + else { + VERIFY(m_bv2offset.find(fbv, offset)); + } + expr_ref t(m.mk_const(fbv), m); + t = m_bv.mk_bv2int(t); + if (!offset.is_zero()) { + t = m_arith.mk_add(t, m_arith.mk_numeral(lo, true)); + } + sub.insert(e, t); + } + } + } + + unsigned get_num_bits(rational const& k) { + SASSERT(!k.is_neg()); + SASSERT(k.is_int()); + rational two(2); + rational bound(1); + unsigned num_bits = 1; + while (bound <= k) { + ++num_bits; + bound *= two; + } + return num_bits; + } + + void flush_assertions() { + bound_manager& bm = *m_bounds.back(); + for (unsigned i = 0; i < m_assertions.size(); ++i) { + bm(m_assertions[i].get()); + } + expr_safe_replace sub(m); + accumulate_sub(sub); + proof_ref proof(m); + expr_ref fml1(m), fml2(m); + if (sub.empty()) { + m_solver->assert_expr(m_assertions); + } + else { + for (unsigned i = 0; i < m_assertions.size(); ++i) { + sub(m_assertions[i].get(), fml1); + m_rewriter(fml1, fml2, proof); + m_solver->assert_expr(fml2); + TRACE("int2bv", tout << fml2 << "\n";); + } + } + m_assertions.reset(); + } +}; + +solver * mk_bounded_int2bv_solver(ast_manager & m, params_ref const & p, solver* s) { + return alloc(bounded_int2bv_solver, m, p, s); +} diff --git a/src/tactic/portfolio/bounded_int2bv_solver.h b/src/tactic/portfolio/bounded_int2bv_solver.h new file mode 100644 index 000000000..5fcf2cd65 --- /dev/null +++ b/src/tactic/portfolio/bounded_int2bv_solver.h @@ -0,0 +1,29 @@ +/*++ +Copyright (c) 2016 Microsoft Corporation + +Module Name: + + bounded_int2bv_solver.h + +Abstract: + + Finite domain solver. + +Author: + + Nikolaj Bjorner (nbjorner) 2016-10-23 + +Notes: + +--*/ +#ifndef BOUNDED_INT2BV_SOLVER_H_ +#define BOUNDED_INT2BV_SOLVER_H_ + +#include"ast.h" +#include"params.h" + +class solver; + +solver * mk_bounded_int2bv_solver(ast_manager & m, params_ref const & p, solver* s); + +#endif diff --git a/src/tactic/portfolio/enum2bv_solver.cpp b/src/tactic/portfolio/enum2bv_solver.cpp new file mode 100644 index 000000000..369402114 --- /dev/null +++ b/src/tactic/portfolio/enum2bv_solver.cpp @@ -0,0 +1,162 @@ +/*++ +Copyright (c) 2016 Microsoft Corporation + +Module Name: + + enum2bv_solver.cpp + +Abstract: + + Finite domain solver. + + Enumeration data-types are translated into bit-vectors, and then + the incremental sat-solver is applied to the resulting assertions. + +Author: + + Nikolaj Bjorner (nbjorner) 2016-10-17 + +Notes: + +--*/ + +#include "solver_na2as.h" +#include "tactic.h" +#include "bv_decl_plugin.h" +#include "datatype_decl_plugin.h" +#include "enum2bv_rewriter.h" +#include "extension_model_converter.h" +#include "filter_model_converter.h" +#include "ast_pp.h" +#include "model_smt2_pp.h" +#include "enum2bv_solver.h" + +class enum2bv_solver : public solver_na2as { + ast_manager& m; + params_ref m_params; + ref m_solver; + enum2bv_rewriter m_rewriter; + +public: + + enum2bv_solver(ast_manager& m, params_ref const& p, solver* s): + solver_na2as(m), + m(m), + m_params(p), + m_solver(s), + m_rewriter(m, p) + { + } + + virtual ~enum2bv_solver() {} + + virtual solver* translate(ast_manager& m, params_ref const& p) { + return alloc(enum2bv_solver, m, p, m_solver->translate(m, p)); + } + + virtual void assert_expr(expr * t) { + expr_ref tmp(t, m); + expr_ref_vector bounds(m); + proof_ref tmp_proof(m); + m_rewriter(t, tmp, tmp_proof); + m_solver->assert_expr(tmp); + m_rewriter.flush_side_constraints(bounds); + m_solver->assert_expr(bounds); + } + + virtual void push_core() { + m_rewriter.push(); + m_solver->push(); + } + + virtual void pop_core(unsigned n) { + m_solver->pop(n); + m_rewriter.pop(n); + } + + virtual lbool check_sat_core(unsigned num_assumptions, expr * const * assumptions) { + return m_solver->check_sat(num_assumptions, assumptions); + } + + virtual void updt_params(params_ref const & p) { m_solver->updt_params(p); } + virtual void collect_param_descrs(param_descrs & r) { m_solver->collect_param_descrs(r); } + virtual void set_produce_models(bool f) { m_solver->set_produce_models(f); } + virtual void set_progress_callback(progress_callback * callback) { m_solver->set_progress_callback(callback); } + virtual void collect_statistics(statistics & st) const { m_solver->collect_statistics(st); } + virtual void get_unsat_core(ptr_vector & r) { m_solver->get_unsat_core(r); } + virtual void get_model(model_ref & mdl) { + m_solver->get_model(mdl); + if (mdl) { + extend_model(mdl); + filter_model(mdl); + } + } + virtual proof * get_proof() { return m_solver->get_proof(); } + virtual std::string reason_unknown() const { return m_solver->reason_unknown(); } + virtual void set_reason_unknown(char const* msg) { m_solver->set_reason_unknown(msg); } + virtual void get_labels(svector & r) { m_solver->get_labels(r); } + virtual ast_manager& get_manager() const { return m; } + virtual lbool find_mutexes(expr_ref_vector const& vars, vector& mutexes) { return m_solver->find_mutexes(vars, mutexes); } + + virtual lbool get_consequences_core(expr_ref_vector const& asms, expr_ref_vector const& vars, expr_ref_vector& consequences) { + + datatype_util dt(m); + bv_util bv(m); + + // translate enumeration constants to bit-vectors. + expr_ref_vector bvars(m), conseq(m); + for (unsigned i = 0; i < vars.size(); ++i) { + func_decl* f; + if (is_app(vars[i]) && is_uninterp_const(vars[i]) && m_rewriter.enum2bv().find(to_app(vars[i])->get_decl(), f)) { + bvars.push_back(m.mk_const(f)); + } + else { + bvars.push_back(vars[i]); + } + } + lbool r = m_solver->get_consequences(asms, bvars, consequences); + std::cout << consequences.size() << "\n"; + + + // translate bit-vector consequences back to enumeration types + for (unsigned i = 0; i < consequences.size(); ++i) { + expr* a, *b, *u, *v; + func_decl* f; + rational num; + unsigned bvsize; + VERIFY(m.is_implies(consequences[i].get(), a, b)); + if (m.is_eq(b, u, v) && is_uninterp_const(u) && m_rewriter.bv2enum().find(to_app(u)->get_decl(), f) && bv.is_numeral(v, num, bvsize)) { + SASSERT(num.is_unsigned()); + expr_ref head(m); + ptr_vector const& enums = *dt.get_datatype_constructors(f->get_range()); + head = m.mk_eq(m.mk_const(f), m.mk_const(enums[num.get_unsigned()])); + consequences[i] = m.mk_implies(a, head); + } + } + return r; + } + + void filter_model(model_ref& mdl) { + filter_model_converter filter(m); + obj_map::iterator it = m_rewriter.enum2bv().begin(), end = m_rewriter.enum2bv().end(); + for (; it != end; ++it) { + filter.insert(it->m_value); + } + filter(mdl, 0); + } + + void extend_model(model_ref& mdl) { + extension_model_converter ext(m); + obj_map::iterator it = m_rewriter.enum2def().begin(), end = m_rewriter.enum2def().end(); + for (; it != end; ++it) { + ext.insert(it->m_key, it->m_value); + + } + ext(mdl, 0); + } + +}; + +solver * mk_enum2bv_solver(ast_manager & m, params_ref const & p, solver* s) { + return alloc(enum2bv_solver, m, p, s); +} diff --git a/src/tactic/portfolio/enum2bv_solver.h b/src/tactic/portfolio/enum2bv_solver.h new file mode 100644 index 000000000..b113c6747 --- /dev/null +++ b/src/tactic/portfolio/enum2bv_solver.h @@ -0,0 +1,29 @@ +/*++ +Copyright (c) 2016 Microsoft Corporation + +Module Name: + + enum2bv_solver.h + +Abstract: + + Finite domain solver. + +Author: + + Nikolaj Bjorner (nbjorner) 2016-10-17 + +Notes: + +--*/ +#ifndef ENUM2BV_SOLVER_H_ +#define ENUM2BV_SOLVER_H_ + +#include"ast.h" +#include"params.h" + +class solver; + +solver * mk_enum2bv_solver(ast_manager & m, params_ref const & p, solver* s); + +#endif diff --git a/src/tactic/portfolio/fd_solver.cpp b/src/tactic/portfolio/fd_solver.cpp index 9447c158c..a534337bc 100644 --- a/src/tactic/portfolio/fd_solver.cpp +++ b/src/tactic/portfolio/fd_solver.cpp @@ -9,9 +9,6 @@ Abstract: Finite domain solver. - Enumeration data-types are translated into bit-vectors, and then - the incremental sat-solver is applied to the resulting assertions. - Author: Nikolaj Bjorner (nbjorner) 2016-10-17 @@ -21,141 +18,16 @@ Notes: --*/ #include "fd_solver.h" -#include "solver_na2as.h" #include "tactic.h" #include "inc_sat_solver.h" -#include "bv_decl_plugin.h" -#include "datatype_decl_plugin.h" -#include "fd_rewriter.h" -#include "extension_model_converter.h" -#include "filter_model_converter.h" -#include "ast_pp.h" -#include "model_smt2_pp.h" - -class fd_solver : public solver_na2as { - ast_manager& m; - params_ref m_params; - ref m_solver; - fd_rewriter m_rewriter; - -public: - - fd_solver(ast_manager& m, params_ref const& p): - solver_na2as(m), - m(m), - m_params(p), - m_solver(mk_inc_sat_solver(m, p)), - m_rewriter(m, p) - { - } - - virtual ~fd_solver() {} - - virtual solver* translate(ast_manager& m, params_ref const& p) { - return alloc(fd_solver, m, p); - } - - virtual void assert_expr(expr * t) { - expr_ref tmp(t, m); - expr_ref_vector bounds(m); - proof_ref tmp_proof(m); - m_rewriter(t, tmp, tmp_proof); - m_solver->assert_expr(tmp); - m_rewriter.flush_side_constraints(bounds); - m_solver->assert_expr(bounds); - } - - virtual void push_core() { - m_rewriter.push(); - m_solver->push(); - } - - virtual void pop_core(unsigned n) { - m_solver->pop(n); - m_rewriter.pop(n); - } - - virtual lbool check_sat_core(unsigned num_assumptions, expr * const * assumptions) { - return m_solver->check_sat(num_assumptions, assumptions); - } - - virtual void updt_params(params_ref const & p) { m_solver->updt_params(p); } - virtual void collect_param_descrs(param_descrs & r) { m_solver->collect_param_descrs(r); } - virtual void set_produce_models(bool f) { m_solver->set_produce_models(f); } - virtual void set_progress_callback(progress_callback * callback) { m_solver->set_progress_callback(callback); } - virtual void collect_statistics(statistics & st) const { m_solver->collect_statistics(st); } - virtual void get_unsat_core(ptr_vector & r) { m_solver->get_unsat_core(r); } - virtual void get_model(model_ref & mdl) { - m_solver->get_model(mdl); - if (mdl) { - extend_model(mdl); - filter_model(mdl); - } - } - virtual proof * get_proof() { return m_solver->get_proof(); } - virtual std::string reason_unknown() const { return m_solver->reason_unknown(); } - virtual void set_reason_unknown(char const* msg) { m_solver->set_reason_unknown(msg); } - virtual void get_labels(svector & r) { m_solver->get_labels(r); } - virtual ast_manager& get_manager() const { return m; } - virtual lbool find_mutexes(expr_ref_vector const& vars, vector& mutexes) { return m_solver->find_mutexes(vars, mutexes); } - - virtual lbool get_consequences_core(expr_ref_vector const& asms, expr_ref_vector const& vars, expr_ref_vector& consequences) { - - datatype_util dt(m); - bv_util bv(m); - - // translate enumeration constants to bit-vectors. - expr_ref_vector bvars(m), conseq(m); - for (unsigned i = 0; i < vars.size(); ++i) { - func_decl* f; - if (is_app(vars[i]) && is_uninterp_const(vars[i]) && m_rewriter.enum2bv().find(to_app(vars[i])->get_decl(), f)) { - bvars.push_back(m.mk_const(f)); - } - else { - bvars.push_back(vars[i]); - } - } - lbool r = m_solver->get_consequences(asms, bvars, consequences); - - // translate bit-vector consequences back to enumeration types - for (unsigned i = 0; i < consequences.size(); ++i) { - expr* a, *b, *u, *v; - func_decl* f; - rational num; - unsigned bvsize; - VERIFY(m.is_implies(consequences[i].get(), a, b)); - if (m.is_eq(b, u, v) && is_uninterp_const(u) && m_rewriter.bv2enum().find(to_app(u)->get_decl(), f) && bv.is_numeral(v, num, bvsize)) { - SASSERT(num.is_unsigned()); - expr_ref head(m); - ptr_vector const& enums = *dt.get_datatype_constructors(f->get_range()); - head = m.mk_eq(m.mk_const(f), m.mk_const(enums[num.get_unsigned()])); - consequences[i] = m.mk_implies(a, head); - } - } - return r; - } - - void filter_model(model_ref& mdl) { - filter_model_converter filter(m); - obj_map::iterator it = m_rewriter.enum2bv().begin(), end = m_rewriter.enum2bv().end(); - for (; it != end; ++it) { - filter.insert(it->m_value); - } - filter(mdl, 0); - } - - void extend_model(model_ref& mdl) { - extension_model_converter ext(m); - obj_map::iterator it = m_rewriter.enum2def().begin(), end = m_rewriter.enum2def().end(); - for (; it != end; ++it) { - ext.insert(it->m_key, it->m_value); - - } - ext(mdl, 0); - } - -}; +#include "enum2bv_solver.h" +#include "pb2bv_solver.h" +#include "bounded_int2bv_solver.h" solver * mk_fd_solver(ast_manager & m, params_ref const & p) { - return alloc(fd_solver, m, p); + solver* s = mk_inc_sat_solver(m, p); + s = mk_enum2bv_solver(m, p, s); + s = mk_pb2bv_solver(m, p, s); + s = mk_bounded_int2bv_solver(m, p, s); + return s; } diff --git a/src/tactic/portfolio/pb2bv_solver.cpp b/src/tactic/portfolio/pb2bv_solver.cpp new file mode 100644 index 000000000..bfd533e8a --- /dev/null +++ b/src/tactic/portfolio/pb2bv_solver.cpp @@ -0,0 +1,127 @@ +/*++ +Copyright (c) 2016 Microsoft Corporation + +Module Name: + + pb2bv_solver.cpp + +Abstract: + + +Author: + + Nikolaj Bjorner (nbjorner) 2016-10-23 + +Notes: + +--*/ + +#include "pb2bv_solver.h" +#include "solver_na2as.h" +#include "tactic.h" +#include "pb2bv_rewriter.h" +#include "filter_model_converter.h" +#include "ast_pp.h" +#include "model_smt2_pp.h" + +class pb2bv_solver : public solver_na2as { + ast_manager& m; + params_ref m_params; + expr_ref_vector m_assertions; + ref m_solver; + pb2bv_rewriter m_rewriter; + +public: + + pb2bv_solver(ast_manager& m, params_ref const& p, solver* s): + solver_na2as(m), + m(m), + m_params(p), + m_assertions(m), + m_solver(s), + m_rewriter(m, p) + { + } + + virtual ~pb2bv_solver() {} + + virtual solver* translate(ast_manager& m, params_ref const& p) { + return alloc(pb2bv_solver, m, p, m_solver->translate(m, p)); + } + + virtual void assert_expr(expr * t) { + m_assertions.push_back(t); + } + + virtual void push_core() { + flush_assertions(); + m_rewriter.push(); + m_solver->push(); + } + + virtual void pop_core(unsigned n) { + m_assertions.reset(); + m_solver->pop(n); + m_rewriter.pop(n); + } + + virtual lbool check_sat_core(unsigned num_assumptions, expr * const * assumptions) { + flush_assertions(); + return m_solver->check_sat(num_assumptions, assumptions); + } + + virtual void updt_params(params_ref const & p) { m_solver->updt_params(p); } + virtual void collect_param_descrs(param_descrs & r) { m_solver->collect_param_descrs(r); } + virtual void set_produce_models(bool f) { m_solver->set_produce_models(f); } + virtual void set_progress_callback(progress_callback * callback) { m_solver->set_progress_callback(callback); } + virtual void collect_statistics(statistics & st) const { + m_rewriter.collect_statistics(st); + m_solver->collect_statistics(st); + } + virtual void get_unsat_core(ptr_vector & r) { m_solver->get_unsat_core(r); } + virtual void get_model(model_ref & mdl) { + m_solver->get_model(mdl); + if (mdl) { + filter_model(mdl); + } + } + virtual proof * get_proof() { return m_solver->get_proof(); } + virtual std::string reason_unknown() const { return m_solver->reason_unknown(); } + virtual void set_reason_unknown(char const* msg) { m_solver->set_reason_unknown(msg); } + virtual void get_labels(svector & r) { m_solver->get_labels(r); } + virtual ast_manager& get_manager() const { return m; } + virtual lbool find_mutexes(expr_ref_vector const& vars, vector& mutexes) { return m_solver->find_mutexes(vars, mutexes); } + virtual lbool get_consequences_core(expr_ref_vector const& asms, expr_ref_vector const& vars, expr_ref_vector& consequences) { + flush_assertions(); + return m_solver->get_consequences(asms, vars, consequences); } + + void filter_model(model_ref& mdl) { + if (m_rewriter.fresh_constants().empty()) { + return; + } + filter_model_converter filter(m); + func_decl_ref_vector const& fns = m_rewriter.fresh_constants(); + for (unsigned i = 0; i < fns.size(); ++i) { + filter.insert(fns[i]); + } + filter(mdl, 0); + } + +private: + void flush_assertions() { + proof_ref proof(m); + expr_ref fml(m); + expr_ref_vector fmls(m); + for (unsigned i = 0; i < m_assertions.size(); ++i) { + m_rewriter(m_assertions[i].get(), fml, proof); + m_solver->assert_expr(fml); + } + m_rewriter.flush_side_constraints(fmls); + m_solver->assert_expr(fmls); + m_assertions.reset(); + } +}; + +solver * mk_pb2bv_solver(ast_manager & m, params_ref const & p, solver* s) { + return alloc(pb2bv_solver, m, p, s); +} diff --git a/src/tactic/portfolio/pb2bv_solver.h b/src/tactic/portfolio/pb2bv_solver.h new file mode 100644 index 000000000..e861e769b --- /dev/null +++ b/src/tactic/portfolio/pb2bv_solver.h @@ -0,0 +1,29 @@ +/*++ +Copyright (c) 2016 Microsoft Corporation + +Module Name: + + pb2bv_solver.h + +Abstract: + + Pseudo-Boolean to bit-vector solver. + +Author: + + Nikolaj Bjorner (nbjorner) 2016-10-23 + +Notes: + +--*/ +#ifndef PB2BV_SOLVER_H_ +#define PB2BV_SOLVER_H_ + +#include"ast.h" +#include"params.h" + +class solver; + +solver * mk_pb2bv_solver(ast_manager & m, params_ref const & p, solver* s); + +#endif diff --git a/src/test/main.cpp b/src/test/main.cpp index 9c6cdd668..320eddd7b 100644 --- a/src/test/main.cpp +++ b/src/test/main.cpp @@ -229,6 +229,7 @@ int main(int argc, char ** argv) { TST_ARGV(ddnf); TST(model_evaluator); TST(get_consequences); + TST(pb2bv); //TST_ARGV(hs); } diff --git a/src/test/pb2bv.cpp b/src/test/pb2bv.cpp new file mode 100644 index 000000000..c114997c5 --- /dev/null +++ b/src/test/pb2bv.cpp @@ -0,0 +1,195 @@ +/*++ +Copyright (c) 2015 Microsoft Corporation + +--*/ + +#include "trace.h" +#include "vector.h" +#include "ast.h" +#include "ast_pp.h" +#include "statistics.h" +#include "reg_decl_plugins.h" +#include "pb2bv_rewriter.h" +#include "smt_kernel.h" +#include "model_smt2_pp.h" +#include "smt_params.h" +#include "ast_util.h" +#include "pb_decl_plugin.h" +#include "th_rewriter.h" +#include "fd_solver.h" +#include "solver.h" + +static void test1() { + ast_manager m; + reg_decl_plugins(m); + pb_util pb(m); + params_ref p; + pb2bv_rewriter rw(m, p); + expr_ref_vector vars(m); + unsigned N = 5; + for (unsigned i = 0; i < N; ++i) { + std::stringstream strm; + strm << "b" << i; + vars.push_back(m.mk_const(symbol(strm.str().c_str()), m.mk_bool_sort())); + } + + for (unsigned k = 1; k <= N; ++k) { + expr_ref fml(m), result(m); + proof_ref proof(m); + fml = pb.mk_at_least_k(vars.size(), vars.c_ptr(), k); + rw(fml, result, proof); + std::cout << fml << " |-> " << result << "\n"; + } + expr_ref_vector lemmas(m); + rw.flush_side_constraints(lemmas); + std::cout << lemmas << "\n"; +} + +static void test_semantics(ast_manager& m, expr_ref_vector const& vars, vector const& coeffs, unsigned k, unsigned kind) { + pb_util pb(m); + params_ref p; + pb2bv_rewriter rw(m, p); + unsigned N = vars.size(); + expr_ref fml1(m), fml2(m), result1(m), result2(m); + proof_ref proof(m); + expr_ref_vector lemmas(m); + th_rewriter th_rw(m); + + switch (kind) { + case 0: fml1 = pb.mk_ge(vars.size(), coeffs.c_ptr(), vars.c_ptr(), rational(k)); break; + case 1: fml1 = pb.mk_le(vars.size(), coeffs.c_ptr(), vars.c_ptr(), rational(k)); break; + default: fml1 = pb.mk_eq(vars.size(), coeffs.c_ptr(), vars.c_ptr(), rational(k)); break; + } + rw(fml1, result1, proof); + rw.flush_side_constraints(lemmas); + std::cout << lemmas << "\n"; + for (unsigned values = 0; values < static_cast(1 << N); ++values) { + smt_params fp; + smt::kernel solver(m, fp); + expr_ref_vector tf(m); + for (unsigned i = 0; i < N; ++i) { + bool is_true = 0 != (values & (1 << i)); + tf.push_back(is_true ? m.mk_true() : m.mk_false()); + solver.assert_expr(is_true ? vars[i] : m.mk_not(vars[i])); + } + + solver.assert_expr(lemmas); + switch (kind) { + case 0: fml2 = pb.mk_ge(tf.size(), coeffs.c_ptr(), tf.c_ptr(), rational(k)); break; + case 1: fml2 = pb.mk_le(tf.size(), coeffs.c_ptr(), tf.c_ptr(), rational(k)); break; + default: fml2 = pb.mk_eq(tf.size(), coeffs.c_ptr(), tf.c_ptr(), rational(k)); break; + } + std::cout << fml1 << " " << fml2 << "\n"; + th_rw(fml2, result2, proof); + SASSERT(m.is_true(result2) || m.is_false(result2)); + lbool res = solver.check(); + SASSERT(res == l_true); + solver.assert_expr(m.is_true(result2) ? m.mk_not(result1) : result1.get()); + res = solver.check(); + SASSERT(res == l_false); + } +} + +static void test_semantics(ast_manager& m, expr_ref_vector const& vars, vector const& coeffs, unsigned k) { + test_semantics(m, vars, coeffs, k, 0); + test_semantics(m, vars, coeffs, k, 1); + test_semantics(m, vars, coeffs, k, 2); +} + +static void test2() { + ast_manager m; + reg_decl_plugins(m); + expr_ref_vector vars(m); + unsigned N = 4; + for (unsigned i = 0; i < N; ++i) { + std::stringstream strm; + strm << "b" << i; + vars.push_back(m.mk_const(symbol(strm.str().c_str()), m.mk_bool_sort())); + } + for (unsigned coeff = 0; coeff < static_cast(1 << N); ++coeff) { + vector coeffs; + for (unsigned i = 0; i < N; ++i) { + bool is_one = 0 != (coeff & (1 << i)); + coeffs.push_back(is_one ? rational(1) : rational(2)); + } + for (unsigned i = 0; i <= N; ++i) { + test_semantics(m, vars, coeffs, i); + } + } +} + + +static void test_solver_semantics(ast_manager& m, expr_ref_vector const& vars, vector const& coeffs, unsigned k, unsigned kind) { + pb_util pb(m); + params_ref p; + unsigned N = vars.size(); + expr_ref fml1(m), fml2(m), result1(m), result2(m); + proof_ref proof(m); + th_rewriter th_rw(m); + + switch (kind) { + case 0: fml1 = pb.mk_ge(vars.size(), coeffs.c_ptr(), vars.c_ptr(), rational(k)); break; + case 1: fml1 = pb.mk_le(vars.size(), coeffs.c_ptr(), vars.c_ptr(), rational(k)); break; + default: fml1 = pb.mk_eq(vars.size(), coeffs.c_ptr(), vars.c_ptr(), rational(k)); break; + } + result1 = m.mk_fresh_const("xx", m.mk_bool_sort()); + for (unsigned values = 0; values < static_cast(1 << N); ++values) { + ref slv = mk_fd_solver(m, p); + expr_ref_vector tf(m); + for (unsigned i = 0; i < N; ++i) { + bool is_true = 0 != (values & (1 << i)); + tf.push_back(is_true ? m.mk_true() : m.mk_false()); + slv->assert_expr(is_true ? vars[i] : m.mk_not(vars[i])); + } + slv->assert_expr(m.mk_eq(result1, fml1)); + + switch (kind) { + case 0: fml2 = pb.mk_ge(tf.size(), coeffs.c_ptr(), tf.c_ptr(), rational(k)); break; + case 1: fml2 = pb.mk_le(tf.size(), coeffs.c_ptr(), tf.c_ptr(), rational(k)); break; + default: fml2 = pb.mk_eq(tf.size(), coeffs.c_ptr(), tf.c_ptr(), rational(k)); break; + } + std::cout << fml1 << " " << fml2 << "\n"; + th_rw(fml2, result2, proof); + SASSERT(m.is_true(result2) || m.is_false(result2)); + lbool res = slv->check_sat(0,0); + SASSERT(res == l_true); + slv->assert_expr(m.is_true(result2) ? m.mk_not(result1) : result1.get()); + res = slv->check_sat(0,0); + SASSERT(res == l_false); + } +} + +static void test_solver_semantics(ast_manager& m, expr_ref_vector const& vars, vector const& coeffs, unsigned k) { + test_solver_semantics(m, vars, coeffs, k, 0); + test_solver_semantics(m, vars, coeffs, k, 1); + test_solver_semantics(m, vars, coeffs, k, 2); +} + +static void test3() { + ast_manager m; + reg_decl_plugins(m); + expr_ref_vector vars(m); + unsigned N = 4; + for (unsigned i = 0; i < N; ++i) { + std::stringstream strm; + strm << "b" << i; + vars.push_back(m.mk_const(symbol(strm.str().c_str()), m.mk_bool_sort())); + } + for (unsigned coeff = 0; coeff < static_cast(1 << N); ++coeff) { + vector coeffs; + for (unsigned i = 0; i < N; ++i) { + bool is_one = 0 != (coeff & (1 << i)); + coeffs.push_back(is_one ? rational(1) : rational(2)); + } + for (unsigned i = 0; i <= N; ++i) { + test_solver_semantics(m, vars, coeffs, i); + } + } +} + +void tst_pb2bv() { + test1(); + test2(); + test3(); +} + diff --git a/src/util/sorting_network.h b/src/util/sorting_network.h index 31ad8a452..0f5d2838e 100644 --- a/src/util/sorting_network.h +++ b/src/util/sorting_network.h @@ -226,7 +226,12 @@ Notes: m_t = EQ; card(k+1, n, xs, out); SASSERT(out.size() >= k+1); - return ctx.mk_min(out[k-1], ctx.mk_not(out[k])); + if (k == 0) { + return ctx.mk_not(out[k]); + } + else { + return ctx.mk_min(out[k-1], ctx.mk_not(out[k])); + } } } From ec5d4f111970ca74bacba12243f681e4a52660d5 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 23 Oct 2016 20:35:20 -0700 Subject: [PATCH 261/536] add example to exercise at-most-1 constraints Signed-off-by: Nikolaj Bjorner --- examples/python/all_interval_series.py | 69 ++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 examples/python/all_interval_series.py diff --git a/examples/python/all_interval_series.py b/examples/python/all_interval_series.py new file mode 100644 index 000000000..485363f02 --- /dev/null +++ b/examples/python/all_interval_series.py @@ -0,0 +1,69 @@ +from z3 import * +import time + +def diff_at_j_is_i(xs, j, i): + assert(0 <= j and j + 1 < len(xs)) + assert(1 <= i and i < len(xs)) + return Or([ And(xs[j][k], xs[j+1][k-i]) for k in range(i,len(xs))] + + [ And(xs[j][k], xs[j+1][k+i]) for k in range(0,len(xs)-i)]) + + +def ais(n): + xij = [ [ Bool("x_%d_%d" % (i,j)) for j in range(n)] for i in range(n) ] + s = SolverFor("QF_FD") +# Optionally replace by (slower) default solver if using +# more then just finite domains (Booleans, Bit-vectors, enumeration types +# and bounded integers) +# s = Solver() + for i in range(n): + s.add(AtMost(xij[i] + [1])) + s.add(Or(xij[i])) + for j in range(n): + xi = [ xij[i][j] for i in range(n) ] + s.add(AtMost(xi + [1])) + s.add(Or(xi)) + dji = [ [ diff_at_j_is_i(xij, j, i + 1) for i in range(n-1)] for j in range(n-1) ] + for j in range(n-1): + s.add(AtMost(dji[j] + [1])) + s.add(Or(dji[j])) + for i in range(n-1): + dj = [dji[j][i] for j in range(n-1)] + s.add(AtMost(dj + [1])) + s.add(Or(dj)) + return s, xij + +def process_model(s, xij, n): + # x_ij integer i is at position j + # d_ij difference between integer at position j, j+1 is i + # sum_j d_ij = 1 i = 1,...,n-1 + # sum_j x_ij = 1 + # sum_i x_ij = 1 + m = s.model() + block = [] + values = [] + for i in range(n): + k = -1 + for j in range(n): + if is_true(m.eval(xij[i][j])): + assert(k == -1) + block += [xij[i][j]] + k = j + values += [k] + print values + sys.stdout.flush() + return block + +def all_models(n): + count = 0 + s, xij = ais(n) + start = time.clock() + while sat == s.check(): + block = process_model(s, xij, n) + s.add(Not(And(block))) + count += 1 + print s.statistics() + print time.clock() - start + print count + +set_option(verbose=1) +all_models(12) From f609ee6298b1e1eedf70227513b9fc01e556adce Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 23 Oct 2016 20:44:25 -0700 Subject: [PATCH 262/536] add documentation Signed-off-by: Nikolaj Bjorner --- examples/python/all_interval_series.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/examples/python/all_interval_series.py b/examples/python/all_interval_series.py index 485363f02..d55017a56 100644 --- a/examples/python/all_interval_series.py +++ b/examples/python/all_interval_series.py @@ -1,3 +1,10 @@ +# Copyright Microsoft Research 2016 +# The following script finds sequences of length n-1 of +# integers 0,..,n-1 such that the difference of the n-1 +# adjacent entries fall in the range 0,..,n-1 +# This is known as the "The All-Interval Series Problem" +# See http://www.csplib.org/Problems/prob007/ + from z3 import * import time From b476784f23923e485f016107552d54b24b2ad1af Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 23 Oct 2016 20:52:44 -0700 Subject: [PATCH 263/536] add missing file Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/enum2bv_rewriter.h | 48 +++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 src/ast/rewriter/enum2bv_rewriter.h diff --git a/src/ast/rewriter/enum2bv_rewriter.h b/src/ast/rewriter/enum2bv_rewriter.h new file mode 100644 index 000000000..1b2c6160f --- /dev/null +++ b/src/ast/rewriter/enum2bv_rewriter.h @@ -0,0 +1,48 @@ +/*++ +Copyright (c) 2016 Microsoft Corporation + +Module Name: + + enum2bv_rewriter.h + +Abstract: + + Conversion from enumeration types to bit-vectors. + +Author: + + Nikolaj Bjorner (nbjorner) 2016-10-18 + +Notes: + +--*/ +#ifndef ENUM_REWRITER_H_ +#define ENUM_REWRITER_H_ + +#include"datatype_decl_plugin.h" +#include"rewriter_types.h" +#include"expr_functors.h" + +class enum2bv_rewriter { + struct imp; + imp* m_imp; +public: + enum2bv_rewriter(ast_manager & m, params_ref const& p); + ~enum2bv_rewriter(); + + void updt_params(params_ref const & p); + ast_manager & m() const; + unsigned get_num_steps() const; + void cleanup(); + obj_map const& enum2bv() const; + obj_map const& bv2enum() const; + obj_map const& enum2def() const; + void operator()(expr * e, expr_ref & result, proof_ref & result_proof); + void push(); + void pop(unsigned num_scopes); + void flush_side_constraints(expr_ref_vector& side_constraints); + unsigned num_translated() const; + void set_is_fd(i_sort_pred* sp) const; +}; + +#endif From 4f3f21bff157152f0fa8927c57ec7dd1810c4f23 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 23 Oct 2016 21:45:35 -0700 Subject: [PATCH 264/536] disable local optimization in presence of non-linear constraints, addresses issue #758 Signed-off-by: Nikolaj Bjorner --- src/smt/theory_arith_aux.h | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/smt/theory_arith_aux.h b/src/smt/theory_arith_aux.h index d2db3a603..50bfee20e 100644 --- a/src/smt/theory_arith_aux.h +++ b/src/smt/theory_arith_aux.h @@ -1056,6 +1056,11 @@ namespace smt { inf_eps_rational theory_arith::maximize(theory_var v, expr_ref& blocker, bool& has_shared) { TRACE("bound_bug", display_var(tout, v); display(tout);); has_shared = false; + if (!m_nl_monomials.empty()) { + has_shared = true; + blocker = mk_gt(v); + return inf_eps_rational(get_value(v)); + } max_min_t r = max_min(v, true, true, has_shared); if (r == UNBOUNDED) { has_shared = false; @@ -1300,6 +1305,7 @@ namespace smt { */ + template bool theory_arith::pick_var_to_leave( @@ -1331,7 +1337,7 @@ namespace smt { if (update_gains(inc, s, coeff_ij, min_gain, max_gain) || (x_i == null_theory_var && !unbounded_gain(max_gain))) { x_i = s; - a_ij = coeff_ij; + a_ij = coeff_ij; } has_shared |= ctx.is_shared(get_enode(s)); } From 5716eaafed5136adb7e5bfcc1c4ab147b13b3e81 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Wed, 14 Sep 2016 13:49:49 +0100 Subject: [PATCH 265/536] whitespace --- src/smt/smt_conflict_resolution.cpp | 164 ++++++++++++++-------------- 1 file changed, 82 insertions(+), 82 deletions(-) diff --git a/src/smt/smt_conflict_resolution.cpp b/src/smt/smt_conflict_resolution.cpp index b28c4e773..4568abb55 100644 --- a/src/smt/smt_conflict_resolution.cpp +++ b/src/smt/smt_conflict_resolution.cpp @@ -22,13 +22,13 @@ Revision History: #include"ast_ll_pp.h" namespace smt { - + // --------------------------- // // Base class // // --------------------------- - + conflict_resolution::conflict_resolution(ast_manager & m, context & ctx, dyn_ack_manager & dyn_ack_manager, @@ -42,7 +42,7 @@ namespace smt { m_dyn_ack_manager(dyn_ack_manager), m_assigned_literals(assigned_literals), m_lemma_atoms(m), - m_todo_js_qhead(0), + m_todo_js_qhead(0), m_antecedents(0), m_watches(watches), m_new_proofs(m), @@ -67,7 +67,7 @@ namespace smt { } /** - \brief Find a common ancestor (anc) of n1 and n2 in the 'proof' tree. + \brief Find a common ancestor (anc) of n1 and n2 in the 'proof' tree. The common ancestor is used to produce irredundant transitivity proofs. n1 = a1 = ... = ai = ANC = ... = root @@ -100,7 +100,7 @@ namespace smt { */ void conflict_resolution::eq_justification2literals(enode * lhs, enode * rhs, eq_justification js) { SASSERT(m_antecedents); - TRACE("conflict_detail", + 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()) { @@ -133,7 +133,7 @@ namespace smt { mark_eq(lhs->get_arg(1), rhs->get_arg(0)); } else { - for (unsigned i = 0; i < num_args; i++) + for (unsigned i = 0; i < num_args; i++) mark_eq(lhs->get_arg(i), rhs->get_arg(i)); } break; @@ -146,9 +146,9 @@ namespace smt { /** \brief Process the transitivity 'proof' from n1 and n2, where n1 and n2 are in the same branch - + n1 -> ... -> n2 - + This method may update m_antecedents, m_todo_js and m_todo_eqs. The resultant set of literals is stored in m_antecedents. @@ -163,7 +163,7 @@ namespace smt { /** \brief Process the justification of n1 = n2. - + This method may update m_antecedents, m_todo_js and m_todo_eqs. The resultant set of literals is stored in m_antecedents. @@ -180,8 +180,8 @@ namespace smt { The result is stored in result. - \remark This method does not reset the vectors m_antecedents, m_todo_js, m_todo_eqs, nor reset the - marks in the justification objects. + \remark This method does not reset the vectors m_antecedents, m_todo_js, m_todo_eqs, nor reset the + marks in the justification objects. */ void conflict_resolution::justification2literals_core(justification * js, literal_vector & result) { SASSERT(m_todo_js_qhead <= m_todo_js.size()); @@ -294,13 +294,13 @@ namespace smt { if (js) r = std::max(r, get_justification_max_lvl(js)); break; - } + } case b_justification::BIN_CLAUSE: r = std::max(r, m_ctx.get_assign_level(js.get_literal())); break; case b_justification::AXIOM: break; - case b_justification::JUSTIFICATION: + case b_justification::JUSTIFICATION: r = std::max(r, get_justification_max_lvl(js.get_justification())); break; default: @@ -313,8 +313,8 @@ namespace smt { bool_var var = antecedent.var(); unsigned lvl = m_ctx.get_assign_level(var); SASSERT(var < static_cast(m_ctx.get_num_bool_vars())); - TRACE("conflict", tout << "processing antecedent (level " << lvl << "):"; - m_ctx.display_literal(tout, antecedent); + TRACE("conflict", tout << "processing antecedent (level " << lvl << "):"; + m_ctx.display_literal(tout, antecedent); m_ctx.display_detailed_literal(tout << " ", antecedent); tout << "\n";); if (!m_ctx.is_marked(var) && lvl > m_ctx.get_base_level()) { @@ -386,17 +386,17 @@ namespace smt { consequent = false_literal; if (not_l != null_literal) consequent = ~not_l; - + m_conflict_lvl = get_max_lvl(consequent, js); - TRACE("conflict_bug", - tout << "conflict_lvl: " << m_conflict_lvl << " scope_lvl: " << m_ctx.get_scope_level() << " base_lvl: " << m_ctx.get_base_level() + TRACE("conflict_bug", + tout << "conflict_lvl: " << m_conflict_lvl << " scope_lvl: " << m_ctx.get_scope_level() << " base_lvl: " << m_ctx.get_base_level() << " search_lvl: " << m_ctx.get_search_level() << "\n"; tout << "js.kind: " << js.get_kind() << "\n"; tout << "consequent: " << consequent << ": "; m_ctx.display_literal_verbose(tout, consequent); tout << "\n"; m_ctx.display(tout, js); tout << "\n"; - ); + ); // m_conflict_lvl can be smaller than m_ctx.get_search_level() when: // there are user level scopes created using the Z3 API, and @@ -413,7 +413,7 @@ namespace smt { } TRACE("conflict", tout << "conflict_lvl: " << m_conflict_lvl << "\n";); - + SASSERT(!m_assigned_literals.empty()); SASSERT(m_todo_js.empty()); @@ -425,32 +425,32 @@ namespace smt { /** \brief Cleanup datastructures used during resolve(), minimize lemma (when minimization is enabled), compute m_new_scope_lvl and m_lemma_iscope_lvl, generate proof if needed. - + This method assumes that the lemma is stored in m_lemma (and the associated atoms in m_lemma_atoms). - + \warning This method assumes the literals in m_lemma[1] ... m_lemma[m_lemma.size() - 1] are marked. */ void conflict_resolution::finalize_resolve(b_justification conflict, literal not_l) { unmark_justifications(0); - + TRACE("conflict", tout << "before minimization:\n"; m_ctx.display_literals(tout, m_lemma); tout << "\n";); - + TRACE("conflict_verbose", tout << "before minimization:\n"; m_ctx.display_literals_verbose(tout, m_lemma); tout << "\n";); - + if (m_params.m_minimize_lemmas) minimize_lemma(); - + TRACE("conflict", tout << "after minimization:\n"; m_ctx.display_literals(tout, m_lemma); tout << "\n";); - + TRACE("conflict_verbose", tout << "after minimization:\n"; m_ctx.display_literals_verbose(tout, m_lemma); @@ -459,7 +459,7 @@ namespace smt { TRACE("conflict_bug", m_ctx.display_literals_verbose(tout, m_lemma); tout << "\n";); - + literal_vector::iterator it = m_lemma.begin(); literal_vector::iterator end = m_lemma.end(); m_new_scope_lvl = m_ctx.get_search_level(); @@ -478,11 +478,11 @@ namespace smt { m_lemma_iscope_lvl = lvl; } } - + TRACE("conflict", tout << "new scope level: " << m_new_scope_lvl << "\n"; tout << "intern. scope level: " << m_lemma_iscope_lvl << "\n";); - + if (m_manager.proofs_enabled()) mk_conflict_proof(conflict, not_l); } @@ -505,7 +505,7 @@ namespace smt { TRACE("conflict", tout << "not_l: "; m_ctx.display_literal(tout, not_l); tout << "\n";); process_antecedent(not_l, num_marks); } - + do { if (get_manager().has_trace_stream()) { @@ -542,7 +542,7 @@ namespace smt { process_antecedent(~l, num_marks); } justification * js = cls->get_justification(); - if (js) + if (js) process_justification(js, num_marks); break; } @@ -558,13 +558,13 @@ namespace smt { default: UNREACHABLE(); } - + while (true) { literal l = m_assigned_literals[idx]; - if (m_ctx.is_marked(l.var())) + if (m_ctx.is_marked(l.var())) break; CTRACE("conflict", m_ctx.get_assign_level(l) != m_conflict_lvl && m_ctx.get_assign_level(l) != m_ctx.get_base_level(), - tout << "assign_level(l): " << m_ctx.get_assign_level(l) << ", conflict_lvl: " << m_conflict_lvl << ", l: "; m_ctx.display_literal(tout, l); + tout << "assign_level(l): " << m_ctx.get_assign_level(l) << ", conflict_lvl: " << m_conflict_lvl << ", l: "; m_ctx.display_literal(tout, l); tout << "\n";); SASSERT(m_ctx.get_assign_level(l) == m_conflict_lvl || // it may also be an (out-of-order) asserted literal @@ -580,7 +580,7 @@ namespace smt { idx--; num_marks--; m_ctx.unset_mark(c_var); - } + } while (num_marks > 0); TRACE("conflict", tout << "FUIP: "; m_ctx.display_literal(tout, consequent); tout << "\n";); @@ -589,8 +589,8 @@ namespace smt { m_lemma_atoms.set(0, m_ctx.bool_var2expr(consequent.var())); // TODO: - // - // equality optimization should go here. + // + // equality optimization should go here. // finalize_resolve(conflict, not_l); @@ -600,7 +600,7 @@ namespace smt { /** \brief Return an approximation for the set of scope levels where the literals in m_lemma - were assigned. + were assigned. */ level_approx_set conflict_resolution::get_lemma_approx_level_set() { level_approx_set result; @@ -640,7 +640,7 @@ namespace smt { unsigned lvl = m_ctx.get_assign_level(var); if (!m_ctx.is_marked(var) && lvl > m_ctx.get_base_level()) { if (m_lvl_set.may_contain(lvl)) { - m_ctx.set_mark(var); + m_ctx.set_mark(var); m_unmark.push_back(var); m_lemma_min_stack.push_back(var); } @@ -667,18 +667,18 @@ namespace smt { } /** - \brief Return true if lit is implied by other marked literals - and/or literals assigned at the base level. - The set lvl_set is used as an optimization. + \brief Return true if lit is implied by other marked literals + and/or literals assigned at the base level. + The set lvl_set is used as an optimization. The idea is to stop the recursive search with a failure - as soon as we find a literal assigned in a level that is not in lvl_set. + as soon as we find a literal assigned in a level that is not in lvl_set. */ bool conflict_resolution::implied_by_marked(literal lit) { m_lemma_min_stack.reset(); // avoid recursive function m_lemma_min_stack.push_back(lit.var()); unsigned old_size = m_unmark.size(); unsigned old_js_qhead = m_todo_js_qhead; - + while (!m_lemma_min_stack.empty()) { bool_var var = m_lemma_min_stack.back(); m_lemma_min_stack.pop_back(); @@ -739,7 +739,7 @@ namespace smt { m_unmark.reset(); m_lvl_set = get_lemma_approx_level_set(); - + unsigned sz = m_lemma.size(); unsigned i = 1; // the first literal is the FUIP unsigned j = 1; @@ -756,7 +756,7 @@ namespace smt { j++; } } - + reset_unmark_and_justifications(0, 0); m_lemma .shrink(j); m_lemma_atoms.shrink(j); @@ -810,7 +810,7 @@ namespace smt { } if (m_manager.coarse_grain_proofs()) return pr; - TRACE("norm_eq_proof", + TRACE("norm_eq_proof", tout << "#" << n1->get_owner_id() << " = #" << n2->get_owner_id() << "\n"; tout << mk_ll_pp(pr, m_manager, true, false);); SASSERT(m_manager.is_eq(fact) || m_manager.is_iff(fact)); @@ -906,7 +906,7 @@ namespace smt { return 0; } } - + /** \brief Return the proof object associated with the given literal if it already exists. Otherwise, return 0 and add l to the todo-list. @@ -939,13 +939,13 @@ namespace smt { // p1: is a proof of "A" // p2: is a proof of "not A" // [unit-resolution p1 p2]: false - // + // // Let us assume that "A" was assigned first during propagation. // Then, the "resolve" method will never select "not A" as a hypothesis. - // "not_A" will be the not_l argument in this method. + // "not_A" will be the not_l argument in this method. // Since we are assuming that "A" was assigned first", m_ctx.get_justification("A") will be // p1. - // + // // So, the test "m_ctx.get_justification(l.var()) == js" is used to check // if l was assigned before ~l. if ((m_ctx.is_marked(l.var()) && m_ctx.get_justification(l.var()) == js) || (js.get_kind() == b_justification::AXIOM)) { @@ -1022,11 +1022,11 @@ namespace smt { tout << mk_pp(m_manager.get_fact(prs[i]), m_manager) << "\n"; } tout << "consequent:\n" << mk_pp(l_exr, m_manager) << "\n";); - TRACE("get_proof", + TRACE("get_proof", tout << l.index() << " " << true_literal.index() << " " << false_literal.index() << " "; m_ctx.display_literal(tout, l); tout << " --->\n"; tout << mk_ll_pp(l_exr, m_manager);); - CTRACE("get_proof_bug_after", + CTRACE("get_proof_bug_after", invocation_counter >= DUMP_AFTER_NUM_INVOCATIONS, tout << l.index() << " " << true_literal.index() << " " << false_literal.index() << " "; m_ctx.display_literal(tout, l); tout << " --->\n"; @@ -1040,7 +1040,7 @@ namespace smt { } } } - + /** \brief Return the proof object associated with the given justification if it already exists. Otherwise, return 0 and add js to the todo-list. @@ -1094,7 +1094,7 @@ namespace smt { i = 2; } } - for (; i < num_lits; i++) + for (; i < num_lits; i++) if (get_proof(~cls->get_literal(i)) == 0) visited = false; return visited; @@ -1109,7 +1109,7 @@ namespace smt { SASSERT(pr); TRACE("proof_gen_bug", tout << "lit2pr_saved: #" << l << "\n";); m_lit2proof.insert(l, pr); - TRACE("mk_proof", + TRACE("mk_proof", tout << mk_bounded_pp(m_ctx.bool_var2expr(l.var()), m_manager, 10) << "\n"; tout << "storing proof for: "; m_ctx.display_literal(tout, l); tout << "\n"; tout << mk_ll_pp(pr, m_manager);); @@ -1118,7 +1118,7 @@ namespace smt { /** \brief Given that lhs = ... = rhs, and lhs reaches rhs in the 'proof' tree branch. Then, return true if all proof objects needed to create the proof steps are already - available. Otherwise return false and update m_todo_pr with info about the proof + available. Otherwise return false and update m_todo_pr with info about the proof objects that need to be created. */ bool conflict_resolution::visit_trans_proof(enode * lhs, enode * rhs) { @@ -1174,7 +1174,7 @@ namespace smt { /** \brief Return true if all proof objects that are used to build the proof that lhs = rhs were - already built. If the result is false, then m_todo_pr is updated with info about the proof + already built. If the result is false, then m_todo_pr is updated with info about the proof objects that need to be created. */ bool conflict_resolution::visit_eq_justications(enode * lhs, enode * rhs) { @@ -1226,7 +1226,7 @@ namespace smt { if (prs1.size() == 1) pr = prs1[0]; else { - TRACE("mk_transitivity", + TRACE("mk_transitivity", unsigned sz = prs1.size(); for (unsigned i = 0; i < sz; i++) { tout << mk_ll_pp(prs1[i], m_manager) << "\n"; @@ -1288,7 +1288,7 @@ namespace smt { } case tp_elem::LITERAL: { literal l = to_literal(elem.m_lidx); - if (m_lit2proof.contains(l)) + if (m_lit2proof.contains(l)) m_todo_pr.pop_back(); else { b_justification js = m_ctx.get_justification(l.var()); @@ -1342,11 +1342,11 @@ namespace smt { void conflict_resolution::process_antecedent_for_unsat_core(literal antecedent) { bool_var var = antecedent.var(); - TRACE("conflict", tout << "processing antecedent: "; - m_ctx.display_literal_info(tout << antecedent << " ", antecedent); - tout << (m_ctx.is_marked(var)?"marked":"not marked"); - tout << "\n";); - + TRACE("conflict", tout << "processing antecedent: "; + m_ctx.display_literal_info(tout << antecedent << " ", antecedent); + tout << (m_ctx.is_marked(var)?"marked":"not marked"); + tout << "\n";); + if (!m_ctx.is_marked(var)) { m_ctx.set_mark(var); m_unmark.push_back(var); @@ -1355,7 +1355,7 @@ namespace smt { m_assumptions.push_back(antecedent); } } - + void conflict_resolution::process_justification_for_unsat_core(justification * js) { literal_vector & antecedents = m_tmp_literal_vector; antecedents.reset(); @@ -1370,7 +1370,7 @@ namespace smt { SASSERT(m_ctx.tracking_assumptions()); m_assumptions.reset(); m_unmark.reset(); - + SASSERT(m_conflict_lvl <= m_ctx.get_search_level()); unsigned search_lvl = m_ctx.get_search_level(); @@ -1378,17 +1378,17 @@ namespace smt { literal consequent = false_literal; if (not_l != null_literal) { consequent = ~not_l; - } - + } + int idx = skip_literals_above_conflict_level(); - + if (not_l != null_literal) process_antecedent_for_unsat_core(consequent); - + if (m_assigned_literals.empty()) { goto end_unsat_core; } - + while (true) { TRACE("unsat_core_bug", tout << consequent << " js.get_kind(): " << js.get_kind() << ", idx: " << idx << "\n";); switch (js.get_kind()) { @@ -1411,7 +1411,7 @@ namespace smt { process_antecedent_for_unsat_core(~l); } justification * js = cls->get_justification(); - if (js) + if (js) process_justification_for_unsat_core(js); break; } @@ -1430,17 +1430,17 @@ namespace smt { if (m_ctx.is_assumption(consequent.var())) { m_assumptions.push_back(consequent); - } + } while (idx >= 0) { literal l = m_assigned_literals[idx]; TRACE("unsat_core_bug", tout << "l: " << l << ", get_assign_level(l): " << m_ctx.get_assign_level(l) << ", is_marked(l): " << m_ctx.is_marked(l.var()) << "\n";); - if (m_ctx.get_assign_level(l) < search_lvl) - goto end_unsat_core; - if (m_ctx.is_marked(l.var())) + if (m_ctx.get_assign_level(l) < search_lvl) + goto end_unsat_core; + if (m_ctx.is_marked(l.var())) break; idx--; } - if (idx < 0) { + if (idx < 0) { goto end_unsat_core; } @@ -1456,12 +1456,12 @@ namespace smt { TRACE("unsat_core", tout << "assumptions:\n"; m_ctx.display_literals(tout, m_assumptions); tout << "\n";); reset_unmark_and_justifications(0, 0); } - - conflict_resolution * mk_conflict_resolution(ast_manager & m, + + conflict_resolution * mk_conflict_resolution(ast_manager & m, context & ctx, dyn_ack_manager & dack_manager, smt_params const & params, - literal_vector const & assigned_literals, + literal_vector const & assigned_literals, vector & watches) { return alloc(conflict_resolution, m, ctx, dack_manager, params, assigned_literals, watches); } From 6b474adc8adb3e8a01a04b76055fa2a59674c48f Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Fri, 16 Sep 2016 16:48:22 +0100 Subject: [PATCH 266/536] Added accessors to extract sign/exponent/significand BV numerals from FP numerals. --- src/api/api_fpa.cpp | 97 +++++++++++++++++++++++++++++++++++++++++ src/api/dotnet/FPNum.cs | 52 +++++++++++++++++++--- src/api/java/FPNum.java | 27 ++++++++++++ src/api/ml/z3.ml | 3 ++ src/api/ml/z3.mli | 12 +++++ src/api/python/z3/z3.py | 24 ++++++++++ src/api/z3_fpa.h | 36 +++++++++++++++ 7 files changed, 246 insertions(+), 5 deletions(-) diff --git a/src/api/api_fpa.cpp b/src/api/api_fpa.cpp index 5d423c725..048113eca 100644 --- a/src/api/api_fpa.cpp +++ b/src/api/api_fpa.cpp @@ -909,6 +909,8 @@ extern "C" { Z3_TRY; LOG_Z3_fpa_get_numeral_sign(c, t, sgn); RESET_ERROR_CODE(); + CHECK_NON_NULL(t, 0); + CHECK_VALID_AST(t, 0); ast_manager & m = mk_c(c)->m(); mpf_manager & mpfm = mk_c(c)->fpautil().fm(); fpa_decl_plugin * plugin = (fpa_decl_plugin*)m.get_plugin(mk_c(c)->get_fpa_fid()); @@ -929,6 +931,101 @@ extern "C" { Z3_CATCH_RETURN(0); } + Z3_ast Z3_API Z3_fpa_get_numeral_sign_bv(Z3_context c, Z3_ast t) { + Z3_TRY; + LOG_Z3_fpa_get_numeral_sign_bv(c, t); + RESET_ERROR_CODE(); + CHECK_NON_NULL(t, 0); + CHECK_VALID_AST(t, 0); + ast_manager & m = mk_c(c)->m(); + mpf_manager & mpfm = mk_c(c)->fpautil().fm(); + unsynch_mpq_manager & mpqm = mpfm.mpq_manager(); + family_id fid = mk_c(c)->get_fpa_fid(); + fpa_util & fu = mk_c(c)->fpautil(); + api::context * ctx = mk_c(c); + expr * e = to_expr(t); + if (!is_app(e) || + is_app_of(e, fid, OP_FPA_NAN)) { + SET_ERROR_CODE(Z3_INVALID_ARG); + RETURN_Z3(0); + } + if (is_app_of(e, fid, OP_FPA_PLUS_INF)) { + expr * r = ctx->bvutil().mk_numeral(0, 1); + ctx->save_ast_trail(r); + RETURN_Z3(of_expr(r)); + } + if (is_app_of(e, fid, OP_FPA_MINUS_INF)) { + expr * r = ctx->bvutil().mk_numeral(1, 1); + ctx->save_ast_trail(r); + RETURN_Z3(of_expr(r)); + } + if (!fu.is_fp(e)) { + SET_ERROR_CODE(Z3_INVALID_ARG); + RETURN_Z3(0); + } + app * a = to_app(e); + RETURN_Z3(of_expr(a->get_arg(0))); + Z3_CATCH_RETURN(0); + } + + Z3_ast Z3_API Z3_fpa_get_numeral_exponent_bv(Z3_context c, Z3_ast t) { + Z3_TRY; + LOG_Z3_fpa_get_numeral_exponent_bv(c, t); + RESET_ERROR_CODE(); + CHECK_NON_NULL(t, 0); + CHECK_VALID_AST(t, 0); + ast_manager & m = mk_c(c)->m(); + mpf_manager & mpfm = mk_c(c)->fpautil().fm(); + unsynch_mpq_manager & mpqm = mpfm.mpq_manager(); + family_id fid = mk_c(c)->get_fpa_fid(); + fpa_util & fu = mk_c(c)->fpautil(); + expr * e = to_expr(t); + if (!is_app(e) || + is_app_of(e, fid, OP_FPA_NAN) || + is_app_of(e, fid, OP_FPA_PLUS_INF) || + is_app_of(e, fid, OP_FPA_MINUS_INF)) { + SET_ERROR_CODE(Z3_INVALID_ARG); + RETURN_Z3(0); + } + if (!fu.is_fp(e)) { + SET_ERROR_CODE(Z3_INVALID_ARG); + RETURN_Z3(0); + } + api::context * ctx = mk_c(c); + app * a = to_app(e); + RETURN_Z3(of_expr(a->get_arg(1))); + Z3_CATCH_RETURN(0); + } + + Z3_ast Z3_API Z3_fpa_get_numeral_significand_bv(Z3_context c, Z3_ast t) { + Z3_TRY; + LOG_Z3_fpa_get_numeral_significand_bv(c, t); + RESET_ERROR_CODE(); + CHECK_NON_NULL(t, 0); + CHECK_VALID_AST(t, 0); + ast_manager & m = mk_c(c)->m(); + mpf_manager & mpfm = mk_c(c)->fpautil().fm(); + unsynch_mpq_manager & mpqm = mpfm.mpq_manager(); + family_id fid = mk_c(c)->get_fpa_fid(); + fpa_util & fu = mk_c(c)->fpautil(); + expr * e = to_expr(t); + if (!is_app(e) || + is_app_of(e, fid, OP_FPA_NAN) || + is_app_of(e, fid, OP_FPA_PLUS_INF) || + is_app_of(e, fid, OP_FPA_MINUS_INF)) { + SET_ERROR_CODE(Z3_INVALID_ARG); + RETURN_Z3(0); + } + if (!fu.is_fp(e)) { + SET_ERROR_CODE(Z3_INVALID_ARG); + RETURN_Z3(0); + } + api::context * ctx = mk_c(c); + app * a = to_app(e); + RETURN_Z3(of_expr(a->get_arg(2))); + Z3_CATCH_RETURN(0); + } + Z3_string Z3_API Z3_fpa_get_numeral_significand_string(Z3_context c, Z3_ast t) { Z3_TRY; LOG_Z3_fpa_get_numeral_significand_string(c, t); diff --git a/src/api/dotnet/FPNum.cs b/src/api/dotnet/FPNum.cs index ac1fae5f5..ed0367481 100644 --- a/src/api/dotnet/FPNum.cs +++ b/src/api/dotnet/FPNum.cs @@ -14,7 +14,7 @@ Author: Christoph Wintersteiger (cwinter) 2013-06-10 Notes: - + --*/ using System; using System.Diagnostics.Contracts; @@ -27,6 +27,48 @@ namespace Microsoft.Z3 [ContractVerification(true)] public class FPNum : FPExpr { + /// + /// The sign of a floating-point numeral as a bit-vector expression + /// + /// + /// NaN's do not have a bit-vector sign, so they are invalid arguments. + /// + public BitVecExpr BVSign + { + get + { + return new BitVecExpr(Context, Native.Z3_fpa_get_numeral_sign_bv(Context.nCtx, NativeObject)); + } + } + + /// + /// The exponent of a floating-point numeral as a bit-vector expression + /// + /// + /// +oo, -oo and NaN's do not have a bit-vector exponent, so they are invalid arguments. + /// + public BitVecExpr BVExponent + { + get + { + return new BitVecExpr(Context, Native.Z3_fpa_get_numeral_exponent_bv(Context.nCtx, NativeObject)); + } + } + + /// + /// The significand of a floating-point numeral as a bit-vector expression + /// + /// + /// +oo, -oo and NaN's do not have a bit-vector significand, so they are invalid arguments. + /// + public BitVecExpr BVSignificand + { + get + { + return new BitVecExpr(Context, Native.Z3_fpa_get_numeral_significand_bv(Context.nCtx, NativeObject)); + } + } + /// /// Retrieves the sign of a floating-point literal /// @@ -38,7 +80,7 @@ namespace Microsoft.Z3 get { int res = 0; - if (Native.Z3_fpa_get_numeral_sign(Context.nCtx, NativeObject, ref res) == 0) + if (Native.Z3_fpa_get_numeral_sign(Context.nCtx, NativeObject, ref res) == 0) throw new Z3Exception("Sign is not a Boolean value"); return res != 0; } @@ -63,7 +105,7 @@ namespace Microsoft.Z3 /// The significand value of a floating-point numeral as a UInt64 /// /// - /// This function extracts the significand bits, without the + /// This function extracts the significand bits, without the /// hidden bit or normalization. Throws an exception if the /// significand does not fit into a UInt64. /// @@ -73,7 +115,7 @@ namespace Microsoft.Z3 { UInt64 result = 0; if (Native.Z3_fpa_get_numeral_significand_uint64(Context.nCtx, NativeObject, ref result) == 0) - throw new Z3Exception("Significand is not a 64 bit unsigned integer"); + throw new Z3Exception("Significand is not a 64 bit unsigned integer"); return result; } } @@ -113,7 +155,7 @@ namespace Microsoft.Z3 /// /// Returns a string representation of the numeral. - /// + /// public override string ToString() { return Native.Z3_get_numeral_string(Context.nCtx, NativeObject); diff --git a/src/api/java/FPNum.java b/src/api/java/FPNum.java index 402d25ebe..7bfca0f86 100644 --- a/src/api/java/FPNum.java +++ b/src/api/java/FPNum.java @@ -21,6 +21,33 @@ package com.microsoft.z3; */ public class FPNum extends FPExpr { + /** + * The sign of a floating-point numeral as a bit-vector expression + * Remarks: NaN's do not have a bit-vector sign, so they are invalid arguments. + * @throws Z3Exception + */ + public BitVecExpr getBVSign() { + return new BitVecExpr(getContext(), Native.fpaGetNumeralSignBv(getContext().nCtx(), getNativeObject())); + } + + /** + * The exponent of a floating-point numeral as a bit-vector expression + * Remarks: +oo, -oo, and NaN's do not have a bit-vector exponent, so they are invalid arguments. + * @throws Z3Exception + */ + public BitVecExpr getBVExponent() { + return new BitVecExpr(getContext(), Native.fpaGetNumeralExponentBv(getContext().nCtx(), getNativeObject())); + } + + /** + * The significand of a floating-point numeral as a bit-vector expression + * Remarks: +oo, -oo, and NaN's do not have a bit-vector significand, so they are invalid arguments. + * @throws Z3Exception + */ + public BitVecExpr getBVSignificand() { + return new BitVecExpr(getContext(), Native.fpaGetNumeralSignificandBv(getContext().nCtx(), getNativeObject())); + } + /** * Retrieves the sign of a floating-point literal * Remarks: returns true if the numeral is negative diff --git a/src/api/ml/z3.ml b/src/api/ml/z3.ml index b7016c4c8..613db591e 100644 --- a/src/api/ml/z3.ml +++ b/src/api/ml/z3.ml @@ -1324,6 +1324,9 @@ struct let mk_to_real = Z3native.mk_fpa_to_real let get_ebits = Z3native.fpa_get_ebits let get_sbits = Z3native.fpa_get_sbits + let get_numeral_sign_bv = Z3native.fpa_get_numeral_sign_bv + let get_numeral_exponent_bv = Z3native.fpa_get_numeral_exponent_bv + let get_numeral_significand_bv = Z3native.fpa_get_numeral_significand_bv let get_numeral_sign = Z3native.fpa_get_numeral_sign let get_numeral_significand_string = Z3native.fpa_get_numeral_significand_string let get_numeral_significand_uint = Z3native.fpa_get_numeral_significand_uint64 diff --git a/src/api/ml/z3.mli b/src/api/ml/z3.mli index 1c91b28aa..e08028c61 100644 --- a/src/api/ml/z3.mli +++ b/src/api/ml/z3.mli @@ -2138,6 +2138,18 @@ sig (** Retrieves the number of bits reserved for the significand in a FloatingPoint sort. *) val get_sbits : context -> Sort.sort -> int + (** Return the sign of a floating-point numeral as a bit-vector expression. + Remark: NaN's do not have a bit-vector sign, so they are invalid arguments. *) + val get_numeral_sign_bv : context -> Expr.expr -> Expr.expr + + (** Return the exponent of a floating-point numeral as a bit-vector expression. + Remark: +oo, -oo and NaN's do not have a bit-vector exponent, so they are invalid arguments. *) + val get_numeral_exponent_bv : context -> Expr.expr -> Expr.expr + + (** Return the significand value of a floating-point numeral as a bit-vector expression. + Remark: +oo, -oo and NaN's do not have a bit-vector significand, so they are invalid arguments. *) + val get_numeral_significand_bv : context -> Expr.expr -> Expr.expr + (** Retrieves the sign of a floating-point literal. *) val get_numeral_sign : context -> Expr.expr -> bool * int diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index a037bbc5d..fc9ef6d62 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -8446,6 +8446,30 @@ class FPNumRef(FPRef): k = self.decl().kind() return (self.num_args() == 0 and (k == Z3_OP_FPA_MINUS_INF or k == Z3_OP_FPA_MINUS_ZERO)) or (self.sign() == True) + """ + The sign of a floating-point numeral as a bit-vector expression + + Remark: NaN's do not have a bit-vector sign, so they are invalid arguments. + """ + def BVSign(self): + return BitVecNumRef(Z3_fpa_get_numeral_sign_bv(self.ctx.ref(), self.as_ast()), ctx) + + """ + The exponent of a floating-point numeral as a bit-vector expression + + Remark: +oo, -oo and NaN's do not have a bit-vector exponent, so they are invalid arguments. + """ + def BVExponent(self): + return BitVecNumRef(Z3_fpa_get_numeral_exponent_bv(self.ctx.ref(), self.as_ast()), ctx) + + """ + The sign of a floating-point numeral as a bit-vector expression + + Remark: +oo, -oo and NaN's do not have a bit-vector significand, so they are invalid arguments. + """ + def BVSignificand(self): + return BitVecNumRef(Z3_fpa_get_numeral_significand_bv(self.ctx.ref(), self.as_ast()), ctx) + """ The sign of the numeral. diff --git a/src/api/z3_fpa.h b/src/api/z3_fpa.h index 510fa0473..9abbb7b60 100644 --- a/src/api/z3_fpa.h +++ b/src/api/z3_fpa.h @@ -822,6 +822,42 @@ extern "C" { */ unsigned Z3_API Z3_fpa_get_sbits(Z3_context c, Z3_sort s); + /** + \brief Retrieves the sign of a floating-point literal as a bit-vector expression. + + \param c logical context + \param t a floating-point numeral + + Remarks: NaN is an invalid argument. + + def_API('Z3_fpa_get_numeral_sign_bv', AST, (_in(CONTEXT), _in(AST))) + */ + Z3_ast Z3_API Z3_fpa_get_numeral_sign_bv(Z3_context c, Z3_ast t); + + /** + \brief Retrieves the significand of a floating-point literal as a bit-vector expression. + + \param c logical context + \param t a floating-point numeral + + Remarks: +oo, -oo and NaN are invalid arguments. + + def_API('Z3_fpa_get_numeral_significand_bv', AST, (_in(CONTEXT), _in(AST))) + */ + Z3_ast Z3_API Z3_fpa_get_numeral_significand_bv(Z3_context c, Z3_ast t); + + /** + \brief Retrieves the exponent of a floating-point literal as a bit-vector expression. + + \param c logical context + \param t a floating-point numeral + + Remarks: +oo, -oo and NaN are invalid arguments. + + def_API('Z3_fpa_get_numeral_exponent_bv', AST, (_in(CONTEXT), _in(AST))) + */ + Z3_ast Z3_API Z3_fpa_get_numeral_exponent_bv(Z3_context c, Z3_ast t); + /** \brief Retrieves the sign of a floating-point literal. From 89d38385db100947e25229d40e5f2b88909e2891 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Mon, 17 Oct 2016 13:31:07 +0100 Subject: [PATCH 267/536] Added functions to test FP numerals for special values. --- src/api/api_fpa.cpp | 96 +++++++++++++++++++++++++++++++++++++++ src/api/z3_fpa.h | 60 ++++++++++++++++++++++++ src/ast/fpa_decl_plugin.h | 4 ++ 3 files changed, 160 insertions(+) diff --git a/src/api/api_fpa.cpp b/src/api/api_fpa.cpp index 048113eca..cc8648c2a 100644 --- a/src/api/api_fpa.cpp +++ b/src/api/api_fpa.cpp @@ -1183,4 +1183,100 @@ extern "C" { Z3_CATCH_RETURN(0); } + Z3_bool Z3_API Z3_fpa_is_numeral_nan(Z3_context c, Z3_ast t) { + Z3_TRY; + Z3_fpa_is_numeral_nan(c, t); + RESET_ERROR_CODE(); + ast_manager & m = mk_c(c)->m(); + api::context * ctx = mk_c(c); + mpf_manager & mpfm = mk_c(c)->fpautil().fm(); + fpa_util & fu = ctx->fpautil(); + if (!is_expr(t) || !fu.is_numeral(to_expr(t))) { + SET_ERROR_CODE(Z3_INVALID_ARG); + return 0; + } + return fu.is_nan(to_expr(t)); + Z3_CATCH_RETURN(Z3_FALSE); + } + + Z3_bool Z3_API Z3_fpa_is_numeral_inf(Z3_context c, Z3_ast t) { + Z3_TRY; + Z3_fpa_is_numeral_inf(c, t); + RESET_ERROR_CODE(); + ast_manager & m = mk_c(c)->m(); + api::context * ctx = mk_c(c); + mpf_manager & mpfm = mk_c(c)->fpautil().fm(); + fpa_util & fu = ctx->fpautil(); + if (!is_expr(t) || !fu.is_numeral(to_expr(t))) { + SET_ERROR_CODE(Z3_INVALID_ARG); + return 0; + } + return fu.is_inf(to_expr(t)); + Z3_CATCH_RETURN(Z3_FALSE); + } + + Z3_bool Z3_API Z3_fpa_is_numeral_zero(Z3_context c, Z3_ast t) { + Z3_TRY; + Z3_fpa_is_numeral_zero(c, t); + RESET_ERROR_CODE(); + ast_manager & m = mk_c(c)->m(); + api::context * ctx = mk_c(c); + mpf_manager & mpfm = mk_c(c)->fpautil().fm(); + fpa_util & fu = ctx->fpautil(); + if (!is_expr(t) || !fu.is_numeral(to_expr(t))) { + SET_ERROR_CODE(Z3_INVALID_ARG); + return 0; + } + return fu.is_zero(to_expr(t)); + Z3_CATCH_RETURN(Z3_FALSE); + } + + Z3_bool Z3_API Z3_fpa_is_numeral_normal(Z3_context c, Z3_ast t) { + Z3_TRY; + Z3_fpa_is_numeral_normal(c, t); + RESET_ERROR_CODE(); + ast_manager & m = mk_c(c)->m(); + api::context * ctx = mk_c(c); + mpf_manager & mpfm = mk_c(c)->fpautil().fm(); + fpa_util & fu = ctx->fpautil(); + if (!is_expr(t) || !fu.is_numeral(to_expr(t))) { + SET_ERROR_CODE(Z3_INVALID_ARG); + return 0; + } + return fu.is_normal(to_expr(t)); + Z3_CATCH_RETURN(Z3_FALSE); + } + + Z3_bool Z3_API Z3_fpa_is_numeral_subnormal(Z3_context c, Z3_ast t) { + Z3_TRY; + Z3_fpa_is_numeral_subnormal(c, t); + RESET_ERROR_CODE(); + ast_manager & m = mk_c(c)->m(); + api::context * ctx = mk_c(c); + mpf_manager & mpfm = mk_c(c)->fpautil().fm(); + fpa_util & fu = ctx->fpautil(); + if (!is_expr(t) || !fu.is_numeral(to_expr(t))) { + SET_ERROR_CODE(Z3_INVALID_ARG); + return 0; + } + return fu.is_subnormal(to_expr(t)); + Z3_CATCH_RETURN(Z3_FALSE); + } + + Z3_bool Z3_API Z3_fpa_is_numeral_positive(Z3_context c, Z3_ast t) { + Z3_TRY; + Z3_fpa_is_numeral_positive(c, t); + RESET_ERROR_CODE(); + ast_manager & m = mk_c(c)->m(); + api::context * ctx = mk_c(c); + mpf_manager & mpfm = mk_c(c)->fpautil().fm(); + fpa_util & fu = ctx->fpautil(); + if (!is_expr(t) || !fu.is_numeral(to_expr(t))) { + SET_ERROR_CODE(Z3_INVALID_ARG); + return 0; + } + return fu.is_positive(to_expr(t)); + Z3_CATCH_RETURN(Z3_FALSE); + } + }; diff --git a/src/api/z3_fpa.h b/src/api/z3_fpa.h index 9abbb7b60..d5da90808 100644 --- a/src/api/z3_fpa.h +++ b/src/api/z3_fpa.h @@ -822,6 +822,66 @@ extern "C" { */ unsigned Z3_API Z3_fpa_get_sbits(Z3_context c, Z3_sort s); + /** + \brief Checks whether a given floating-point numeral is a NaN. + + \param c logical context + \param t a floating-point numeral + + def_API('Z3_fpa_is_numeral_nan', AST, (_in(CONTEXT), _in(AST))) + */ + Z3_bool Z3_API Z3_fpa_is_numeral_nan(Z3_context c, Z3_ast t); + + /** + \brief Checks whether a given floating-point numeral is a +oo or -oo. + + \param c logical context + \param t a floating-point numeral + + def_API('Z3_fpa_is_numeral_inf', AST, (_in(CONTEXT), _in(AST))) + */ + Z3_bool Z3_API Z3_fpa_is_numeral_inf(Z3_context c, Z3_ast t); + + /** + \brief Checks whether a given floating-point numeral is +zero or -zero. + + \param c logical context + \param t a floating-point numeral + + def_API('Z3_fpa_is_numeral_zero', AST, (_in(CONTEXT), _in(AST))) + */ + Z3_bool Z3_API Z3_fpa_is_numeral_zero(Z3_context c, Z3_ast t); + + /** + \brief Checks whether a given floating-point numeral is normal. + + \param c logical context + \param t a floating-point numeral + + def_API('Z3_fpa_is_numeral_normal', AST, (_in(CONTEXT), _in(AST))) + */ + Z3_bool Z3_API Z3_fpa_is_numeral_normal(Z3_context c, Z3_ast t); + + /** + \brief Checks whether a given floating-point numeral is subnormal. + + \param c logical context + \param t a floating-point numeral + + def_API('Z3_fpa_is_numeral_subnormal', AST, (_in(CONTEXT), _in(AST))) + */ + Z3_bool Z3_API Z3_fpa_is_numeral_subnormal(Z3_context c, Z3_ast t); + + /** + \brief Checks whether a given floating-point numeral is positive. + + \param c logical context + \param t a floating-point numeral + + def_API('Z3_fpa_is_numeral_positive', AST, (_in(CONTEXT), _in(AST))) + */ + Z3_bool Z3_API Z3_fpa_is_numeral_positive(Z3_context c, Z3_ast t); + /** \brief Retrieves the sign of a floating-point literal as a bit-vector expression. diff --git a/src/ast/fpa_decl_plugin.h b/src/ast/fpa_decl_plugin.h index c00bed7ae..7c9c311a8 100644 --- a/src/ast/fpa_decl_plugin.h +++ b/src/ast/fpa_decl_plugin.h @@ -288,11 +288,15 @@ public: app * mk_nzero(sort * s) { return mk_nzero(get_ebits(s), get_sbits(s)); } bool is_nan(expr * n) { scoped_mpf v(fm()); return is_numeral(n, v) && fm().is_nan(v); } + bool is_inf(expr * n) { scoped_mpf v(fm()); return is_numeral(n, v) && fm().is_inf(v); } bool is_pinf(expr * n) { scoped_mpf v(fm()); return is_numeral(n, v) && fm().is_pinf(v); } bool is_ninf(expr * n) { scoped_mpf v(fm()); return is_numeral(n, v) && fm().is_ninf(v); } bool is_zero(expr * n) { scoped_mpf v(fm()); return is_numeral(n, v) && fm().is_zero(v); } bool is_pzero(expr * n) { scoped_mpf v(fm()); return is_numeral(n, v) && fm().is_pzero(v); } bool is_nzero(expr * n) { scoped_mpf v(fm()); return is_numeral(n, v) && fm().is_nzero(v); } + bool is_normal(expr * n) { scoped_mpf v(fm()); return is_numeral(n, v) && fm().is_normal(v); } + bool is_subnormal(expr * n) { scoped_mpf v(fm()); return is_numeral(n, v) && fm().is_denormal(v); } + bool is_positive(expr * n) { scoped_mpf v(fm()); return is_numeral(n, v) && fm().is_pos(v); } app * mk_fp(expr * sgn, expr * exp, expr * sig) { SASSERT(m_bv_util.is_bv(sgn) && m_bv_util.get_bv_size(sgn) == 1); From 8926b3311da59c2298035b1ca4e33727b5bceeb7 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Mon, 17 Oct 2016 14:05:38 +0100 Subject: [PATCH 268/536] Fixed FP numeral special value sig/exp extraction functions. --- src/api/z3_fpa.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/api/z3_fpa.h b/src/api/z3_fpa.h index d5da90808..5544099d6 100644 --- a/src/api/z3_fpa.h +++ b/src/api/z3_fpa.h @@ -828,7 +828,7 @@ extern "C" { \param c logical context \param t a floating-point numeral - def_API('Z3_fpa_is_numeral_nan', AST, (_in(CONTEXT), _in(AST))) + def_API('Z3_fpa_is_numeral_nan', BOOL, (_in(CONTEXT), _in(AST))) */ Z3_bool Z3_API Z3_fpa_is_numeral_nan(Z3_context c, Z3_ast t); @@ -838,7 +838,7 @@ extern "C" { \param c logical context \param t a floating-point numeral - def_API('Z3_fpa_is_numeral_inf', AST, (_in(CONTEXT), _in(AST))) + def_API('Z3_fpa_is_numeral_inf', BOOL, (_in(CONTEXT), _in(AST))) */ Z3_bool Z3_API Z3_fpa_is_numeral_inf(Z3_context c, Z3_ast t); @@ -848,7 +848,7 @@ extern "C" { \param c logical context \param t a floating-point numeral - def_API('Z3_fpa_is_numeral_zero', AST, (_in(CONTEXT), _in(AST))) + def_API('Z3_fpa_is_numeral_zero', BOOL, (_in(CONTEXT), _in(AST))) */ Z3_bool Z3_API Z3_fpa_is_numeral_zero(Z3_context c, Z3_ast t); @@ -858,7 +858,7 @@ extern "C" { \param c logical context \param t a floating-point numeral - def_API('Z3_fpa_is_numeral_normal', AST, (_in(CONTEXT), _in(AST))) + def_API('Z3_fpa_is_numeral_normal', BOOL, (_in(CONTEXT), _in(AST))) */ Z3_bool Z3_API Z3_fpa_is_numeral_normal(Z3_context c, Z3_ast t); @@ -868,7 +868,7 @@ extern "C" { \param c logical context \param t a floating-point numeral - def_API('Z3_fpa_is_numeral_subnormal', AST, (_in(CONTEXT), _in(AST))) + def_API('Z3_fpa_is_numeral_subnormal', BOOL, (_in(CONTEXT), _in(AST))) */ Z3_bool Z3_API Z3_fpa_is_numeral_subnormal(Z3_context c, Z3_ast t); @@ -878,7 +878,7 @@ extern "C" { \param c logical context \param t a floating-point numeral - def_API('Z3_fpa_is_numeral_positive', AST, (_in(CONTEXT), _in(AST))) + def_API('Z3_fpa_is_numeral_positive', BOOL, (_in(CONTEXT), _in(AST))) */ Z3_bool Z3_API Z3_fpa_is_numeral_positive(Z3_context c, Z3_ast t); From 0a11e8f3c00d35e1acdbe729c13b019a3875073b Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Fri, 21 Oct 2016 16:00:56 +0100 Subject: [PATCH 269/536] Resolved rebase conflicts --- src/api/api_fpa.cpp | 94 +++++++++++++++++++++++++++------------------ 1 file changed, 56 insertions(+), 38 deletions(-) diff --git a/src/api/api_fpa.cpp b/src/api/api_fpa.cpp index cc8648c2a..ce0cf1ae6 100644 --- a/src/api/api_fpa.cpp +++ b/src/api/api_fpa.cpp @@ -913,8 +913,9 @@ extern "C" { CHECK_VALID_AST(t, 0); ast_manager & m = mk_c(c)->m(); mpf_manager & mpfm = mk_c(c)->fpautil().fm(); - fpa_decl_plugin * plugin = (fpa_decl_plugin*)m.get_plugin(mk_c(c)->get_fpa_fid()); family_id fid = mk_c(c)->get_fpa_fid(); + fpa_decl_plugin * plugin = (fpa_decl_plugin*)m.get_plugin(fid); + fpa_util & fu = mk_c(c)->fpautil(); expr * e = to_expr(t); if (!is_app(e) || is_app_of(e, fid, OP_FPA_NAN) || !is_fp(c, t)) { SET_ERROR_CODE(Z3_INVALID_ARG); @@ -941,30 +942,27 @@ extern "C" { mpf_manager & mpfm = mk_c(c)->fpautil().fm(); unsynch_mpq_manager & mpqm = mpfm.mpq_manager(); family_id fid = mk_c(c)->get_fpa_fid(); + fpa_decl_plugin * plugin = (fpa_decl_plugin*)m.get_plugin(fid); fpa_util & fu = mk_c(c)->fpautil(); api::context * ctx = mk_c(c); expr * e = to_expr(t); - if (!is_app(e) || - is_app_of(e, fid, OP_FPA_NAN)) { + if (!is_app(e) || is_app_of(e, fid, OP_FPA_NAN) || !fu.is_fp(e)) { SET_ERROR_CODE(Z3_INVALID_ARG); RETURN_Z3(0); } - if (is_app_of(e, fid, OP_FPA_PLUS_INF)) { - expr * r = ctx->bvutil().mk_numeral(0, 1); - ctx->save_ast_trail(r); - RETURN_Z3(of_expr(r)); - } - if (is_app_of(e, fid, OP_FPA_MINUS_INF)) { - expr * r = ctx->bvutil().mk_numeral(1, 1); - ctx->save_ast_trail(r); - RETURN_Z3(of_expr(r)); - } - if (!fu.is_fp(e)) { + scoped_mpf val(mpfm); + bool r = plugin->is_numeral(to_expr(t), val); + if (!r || mpfm.is_nan(val)) { SET_ERROR_CODE(Z3_INVALID_ARG); - RETURN_Z3(0); + return 0; } - app * a = to_app(e); - RETURN_Z3(of_expr(a->get_arg(0))); + app * a; + if (mpfm.is_pos(val)) + a = ctx->bvutil().mk_numeral(0, 1); + else + a = ctx->bvutil().mk_numeral(1, 1); + mk_c(c)->save_ast_trail(a); + RETURN_Z3(of_expr(a)); Z3_CATCH_RETURN(0); } @@ -978,22 +976,31 @@ extern "C" { mpf_manager & mpfm = mk_c(c)->fpautil().fm(); unsynch_mpq_manager & mpqm = mpfm.mpq_manager(); family_id fid = mk_c(c)->get_fpa_fid(); + fpa_decl_plugin * plugin = (fpa_decl_plugin*)m.get_plugin(fid); fpa_util & fu = mk_c(c)->fpautil(); expr * e = to_expr(t); - if (!is_app(e) || - is_app_of(e, fid, OP_FPA_NAN) || - is_app_of(e, fid, OP_FPA_PLUS_INF) || - is_app_of(e, fid, OP_FPA_MINUS_INF)) { + if (!is_app(e) || is_app_of(e, fid, OP_FPA_NAN) || !fu.is_fp(e)) { SET_ERROR_CODE(Z3_INVALID_ARG); RETURN_Z3(0); } - if (!fu.is_fp(e)) { + scoped_mpf val(mpfm); + bool r = plugin->is_numeral(e, val); + if (!r || !(mpfm.is_normal(val) || mpfm.is_denormal(val) || mpfm.is_zero(val) || mpfm.is_inf(val))) { SET_ERROR_CODE(Z3_INVALID_ARG); RETURN_Z3(0); } - api::context * ctx = mk_c(c); - app * a = to_app(e); - RETURN_Z3(of_expr(a->get_arg(1))); + unsigned ebits = val.get().get_ebits(); + mpf_exp_t q = mpfm.exp(val); + mpf_exp_t q_biassed = mpfm.bias_exp(ebits, q); + app * a; + if (mpfm.is_inf(val)) + a = mk_c(c)->bvutil().mk_numeral(-1, ebits); + else if (mpfm.is_zero(val) || mpfm.is_denormal(val)) + a = mk_c(c)->bvutil().mk_numeral(0, ebits); + else + a = mk_c(c)->bvutil().mk_numeral(q_biassed, ebits); + mk_c(c)->save_ast_trail(a); + RETURN_Z3(of_expr(a)); Z3_CATCH_RETURN(0); } @@ -1007,22 +1014,27 @@ extern "C" { mpf_manager & mpfm = mk_c(c)->fpautil().fm(); unsynch_mpq_manager & mpqm = mpfm.mpq_manager(); family_id fid = mk_c(c)->get_fpa_fid(); + fpa_decl_plugin * plugin = (fpa_decl_plugin*)m.get_plugin(fid); + SASSERT(plugin != 0); fpa_util & fu = mk_c(c)->fpautil(); expr * e = to_expr(t); - if (!is_app(e) || - is_app_of(e, fid, OP_FPA_NAN) || - is_app_of(e, fid, OP_FPA_PLUS_INF) || - is_app_of(e, fid, OP_FPA_MINUS_INF)) { + if (!is_app(e) || is_app_of(e, fid, OP_FPA_NAN) || !fu.is_fp(e)) { SET_ERROR_CODE(Z3_INVALID_ARG); RETURN_Z3(0); } - if (!fu.is_fp(e)) { + scoped_mpf val(mpfm); + bool r = plugin->is_numeral(e, val); + if (!r || !(mpfm.is_normal(val) || mpfm.is_denormal(val) || mpfm.is_zero(val) || mpfm.is_inf(val))) { SET_ERROR_CODE(Z3_INVALID_ARG); RETURN_Z3(0); } - api::context * ctx = mk_c(c); - app * a = to_app(e); - RETURN_Z3(of_expr(a->get_arg(2))); + unsigned sbits = val.get().get_sbits(); + scoped_mpq q(mpqm); + mpqm.set(q, mpfm.sig(val)); + if (mpfm.is_inf(val)) mpqm.set(q, 0); + app * a = mk_c(c)->bvutil().mk_numeral(q.get(), sbits); + mk_c(c)->save_ast_trail(a); + RETURN_Z3(of_expr(a)); Z3_CATCH_RETURN(0); } @@ -1038,6 +1050,7 @@ extern "C" { family_id fid = mk_c(c)->get_fpa_fid(); fpa_decl_plugin * plugin = (fpa_decl_plugin*)m.get_plugin(fid); SASSERT(plugin != 0); + fpa_util & fu = mk_c(c)->fpautil(); expr * e = to_expr(t); if (!is_app(e) || is_app_of(e, fid, OP_FPA_NAN) || !is_fp(c, t)) { SET_ERROR_CODE(Z3_INVALID_ARG); @@ -1045,8 +1058,8 @@ extern "C" { } scoped_mpf val(mpfm); bool r = plugin->is_numeral(e, val); - if (!r || !(mpfm.is_normal(val) || mpfm.is_denormal(val) || mpfm.is_zero(val))) { - SET_ERROR_CODE(Z3_INVALID_ARG) + if (!r || !(mpfm.is_normal(val) || mpfm.is_denormal(val) || mpfm.is_zero(val) || mpfm.is_inf(val))) { + SET_ERROR_CODE(Z3_INVALID_ARG); return ""; } unsigned sbits = val.get().get_sbits(); @@ -1071,6 +1084,7 @@ extern "C" { family_id fid = mk_c(c)->get_fpa_fid(); fpa_decl_plugin * plugin = (fpa_decl_plugin*)m.get_plugin(fid); SASSERT(plugin != 0); + fpa_util & fu = mk_c(c)->fpautil(); expr * e = to_expr(t); if (!is_app(e) || is_app_of(e, fid, OP_FPA_NAN) || !is_fp(c, t)) { SET_ERROR_CODE(Z3_INVALID_ARG); @@ -1081,7 +1095,7 @@ extern "C" { bool r = plugin->is_numeral(e, val); const mpz & z = mpfm.sig(val); if (!r || - !(mpfm.is_normal(val) || mpfm.is_denormal(val) || mpfm.is_zero(val)) || + !(mpfm.is_normal(val) || mpfm.is_denormal(val) || mpfm.is_zero(val) || mpfm.is_inf(val)) || !mpzm.is_uint64(z)) { SET_ERROR_CODE(Z3_INVALID_ARG); *n = 0; @@ -1101,6 +1115,7 @@ extern "C" { family_id fid = mk_c(c)->get_fpa_fid(); fpa_decl_plugin * plugin = (fpa_decl_plugin*)m.get_plugin(mk_c(c)->get_fpa_fid()); SASSERT(plugin != 0); + fpa_util & fu = mk_c(c)->fpautil(); expr * e = to_expr(t); if (!is_app(e) || is_app_of(e, fid, OP_FPA_NAN) || !is_fp(c, t)) { SET_ERROR_CODE(Z3_INVALID_ARG); @@ -1108,12 +1123,13 @@ extern "C" { } scoped_mpf val(mpfm); bool r = plugin->is_numeral(e, val); - if (!r || !(mpfm.is_normal(val) || mpfm.is_denormal(val) || mpfm.is_zero(val))) { + if (!r || !(mpfm.is_normal(val) || mpfm.is_denormal(val) || mpfm.is_zero(val) || mpfm.is_inf(val))) { SET_ERROR_CODE(Z3_INVALID_ARG); return ""; } mpf_exp_t exp = mpfm.is_zero(val) ? 0 : mpfm.is_denormal(val) ? mpfm.mk_min_exp(val.get().get_ebits()) : + mpfm.is_inf(val) ? mpfm.mk_top_exp(val.get().get_ebits()) : mpfm.exp(val); std::stringstream ss; ss << exp; @@ -1130,6 +1146,7 @@ extern "C" { family_id fid = mk_c(c)->get_fpa_fid(); fpa_decl_plugin * plugin = (fpa_decl_plugin*)m.get_plugin(mk_c(c)->get_fpa_fid()); SASSERT(plugin != 0); + fpa_util & fu = mk_c(c)->fpautil(); expr * e = to_expr(t); if (!is_app(e) || is_app_of(e, fid, OP_FPA_NAN) || !is_fp(c, t)) { SET_ERROR_CODE(Z3_INVALID_ARG); @@ -1138,13 +1155,14 @@ extern "C" { } scoped_mpf val(mpfm); bool r = plugin->is_numeral(e, val); - if (!r || !(mpfm.is_normal(val) || mpfm.is_denormal(val) || mpfm.is_zero(val))) { + if (!r || !(mpfm.is_normal(val) || mpfm.is_denormal(val) || mpfm.is_zero(val) || mpfm.is_inf(val))) { SET_ERROR_CODE(Z3_INVALID_ARG); *n = 0; return 0; } *n = mpfm.is_zero(val) ? 0 : mpfm.is_denormal(val) ? mpfm.mk_min_exp(val.get().get_ebits()) : + mpfm.is_inf(val) ? mpfm.mk_top_exp(val.get().get_ebits()) : mpfm.exp(val); return 1; Z3_CATCH_RETURN(0); From abcb6040d4593545a7019a4f4431444bc4d03dad Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Fri, 21 Oct 2016 17:39:31 +0100 Subject: [PATCH 270/536] Refactored FPA numeral accessors. --- src/api/api_fpa.cpp | 102 +++++++++++++++++---------------- src/api/dotnet/FPNum.cs | 71 ++++++++++------------- src/api/java/FPNum.java | 66 ++++++++++----------- src/api/python/z3/z3.py | 60 +++++++++---------- src/api/python/z3/z3printer.py | 4 +- src/api/z3_fpa.h | 44 ++++++++------ 6 files changed, 175 insertions(+), 172 deletions(-) diff --git a/src/api/api_fpa.cpp b/src/api/api_fpa.cpp index ce0cf1ae6..669df8666 100644 --- a/src/api/api_fpa.cpp +++ b/src/api/api_fpa.cpp @@ -946,7 +946,7 @@ extern "C" { fpa_util & fu = mk_c(c)->fpautil(); api::context * ctx = mk_c(c); expr * e = to_expr(t); - if (!is_app(e) || is_app_of(e, fid, OP_FPA_NAN) || !fu.is_fp(e)) { + if (!is_app(e) || is_app_of(e, fid, OP_FPA_NAN) || !is_fp(c, t)) { SET_ERROR_CODE(Z3_INVALID_ARG); RETURN_Z3(0); } @@ -956,6 +956,7 @@ extern "C" { SET_ERROR_CODE(Z3_INVALID_ARG); return 0; } + std::cout << "val=" << mpfm.to_string(val) << std::endl; app * a; if (mpfm.is_pos(val)) a = ctx->bvutil().mk_numeral(0, 1); @@ -966,44 +967,6 @@ extern "C" { Z3_CATCH_RETURN(0); } - Z3_ast Z3_API Z3_fpa_get_numeral_exponent_bv(Z3_context c, Z3_ast t) { - Z3_TRY; - LOG_Z3_fpa_get_numeral_exponent_bv(c, t); - RESET_ERROR_CODE(); - CHECK_NON_NULL(t, 0); - CHECK_VALID_AST(t, 0); - ast_manager & m = mk_c(c)->m(); - mpf_manager & mpfm = mk_c(c)->fpautil().fm(); - unsynch_mpq_manager & mpqm = mpfm.mpq_manager(); - family_id fid = mk_c(c)->get_fpa_fid(); - fpa_decl_plugin * plugin = (fpa_decl_plugin*)m.get_plugin(fid); - fpa_util & fu = mk_c(c)->fpautil(); - expr * e = to_expr(t); - if (!is_app(e) || is_app_of(e, fid, OP_FPA_NAN) || !fu.is_fp(e)) { - SET_ERROR_CODE(Z3_INVALID_ARG); - RETURN_Z3(0); - } - scoped_mpf val(mpfm); - bool r = plugin->is_numeral(e, val); - if (!r || !(mpfm.is_normal(val) || mpfm.is_denormal(val) || mpfm.is_zero(val) || mpfm.is_inf(val))) { - SET_ERROR_CODE(Z3_INVALID_ARG); - RETURN_Z3(0); - } - unsigned ebits = val.get().get_ebits(); - mpf_exp_t q = mpfm.exp(val); - mpf_exp_t q_biassed = mpfm.bias_exp(ebits, q); - app * a; - if (mpfm.is_inf(val)) - a = mk_c(c)->bvutil().mk_numeral(-1, ebits); - else if (mpfm.is_zero(val) || mpfm.is_denormal(val)) - a = mk_c(c)->bvutil().mk_numeral(0, ebits); - else - a = mk_c(c)->bvutil().mk_numeral(q_biassed, ebits); - mk_c(c)->save_ast_trail(a); - RETURN_Z3(of_expr(a)); - Z3_CATCH_RETURN(0); - } - Z3_ast Z3_API Z3_fpa_get_numeral_significand_bv(Z3_context c, Z3_ast t) { Z3_TRY; LOG_Z3_fpa_get_numeral_significand_bv(c, t); @@ -1018,7 +981,7 @@ extern "C" { SASSERT(plugin != 0); fpa_util & fu = mk_c(c)->fpautil(); expr * e = to_expr(t); - if (!is_app(e) || is_app_of(e, fid, OP_FPA_NAN) || !fu.is_fp(e)) { + if (!is_app(e) || is_app_of(e, fid, OP_FPA_NAN) || !is_fp(c, t)) { SET_ERROR_CODE(Z3_INVALID_ARG); RETURN_Z3(0); } @@ -1106,9 +1069,9 @@ extern "C" { Z3_CATCH_RETURN(0); } - Z3_string Z3_API Z3_fpa_get_numeral_exponent_string(Z3_context c, Z3_ast t) { + Z3_string Z3_API Z3_fpa_get_numeral_exponent_string(Z3_context c, Z3_ast t, Z3_bool biased) { Z3_TRY; - LOG_Z3_fpa_get_numeral_exponent_string(c, t); + LOG_Z3_fpa_get_numeral_exponent_string(c, t, biased); RESET_ERROR_CODE(); ast_manager & m = mk_c(c)->m(); mpf_manager & mpfm = mk_c(c)->fpautil().fm(); @@ -1127,19 +1090,21 @@ extern "C" { SET_ERROR_CODE(Z3_INVALID_ARG); return ""; } + unsigned ebits = val.get().get_ebits(); mpf_exp_t exp = mpfm.is_zero(val) ? 0 : - mpfm.is_denormal(val) ? mpfm.mk_min_exp(val.get().get_ebits()) : - mpfm.is_inf(val) ? mpfm.mk_top_exp(val.get().get_ebits()) : - mpfm.exp(val); + mpfm.is_denormal(val) ? mpfm.mk_min_exp(ebits) : + mpfm.is_inf(val) ? mpfm.mk_top_exp(ebits) : + mpfm.bias_exp(ebits, mpfm.exp(val)); + if (!biased) mpfm.unbias_exp(ebits, exp); std::stringstream ss; ss << exp; return mk_c(c)->mk_external_string(ss.str()); Z3_CATCH_RETURN(""); } - Z3_bool Z3_API Z3_fpa_get_numeral_exponent_int64(Z3_context c, Z3_ast t, __int64 * n) { + Z3_bool Z3_API Z3_fpa_get_numeral_exponent_int64(Z3_context c, Z3_ast t, __int64 * n, Z3_bool biased) { Z3_TRY; - LOG_Z3_fpa_get_numeral_exponent_int64(c, t, n); + LOG_Z3_fpa_get_numeral_exponent_int64(c, t, n, biased); RESET_ERROR_CODE(); ast_manager & m = mk_c(c)->m(); mpf_manager & mpfm = mk_c(c)->fpautil().fm(); @@ -1160,14 +1125,51 @@ extern "C" { *n = 0; return 0; } + unsigned ebits = val.get().get_ebits(); *n = mpfm.is_zero(val) ? 0 : - mpfm.is_denormal(val) ? mpfm.mk_min_exp(val.get().get_ebits()) : - mpfm.is_inf(val) ? mpfm.mk_top_exp(val.get().get_ebits()) : - mpfm.exp(val); + mpfm.is_denormal(val) ? mpfm.mk_min_exp(ebits) : + mpfm.is_inf(val) ? mpfm.mk_top_exp(ebits) : + mpfm.bias_exp(ebits, mpfm.exp(val)); + if (!biased) *n = mpfm.unbias_exp(ebits, *n); return 1; Z3_CATCH_RETURN(0); } + Z3_ast Z3_API Z3_fpa_get_numeral_exponent_bv(Z3_context c, Z3_ast t, Z3_bool biased) { + Z3_TRY; + LOG_Z3_fpa_get_numeral_exponent_bv(c, t, biased); + RESET_ERROR_CODE(); + CHECK_NON_NULL(t, 0); + CHECK_VALID_AST(t, 0); + ast_manager & m = mk_c(c)->m(); + mpf_manager & mpfm = mk_c(c)->fpautil().fm(); + unsynch_mpq_manager & mpqm = mpfm.mpq_manager(); + family_id fid = mk_c(c)->get_fpa_fid(); + fpa_decl_plugin * plugin = (fpa_decl_plugin*)m.get_plugin(fid); + fpa_util & fu = mk_c(c)->fpautil(); + expr * e = to_expr(t); + if (!is_app(e) || is_app_of(e, fid, OP_FPA_NAN) || !is_fp(c, t)) { + SET_ERROR_CODE(Z3_INVALID_ARG); + RETURN_Z3(0); + } + scoped_mpf val(mpfm); + bool r = plugin->is_numeral(e, val); + if (!r || !(mpfm.is_normal(val) || mpfm.is_denormal(val) || mpfm.is_zero(val) || mpfm.is_inf(val))) { + SET_ERROR_CODE(Z3_INVALID_ARG); + RETURN_Z3(0); + } + unsigned ebits = val.get().get_ebits(); + mpf_exp_t exp = mpfm.is_zero(val) ? 0 : + mpfm.is_denormal(val) ? mpfm.mk_min_exp(ebits) : + mpfm.is_inf(val) ? mpfm.mk_top_exp(ebits) : + mpfm.bias_exp(ebits, mpfm.exp(val)); + if (!biased) exp = mpfm.unbias_exp(ebits, exp); + app * a = mk_c(c)->bvutil().mk_numeral(exp, ebits); + mk_c(c)->save_ast_trail(a); + RETURN_Z3(of_expr(a)); + Z3_CATCH_RETURN(0); + } + Z3_ast Z3_API Z3_mk_fpa_to_ieee_bv(Z3_context c, Z3_ast t) { Z3_TRY; LOG_Z3_mk_fpa_to_ieee_bv(c, t); diff --git a/src/api/dotnet/FPNum.cs b/src/api/dotnet/FPNum.cs index ed0367481..705e7304e 100644 --- a/src/api/dotnet/FPNum.cs +++ b/src/api/dotnet/FPNum.cs @@ -33,7 +33,7 @@ namespace Microsoft.Z3 /// /// NaN's do not have a bit-vector sign, so they are invalid arguments. /// - public BitVecExpr BVSign + public BitVecExpr SignBV { get { @@ -41,34 +41,6 @@ namespace Microsoft.Z3 } } - /// - /// The exponent of a floating-point numeral as a bit-vector expression - /// - /// - /// +oo, -oo and NaN's do not have a bit-vector exponent, so they are invalid arguments. - /// - public BitVecExpr BVExponent - { - get - { - return new BitVecExpr(Context, Native.Z3_fpa_get_numeral_exponent_bv(Context.nCtx, NativeObject)); - } - } - - /// - /// The significand of a floating-point numeral as a bit-vector expression - /// - /// - /// +oo, -oo and NaN's do not have a bit-vector significand, so they are invalid arguments. - /// - public BitVecExpr BVSignificand - { - get - { - return new BitVecExpr(Context, Native.Z3_fpa_get_numeral_significand_bv(Context.nCtx, NativeObject)); - } - } - /// /// Retrieves the sign of a floating-point literal /// @@ -121,28 +93,47 @@ namespace Microsoft.Z3 } /// - /// Return the exponent value of a floating-point numeral as a string + /// The significand of a floating-point numeral as a bit-vector expression /// - public string Exponent + /// + /// +oo, -oo and NaN's do not have a bit-vector significand, so they are invalid arguments. + /// + public BitVecExpr SignificandBV { get { - return Native.Z3_fpa_get_numeral_exponent_string(Context.nCtx, NativeObject); + return new BitVecExpr(Context, Native.Z3_fpa_get_numeral_significand_bv(Context.nCtx, NativeObject)); } } + /// + /// Return the (biased) exponent value of a floating-point numeral as a string + /// + public string Exponent(bool biased = true) + { + return Native.Z3_fpa_get_numeral_exponent_string(Context.nCtx, NativeObject, biased ? 1 : 0); + } + /// /// Return the exponent value of a floating-point numeral as a signed 64-bit integer /// - public Int64 ExponentInt64 + public Int64 ExponentInt64(bool biased = true) { - get - { - Int64 result = 0; - if (Native.Z3_fpa_get_numeral_exponent_int64(Context.nCtx, NativeObject, ref result) == 0) - throw new Z3Exception("Exponent is not a 64 bit integer"); - return result; - } + Int64 result = 0; + if (Native.Z3_fpa_get_numeral_exponent_int64(Context.nCtx, NativeObject, ref result, biased ? 1 : 0) == 0) + throw new Z3Exception("Exponent is not a 64 bit integer"); + return result; + } + + /// + /// The exponent of a floating-point numeral as a bit-vector expression + /// + /// + /// +oo, -oo and NaN's do not have a bit-vector exponent, so they are invalid arguments. + /// + public BitVecExpr ExponentBV(bool biased = true) + { + return new BitVecExpr(Context, Native.Z3_fpa_get_numeral_exponent_bv(Context.nCtx, NativeObject, biased ? 1 : 0)); } #region Internal diff --git a/src/api/java/FPNum.java b/src/api/java/FPNum.java index 7bfca0f86..252d9e012 100644 --- a/src/api/java/FPNum.java +++ b/src/api/java/FPNum.java @@ -20,34 +20,7 @@ package com.microsoft.z3; * FloatingPoint Numerals */ public class FPNum extends FPExpr -{ - /** - * The sign of a floating-point numeral as a bit-vector expression - * Remarks: NaN's do not have a bit-vector sign, so they are invalid arguments. - * @throws Z3Exception - */ - public BitVecExpr getBVSign() { - return new BitVecExpr(getContext(), Native.fpaGetNumeralSignBv(getContext().nCtx(), getNativeObject())); - } - - /** - * The exponent of a floating-point numeral as a bit-vector expression - * Remarks: +oo, -oo, and NaN's do not have a bit-vector exponent, so they are invalid arguments. - * @throws Z3Exception - */ - public BitVecExpr getBVExponent() { - return new BitVecExpr(getContext(), Native.fpaGetNumeralExponentBv(getContext().nCtx(), getNativeObject())); - } - - /** - * The significand of a floating-point numeral as a bit-vector expression - * Remarks: +oo, -oo, and NaN's do not have a bit-vector significand, so they are invalid arguments. - * @throws Z3Exception - */ - public BitVecExpr getBVSignificand() { - return new BitVecExpr(getContext(), Native.fpaGetNumeralSignificandBv(getContext().nCtx(), getNativeObject())); - } - +{ /** * Retrieves the sign of a floating-point literal * Remarks: returns true if the numeral is negative @@ -60,6 +33,15 @@ public class FPNum extends FPExpr return res.value != 0; } + /** + * The sign of a floating-point numeral as a bit-vector expression + * Remarks: NaN's do not have a bit-vector sign, so they are invalid arguments. + * @throws Z3Exception + */ + public BitVecExpr getSignBV() { + return new BitVecExpr(getContext(), Native.fpaGetNumeralSignBv(getContext().nCtx(), getNativeObject())); + } + /** * The significand value of a floating-point numeral as a string * Remarks: The significand s is always 0 < s < 2.0; the resulting string is long @@ -84,25 +66,45 @@ public class FPNum extends FPExpr throw new Z3Exception("Significand is not a 64 bit unsigned integer"); return res.value; } + + /** + * The significand of a floating-point numeral as a bit-vector expression + * Remarks: NaN is an invalid argument. + * @throws Z3Exception + */ + public BitVecExpr getSignificandBV() { + return new BitVecExpr(getContext(), Native.fpaGetNumeralSignificandBv(getContext().nCtx(), getNativeObject())); + } /** * Return the exponent value of a floating-point numeral as a string + * Remarks: NaN is an invalid argument. * @throws Z3Exception */ - public String getExponent() { - return Native.fpaGetNumeralExponentString(getContext().nCtx(), getNativeObject()); + public String getExponent(boolean biased) { + return Native.fpaGetNumeralExponentString(getContext().nCtx(), getNativeObject(), biased); } /** * Return the exponent value of a floating-point numeral as a signed 64-bit integer + * Remarks: NaN is an invalid argument. * @throws Z3Exception */ - public long getExponentInt64() { + public long getExponentInt64(boolean biased) { Native.LongPtr res = new Native.LongPtr(); - if (!Native.fpaGetNumeralExponentInt64(getContext().nCtx(), getNativeObject(), res)) + if (!Native.fpaGetNumeralExponentInt64(getContext().nCtx(), getNativeObject(), res, biased)) throw new Z3Exception("Exponent is not a 64 bit integer"); return res.value; } + + /** + * The exponent of a floating-point numeral as a bit-vector expression + * Remarks: NaN is an invalid argument. + * @throws Z3Exception + */ + public BitVecExpr getExponentBV(boolean biased) { + return new BitVecExpr(getContext(), Native.fpaGetNumeralExponentBv(getContext().nCtx(), getNativeObject(), biased)); + } public FPNum(Context ctx, long obj) { diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index fc9ef6d62..e651fc04f 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -8445,31 +8445,7 @@ class FPNumRef(FPRef): def isNegative(self): k = self.decl().kind() return (self.num_args() == 0 and (k == Z3_OP_FPA_MINUS_INF or k == Z3_OP_FPA_MINUS_ZERO)) or (self.sign() == True) - - """ - The sign of a floating-point numeral as a bit-vector expression - - Remark: NaN's do not have a bit-vector sign, so they are invalid arguments. - """ - def BVSign(self): - return BitVecNumRef(Z3_fpa_get_numeral_sign_bv(self.ctx.ref(), self.as_ast()), ctx) - """ - The exponent of a floating-point numeral as a bit-vector expression - - Remark: +oo, -oo and NaN's do not have a bit-vector exponent, so they are invalid arguments. - """ - def BVExponent(self): - return BitVecNumRef(Z3_fpa_get_numeral_exponent_bv(self.ctx.ref(), self.as_ast()), ctx) - - """ - The sign of a floating-point numeral as a bit-vector expression - - Remark: +oo, -oo and NaN's do not have a bit-vector significand, so they are invalid arguments. - """ - def BVSignificand(self): - return BitVecNumRef(Z3_fpa_get_numeral_significand_bv(self.ctx.ref(), self.as_ast()), ctx) - """ The sign of the numeral. @@ -8486,6 +8462,15 @@ class FPNumRef(FPRef): raise Z3Exception("error retrieving the sign of a numeral.") return l.value != 0 + """ + The sign of a floating-point numeral as a bit-vector expression + + Remark: NaN's are invalid arguments. + """ + def sign_as_bv(self): + return BitVecNumRef(Z3_fpa_get_numeral_sign_bv(self.ctx.ref(), self.as_ast()), self.ctx) + + """ The significand of the numeral. @@ -8495,6 +8480,14 @@ class FPNumRef(FPRef): """ def significand(self): return Z3_fpa_get_numeral_significand_string(self.ctx.ref(), self.as_ast()) + + """ + The significand of a floating-point numeral as a bit-vector expression + + Remark: NaN are invalid arguments. + """ + def significand_as_bv(self): + return BitVecNumRef(Z3_fpa_get_numeral_significand_bv(self.ctx.ref(), self.as_ast()), self.ctx) """ The exponent of the numeral. @@ -8503,8 +8496,8 @@ class FPNumRef(FPRef): >>> x.exponent() 1 """ - def exponent(self): - return Z3_fpa_get_numeral_exponent_string(self.ctx.ref(), self.as_ast()) + def exponent(self, biased=True): + return Z3_fpa_get_numeral_exponent_string(self.ctx.ref(), self.as_ast(), biased) """ The exponent of the numeral as a long. @@ -8513,12 +8506,21 @@ class FPNumRef(FPRef): >>> x.exponent_as_long() 1 """ - def exponent_as_long(self): + def exponent_as_long(self, biased=True): ptr = (ctypes.c_longlong * 1)() - if not Z3_fpa_get_numeral_exponent_int64(self.ctx.ref(), self.as_ast(), ptr): + if not Z3_fpa_get_numeral_exponent_int64(self.ctx.ref(), self.as_ast(), ptr, biased): raise Z3Exception("error retrieving the exponent of a numeral.") return ptr[0] + """ + The exponent of a floating-point numeral as a bit-vector expression + + Remark: NaNs are invalid arguments. + """ + def exponent_as_bv(self, biased=True): + return BitVecNumRef(Z3_fpa_get_numeral_exponent_bv(self.ctx.ref(), self.as_ast(), biased), self.ctx) + + """ The string representation of the numeral. @@ -8527,7 +8529,7 @@ class FPNumRef(FPRef): 1.25*(2**4) """ def as_string(self): - s = Z3_fpa_get_numeral_string(self.ctx.ref(), self.as_ast()) + s = Z3_get_numeral_string(self.ctx.ref(), self.as_ast()) return ("FPVal(%s, %s)" % (s, self.sort())) def is_fp(a): diff --git a/src/api/python/z3/z3printer.py b/src/api/python/z3/z3printer.py index 2e3a528bf..8a67fa911 100644 --- a/src/api/python/z3/z3printer.py +++ b/src/api/python/z3/z3printer.py @@ -620,8 +620,8 @@ class Formatter: r = [] sgn = c_int(0) sgnb = Z3_fpa_get_numeral_sign(a.ctx_ref(), a.ast, byref(sgn)) + exp = Z3_fpa_get_numeral_exponent_string(a.ctx_ref(), a.ast, False) sig = Z3_fpa_get_numeral_significand_string(a.ctx_ref(), a.ast) - exp = Z3_fpa_get_numeral_exponent_string(a.ctx_ref(), a.ast) r.append(to_format('FPVal(')) if sgnb and sgn.value != 0: r.append(to_format('-')) @@ -650,8 +650,8 @@ class Formatter: r = [] sgn = (ctypes.c_int)(0) sgnb = Z3_fpa_get_numeral_sign(a.ctx_ref(), a.ast, byref(sgn)) + exp = Z3_fpa_get_numeral_exponent_string(a.ctx_ref(), a.ast, False) sig = Z3_fpa_get_numeral_significand_string(a.ctx_ref(), a.ast) - exp = Z3_fpa_get_numeral_exponent_string(a.ctx_ref(), a.ast) if sgnb and sgn.value != 0: r.append(to_format('-')) r.append(to_format(sig)) diff --git a/src/api/z3_fpa.h b/src/api/z3_fpa.h index 5544099d6..420106838 100644 --- a/src/api/z3_fpa.h +++ b/src/api/z3_fpa.h @@ -900,24 +900,12 @@ extern "C" { \param c logical context \param t a floating-point numeral - Remarks: +oo, -oo and NaN are invalid arguments. + Remarks: NaN is an invalid argument. def_API('Z3_fpa_get_numeral_significand_bv', AST, (_in(CONTEXT), _in(AST))) */ Z3_ast Z3_API Z3_fpa_get_numeral_significand_bv(Z3_context c, Z3_ast t); - /** - \brief Retrieves the exponent of a floating-point literal as a bit-vector expression. - - \param c logical context - \param t a floating-point numeral - - Remarks: +oo, -oo and NaN are invalid arguments. - - def_API('Z3_fpa_get_numeral_exponent_bv', AST, (_in(CONTEXT), _in(AST))) - */ - Z3_ast Z3_API Z3_fpa_get_numeral_exponent_bv(Z3_context c, Z3_ast t); - /** \brief Retrieves the sign of a floating-point literal. @@ -954,23 +942,25 @@ extern "C" { Remarks: This function extracts the significand bits in `t`, without the hidden bit or normalization. Sets the Z3_INVALID_ARG error code if the - significand does not fit into a uint64. + significand does not fit into a uint64. NaN is an invalid argument. def_API('Z3_fpa_get_numeral_significand_uint64', BOOL, (_in(CONTEXT), _in(AST), _out(UINT64))) */ Z3_bool Z3_API Z3_fpa_get_numeral_significand_uint64(Z3_context c, Z3_ast t, __uint64 * n); /** - \brief Return the exponent value of a floating-point numeral as a string + \brief Return the exponent value of a floating-point numeral as a string. \param c logical context \param t a floating-point numeral + \param biased flag to indicate whether the result is in biased representation Remarks: This function extracts the exponent in `t`, without normalization. + NaN is an invalid argument. - def_API('Z3_fpa_get_numeral_exponent_string', STRING, (_in(CONTEXT), _in(AST))) + def_API('Z3_fpa_get_numeral_exponent_string', STRING, (_in(CONTEXT), _in(AST), _in(BOOL))) */ - Z3_string Z3_API Z3_fpa_get_numeral_exponent_string(Z3_context c, Z3_ast t); + Z3_string Z3_API Z3_fpa_get_numeral_exponent_string(Z3_context c, Z3_ast t, Z3_bool biased); /** \brief Return the exponent value of a floating-point numeral as a signed 64-bit integer @@ -978,12 +968,28 @@ extern "C" { \param c logical context \param t a floating-point numeral \param n exponent + \param biased flag to indicate whether the result is in biased representation Remarks: This function extracts the exponent in `t`, without normalization. + NaN is an invalid argument. - def_API('Z3_fpa_get_numeral_exponent_int64', BOOL, (_in(CONTEXT), _in(AST), _out(INT64))) + def_API('Z3_fpa_get_numeral_exponent_int64', BOOL, (_in(CONTEXT), _in(AST), _out(INT64), _in(BOOL))) */ - Z3_bool Z3_API Z3_fpa_get_numeral_exponent_int64(Z3_context c, Z3_ast t, __int64 * n); + Z3_bool Z3_API Z3_fpa_get_numeral_exponent_int64(Z3_context c, Z3_ast t, __int64 * n, Z3_bool biased); + + /** + \brief Retrieves the exponent of a floating-point literal as a bit-vector expression. + + \param c logical context + \param t a floating-point numeral + \param biased flag to indicate whether the result is in biased representation + + Remarks: This function extracts the exponent in `t`, without normalization. + NaN is an invalid arguments. + + def_API('Z3_fpa_get_numeral_exponent_bv', AST, (_in(CONTEXT), _in(AST), _in(BOOL))) + */ + Z3_ast Z3_API Z3_fpa_get_numeral_exponent_bv(Z3_context c, Z3_ast t, Z3_bool biased); /** \brief Conversion of a floating-point term into a bit-vector term in IEEE 754-2008 format. From df2a569d25afdd15edd6e9fa495f9d8238e4886c Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Mon, 24 Oct 2016 13:29:17 +0100 Subject: [PATCH 271/536] Replaced antiquated header with modern equivalent. --- src/cmd_context/check_logic.cpp | 34 ++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/src/cmd_context/check_logic.cpp b/src/cmd_context/check_logic.cpp index d9fe9ab72..d598dfa39 100644 --- a/src/cmd_context/check_logic.cpp +++ b/src/cmd_context/check_logic.cpp @@ -24,7 +24,7 @@ Revision History: #include"datatype_decl_plugin.h" #include"ast_pp.h" #include"for_each_expr.h" -#include +#include struct check_logic::imp { ast_manager & m; @@ -189,7 +189,7 @@ struct check_logic::imp { else { m_unknown_logic = true; } - + m_logic = logic; } @@ -237,7 +237,7 @@ struct check_logic::imp { } } - void operator()(var * n) { + void operator()(var * n) { if (!m_quantifiers) fail("logic does not support quantifiers"); check_sort(m.get_sort(n)); @@ -279,7 +279,7 @@ struct check_logic::imp { } } } - + // check if the divisor is a numeral void check_div(app * n) { SASSERT(n->get_num_args() == 2); @@ -328,8 +328,8 @@ struct check_logic::imp { return false; non_numeral = arg; } - if (non_numeral == 0) - return true; + if (non_numeral == 0) + return true; if (is_diff_var(non_numeral)) return true; if (!m_a_util.is_add(non_numeral) && !m_a_util.is_sub(non_numeral)) @@ -338,10 +338,10 @@ struct check_logic::imp { } return true; } - + bool is_diff_arg(expr * t) { if (is_diff_var(t)) - return true; + return true; if (is_numeral(t)) return true; if (m_a_util.is_add(t) || m_a_util.is_sub(t)) @@ -366,7 +366,7 @@ struct check_logic::imp { expr * t1 = to_app(lhs)->get_arg(0); expr * t2 = to_app(lhs)->get_arg(1); if (is_diff_var(t1) && is_diff_var(t2)) - return; + return; if (m_a_util.is_add(t1) && m_a_util.is_add(t2)) { // QF_RDL supports (<= (- (+ x ... x) (+ y ... y)) c) if (to_app(t1)->get_num_args() != to_app(t2)->get_num_args()) @@ -391,7 +391,7 @@ struct check_logic::imp { check_diff_arg(n); } } - + void operator()(app * n) { sort * s = m.get_sort(n); check_sort(s); @@ -415,18 +415,18 @@ struct check_logic::imp { if (!m_ints || !m_reals) { if (m_a_util.is_to_real(n) || m_a_util.is_to_int(n)) fail("logic does not support casting operators"); - } + } } else if (fid == m_bv_util.get_family_id()) { - // nothing to check... + // nothing to check... } else if (fid == m_ar_util.get_family_id()) { - // nothing to check... + // nothing to check... if (m_diff) check_diff_args(n); } else if (fid == m.get_basic_family_id()) { - // nothing to check... + // nothing to check... if (m_diff) { if (m.is_eq(n)) check_diff_predicate(n); @@ -449,8 +449,8 @@ struct check_logic::imp { fail(strm.str().c_str()); } } - - void operator()(quantifier * n) { + + void operator()(quantifier * n) { if (!m_quantifiers) fail("logic does not support quantifiers"); } @@ -490,7 +490,7 @@ struct check_logic::imp { check_logic::check_logic() { m_imp = 0; } - + check_logic::~check_logic() { if (m_imp) dealloc(m_imp); From 5fee1ea3c0719b953ea5f3cae0784c5fe12cb78d Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Mon, 24 Oct 2016 14:08:33 +0100 Subject: [PATCH 272/536] removed unused variables --- src/api/api_fpa.cpp | 22 ---------------------- 1 file changed, 22 deletions(-) diff --git a/src/api/api_fpa.cpp b/src/api/api_fpa.cpp index 669df8666..9b8934d30 100644 --- a/src/api/api_fpa.cpp +++ b/src/api/api_fpa.cpp @@ -915,7 +915,6 @@ extern "C" { mpf_manager & mpfm = mk_c(c)->fpautil().fm(); family_id fid = mk_c(c)->get_fpa_fid(); fpa_decl_plugin * plugin = (fpa_decl_plugin*)m.get_plugin(fid); - fpa_util & fu = mk_c(c)->fpautil(); expr * e = to_expr(t); if (!is_app(e) || is_app_of(e, fid, OP_FPA_NAN) || !is_fp(c, t)) { SET_ERROR_CODE(Z3_INVALID_ARG); @@ -940,10 +939,8 @@ extern "C" { CHECK_VALID_AST(t, 0); ast_manager & m = mk_c(c)->m(); mpf_manager & mpfm = mk_c(c)->fpautil().fm(); - unsynch_mpq_manager & mpqm = mpfm.mpq_manager(); family_id fid = mk_c(c)->get_fpa_fid(); fpa_decl_plugin * plugin = (fpa_decl_plugin*)m.get_plugin(fid); - fpa_util & fu = mk_c(c)->fpautil(); api::context * ctx = mk_c(c); expr * e = to_expr(t); if (!is_app(e) || is_app_of(e, fid, OP_FPA_NAN) || !is_fp(c, t)) { @@ -979,7 +976,6 @@ extern "C" { family_id fid = mk_c(c)->get_fpa_fid(); fpa_decl_plugin * plugin = (fpa_decl_plugin*)m.get_plugin(fid); SASSERT(plugin != 0); - fpa_util & fu = mk_c(c)->fpautil(); expr * e = to_expr(t); if (!is_app(e) || is_app_of(e, fid, OP_FPA_NAN) || !is_fp(c, t)) { SET_ERROR_CODE(Z3_INVALID_ARG); @@ -1013,7 +1009,6 @@ extern "C" { family_id fid = mk_c(c)->get_fpa_fid(); fpa_decl_plugin * plugin = (fpa_decl_plugin*)m.get_plugin(fid); SASSERT(plugin != 0); - fpa_util & fu = mk_c(c)->fpautil(); expr * e = to_expr(t); if (!is_app(e) || is_app_of(e, fid, OP_FPA_NAN) || !is_fp(c, t)) { SET_ERROR_CODE(Z3_INVALID_ARG); @@ -1047,7 +1042,6 @@ extern "C" { family_id fid = mk_c(c)->get_fpa_fid(); fpa_decl_plugin * plugin = (fpa_decl_plugin*)m.get_plugin(fid); SASSERT(plugin != 0); - fpa_util & fu = mk_c(c)->fpautil(); expr * e = to_expr(t); if (!is_app(e) || is_app_of(e, fid, OP_FPA_NAN) || !is_fp(c, t)) { SET_ERROR_CODE(Z3_INVALID_ARG); @@ -1078,7 +1072,6 @@ extern "C" { family_id fid = mk_c(c)->get_fpa_fid(); fpa_decl_plugin * plugin = (fpa_decl_plugin*)m.get_plugin(mk_c(c)->get_fpa_fid()); SASSERT(plugin != 0); - fpa_util & fu = mk_c(c)->fpautil(); expr * e = to_expr(t); if (!is_app(e) || is_app_of(e, fid, OP_FPA_NAN) || !is_fp(c, t)) { SET_ERROR_CODE(Z3_INVALID_ARG); @@ -1111,7 +1104,6 @@ extern "C" { family_id fid = mk_c(c)->get_fpa_fid(); fpa_decl_plugin * plugin = (fpa_decl_plugin*)m.get_plugin(mk_c(c)->get_fpa_fid()); SASSERT(plugin != 0); - fpa_util & fu = mk_c(c)->fpautil(); expr * e = to_expr(t); if (!is_app(e) || is_app_of(e, fid, OP_FPA_NAN) || !is_fp(c, t)) { SET_ERROR_CODE(Z3_INVALID_ARG); @@ -1143,10 +1135,8 @@ extern "C" { CHECK_VALID_AST(t, 0); ast_manager & m = mk_c(c)->m(); mpf_manager & mpfm = mk_c(c)->fpautil().fm(); - unsynch_mpq_manager & mpqm = mpfm.mpq_manager(); family_id fid = mk_c(c)->get_fpa_fid(); fpa_decl_plugin * plugin = (fpa_decl_plugin*)m.get_plugin(fid); - fpa_util & fu = mk_c(c)->fpautil(); expr * e = to_expr(t); if (!is_app(e) || is_app_of(e, fid, OP_FPA_NAN) || !is_fp(c, t)) { SET_ERROR_CODE(Z3_INVALID_ARG); @@ -1207,9 +1197,7 @@ extern "C" { Z3_TRY; Z3_fpa_is_numeral_nan(c, t); RESET_ERROR_CODE(); - ast_manager & m = mk_c(c)->m(); api::context * ctx = mk_c(c); - mpf_manager & mpfm = mk_c(c)->fpautil().fm(); fpa_util & fu = ctx->fpautil(); if (!is_expr(t) || !fu.is_numeral(to_expr(t))) { SET_ERROR_CODE(Z3_INVALID_ARG); @@ -1223,9 +1211,7 @@ extern "C" { Z3_TRY; Z3_fpa_is_numeral_inf(c, t); RESET_ERROR_CODE(); - ast_manager & m = mk_c(c)->m(); api::context * ctx = mk_c(c); - mpf_manager & mpfm = mk_c(c)->fpautil().fm(); fpa_util & fu = ctx->fpautil(); if (!is_expr(t) || !fu.is_numeral(to_expr(t))) { SET_ERROR_CODE(Z3_INVALID_ARG); @@ -1239,9 +1225,7 @@ extern "C" { Z3_TRY; Z3_fpa_is_numeral_zero(c, t); RESET_ERROR_CODE(); - ast_manager & m = mk_c(c)->m(); api::context * ctx = mk_c(c); - mpf_manager & mpfm = mk_c(c)->fpautil().fm(); fpa_util & fu = ctx->fpautil(); if (!is_expr(t) || !fu.is_numeral(to_expr(t))) { SET_ERROR_CODE(Z3_INVALID_ARG); @@ -1255,9 +1239,7 @@ extern "C" { Z3_TRY; Z3_fpa_is_numeral_normal(c, t); RESET_ERROR_CODE(); - ast_manager & m = mk_c(c)->m(); api::context * ctx = mk_c(c); - mpf_manager & mpfm = mk_c(c)->fpautil().fm(); fpa_util & fu = ctx->fpautil(); if (!is_expr(t) || !fu.is_numeral(to_expr(t))) { SET_ERROR_CODE(Z3_INVALID_ARG); @@ -1271,9 +1253,7 @@ extern "C" { Z3_TRY; Z3_fpa_is_numeral_subnormal(c, t); RESET_ERROR_CODE(); - ast_manager & m = mk_c(c)->m(); api::context * ctx = mk_c(c); - mpf_manager & mpfm = mk_c(c)->fpautil().fm(); fpa_util & fu = ctx->fpautil(); if (!is_expr(t) || !fu.is_numeral(to_expr(t))) { SET_ERROR_CODE(Z3_INVALID_ARG); @@ -1287,9 +1267,7 @@ extern "C" { Z3_TRY; Z3_fpa_is_numeral_positive(c, t); RESET_ERROR_CODE(); - ast_manager & m = mk_c(c)->m(); api::context * ctx = mk_c(c); - mpf_manager & mpfm = mk_c(c)->fpautil().fm(); fpa_util & fu = ctx->fpautil(); if (!is_expr(t) || !fu.is_numeral(to_expr(t))) { SET_ERROR_CODE(Z3_INVALID_ARG); From 79f1d7b4d40781932c44aaaa31f13d9ce7e1865f Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Mon, 24 Oct 2016 15:27:47 +0100 Subject: [PATCH 273/536] fixed GCC build issue in tests --- src/test/sorting_network.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/sorting_network.cpp b/src/test/sorting_network.cpp index 8b2aadee3..a64d3a70f 100644 --- a/src/test/sorting_network.cpp +++ b/src/test/sorting_network.cpp @@ -416,7 +416,7 @@ static void test_at_most1() { for (unsigned i = 0; i < 5; ++i) { in.push_back(m.mk_fresh_const("a",m.mk_bool_sort())); } - in[4] = in[3]; + in[4] = in[3].get(); ast_ext2 ext(m); psort_nw sn(ext); From 6cf54a226e003b334b78bb0f6cbd4654fa289f78 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 24 Oct 2016 08:25:02 -0700 Subject: [PATCH 274/536] a more efficient encoding for pseudo-Boolean inequality constraints into bit-vectors Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/pb2bv_rewriter.cpp | 237 ++++++++++++---------------- 1 file changed, 103 insertions(+), 134 deletions(-) diff --git a/src/ast/rewriter/pb2bv_rewriter.cpp b/src/ast/rewriter/pb2bv_rewriter.cpp index 0aeeea81a..48d566f11 100644 --- a/src/ast/rewriter/pb2bv_rewriter.cpp +++ b/src/ast/rewriter/pb2bv_rewriter.cpp @@ -24,6 +24,7 @@ Notes: #include"sorting_network.h" #include"ast_util.h" #include"ast_pp.h" +#include"lbool.h" struct pb2bv_rewriter::imp { @@ -79,150 +80,118 @@ struct pb2bv_rewriter::imp { bv_util bv; expr_ref_vector m_trail; - unsigned get_num_bits(func_decl* f) { - rational r(0); - unsigned sz = f->get_arity(); - for (unsigned i = 0; i < sz; ++i) { - r += pb.get_coeff(f, i); + template + expr_ref mk_le_ge(expr_ref_vector& fmls, expr* a, expr* b, expr* bound) { + expr_ref x(m), y(m), result(m); + unsigned nb = bv.get_bv_size(a); + x = bv.mk_zero_extend(1, a); + y = bv.mk_zero_extend(1, b); + result = bv.mk_bv_add(x, y); + x = bv.mk_extract(nb, nb, result); + result = bv.mk_extract(nb-1, 0, result); + if (is_le != l_false) { + fmls.push_back(m.mk_eq(x, bv.mk_numeral(rational::zero(), 1))); + fmls.push_back(bv.mk_ule(result, bound)); } - r = r > pb.get_k(f)? r : pb.get_k(f); - return r.get_num_bits(); + else { + fmls.push_back(m.mk_eq(x, bv.mk_numeral(rational::one(), 1))); + fmls.push_back(bv.mk_ule(bound, result)); + } + return result; + } - void mk_bv(func_decl * f, unsigned sz, expr * const* args, expr_ref & result) { - - expr_ref zero(m), a(m), b(m); - expr_ref_vector es(m); - unsigned bw = get_num_bits(f); - zero = bv.mk_numeral(rational(0), bw); + // + // create a circuit of size sz*log(k) + // by forming a binary tree adding pairs of values that are assumed <= k, + // and in each step we check that the result is <= k by checking the overflow + // bit and that the non-overflow bits are <= k. + // The procedure for checking >= k is symmetric and checking for = k is + // achieved by checking <= k on intermediary addends and the resulting sum is = k. + // + template + expr_ref mk_le_ge(func_decl *f, unsigned sz, expr * const* args, rational const & k) { + if (k.is_zero()) { + if (is_le != l_false) { + return expr_ref(m.mk_not(mk_or(m, sz, args)), m); + } + else { + return expr_ref(m.mk_true(), m); + } + } + SASSERT(k.is_pos()); + expr_ref zero(m), bound(m); + expr_ref_vector es(m), fmls(m); + unsigned nb = k.get_num_bits(); + zero = bv.mk_numeral(rational(0), nb); + bound = bv.mk_numeral(k, nb); for (unsigned i = 0; i < sz; ++i) { - es.push_back(mk_ite(args[i], bv.mk_numeral(pb.get_coeff(f, i), bw), zero)); - } - switch (es.size()) { - case 0: a = zero; break; - case 1: a = es[0].get(); break; - default: - a = es[0].get(); - for (unsigned i = 1; i < es.size(); ++i) { - a = bv.mk_bv_add(a, es[i].get()); - } - break; - } - b = bv.mk_numeral(pb.get_k(f), bw); - - switch (f->get_decl_kind()) { - case OP_AT_MOST_K: - case OP_PB_LE: - result = bv.mk_ule(a, b); - break; - case OP_AT_LEAST_K: - case OP_PB_GE: - result = bv.mk_ule(b, a); - break; - case OP_PB_EQ: - result = m.mk_eq(a, b); - break; - default: - UNREACHABLE(); - } - TRACE("pb", tout << result << "\n";); - } - - bool mk_shannon(func_decl * f, unsigned sz, expr * const* args, expr_ref & result) { - decl_kind kind = f->get_decl_kind(); - if (kind != OP_PB_GE && kind != OP_AT_LEAST_K) { - return false; - } - unsigned max_clauses = sz*10; - vector argcs; - for (unsigned i = 0; i < sz; ++i) { - argcs.push_back(argc_t(args[i], pb.get_coeff(f, i))); - } - std::sort(argcs.begin(), argcs.end(), argc_gt()); - DEBUG_CODE( - for (unsigned i = 0; i + 1 < sz; ++i) { - SASSERT(argcs[i].m_coeff >= argcs[i+1].m_coeff); - }); - result = m.mk_app(f, sz, args); - TRACE("pb", tout << result << "\n";); - argc_cache cache; - expr_ref_vector trail(m); - vector todo_k; - unsigned_vector todo_i; - todo_k.push_back(pb.get_k(f)); - todo_i.push_back(0); - argc_entry entry1; - while (!todo_i.empty()) { - SASSERT(todo_i.size() == todo_k.size()); - if (cache.size() > max_clauses) { - return false; - } - unsigned i = todo_i.back(); - rational k = todo_k.back(); - argc_entry entry(i, k); - if (cache.contains(entry)) { - todo_i.pop_back(); - todo_k.pop_back(); - continue; - } - SASSERT(i < sz); - SASSERT(!k.is_neg()); - rational const& coeff = argcs[i].m_coeff; - expr* arg = argcs[i].m_arg; - if (i + 1 == sz) { - if (k.is_zero()) { - entry.m_value = m.mk_true(); - } - else if (coeff < k) { - entry.m_value = m.mk_false(); - } - else if (coeff.is_zero()) { - entry.m_value = m.mk_true(); + if (pb.get_coeff(f, i) > k) { + if (is_le != l_false) { + fmls.push_back(m.mk_not(args[i])); } else { - SASSERT(coeff >= k && k.is_pos()); - entry.m_value = arg; + fmls.push_back(args[i]); } - todo_i.pop_back(); - todo_k.pop_back(); - cache.insert(entry); - continue; - } - entry.m_index++; - expr* lo = 0, *hi = 0; - if (cache.find(entry, entry1)) { - lo = entry1.m_value; } else { - todo_i.push_back(i+1); - todo_k.push_back(k); - } - entry.m_k -= coeff; - if (!entry.m_k.is_pos()) { - hi = m.mk_true(); + es.push_back(mk_ite(args[i], bv.mk_numeral(pb.get_coeff(f, i), nb), zero)); } - else if (cache.find(entry, entry1)) { - hi = entry1.m_value; + } + while (es.size() > 1) { + for (unsigned i = 0; i + 1 < es.size(); i += 2) { + es[i/2] = mk_le_ge(fmls, es[i].get(), es[i+1].get(), bound); } - else { - todo_i.push_back(i+1); - todo_k.push_back(entry.m_k); + if ((es.size() % 2) == 1) { + es[es.size()/2] = es.back(); } - if (hi && lo) { - todo_i.pop_back(); - todo_k.pop_back(); - entry.m_index = i; - entry.m_k = k; - entry.m_value = mk_ite(arg, hi, lo); - trail.push_back(entry.m_value); - cache.insert(entry); - } - } - argc_entry entry(0, pb.get_k(f)); - VERIFY(cache.find(entry, entry)); - result = entry.m_value; - TRACE("pb", tout << result << "\n";); - return true; + es.shrink((1 + es.size())/2); + } + switch (is_le) { + case l_true: + return mk_and(fmls); + case l_false: + fmls.push_back(bv.mk_ule(bound, es.back())); + return mk_or(fmls); + case l_undef: + fmls.push_back(m.mk_eq(bound, es.back())); + return mk_and(fmls); + default: + UNREACHABLE(); + return expr_ref(m.mk_true(), m); + } + } + + expr_ref mk_bv(func_decl * f, unsigned sz, expr * const* args) { + decl_kind kind = f->get_decl_kind(); + rational k = pb.get_k(f); + SASSERT(!k.is_neg()); + switch (kind) { + case OP_PB_GE: + case OP_AT_LEAST_K: { + expr_ref_vector nargs(m); + nargs.append(sz, args); + dualize(f, nargs, k); + SASSERT(!k.is_neg()); + return mk_le_ge(f, sz, nargs.c_ptr(), k); + } + case OP_PB_LE: + case OP_AT_MOST_K: + return mk_le_ge(f, sz, args, k); + case OP_PB_EQ: + return mk_le_ge(f, sz, args, k); + default: + UNREACHABLE(); + return expr_ref(m.mk_true(), m); + } + } + + void dualize(func_decl* f, expr_ref_vector & args, rational & k) { + k.neg(); + for (unsigned i = 0; i < args.size(); ++i) { + k += pb.get_coeff(f, i); + args[i] = ::mk_not(m, args[i].get()); + } } expr* negate(expr* e) { @@ -346,8 +315,8 @@ struct pb2bv_rewriter::imp { else if (pb.is_ge(f) && pb.get_k(f).is_unsigned() && pb.has_unit_coefficients(f)) { result = m_sort.ge(true, pb.get_k(f).get_unsigned(), sz, args); } - else if (!mk_shannon(f, sz, args, result)) { - mk_bv(f, sz, args, result); + else { + result = mk_bv(f, sz, args); } } From 33e7dccd428ab194533811951a1412b49e1e44b1 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 24 Oct 2016 09:11:02 -0700 Subject: [PATCH 275/536] merge Signed-off-by: Nikolaj Bjorner --- src/smt/theory_pb.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/smt/theory_pb.cpp b/src/smt/theory_pb.cpp index d4f7bf30e..73e427b0b 100644 --- a/src/smt/theory_pb.cpp +++ b/src/smt/theory_pb.cpp @@ -1292,8 +1292,8 @@ namespace smt { IF_VERBOSE(1, verbose_stream() << "(smt.pb compile sorting network bound: " << k << " literals: " << in.size() - << " clauses: " << num_compiled_clauses - << " vars: " << num_compiled_vars << ")\n";); + << " clauses: " << sortnw.m_stats.m_num_compiled_clauses + << " vars: " << sortnw.m_stats.m_num_compiled_vars << ")\n";); // auxiliary clauses get removed when popping scopes. // we have to recompile the circuit after back-tracking. From c68c56b0e7190fa220ad7e0741a6c5eec2b7efa6 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 24 Oct 2016 13:09:27 -0700 Subject: [PATCH 276/536] fix incorrect assertion when checking signs of literals, exposed by mitls regressions Signed-off-by: Nikolaj Bjorner --- src/smt/smt_context.cpp | 9 +++++---- src/smt/smt_internalizer.cpp | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index 5f258fc61..912bbeb36 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -3773,15 +3773,16 @@ namespace smt { #ifdef Z3DEBUG for (unsigned i = 0; i < num_lits; i++) { literal l = lits[i]; - if (m_manager.is_not(expr_lits.get(i))) { + expr* real_atom; + if (expr_signs[i] != l.sign()) { + + VERIFY(m_manager.is_not(expr_lits.get(i), real_atom)); // the sign must have flipped when internalizing - expr * real_atom = to_app(expr_lits.get(i))->get_arg(0); + CTRACE("resolve_conflict_bug", real_atom != bool_var2expr(l.var()), tout << mk_pp(real_atom, m_manager) << "\n" << mk_pp(bool_var2expr(l.var()), m_manager) << "\n";); SASSERT(real_atom == bool_var2expr(l.var())); - SASSERT(expr_signs[i] != l.sign()); } else { SASSERT(expr_lits.get(i) == bool_var2expr(l.var())); - SASSERT(expr_signs[i] == l.sign()); } } #endif diff --git a/src/smt/smt_internalizer.cpp b/src/smt/smt_internalizer.cpp index 94ce453b4..8028feae6 100644 --- a/src/smt/smt_internalizer.cpp +++ b/src/smt/smt_internalizer.cpp @@ -840,7 +840,7 @@ namespace smt { } #endif TRACE("mk_bool_var", tout << "creating boolean variable: " << v << " for:\n" << mk_pp(n, m_manager) << "\n";); - TRACE("mk_var_bug", tout << "mk_bool: " << v << "\n";); + TRACE("mk_var_bug", tout << "mk_bool: " << v << "\n";); set_bool_var(id, v); m_bdata.reserve(v+1); m_activity.reserve(v+1); From a880e5f49be687222b1dd26facf518a1fed7a5ec Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 24 Oct 2016 13:12:36 -0700 Subject: [PATCH 277/536] fix incorrection assertion when checking signs of literals, exposed by miTLS regressions Signed-off-by: Nikolaj Bjorner --- src/smt/smt_context.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index 5f258fc61..832d4dac7 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -3773,15 +3773,15 @@ namespace smt { #ifdef Z3DEBUG for (unsigned i = 0; i < num_lits; i++) { literal l = lits[i]; - if (m_manager.is_not(expr_lits.get(i))) { + if (expr_signs[i] != l.sign()) { + expr* real_atom; + VERIFY(m_manager.is_not(expr_lits.get(i), real_atom)); // the sign must have flipped when internalizing - expr * real_atom = to_app(expr_lits.get(i))->get_arg(0); + CTRACE("resolve_conflict_bug", real_atom != bool_var2expr(l.var()), tout << mk_pp(real_atom, m_manager) << "\n" << mk_pp(bool_var2expr(l.var()), m_manager) << "\n";); SASSERT(real_atom == bool_var2expr(l.var())); - SASSERT(expr_signs[i] != l.sign()); } else { SASSERT(expr_lits.get(i) == bool_var2expr(l.var())); - SASSERT(expr_signs[i] == l.sign()); } } #endif From e4d2c5867aa24c04c87c48bb2bec453f401f66e6 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 24 Oct 2016 15:52:47 -0700 Subject: [PATCH 278/536] remove dead (and incorrect) code Signed-off-by: Nikolaj Bjorner --- src/sat/sat_solver.cpp | 22 +++++--- src/solver/mus.cpp | 115 ++++------------------------------------- 2 files changed, 26 insertions(+), 111 deletions(-) diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 1e667eccc..c3aaa5697 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -3151,7 +3151,7 @@ namespace sat { lbool solver::get_consequences(literal_vector const& asms, literal_vector const& lits, vector& conseq) { m_antecedents.reset(); - literal_set unfixed(lits), assumptions(asms); + literal_set vars(lits), assumptions(asms); pop_to_base_level(); if (inconsistent()) return l_false; @@ -3162,11 +3162,12 @@ namespace sat { propagate(false); if (check_inconsistent()) return l_false; - unsigned num_units = 0; - extract_fixed_consequences(num_units, assumptions, unfixed, conseq); - while (!unfixed.empty()) { + unsigned num_units = 0, num_iterations = 0; + extract_fixed_consequences(num_units, assumptions, vars, conseq); + while (!vars.empty()) { + ++num_iterations; checkpoint(); - literal_set::iterator it = unfixed.begin(), end = unfixed.end(); + literal_set::iterator it = vars.begin(), end = vars.end(); for (; it != end; ++it) { literal lit = *it; if (value(lit) != l_undef) { @@ -3197,9 +3198,16 @@ namespace sat { m_inconsistent = false; } if (is_sat == l_true) { - delete_unfixed(unfixed); + delete_unfixed(vars); } - extract_fixed_consequences(num_units, assumptions, unfixed, conseq); + extract_fixed_consequences(num_units, assumptions, vars, conseq); + IF_VERBOSE(1, verbose_stream() << "(get-consequences" + << " iterations: " << num_iterations + << " variables: " << vars.size() + << " fixed: " << conseq.size() + << " unfixed: " << lits.size() - conseq.size() - vars.size() + << ")\n";); + } return l_true; } diff --git a/src/solver/mus.cpp b/src/solver/mus.cpp index 81635f906..91d47386e 100644 --- a/src/solver/mus.cpp +++ b/src/solver/mus.cpp @@ -239,6 +239,17 @@ struct mus::imp { return l_false; } + void get_core(expr_set& core) { + core.reset(); + ptr_vector core_exprs; + m_solver.get_unsat_core(core_exprs); + for (unsigned i = 0; i < core_exprs.size(); ++i) { + if (m_expr2lit.contains(core_exprs[i])) { + core.insert(core_exprs[i]); + } + } + } + bool have_intersection(expr_set const& A, expr_set const& B) { if (A.size() < B.size()) { expr_set::iterator it = A.begin(), end = A.end(); @@ -345,110 +356,6 @@ struct mus::imp { return m_weight; } - - lbool qx(expr_ref_vector& mus) { - expr_set core, support; - for (unsigned i = 0; i < m_lit2expr.size(); ++i) { - core.insert(m_lit2expr[i].get()); - } - lbool is_sat = qx(core, support, false); - if (is_sat == l_true) { - expr_set::iterator it = core.begin(), end = core.end(); - mus.reset(); - for (; it != end; ++it) { - mus.push_back(*it); - } - } - return is_sat; - } - - lbool qx(expr_set& assignment, expr_set& support, bool has_support) { - lbool is_sat = l_true; -#if 0 - if (s.m_config.m_minimize_core_partial && s.m_stats.m_restart - m_restart > m_max_restarts) { - IF_VERBOSE(1, verbose_stream() << "(sat restart budget exceeded)\n";); - return l_true; - } -#endif - if (has_support) { - expr_ref_vector asms(m); - scoped_append _sa1(*this, asms, support); - scoped_append _sa2(*this, asms, m_assumptions); - is_sat = m_solver.check_sat(asms); - switch (is_sat) { - case l_false: { - expr_set core; - get_core(core); - support &= core; - assignment.reset(); - return l_true; - } - case l_undef: - return l_undef; - case l_true: - update_model(); - break; - default: - break; - } - } - if (assignment.size() == 1) { - return l_true; - } - expr_set assign2; - split(assignment, assign2); - support |= assignment; - is_sat = qx(assign2, support, !assignment.empty()); - unsplit(support, assignment); - if (is_sat != l_true) return is_sat; - support |= assign2; - is_sat = qx(assignment, support, !assign2.empty()); - assignment |= assign2; - unsplit(support, assign2); - return is_sat; - } - - void get_core(expr_set& core) { - core.reset(); - ptr_vector core_exprs; - m_solver.get_unsat_core(core_exprs); - for (unsigned i = 0; i < core_exprs.size(); ++i) { - if (m_expr2lit.contains(core_exprs[i])) { - core.insert(core_exprs[i]); - } - } - } - - void unsplit(expr_set& A, expr_set& B) { - expr_set A1, B1; - expr_set::iterator it = A.begin(), end = A.end(); - for (; it != end; ++it) { - if (B.contains(*it)) { - B1.insert(*it); - } - else { - A1.insert(*it); - } - } - A = A1; - B = B1; - } - - void split(expr_set& lits1, expr_set& lits2) { - unsigned half = lits1.size()/2; - expr_set lits3; - expr_set::iterator it = lits1.begin(), end = lits1.end(); - for (unsigned i = 0; it != end; ++it, ++i) { - if (i < half) { - lits3.insert(*it); - } - else { - lits2.insert(*it); - } - } - lits1 = lits3; - } - }; mus::mus(solver& s) { From b82b53dc349cf90b522983d3d03afec1d1a85167 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 24 Oct 2016 17:41:52 -0700 Subject: [PATCH 279/536] add handling of pseudo-boolean inequalities that use if-expressions over Booleans and arihmetic instead of built-in PB predicates Signed-off-by: Nikolaj Bjorner --- src/ast/arith_decl_plugin.h | 4 + src/ast/rewriter/pb2bv_rewriter.cpp | 162 ++++++++++++++++++------ src/tactic/portfolio/enum2bv_solver.cpp | 2 - 3 files changed, 125 insertions(+), 43 deletions(-) diff --git a/src/ast/arith_decl_plugin.h b/src/ast/arith_decl_plugin.h index 4f0379674..410c50852 100644 --- a/src/ast/arith_decl_plugin.h +++ b/src/ast/arith_decl_plugin.h @@ -264,6 +264,10 @@ public: bool is_ge(expr const * n) const { return is_app_of(n, m_afid, OP_GE); } bool is_lt(expr const * n) const { return is_app_of(n, m_afid, OP_LT); } bool is_gt(expr const * n) const { return is_app_of(n, m_afid, OP_GT); } + bool is_le(func_decl const * n) const { return is_decl_of(n, m_afid, OP_LE); } + bool is_ge(func_decl const * n) const { return is_decl_of(n, m_afid, OP_GE); } + bool is_lt(func_decl const * n) const { return is_decl_of(n, m_afid, OP_LT); } + bool is_gt(func_decl const * n) const { return is_decl_of(n, m_afid, OP_GT); } bool is_add(expr const * n) const { return is_app_of(n, m_afid, OP_ADD); } bool is_sub(expr const * n) const { return is_app_of(n, m_afid, OP_SUB); } bool is_uminus(expr const * n) const { return is_app_of(n, m_afid, OP_UMINUS); } diff --git a/src/ast/rewriter/pb2bv_rewriter.cpp b/src/ast/rewriter/pb2bv_rewriter.cpp index 48d566f11..5cd7789ff 100644 --- a/src/ast/rewriter/pb2bv_rewriter.cpp +++ b/src/ast/rewriter/pb2bv_rewriter.cpp @@ -79,6 +79,9 @@ struct pb2bv_rewriter::imp { pb_util pb; bv_util bv; expr_ref_vector m_trail; + expr_ref_vector m_args; + rational m_k; + vector m_coeffs; template expr_ref mk_le_ge(expr_ref_vector& fmls, expr* a, expr* b, expr* bound) { @@ -109,8 +112,22 @@ struct pb2bv_rewriter::imp { // The procedure for checking >= k is symmetric and checking for = k is // achieved by checking <= k on intermediary addends and the resulting sum is = k. // + // is_le = l_true - <= + // is_le = l_undef - = + // is_le = l_false - >= + // template - expr_ref mk_le_ge(func_decl *f, unsigned sz, expr * const* args, rational const & k) { + expr_ref mk_le_ge(unsigned sz, expr * const* args, rational const & k) { + TRACE("pb", + for (unsigned i = 0; i < sz; ++i) { + tout << m_coeffs[i] << "*" << mk_pp(args[i], m) << " "; + } + switch (is_le) { + case l_true: tout << "<= "; break; + case l_undef: tout << "= "; break; + case l_false: tout << ">= "; break; + } + tout << m_k << "\n";); if (k.is_zero()) { if (is_le != l_false) { return expr_ref(m.mk_not(mk_or(m, sz, args)), m); @@ -119,6 +136,9 @@ struct pb2bv_rewriter::imp { return expr_ref(m.mk_true(), m); } } + if (k.is_neg()) { + return expr_ref((is_le == l_false)?m.mk_true():m.mk_false(), m); + } SASSERT(k.is_pos()); expr_ref zero(m), bound(m); expr_ref_vector es(m), fmls(m); @@ -126,7 +146,8 @@ struct pb2bv_rewriter::imp { zero = bv.mk_numeral(rational(0), nb); bound = bv.mk_numeral(k, nb); for (unsigned i = 0; i < sz; ++i) { - if (pb.get_coeff(f, i) > k) { + SASSERT(!m_coeffs[i].is_neg()); + if (m_coeffs[i] > k) { if (is_le != l_false) { fmls.push_back(m.mk_not(args[i])); } @@ -135,7 +156,7 @@ struct pb2bv_rewriter::imp { } } else { - es.push_back(mk_ite(args[i], bv.mk_numeral(pb.get_coeff(f, i), nb), zero)); + es.push_back(mk_ite(args[i], bv.mk_numeral(m_coeffs[i], nb), zero)); } } while (es.size() > 1) { @@ -165,6 +186,10 @@ struct pb2bv_rewriter::imp { expr_ref mk_bv(func_decl * f, unsigned sz, expr * const* args) { decl_kind kind = f->get_decl_kind(); rational k = pb.get_k(f); + m_coeffs.reset(); + for (unsigned i = 0; i < sz; ++i) { + m_coeffs.push_back(pb.get_coeff(f, i)); + } SASSERT(!k.is_neg()); switch (kind) { case OP_PB_GE: @@ -173,13 +198,13 @@ struct pb2bv_rewriter::imp { nargs.append(sz, args); dualize(f, nargs, k); SASSERT(!k.is_neg()); - return mk_le_ge(f, sz, nargs.c_ptr(), k); + return mk_le_ge(sz, nargs.c_ptr(), k); } case OP_PB_LE: case OP_AT_MOST_K: - return mk_le_ge(f, sz, args, k); + return mk_le_ge(sz, args, k); case OP_PB_EQ: - return mk_le_ge(f, sz, args, k); + return mk_le_ge(sz, args, k); default: UNREACHABLE(); return expr_ref(m.mk_true(), m); @@ -228,7 +253,6 @@ struct pb2bv_rewriter::imp { } } - public: card2bv_rewriter(imp& i, ast_manager& m): @@ -238,7 +262,8 @@ struct pb2bv_rewriter::imp { pb(m), bv(m), m_sort(*this), - m_trail(m) + m_trail(m), + m_args(m) {} br_status mk_app_core(func_decl * f, unsigned sz, expr * const* args, expr_ref & result) { @@ -247,8 +272,31 @@ struct pb2bv_rewriter::imp { ++m_imp.m_num_translated; return BR_DONE; } - else if (f->get_family_id() == au.get_family_id() && mk_arith(f, sz, args, result)) { + else if (au.is_le(f) && is_pb(args[0], args[1])) { ++m_imp.m_num_translated; + result = mk_le_ge(m_args.size(), m_args.c_ptr(), m_k); + return BR_DONE; + } + else if (au.is_lt(f) && is_pb(args[0], args[1])) { + ++m_imp.m_num_translated; + ++m_k; + result = mk_le_ge(m_args.size(), m_args.c_ptr(), m_k); + return BR_DONE; + } + else if (au.is_ge(f) && is_pb(args[1], args[0])) { + ++m_imp.m_num_translated; + result = mk_le_ge(m_args.size(), m_args.c_ptr(), m_k); + return BR_DONE; + } + else if (au.is_gt(f) && is_pb(args[1], args[0])) { + ++m_imp.m_num_translated; + ++m_k; + result = mk_le_ge(m_args.size(), m_args.c_ptr(), m_k); + return BR_DONE; + } + else if (m.is_eq(f) && is_pb(args[0], args[1])) { + ++m_imp.m_num_translated; + result = mk_le_ge(m_args.size(), m_args.c_ptr(), m_k); return BR_DONE; } else { @@ -256,43 +304,75 @@ struct pb2bv_rewriter::imp { } } - // - // NSB: review - // we should remove this code and rely on a layer above to deal with - // whatever it accomplishes. It seems to break types. - // - bool mk_arith(func_decl * f, unsigned sz, expr * const* args, expr_ref & result) { - if (f->get_decl_kind() == OP_ADD) { - unsigned bits = 0; - for (unsigned i = 0; i < sz; i++) { - rational val1, val2; - if (au.is_int(args[i]) && au.is_numeral(args[i], val1)) { - bits += val1.get_num_bits(); + bool is_pb(expr* x, expr* y) { + m_args.reset(); + m_coeffs.reset(); + m_k.reset(); + return is_pb(x, rational::one()) && is_pb(y, rational::minus_one()); + } + + bool is_pb(expr* e, rational const& mul) { + if (!is_app(e)) { + return false; + } + app* a = to_app(e); + rational r, r1, r2; + expr* c, *th, *el; + unsigned sz = a->get_num_args(); + if (a->get_family_id() == au.get_family_id()) { + switch (a->get_decl_kind()) { + case OP_ADD: + for (unsigned i = 0; i < sz; ++i) { + if (!is_pb(a->get_arg(i), mul)) return false; } - else if (m.is_ite(args[i]) && - au.is_numeral(to_app(args[i])->get_arg(1), val1) && val1.is_one() && - au.is_numeral(to_app(args[i])->get_arg(2), val2) && val2.is_zero()) { - bits++; + return true; + case OP_SUB: { + if (!is_pb(a->get_arg(0), mul)) return false; + r = -mul; + for (unsigned i = 1; i < sz; ++i) { + if (!is_pb(a->get_arg(1), r)) return false; } - else - return false; + return true; + } + case OP_UMINUS: + return is_pb(a->get_arg(0), -mul); + case OP_NUM: + VERIFY(au.is_numeral(a, r)); + m_k += mul * r; + return true; + case OP_MUL: + if (sz != 2) { + return false; + } + if (au.is_numeral(a->get_arg(0), r)) { + r *= mul; + return is_pb(a->get_arg(1), r); + } + if (au.is_numeral(a->get_arg(1), r)) { + r *= mul; + return is_pb(a->get_arg(0), r); + } + return false; + default: + return false; + } + } + if (m.is_ite(a, c, th, el) && au.is_numeral(th, r1) && au.is_numeral(el, r2)) { + r1 *= mul; + r2 *= mul; + if (r1 < r2) { + m_args.push_back(::mk_not(m, c)); + m_coeffs.push_back(r2-r1); + m_k -= r1; + } + else { + m_args.push_back(c); + m_coeffs.push_back(r1-r2); + m_k -= r2; } - - result = 0; - for (unsigned i = 0; i < sz; i++) { - rational val1, val2; - expr * q; - if (au.is_int(args[i]) && au.is_numeral(args[i], val1)) - q = bv.mk_numeral(val1, bits); - else - q = mk_ite(to_app(args[i])->get_arg(0), bv.mk_numeral(1, bits), bv.mk_numeral(0, bits)); - result = (i == 0) ? q : bv.mk_bv_add(result.get(), q); - } return true; } - else { - return false; - } + return false; } void mk_pb(func_decl * f, unsigned sz, expr * const* args, expr_ref & result) { diff --git a/src/tactic/portfolio/enum2bv_solver.cpp b/src/tactic/portfolio/enum2bv_solver.cpp index 369402114..b0f11cb91 100644 --- a/src/tactic/portfolio/enum2bv_solver.cpp +++ b/src/tactic/portfolio/enum2bv_solver.cpp @@ -115,8 +115,6 @@ public: } } lbool r = m_solver->get_consequences(asms, bvars, consequences); - std::cout << consequences.size() << "\n"; - // translate bit-vector consequences back to enumeration types for (unsigned i = 0; i < consequences.size(); ++i) { From fefd00aa4980dd7410f2315a6e3033c349f6b266 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 24 Oct 2016 20:28:56 -0700 Subject: [PATCH 280/536] fix sign of constant in pb constraint Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/pb2bv_rewriter.cpp | 36 ++--------------------------- 1 file changed, 2 insertions(+), 34 deletions(-) diff --git a/src/ast/rewriter/pb2bv_rewriter.cpp b/src/ast/rewriter/pb2bv_rewriter.cpp index 5cd7789ff..4f538867e 100644 --- a/src/ast/rewriter/pb2bv_rewriter.cpp +++ b/src/ast/rewriter/pb2bv_rewriter.cpp @@ -29,39 +29,6 @@ Notes: struct pb2bv_rewriter::imp { - struct argc_t { - expr* m_arg; - rational m_coeff; - argc_t():m_arg(0), m_coeff(0) {} - argc_t(expr* arg, rational const& r): m_arg(arg), m_coeff(r) {} - }; - - struct argc_gt { - bool operator()(argc_t const& a, argc_t const& b) const { - return a.m_coeff > b.m_coeff; - } - }; - - struct argc_entry { - unsigned m_index; - rational m_k; - expr* m_value; - argc_entry(unsigned i, rational const& k): m_index(i), m_k(k), m_value(0) {} - argc_entry():m_index(0), m_k(0), m_value(0) {} - - struct eq { - bool operator()(argc_entry const& a, argc_entry const& b) const { - return a.m_index == b.m_index && a.m_k == b.m_k; - } - }; - struct hash { - unsigned operator()(argc_entry const& a) const { - return a.m_index ^ a.m_k.hash(); - } - }; - }; - typedef hashtable argc_cache; - ast_manager& m; params_ref m_params; expr_ref_vector m_lemmas; @@ -121,6 +88,7 @@ struct pb2bv_rewriter::imp { TRACE("pb", for (unsigned i = 0; i < sz; ++i) { tout << m_coeffs[i] << "*" << mk_pp(args[i], m) << " "; + if (i + 1 < sz && !m_coeffs[i+1].is_neg()) tout << "+ "; } switch (is_le) { case l_true: tout << "<= "; break; @@ -338,7 +306,7 @@ struct pb2bv_rewriter::imp { return is_pb(a->get_arg(0), -mul); case OP_NUM: VERIFY(au.is_numeral(a, r)); - m_k += mul * r; + m_k -= mul * r; return true; case OP_MUL: if (sz != 2) { From dc78a0413528087ba8fc1148840655de808848d2 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Tue, 25 Oct 2016 12:20:45 +0100 Subject: [PATCH 281/536] removed debug output --- src/api/api_fpa.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/api/api_fpa.cpp b/src/api/api_fpa.cpp index 9b8934d30..8196fb826 100644 --- a/src/api/api_fpa.cpp +++ b/src/api/api_fpa.cpp @@ -953,7 +953,6 @@ extern "C" { SET_ERROR_CODE(Z3_INVALID_ARG); return 0; } - std::cout << "val=" << mpfm.to_string(val) << std::endl; app * a; if (mpfm.is_pos(val)) a = ctx->bvutil().mk_numeral(0, 1); From 963dfad10e304a6677c9e16dfb97f4c6ca478d6f Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Tue, 25 Oct 2016 14:15:43 +0100 Subject: [PATCH 282/536] fix for biased flag on get_numeral_exponent_string --- src/api/api_fpa.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/api_fpa.cpp b/src/api/api_fpa.cpp index 8196fb826..b24b7df0a 100644 --- a/src/api/api_fpa.cpp +++ b/src/api/api_fpa.cpp @@ -1087,7 +1087,7 @@ extern "C" { mpfm.is_denormal(val) ? mpfm.mk_min_exp(ebits) : mpfm.is_inf(val) ? mpfm.mk_top_exp(ebits) : mpfm.bias_exp(ebits, mpfm.exp(val)); - if (!biased) mpfm.unbias_exp(ebits, exp); + if (!biased) exp = mpfm.unbias_exp(ebits, exp); std::stringstream ss; ss << exp; return mk_c(c)->mk_external_string(ss.str()); From 6ea45b4d65f36f0299007dc172477ec6e8478727 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Tue, 25 Oct 2016 14:23:55 +0100 Subject: [PATCH 283/536] fix for Python API installation --- scripts/mk_util.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/scripts/mk_util.py b/scripts/mk_util.py index 309b08297..a86499149 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -1505,6 +1505,9 @@ class PythonInstallComponent(Component): os.path.join(self.pythonPkgDir, 'z3', '__pycache__', '*.pyc'), in_prefix=self.in_prefix_install ) + MakeRuleCmd.remove_installed_files(out, + os.path.join(self.pythonPkgDir, 'z3', 'lib', + self.libz3Component.dll_file())) def mk_makefile(self, out): return From 8c5c564d6ce49c1bfc80175a457712ee30691af7 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Tue, 25 Oct 2016 14:31:29 +0100 Subject: [PATCH 284/536] fixed initialization order warning in pb2bv_rewriter --- src/ast/rewriter/pb2bv_rewriter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ast/rewriter/pb2bv_rewriter.cpp b/src/ast/rewriter/pb2bv_rewriter.cpp index 4f538867e..8871c3dd8 100644 --- a/src/ast/rewriter/pb2bv_rewriter.cpp +++ b/src/ast/rewriter/pb2bv_rewriter.cpp @@ -224,12 +224,12 @@ struct pb2bv_rewriter::imp { public: card2bv_rewriter(imp& i, ast_manager& m): + m_sort(*this), m(m), m_imp(i), au(m), pb(m), bv(m), - m_sort(*this), m_trail(m), m_args(m) {} From c7fddf80c2a84d5235ddf4325cd2194de66d0083 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Tue, 25 Oct 2016 14:34:00 +0100 Subject: [PATCH 285/536] fixed unhandled case warning in test/qe_arith.cpp --- src/test/qe_arith.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/test/qe_arith.cpp b/src/test/qe_arith.cpp index 79495e24f..a73f7ed38 100644 --- a/src/test/qe_arith.cpp +++ b/src/test/qe_arith.cpp @@ -375,6 +375,9 @@ static void add_random_ineq( case opt::t_le: fml = a.mk_le(t1, t2); break; + case opt::t_mod: + NOT_IMPLEMENTED_YET(); + break; } fmls.push_back(fml); mbo.add_constraint(vars, rational(coeff), rel); From 461e88e34cfd6819343297e1ee87543a1ea3817e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 25 Oct 2016 20:32:13 -0700 Subject: [PATCH 286/536] additional robustness check for incremental sat solver core when it recieves interpreted constants, added PB equality to interface and special handling of equalities to adddress performance gap documented in #755 Signed-off-by: Nikolaj Bjorner --- contrib/cmake/src/solver/CMakeLists.txt | 1 + src/api/api_pb.cpp | 18 ++ src/api/dotnet/Context.cs | 15 ++ src/api/dotnet/Optimize.cs | 9 +- src/api/python/z3/z3.py | 20 ++ src/api/z3_api.h | 16 ++ src/sat/sat_solver/inc_sat_solver.cpp | 10 + src/sat/tactic/goal2sat.cpp | 17 +- src/sat/tactic/goal2sat.h | 6 +- src/smt/tactic/smt_tactic.cpp | 55 +----- src/smt/tactic/smt_tactic.h | 2 - src/solver/combined_solver.cpp | 1 + src/solver/solver2tactic.cpp | 179 ++++++++++++++++++ src/solver/solver2tactic.h | 30 +++ src/solver/tactic2solver.cpp | 1 + src/tactic/arith/bound_manager.cpp | 39 +++- src/tactic/arith/bound_manager.h | 2 + src/tactic/nlsat_smt/nl_purify_tactic.cpp | 1 + .../portfolio/bounded_int2bv_solver.cpp | 10 + src/tactic/portfolio/smt_strategic_solver.cpp | 3 + src/util/sorting_network.h | 79 ++++++-- 21 files changed, 430 insertions(+), 84 deletions(-) create mode 100644 src/solver/solver2tactic.cpp create mode 100644 src/solver/solver2tactic.h diff --git a/contrib/cmake/src/solver/CMakeLists.txt b/contrib/cmake/src/solver/CMakeLists.txt index 8142ca872..7f54e7745 100644 --- a/contrib/cmake/src/solver/CMakeLists.txt +++ b/contrib/cmake/src/solver/CMakeLists.txt @@ -5,6 +5,7 @@ z3_add_component(solver mus.cpp solver.cpp solver_na2as.cpp + solver2tactic.cpp tactic2solver.cpp COMPONENT_DEPENDENCIES model diff --git a/src/api/api_pb.cpp b/src/api/api_pb.cpp index 6d5a56d2c..b7c28c34f 100644 --- a/src/api/api_pb.cpp +++ b/src/api/api_pb.cpp @@ -57,5 +57,23 @@ extern "C" { Z3_CATCH_RETURN(0); } + Z3_ast Z3_API Z3_mk_pbeq(Z3_context c, unsigned num_args, + Z3_ast const args[], int _coeffs[], + int k) { + Z3_TRY; + LOG_Z3_mk_pble(c, num_args, args, _coeffs, k); + RESET_ERROR_CODE(); + pb_util util(mk_c(c)->m()); + vector coeffs; + for (unsigned i = 0; i < num_args; ++i) { + coeffs.push_back(rational(_coeffs[i])); + } + ast* a = util.mk_eq(num_args, coeffs.c_ptr(), to_exprs(args), rational(k)); + mk_c(c)->save_ast_trail(a); + check_sorts(c, a); + RETURN_Z3(of_ast(a)); + Z3_CATCH_RETURN(0); + } + }; diff --git a/src/api/dotnet/Context.cs b/src/api/dotnet/Context.cs index 6ca48fcb0..c3c33a41e 100644 --- a/src/api/dotnet/Context.cs +++ b/src/api/dotnet/Context.cs @@ -2640,6 +2640,21 @@ namespace Microsoft.Z3 AST.ArrayToNative(args), coeffs, k)); } + + /// + /// Create a pseudo-Boolean equal constraint. + /// + public BoolExpr MkPBEq(int[] coeffs, BoolExpr[] args, int k) + { + Contract.Requires(args != null); + Contract.Requires(coeffs != null); + Contract.Requires(args.Length == coeffs.Length); + Contract.Requires(Contract.Result() != null); + CheckContextMatch(args); + return new BoolExpr(this, Native.Z3_mk_pbeq(nCtx, (uint) args.Length, + AST.ArrayToNative(args), + coeffs, k)); + } #endregion #region Numerals diff --git a/src/api/dotnet/Optimize.cs b/src/api/dotnet/Optimize.cs index 036aaf2f2..c8954a473 100644 --- a/src/api/dotnet/Optimize.cs +++ b/src/api/dotnet/Optimize.cs @@ -258,10 +258,13 @@ namespace Microsoft.Z3 /// /// Return a string the describes why the last to check returned unknown /// - public String getReasonUnknown() + public String ReasonUnknown { - Contract.Ensures(Contract.Result() != null); - return Native.Z3_optimize_get_reason_unknown(Context.nCtx, NativeObject); + get + { + Contract.Ensures(Contract.Result() != null); + return Native.Z3_optimize_get_reason_unknown(Context.nCtx, NativeObject); + } } diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index a037bbc5d..514a45fc6 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -7654,6 +7654,26 @@ def PbLe(args, k): _coeffs[i] = coeffs[i] return BoolRef(Z3_mk_pble(ctx.ref(), sz, _args, _coeffs, k), ctx) +def PbEq(args, k): + """Create a Pseudo-Boolean inequality k constraint. + + >>> a, b, c = Bools('a b c') + >>> f = PbEq(((a,1),(b,3),(c,2)), 3) + """ + args = _get_args(args) + args, coeffs = zip(*args) + if __debug__: + _z3_assert(len(args) > 0, "Non empty list of arguments expected") + ctx = _ctx_from_ast_arg_list(args) + if __debug__: + _z3_assert(ctx is not None, "At least one of the arguments must be a Z3 expression") + args = _coerce_expr_list(args, ctx) + _args, sz = _to_ast_array(args) + _coeffs = (ctypes.c_int * len(coeffs))() + for i in range(len(coeffs)): + _coeffs[i] = coeffs[i] + return BoolRef(Z3_mk_pbeq(ctx.ref(), sz, _args, _coeffs, k), ctx) + def solve(*args, **keywords): """Solve the constraints `*args`. diff --git a/src/api/z3_api.h b/src/api/z3_api.h index 9e9771884..069f83340 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -861,6 +861,9 @@ typedef enum - Z3_OP_PB_GE: Generalized Pseudo-Boolean cardinality constraint. Example 2*x + 3*y + 2*z >= 4 + - Z3_OP_PB_EQ: Generalized Pseudo-Boolean equality constraint. + Example 2*x + 1*y + 2*z + 1*u = 4 + - Z3_OP_FPA_RM_NEAREST_TIES_TO_EVEN: Floating-point rounding mode RNE - Z3_OP_FPA_RM_NEAREST_TIES_TO_AWAY: Floating-point rounding mode RNA @@ -1166,6 +1169,7 @@ typedef enum { Z3_OP_PB_AT_MOST=0x900, Z3_OP_PB_LE, Z3_OP_PB_GE, + Z3_OP_PB_EQ, // Floating-Point Arithmetic Z3_OP_FPA_RM_NEAREST_TIES_TO_EVEN, @@ -3913,6 +3917,18 @@ extern "C" { Z3_ast const args[], int coeffs[], int k); + /** + \brief Pseudo-Boolean relations. + + Encode k1*p1 + k2*p2 + ... + kn*pn = k + + def_API('Z3_mk_pbeq', AST, (_in(CONTEXT), _in(UINT), _in_array(1,AST), _in_array(1,INT), _in(INT))) + */ + + Z3_ast Z3_API Z3_mk_pbeq(Z3_context c, unsigned num_args, + Z3_ast const args[], int coeffs[], + int k); + /** \brief Convert a \c Z3_func_decl into \c Z3_ast. This is just type casting. diff --git a/src/sat/sat_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp index 349b60f55..d091339bd 100644 --- a/src/sat/sat_solver/inc_sat_solver.cpp +++ b/src/sat/sat_solver/inc_sat_solver.cpp @@ -371,8 +371,18 @@ private: return l_undef; } g = m_subgoals[0]; + expr_ref_vector atoms(m); TRACE("sat", g->display_with_dependencies(tout);); m_goal2sat(*g, m_params, m_solver, m_map, dep2asm, true); + m_goal2sat.get_interpreted_atoms(atoms); + if (!atoms.empty()) { + std::stringstream strm; + strm << "interpreted atoms sent to SAT solver " << atoms; + TRACE("sat", std::cout << strm.str() << "\n";); + IF_VERBOSE(1, verbose_stream() << strm.str() << "\n";); + set_reason_unknown(strm.str().c_str()); + return l_undef; + } return l_true; } diff --git a/src/sat/tactic/goal2sat.cpp b/src/sat/tactic/goal2sat.cpp index 4d5542866..136921914 100644 --- a/src/sat/tactic/goal2sat.cpp +++ b/src/sat/tactic/goal2sat.cpp @@ -59,6 +59,7 @@ struct goal2sat::imp { bool m_ite_extra; unsigned long long m_max_memory; expr_ref_vector m_trail; + expr_ref_vector m_interpreted_atoms; bool m_default_external; imp(ast_manager & _m, params_ref const & p, sat::solver & s, atom2bool_var & map, dep2asm_map& dep2asm, bool default_external): @@ -67,6 +68,7 @@ struct goal2sat::imp { m_map(map), m_dep2asm(dep2asm), m_trail(m), + m_interpreted_atoms(m), m_default_external(default_external) { updt_params(p); m_true = sat::null_bool_var; @@ -128,6 +130,9 @@ struct goal2sat::imp { m_map.insert(t, v); l = sat::literal(v, sign); TRACE("goal2sat", tout << "new_var: " << v << "\n" << mk_ismt2_pp(t, m) << "\n";); + if (ext && !is_uninterp_const(t)) { + m_interpreted_atoms.push_back(t); + } } } else { @@ -474,7 +479,7 @@ bool goal2sat::has_unsupported_bool(goal const & g) { return test(g); } -goal2sat::goal2sat():m_imp(0) { +goal2sat::goal2sat():m_imp(0), m_interpreted_atoms(0) { } void goal2sat::collect_param_descrs(param_descrs & r) { @@ -492,10 +497,20 @@ struct goal2sat::scoped_set_imp { } }; + void goal2sat::operator()(goal const & g, params_ref const & p, sat::solver & t, atom2bool_var & m, dep2asm_map& dep2asm, bool default_external) { imp proc(g.m(), p, t, m, dep2asm, default_external); scoped_set_imp set(this, &proc); proc(g); + dealloc(m_interpreted_atoms); + m_interpreted_atoms = alloc(expr_ref_vector, g.m()); + m_interpreted_atoms->append(proc.m_interpreted_atoms); +} + +void goal2sat::get_interpreted_atoms(expr_ref_vector& atoms) { + if (m_interpreted_atoms) { + atoms.append(*m_interpreted_atoms); + } } diff --git a/src/sat/tactic/goal2sat.h b/src/sat/tactic/goal2sat.h index c6776f2f7..cd63cd497 100644 --- a/src/sat/tactic/goal2sat.h +++ b/src/sat/tactic/goal2sat.h @@ -38,8 +38,11 @@ class goal2sat { struct imp; imp * m_imp; struct scoped_set_imp; + expr_ref_vector* m_interpreted_atoms; + public: goal2sat(); + ~goal2sat() { dealloc(m_interpreted_atoms); } typedef obj_map dep2asm_map; @@ -53,12 +56,13 @@ public: \remark m doesn't need to be empty. the definitions there are reused. - + \warning conversion throws a tactic_exception, if it is interrupted (by set_cancel), an unsupported operator is found, or memory consumption limit is reached (set with param :max-memory). */ void operator()(goal const & g, params_ref const & p, sat::solver & t, atom2bool_var & m, dep2asm_map& dep2asm, bool default_external = false); + void get_interpreted_atoms(expr_ref_vector& atoms); }; diff --git a/src/smt/tactic/smt_tactic.cpp b/src/smt/tactic/smt_tactic.cpp index f2fbcf6d9..2909d8848 100644 --- a/src/smt/tactic/smt_tactic.cpp +++ b/src/smt/tactic/smt_tactic.cpp @@ -24,63 +24,10 @@ Notes: #include"rewriter_types.h" #include"filter_model_converter.h" #include"ast_util.h" +#include"solver2tactic.h" typedef obj_map expr2expr_map; -void extract_clauses_and_dependencies(goal_ref const& g, expr_ref_vector& clauses, ptr_vector& assumptions, expr2expr_map& bool2dep, ref& fmc) { - expr2expr_map dep2bool; - ptr_vector deps; - ast_manager& m = g->m(); - expr_ref_vector clause(m); - unsigned sz = g->size(); - for (unsigned i = 0; i < sz; i++) { - expr * f = g->form(i); - expr_dependency * d = g->dep(i); - if (d == 0 || !g->unsat_core_enabled()) { - clauses.push_back(f); - } - else { - // create clause (not d1 \/ ... \/ not dn \/ f) when the d's are the assumptions/dependencies of f. - clause.reset(); - clause.push_back(f); - deps.reset(); - m.linearize(d, deps); - SASSERT(!deps.empty()); // d != 0, then deps must not be empty - ptr_vector::iterator it = deps.begin(); - ptr_vector::iterator end = deps.end(); - for (; it != end; ++it) { - expr * d = *it; - if (is_uninterp_const(d) && m.is_bool(d)) { - // no need to create a fresh boolean variable for d - if (!bool2dep.contains(d)) { - assumptions.push_back(d); - bool2dep.insert(d, d); - } - clause.push_back(m.mk_not(d)); - } - else { - // must normalize assumption - expr * b = 0; - if (!dep2bool.find(d, b)) { - b = m.mk_fresh_const(0, m.mk_bool_sort()); - dep2bool.insert(d, b); - bool2dep.insert(b, d); - assumptions.push_back(b); - if (!fmc) { - fmc = alloc(filter_model_converter, m); - } - fmc->insert(to_app(b)->get_decl()); - } - clause.push_back(m.mk_not(b)); - } - } - SASSERT(clause.size() > 1); - expr_ref cls(m); - cls = mk_or(m, clause.size(), clause.c_ptr()); - clauses.push_back(cls); - } - } -} class smt_tactic : public tactic { smt_params m_params; diff --git a/src/smt/tactic/smt_tactic.h b/src/smt/tactic/smt_tactic.h index dd113634b..a23695fd1 100644 --- a/src/smt/tactic/smt_tactic.h +++ b/src/smt/tactic/smt_tactic.h @@ -32,8 +32,6 @@ tactic * mk_smt_tactic(params_ref const & p = params_ref()); tactic * mk_smt_tactic_using(bool auto_config = true, params_ref const & p = params_ref()); -void extract_clauses_and_dependencies(goal_ref const& g, expr_ref_vector& clauses, ptr_vector& assumptions, obj_map& bool2dep, ref& fmc); - /* ADD_TACTIC("smt", "apply a SAT based SMT solver.", "mk_smt_tactic(p)") */ diff --git a/src/solver/combined_solver.cpp b/src/solver/combined_solver.cpp index fc76f85c1..2856315bd 100644 --- a/src/solver/combined_solver.cpp +++ b/src/solver/combined_solver.cpp @@ -196,6 +196,7 @@ public: virtual lbool get_consequences(expr_ref_vector const& asms, expr_ref_vector const& vars, expr_ref_vector& consequences) { switch_inc_mode(); + m_use_solver1_results = false; return m_solver2->get_consequences(asms, vars, consequences); } diff --git a/src/solver/solver2tactic.cpp b/src/solver/solver2tactic.cpp new file mode 100644 index 000000000..53b120fea --- /dev/null +++ b/src/solver/solver2tactic.cpp @@ -0,0 +1,179 @@ +/*++ +Copyright (c) 2016 Microsoft Corporation + +Module Name: + + solver2tactic.cpp + +Abstract: + + Convert solver to a tactic. + +Author: + + Nikolaj Bjorner (nbjorner) 2016-10-17 + +Notes: + +--*/ + +#include "solver.h" +#include "tactic.h" +#include"filter_model_converter.h" +#include "solver2tactic.h" +#include "ast_util.h" + +typedef obj_map expr2expr_map; + +void extract_clauses_and_dependencies(goal_ref const& g, expr_ref_vector& clauses, ptr_vector& assumptions, expr2expr_map& bool2dep, ref& fmc) { + expr2expr_map dep2bool; + ptr_vector deps; + ast_manager& m = g->m(); + expr_ref_vector clause(m); + unsigned sz = g->size(); + for (unsigned i = 0; i < sz; i++) { + expr * f = g->form(i); + expr_dependency * d = g->dep(i); + if (d == 0 || !g->unsat_core_enabled()) { + clauses.push_back(f); + } + else { + // create clause (not d1 \/ ... \/ not dn \/ f) when the d's are the assumptions/dependencies of f. + clause.reset(); + clause.push_back(f); + deps.reset(); + m.linearize(d, deps); + SASSERT(!deps.empty()); // d != 0, then deps must not be empty + ptr_vector::iterator it = deps.begin(); + ptr_vector::iterator end = deps.end(); + for (; it != end; ++it) { + expr * d = *it; + if (is_uninterp_const(d) && m.is_bool(d)) { + // no need to create a fresh boolean variable for d + if (!bool2dep.contains(d)) { + assumptions.push_back(d); + bool2dep.insert(d, d); + } + clause.push_back(m.mk_not(d)); + } + else { + // must normalize assumption + expr * b = 0; + if (!dep2bool.find(d, b)) { + b = m.mk_fresh_const(0, m.mk_bool_sort()); + dep2bool.insert(d, b); + bool2dep.insert(b, d); + assumptions.push_back(b); + if (!fmc) { + fmc = alloc(filter_model_converter, m); + } + fmc->insert(to_app(b)->get_decl()); + } + clause.push_back(m.mk_not(b)); + } + } + SASSERT(clause.size() > 1); + expr_ref cls(m); + cls = mk_or(m, clause.size(), clause.c_ptr()); + clauses.push_back(cls); + } + } +} + +class solver2tactic : public tactic { + ast_manager& m; + ref m_solver; + params_ref m_params; + +public: + solver2tactic(solver* s): + m(s->get_manager()), + m_solver(s) + {} + + virtual void updt_params(params_ref const & p) { + m_solver->updt_params(p); + } + + virtual void collect_param_descrs(param_descrs & r) { + m_solver->collect_param_descrs(r); + } + + virtual void operator()(/* in */ goal_ref const & in, + /* out */ goal_ref_buffer & result, + /* out */ model_converter_ref & mc, + /* out */ proof_converter_ref & pc, + /* out */ expr_dependency_ref & core) { + expr_ref_vector clauses(m); + expr2expr_map bool2dep; + ptr_vector assumptions; + ref fmc; + extract_clauses_and_dependencies(in, clauses, assumptions, bool2dep, fmc); + m_solver->push(); + m_solver->assert_expr(clauses); + lbool r = m_solver->check_sat(assumptions.size(), assumptions.c_ptr()); + switch (r) { + case l_true: + if (in->models_enabled()) { + model_ref mdl; + m_solver->get_model(mdl); + mc = model2model_converter(mdl.get()); + mc = concat(fmc.get(), mc.get()); + } + in->reset(); + result.push_back(in.get()); + pc = 0; + core = 0; + break; + case l_false: { + in->reset(); + proof* pr = 0; + expr_dependency* lcore = 0; + if (in->proofs_enabled()) { + pr = m_solver->get_proof(); + } + if (in->unsat_core_enabled()) { + ptr_vector core; + m_solver->get_unsat_core(core); + for (unsigned i = 0; i < core.size(); ++i) { + lcore = m.mk_join(lcore, m.mk_leaf(bool2dep.find(core[i]))); + } + } + in->assert_expr(m.mk_false(), pr, lcore); + result.push_back(in.get()); + mc = 0; + pc = 0; + core = 0; + break; + } + case l_undef: + if (m.canceled()) { + throw tactic_exception(Z3_CANCELED_MSG); + } + throw tactic_exception(m_solver->reason_unknown().c_str()); + } + m_solver->pop(1); + } + + virtual void collect_statistics(statistics & st) const { + m_solver->collect_statistics(st); + } + virtual void reset_statistics() {} + + virtual void cleanup() { + m_solver = m_solver->translate(m, m_params); + } + virtual void reset() { cleanup(); } + + virtual void set_logic(symbol const & l) {} + + virtual void set_progress_callback(progress_callback * callback) { + m_solver->set_progress_callback(callback); + } + + virtual tactic * translate(ast_manager & m) { + return alloc(solver2tactic, m_solver->translate(m, m_params)); + } +}; + +tactic* mk_solver2tactic(solver* s) { return alloc(solver2tactic, s); } diff --git a/src/solver/solver2tactic.h b/src/solver/solver2tactic.h new file mode 100644 index 000000000..65fbd37b1 --- /dev/null +++ b/src/solver/solver2tactic.h @@ -0,0 +1,30 @@ +/*++ +Copyright (c) 2016 Microsoft Corporation + +Module Name: + + solver2tactic.h + +Abstract: + + Convert solver to a tactic. + +Author: + + Nikolaj Bjorner (nbjorner) 2016-10-17 + +Notes: + +--*/ +#ifndef SOLVER2TACTIC_H_ +#define SOLVER2TACTIC_H_ + +#include "tactic.h" +#include "filter_model_converter.h" +class solver; + +tactic * mk_solver2tactic(solver* s); + +void extract_clauses_and_dependencies(goal_ref const& g, expr_ref_vector& clauses, ptr_vector& assumptions, obj_map& bool2dep, ref& fmc); + +#endif diff --git a/src/solver/tactic2solver.cpp b/src/solver/tactic2solver.cpp index f53301948..213ba5c1c 100644 --- a/src/solver/tactic2solver.cpp +++ b/src/solver/tactic2solver.cpp @@ -160,6 +160,7 @@ lbool tactic2solver::check_sat_core(unsigned num_assumptions, expr * const * ass } } catch (z3_error & ex) { + TRACE("tactic2solver", tout << "exception: " << ex.msg() << "\n";); throw ex; } catch (z3_exception & ex) { diff --git a/src/tactic/arith/bound_manager.cpp b/src/tactic/arith/bound_manager.cpp index ed77467c3..97d93658c 100644 --- a/src/tactic/arith/bound_manager.cpp +++ b/src/tactic/arith/bound_manager.cpp @@ -79,12 +79,23 @@ static bool is_strict(decl_kind k) { return k == OP_LT || k == OP_GT; } +bool bound_manager::is_numeral(expr* v, numeral& n, bool& is_int) { + expr* w; + if (m_util.is_uminus(v, w) && is_numeral(w, n, is_int)) { + n.neg(); + return true; + } + return m_util.is_numeral(v, n, is_int); +} + void bound_manager::operator()(expr * f, expr_dependency * d) { TRACE("bound_manager", tout << "processing:\n" << mk_ismt2_pp(f, m()) << "\n";); expr * v; numeral n; if (is_disjunctive_bound(f, d)) return; + if (is_equality_bound(f, d)) + return; bool pos = true; while (m().is_not(f, f)) pos = !pos; @@ -99,10 +110,10 @@ void bound_manager::operator()(expr * f, expr_dependency * d) { expr * lhs = t->get_arg(0); expr * rhs = t->get_arg(1); bool is_int; - if (is_uninterp_const(lhs) && m_util.is_numeral(rhs, n, is_int)) { + if (is_uninterp_const(lhs) && is_numeral(rhs, n, is_int)) { v = lhs; } - else if (is_uninterp_const(rhs) && m_util.is_numeral(lhs, n, is_int)) { + else if (is_uninterp_const(rhs) && is_numeral(lhs, n, is_int)) { v = rhs; k = swap_decl(k); } @@ -165,6 +176,26 @@ void bound_manager::insert_lower(expr * v, bool strict, numeral const & n, expr_ } } +bool bound_manager::is_equality_bound(expr * f, expr_dependency * d) { + expr* x, *y; + if (!m().is_eq(f, x, y)) { + return false; + } + if (!is_uninterp_const(x)) { + std::swap(x, y); + } + numeral n; + bool is_int; + if (is_uninterp_const(x) && is_numeral(y, n, is_int)) { + insert_lower(x, false, n, d); + insert_upper(x, false, n, d); + return true; + } + else { + return false; + } +} + bool bound_manager::is_disjunctive_bound(expr * f, expr_dependency * d) { numeral lo, hi, n; if (!m().is_or(f)) return false; @@ -176,14 +207,14 @@ bool bound_manager::is_disjunctive_bound(expr * f, expr_dependency * d) { expr * e = to_app(f)->get_arg(i); if (!m().is_eq(e, x, y)) return false; if (is_uninterp_const(x) && - m_util.is_numeral(y, n, is_int) && is_int && + is_numeral(y, n, is_int) && is_int && (x == v || v == 0)) { if (v == 0) { v = x; lo = hi = n; } if (n < lo) lo = n; if (n > hi) hi = n; } else if (is_uninterp_const(y) && - m_util.is_numeral(x, n, is_int) && is_int && + is_numeral(x, n, is_int) && is_int && (y == v || v == 0)) { if (v == 0) { v = y; lo = hi = n; } if (n < lo) lo = n; diff --git a/src/tactic/arith/bound_manager.h b/src/tactic/arith/bound_manager.h index cc0d693e9..6a4dc2c96 100644 --- a/src/tactic/arith/bound_manager.h +++ b/src/tactic/arith/bound_manager.h @@ -36,6 +36,8 @@ private: obj_map m_upper_deps; ptr_vector m_bounded_vars; bool is_disjunctive_bound(expr * f, expr_dependency * d); + bool is_equality_bound(expr * f, expr_dependency * d); + bool is_numeral(expr* v, rational& n, bool& is_int); void insert_lower(expr * v, bool strict, numeral const & n, expr_dependency * d); void insert_upper(expr * v, bool strict, numeral const & n, expr_dependency * d); public: diff --git a/src/tactic/nlsat_smt/nl_purify_tactic.cpp b/src/tactic/nlsat_smt/nl_purify_tactic.cpp index d8b016d7b..46b5a51b0 100644 --- a/src/tactic/nlsat_smt/nl_purify_tactic.cpp +++ b/src/tactic/nlsat_smt/nl_purify_tactic.cpp @@ -59,6 +59,7 @@ Revision History: #include "model_smt2_pp.h" #include "expr_safe_replace.h" #include "ast_util.h" +#include "solver2tactic.h" class nl_purify_tactic : public tactic { diff --git a/src/tactic/portfolio/bounded_int2bv_solver.cpp b/src/tactic/portfolio/bounded_int2bv_solver.cpp index f7236351c..688d9403a 100644 --- a/src/tactic/portfolio/bounded_int2bv_solver.cpp +++ b/src/tactic/portfolio/bounded_int2bv_solver.cpp @@ -251,6 +251,16 @@ private: } sub.insert(e, t); } + else { + IF_VERBOSE(1, + verbose_stream() << "unprocessed entry: " << mk_pp(e, m) << "\n"; + if (bm.has_lower(e, lo, s1)) { + verbose_stream() << "lower: " << lo << " " << s1 << "\n"; + } + if (bm.has_upper(e, hi, s2)) { + verbose_stream() << "upper: " << hi << " " << s2 << "\n"; + }); + } } } diff --git a/src/tactic/portfolio/smt_strategic_solver.cpp b/src/tactic/portfolio/smt_strategic_solver.cpp index 81825221e..d2414ec72 100644 --- a/src/tactic/portfolio/smt_strategic_solver.cpp +++ b/src/tactic/portfolio/smt_strategic_solver.cpp @@ -40,6 +40,7 @@ Notes: #include"inc_sat_solver.h" #include"fd_solver.h" #include"bv_rewriter.h" +#include"solver2tactic.h" tactic * mk_tactic_for_logic(ast_manager & m, params_ref const & p, symbol const & logic) { @@ -89,6 +90,8 @@ tactic * mk_tactic_for_logic(ast_manager & m, params_ref const & p, symbol const return mk_qffpbv_tactic(m, p); else if (logic=="HORN") return mk_horn_tactic(m, p); + else if (logic == "QF_FD") + return mk_solver2tactic(mk_fd_solver(m, p)); //else if (logic=="QF_UFNRA") // return mk_qfufnra_tactic(m, p); else diff --git a/src/util/sorting_network.h b/src/util/sorting_network.h index 0f5d2838e..9e35d6e8b 100644 --- a/src/util/sorting_network.h +++ b/src/util/sorting_network.h @@ -202,7 +202,8 @@ Notes: return ge(full, k, n, in.c_ptr()); } else if (k == 1) { - return mk_at_most_1(full, n, xs); + literal_vector ors; + return mk_at_most_1(full, n, xs, ors); } else { SASSERT(2*k <= n); @@ -221,6 +222,9 @@ Notes: if (dualize(k, n, xs, in)) { return eq(k, n, in.c_ptr()); } + else if (k == 1) { + return mk_exactly_1(true, n, xs); + } else { SASSERT(2*k <= n); m_t = EQ; @@ -238,12 +242,56 @@ Notes: private: - literal mk_at_most_1(bool full, unsigned n, literal const* xs) { + + literal mk_and(literal l1, literal l2) { + literal result = fresh(); + add_clause(ctx.mk_not(result), l1); + add_clause(ctx.mk_not(result), l2); + add_clause(ctx.mk_not(l1), ctx.mk_not(l2), result); + return result; + } + + void mk_implies_or(literal l, unsigned n, literal const* xs) { + literal_vector lits(n, xs); + lits.push_back(ctx.mk_not(l)); + add_clause(lits); + } + + void mk_or_implies(literal l, unsigned n, literal const* xs) { + for (unsigned j = 0; j < n; ++j) { + add_clause(ctx.mk_not(xs[j]), l); + } + } + + literal mk_or(literal_vector const& ors) { + if (ors.size() == 1) { + return ors[0]; + } + literal result = fresh(); + mk_implies_or(result, ors.size(), ors.c_ptr()); + mk_or_implies(result, ors.size(), ors.c_ptr()); + return result; + } + + literal mk_exactly_1(bool full, unsigned n, literal const* xs) { + literal_vector ors; + literal r1 = mk_at_most_1(full, n, xs, ors); + + if (full) { + r1 = mk_and(r1, mk_or(ors)); + } + else { + mk_implies_or(r1, ors.size(), ors.c_ptr()); + } + return r1; + } + + literal mk_at_most_1(bool full, unsigned n, literal const* xs, literal_vector& ors) { TRACE("pb", tout << (full?"full":"partial") << " "; for (unsigned i = 0; i < n; ++i) tout << xs[i] << " "; tout << "\n";); - if (!full && n >= 4) { + if (false && !full && n >= 4) { return mk_at_most_1_bimander(n, xs); } literal_vector in(n, xs); @@ -252,9 +300,10 @@ Notes: literal_vector ands; ands.push_back(result); while (!in.empty()) { - literal_vector ors; + ors.reset(); unsigned i = 0; unsigned n = in.size(); + if (n + 1 == inc_size) ++inc_size; bool last = n <= inc_size; for (; i + inc_size < n; i += inc_size) { mk_at_most_1_small(full, last, inc_size, in.c_ptr() + i, result, ands, ors); @@ -267,7 +316,6 @@ Notes: } in.reset(); in.append(ors); - ors.reset(); } if (full) { add_clause(ands); @@ -278,23 +326,16 @@ Notes: void mk_at_most_1_small(bool full, bool last, unsigned n, literal const* xs, literal result, literal_vector& ands, literal_vector& ors) { SASSERT(n > 0); if (n == 1) { - if (!last) { - ors.push_back(xs[0]); - } + ors.push_back(xs[0]); return; } - if (!last) { - literal ex = fresh(); - for (unsigned j = 0; j < n; ++j) { - add_clause(ctx.mk_not(xs[j]), ex); - } - if (full) { - literal_vector lits(n, xs); - lits.push_back(ctx.mk_not(ex)); - add_clause(lits.size(), lits.c_ptr()); - } - ors.push_back(ex); + literal ex = fresh(); + mk_or_implies(ex, n, xs); + if (full) { + mk_implies_or(ex, n, xs); } + ors.push_back(ex); + // result => xs[0] + ... + xs[n-1] <= 1 for (unsigned i = 0; i < n; ++i) { for (unsigned j = i + 1; j < n; ++j) { From da4289fadc378f5cc601abeb5e37176ed16c9b8a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 25 Oct 2016 20:47:48 -0700 Subject: [PATCH 287/536] fix unit tests for pb Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/pb2bv_rewriter.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/ast/rewriter/pb2bv_rewriter.cpp b/src/ast/rewriter/pb2bv_rewriter.cpp index 8871c3dd8..0cae3f307 100644 --- a/src/ast/rewriter/pb2bv_rewriter.cpp +++ b/src/ast/rewriter/pb2bv_rewriter.cpp @@ -140,10 +140,17 @@ struct pb2bv_rewriter::imp { case l_true: return mk_and(fmls); case l_false: - fmls.push_back(bv.mk_ule(bound, es.back())); + if (!es.empty()) { + fmls.push_back(bv.mk_ule(bound, es.back())); + } return mk_or(fmls); case l_undef: - fmls.push_back(m.mk_eq(bound, es.back())); + if (es.empty()) { + fmls.push_back(m.mk_bool_val(k.is_zero())); + } + else { + fmls.push_back(m.mk_eq(bound, es.back())); + } return mk_and(fmls); default: UNREACHABLE(); From 86285e1641c8339e23edddf1236afc7f2253ac7a Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Wed, 26 Oct 2016 12:59:26 +0100 Subject: [PATCH 288/536] disabled unnecessary assertion --- scripts/mk_util.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/mk_util.py b/scripts/mk_util.py index a86499149..0fac30e35 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -3278,7 +3278,7 @@ class MakeRuleCmd(object): #print("WARNING: Generating makefile rule that {}s {} '{}' which is outside the installation prefix '{}'.".format( # action_string, 'to' if is_install else 'from', path, PREFIX)) else: - assert not os.path.isabs(path) + # assert not os.path.isabs(path) install_root = cls.install_root() return install_root From ead970b4778330768e64a04f13a46289f974cb85 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Wed, 26 Oct 2016 14:08:33 +0100 Subject: [PATCH 289/536] Bugfix for Python API. Thanks to John D. Ramsdell for reporting this issue (http://stackoverflow.com/questions/39584779/why-is-the-sort-of-a-bound-variable-forced-not-to-be-a-finite-domain-sort). --- src/api/python/z3/z3.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index 514a45fc6..b9d7f6df0 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -1817,7 +1817,7 @@ class QuantifierRef(BoolRef): """ if __debug__: _z3_assert(idx < self.num_vars(), "Invalid variable idx") - return SortRef(Z3_get_quantifier_bound_sort(self.ctx_ref(), self.ast, idx), self.ctx) + return _to_sort_ref(Z3_get_quantifier_bound_sort(self.ctx_ref(), self.ast, idx), self.ctx) def children(self): """Return a list containing a single element self.body() From e381cef92ca88e48a875d3da1a4cb3cb32206352 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Wed, 26 Oct 2016 15:12:10 +0100 Subject: [PATCH 290/536] Marked .NET Z3Exception as serializable --- src/api/dotnet/Z3Exception.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/api/dotnet/Z3Exception.cs b/src/api/dotnet/Z3Exception.cs index adda43995..71e4fef1a 100644 --- a/src/api/dotnet/Z3Exception.cs +++ b/src/api/dotnet/Z3Exception.cs @@ -14,7 +14,7 @@ Author: Christoph Wintersteiger (cwinter) 2012-03-15 Notes: - + --*/ using System; @@ -24,6 +24,7 @@ namespace Microsoft.Z3 /// /// The exception base class for error reporting from Z3 /// + [Serializable] public class Z3Exception : Exception { /// From cf93e39666d286faea77475725657f0caf1bb6f8 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Wed, 26 Oct 2016 15:54:33 +0100 Subject: [PATCH 291/536] Fixed FPA unbiased exponent accessors --- src/api/api_fpa.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/api/api_fpa.cpp b/src/api/api_fpa.cpp index b24b7df0a..dc06bae5b 100644 --- a/src/api/api_fpa.cpp +++ b/src/api/api_fpa.cpp @@ -1087,7 +1087,8 @@ extern "C" { mpfm.is_denormal(val) ? mpfm.mk_min_exp(ebits) : mpfm.is_inf(val) ? mpfm.mk_top_exp(ebits) : mpfm.bias_exp(ebits, mpfm.exp(val)); - if (!biased) exp = mpfm.unbias_exp(ebits, exp); + if (mpfm.is_normal(val) && !biased) + exp = mpfm.exp(val); std::stringstream ss; ss << exp; return mk_c(c)->mk_external_string(ss.str()); @@ -1121,7 +1122,8 @@ extern "C" { mpfm.is_denormal(val) ? mpfm.mk_min_exp(ebits) : mpfm.is_inf(val) ? mpfm.mk_top_exp(ebits) : mpfm.bias_exp(ebits, mpfm.exp(val)); - if (!biased) *n = mpfm.unbias_exp(ebits, *n); + if (mpfm.is_normal(val) && !biased) + *n = mpfm.exp(val); return 1; Z3_CATCH_RETURN(0); } @@ -1152,7 +1154,11 @@ extern "C" { mpfm.is_denormal(val) ? mpfm.mk_min_exp(ebits) : mpfm.is_inf(val) ? mpfm.mk_top_exp(ebits) : mpfm.bias_exp(ebits, mpfm.exp(val)); - if (!biased) exp = mpfm.unbias_exp(ebits, exp); + if (mpfm.is_normal(val) && !biased) { + std::cout << "unbiassing" << std::endl; + exp = mpfm.exp(val); + } + app * a = mk_c(c)->bvutil().mk_numeral(exp, ebits); mk_c(c)->save_ast_trail(a); RETURN_Z3(of_expr(a)); From bea7bc5e30170694af655bc244a4dd9b8da1b2d8 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Wed, 26 Oct 2016 16:32:44 +0100 Subject: [PATCH 292/536] Bugfix for bv2fpa_converter. Fixes #767. --- src/ast/fpa/bv2fpa_converter.cpp | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/ast/fpa/bv2fpa_converter.cpp b/src/ast/fpa/bv2fpa_converter.cpp index 07a24e40a..0dec98e5c 100644 --- a/src/ast/fpa/bv2fpa_converter.cpp +++ b/src/ast/fpa/bv2fpa_converter.cpp @@ -322,10 +322,17 @@ void bv2fpa_converter::convert_consts(model_core * mc, model_core * target_model v2 = mc->get_const_interp(a2->get_decl()); #else expr * bv = mc->get_const_interp(to_app(to_app(a0)->get_arg(0))->get_decl()); - unsigned bv_sz = m_bv_util.get_bv_size(bv); - v0 = m_bv_util.mk_extract(bv_sz-1, bv_sz-1, bv); - v1 = m_bv_util.mk_extract(bv_sz-2, sbits-1, bv); - v2 = m_bv_util.mk_extract(sbits-2, 0, bv); + if (bv == 0) { + v0 = m_bv_util.mk_numeral(0, 1); + v1 = m_bv_util.mk_numeral(0, ebits); + v2 = m_bv_util.mk_numeral(0, sbits-1); + } + else { + unsigned bv_sz = m_bv_util.get_bv_size(bv); + v0 = m_bv_util.mk_extract(bv_sz-1, bv_sz-1, bv); + v1 = m_bv_util.mk_extract(bv_sz-2, sbits-1, bv); + v2 = m_bv_util.mk_extract(sbits-2, 0, bv); + } #endif if (!v0) v0 = m_bv_util.mk_numeral(0, 1); From c573a7446bfe8038d0692a0cfd738fbdb557c339 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Wed, 26 Oct 2016 18:44:25 +0100 Subject: [PATCH 293/536] Added FPA numeral predicates to .NET API --- src/api/dotnet/FPNum.cs | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/api/dotnet/FPNum.cs b/src/api/dotnet/FPNum.cs index 705e7304e..05eda00b3 100644 --- a/src/api/dotnet/FPNum.cs +++ b/src/api/dotnet/FPNum.cs @@ -136,6 +136,36 @@ namespace Microsoft.Z3 return new BitVecExpr(Context, Native.Z3_fpa_get_numeral_exponent_bv(Context.nCtx, NativeObject, biased ? 1 : 0)); } + /// + /// Indicates whether the numeral is a NaN. + /// + public bool IsNaN { get { return Native.Z3_fpa_is_numeral_nan(Context.nCtx, NativeObject) != 0; } } + + /// + /// Indicates whether the numeral is a +oo or -oo. + /// + public bool IsInf { get { return Native.Z3_fpa_is_numeral_inf(Context.nCtx, NativeObject) != 0; } } + + /// + /// Indicates whether the numeral is +zero or -zero. + /// + public bool IsZero{ get { return Native.Z3_fpa_is_numeral_zero(Context.nCtx, NativeObject) != 0; } } + + /// + /// Indicates whether the numeral is normal. + /// + public bool IsNormal { get { return Native.Z3_fpa_is_numeral_normal(Context.nCtx, NativeObject) != 0; } } + + /// + /// Indicates whether the numeral is subnormal. + /// + public bool IsSubnormal { get { return Native.Z3_fpa_is_numeral_subnormal(Context.nCtx, NativeObject) != 0; } } + + /// + /// Indicates whether the numeral is positive. + /// + public bool IsPositive { get { return Native.Z3_fpa_is_numeral_positive(Context.nCtx, NativeObject) != 0; } } + #region Internal internal FPNum(Context ctx, IntPtr obj) : base(ctx, obj) From 935c523ef8ed8672b2e99a45f4d1caca29bfd81b Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Wed, 26 Oct 2016 18:44:35 +0100 Subject: [PATCH 294/536] Added FPA numeral predicates to Java API --- src/api/java/FPNum.java | 64 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 62 insertions(+), 2 deletions(-) diff --git a/src/api/java/FPNum.java b/src/api/java/FPNum.java index 252d9e012..a8f8af4ff 100644 --- a/src/api/java/FPNum.java +++ b/src/api/java/FPNum.java @@ -105,6 +105,67 @@ public class FPNum extends FPExpr public BitVecExpr getExponentBV(boolean biased) { return new BitVecExpr(getContext(), Native.fpaGetNumeralExponentBv(getContext().nCtx(), getNativeObject(), biased)); } + + + /** + * Indicates whether the numeral is a NaN. + * @throws Z3Exception on error + * @return a boolean + **/ + public boolean isNaN() + { + return Native.fpaIsNumeralNan(getContext().nCtx(), getNativeObject()); + } + + /** + * Indicates whether the numeral is a +oo or -oo. + * @throws Z3Exception on error + * @return a boolean + **/ + public boolean isInf() + { + return Native.fpaIsNumeralInf(getContext().nCtx(), getNativeObject()); + } + + /** + * Indicates whether the numeral is +zero or -zero. + * @throws Z3Exception on error + * @return a boolean + **/ + public boolean isZero() + { + return Native.fpaIsNumeralZero(getContext().nCtx(), getNativeObject()); + } + + /** + * Indicates whether the numeral is normal. + * @throws Z3Exception on error + * @return a boolean + **/ + public boolean isNormal() + { + return Native.fpaIsNumeralNormal(getContext().nCtx(), getNativeObject()); + } + + /** + * Indicates whether the numeral is subnormal. + * @throws Z3Exception on error + * @return a boolean + **/ + public boolean isSubnormal() + { + return Native.fpaIsNumeralSubnormal(getContext().nCtx(), getNativeObject()); + } + + /** + * Indicates whether the numeral is positive. + * @throws Z3Exception on error + * @return a boolean + **/ + public boolean isPositive() + { + return Native.fpaIsNumeralPositive(getContext().nCtx(), getNativeObject()); + } public FPNum(Context ctx, long obj) { @@ -117,6 +178,5 @@ public class FPNum extends FPExpr public String toString() { return Native.getNumeralString(getContext().nCtx(), getNativeObject()); - } - + } } From 23c58a1ef6aa8ccc33d750921854ab9fb4b3cc42 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Wed, 26 Oct 2016 18:53:20 +0100 Subject: [PATCH 295/536] Added FPA numeral predicates to ML API --- src/api/ml/z3.ml | 6 ++++++ src/api/ml/z3.mli | 18 ++++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/src/api/ml/z3.ml b/src/api/ml/z3.ml index dbf36c6a4..565adf976 100644 --- a/src/api/ml/z3.ml +++ b/src/api/ml/z3.ml @@ -1332,6 +1332,12 @@ struct let get_numeral_significand_string = Z3native.fpa_get_numeral_significand_string let get_numeral_significand_uint = Z3native.fpa_get_numeral_significand_uint64 let get_numeral_significand_bv = Z3native.fpa_get_numeral_significand_bv + let is_numeral_nan = Z3native.fpa_is_numeral_nan + let is_numeral_inf = Z3native.fpa_is_numeral_inf + let is_numeral_zero = Z3native.fpa_is_numeral_zero + let is_numeral_normal = Z3native.fpa_is_numeral_normal + let is_numeral_subnormal = Z3native.fpa_is_numeral_subnormal + let is_numeral_positive = Z3native.fpa_is_numeral_positive let mk_to_ieee_bv = Z3native.mk_fpa_to_ieee_bv let mk_to_fp_int_real = Z3native.mk_fpa_to_fp_int_real let numeral_to_string x = Z3native.get_numeral_string (Expr.gc x) x diff --git a/src/api/ml/z3.mli b/src/api/ml/z3.mli index 2a73c08fb..a2ecf54c2 100644 --- a/src/api/ml/z3.mli +++ b/src/api/ml/z3.mli @@ -2168,6 +2168,24 @@ sig significand does not fit into an int. *) val get_numeral_significand_uint : context -> Expr.expr -> bool * int + (** Indicates whether a floating-point numeral is a NaN. *) + val is_numeral_nan : context -> Expr.expr -> bool + + (** Indicates whether a floating-point numeral is +oo or -oo. *) + val is_numeral_inf : context -> Expr.expr -> bool + + (** Indicates whether a floating-point numeral is +zero or -zero. *) + val is_numeral_zero : context -> Expr.expr -> bool + + (** Indicates whether a floating-point numeral is normal. *) + val is_numeral_normal : context -> Expr.expr -> bool + + (** Indicates whether a floating-point numeral is subnormal. *) + val is_numeral_subnormal : context -> Expr.expr -> bool + + (** Indicates whether a floating-point numeral is positive. *) + val is_numeral_positive : context -> Expr.expr -> bool + (** Conversion of a floating-point term into a bit-vector term in IEEE 754-2008 format. *) val mk_to_ieee_bv : context -> Expr.expr -> Expr.expr From 4bd83724dddcc03c32ec5fa683590f2de631514d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 26 Oct 2016 19:15:05 -0700 Subject: [PATCH 296/536] remove conflict on false disequality, introduced regression Signed-off-by: Nikolaj Bjorner --- src/sat/sat_solver.cpp | 4 +++- src/sat/sat_solver/inc_sat_solver.cpp | 21 ++++++++++++++------- src/smt/smt_context.cpp | 3 ++- src/solver/solver2tactic.cpp | 4 +--- src/util/sorting_network.h | 26 ++++++++++++++++++++++++++ 5 files changed, 46 insertions(+), 12 deletions(-) diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index c3aaa5697..ab98fd8a0 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -3168,7 +3168,8 @@ namespace sat { ++num_iterations; checkpoint(); literal_set::iterator it = vars.begin(), end = vars.end(); - for (; it != end; ++it) { + unsigned chunk_size = 100; + for (; it != end && chunk_size > 0; ++it) { literal lit = *it; if (value(lit) != l_undef) { continue; @@ -3182,6 +3183,7 @@ namespace sat { return l_false; } propagate(false); + --chunk_size; } } lbool is_sat; diff --git a/src/sat/sat_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp index d091339bd..592603e53 100644 --- a/src/sat/sat_solver/inc_sat_solver.cpp +++ b/src/sat/sat_solver/inc_sat_solver.cpp @@ -257,10 +257,12 @@ public: bool_var2conseq.insert(lconseq[i][0].var(), i); } - // extract original fixed variables + // extract original fixed variables + u_map asm2dep; + extract_asm2dep(dep2asm, asm2dep); for (unsigned i = 0; i < vars.size(); ++i) { expr_ref cons(m); - if (extract_fixed_variable(dep2asm, vars[i], bool_var2conseq, lconseq, cons)) { + if (extract_fixed_variable(dep2asm, asm2dep, vars[i], bool_var2conseq, lconseq, cons)) { conseq.push_back(cons); } } @@ -378,7 +380,7 @@ private: if (!atoms.empty()) { std::stringstream strm; strm << "interpreted atoms sent to SAT solver " << atoms; - TRACE("sat", std::cout << strm.str() << "\n";); + TRACE("sat", tout << strm.str() << "\n";); IF_VERBOSE(1, verbose_stream() << strm.str() << "\n";); set_reason_unknown(strm.str().c_str()); return l_undef; @@ -449,9 +451,7 @@ private: return internalized; } - bool extract_fixed_variable(dep2asm_t& dep2asm, expr* v, u_map const& bool_var2conseq, vector const& lconseq, expr_ref& conseq) { - u_map asm2dep; - extract_asm2dep(dep2asm, asm2dep); + bool extract_fixed_variable(dep2asm_t& dep2asm, u_map& asm2dep, expr* v, u_map const& bool_var2conseq, vector const& lconseq, expr_ref& conseq) { sat::bool_var_vector bvars; if (!internalize_var(v, bvars)) { @@ -484,6 +484,7 @@ private: return true; } + vector m_exps; void internalize_value(sat::literal_vector const& value, expr* v, expr_ref& val) { bv_util bvutil(m); if (is_uninterp_const(v) && m.is_bool(v)) { @@ -492,10 +493,16 @@ private: } else if (is_uninterp_const(v) && bvutil.is_bv_sort(m.get_sort(v))) { SASSERT(value.size() == bvutil.get_bv_size(v)); + if (m_exps.empty()) { + m_exps.push_back(rational::one()); + } + while (m_exps.size() < value.size()) { + m_exps.push_back(rational(2)*m_exps.back()); + } rational r(0); for (unsigned i = 0; i < value.size(); ++i) { if (!value[i].sign()) { - r += rational(2).expt(i); + r += m_exps[i]; } } val = m.mk_eq(v, bvutil.mk_numeral(r, value.size())); diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index 832d4dac7..027790da8 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -1111,7 +1111,8 @@ namespace smt { if (r1 == r2) { TRACE("add_diseq_inconsistent", tout << "add_diseq #" << n1->get_owner_id() << " #" << n2->get_owner_id() << " inconsistency, scope_lvl: " << m_scope_lvl << "\n";); - return false; // context is inconsistent + return true; + // return false; // context is inconsistent } // Propagate disequalities to theories diff --git a/src/solver/solver2tactic.cpp b/src/solver/solver2tactic.cpp index 53b120fea..8646d4813 100644 --- a/src/solver/solver2tactic.cpp +++ b/src/solver/solver2tactic.cpp @@ -160,9 +160,7 @@ public: } virtual void reset_statistics() {} - virtual void cleanup() { - m_solver = m_solver->translate(m, m_params); - } + virtual void cleanup() { } virtual void reset() { cleanup(); } virtual void set_logic(symbol const & l) {} diff --git a/src/util/sorting_network.h b/src/util/sorting_network.h index 9e35d6e8b..df3428ef3 100644 --- a/src/util/sorting_network.h +++ b/src/util/sorting_network.h @@ -251,6 +251,15 @@ Notes: return result; } +#if 0 + literal mk_and(literal_vector const& lits) { + if (lits.size() == 1) { + return lits[0]; + } + + } +#endif + void mk_implies_or(literal l, unsigned n, literal const* xs) { literal_vector lits(n, xs); lits.push_back(ctx.mk_not(l)); @@ -337,11 +346,28 @@ Notes: ors.push_back(ex); // result => xs[0] + ... + xs[n-1] <= 1 +#if 1 for (unsigned i = 0; i < n; ++i) { for (unsigned j = i + 1; j < n; ++j) { add_clause(ctx.mk_not(result), ctx.mk_not(xs[i]), ctx.mk_not(xs[j])); } } +#else + literal_vector atm; + for (unsigned i = 0; i < n; ++i) { + // at => !xs[1] & .. & !xs[i-1] & !xs[i+1] & ... & !xs[n-1] + literal at = fresh(); + for (unsigned j = 0; j < n; ++j) { + if (i != j) { + add_clause(ctx.mk_not(at), ctx.mk_not(xs[j])); + } + } + atm.push_back(at); + } + atm.push_back(ctx.mk_not(result)); + add_clause(atm); + +#endif // xs[0] + ... + xs[n-1] <= 1 => and_x if (full) { literal and_i = fresh(); From e4f7ff98813902ba5a23cfc7ef41629820befb56 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Thu, 27 Oct 2016 15:06:24 +0100 Subject: [PATCH 297/536] Added Z3_fpa_is_numeral_negative to FPA API --- src/api/api_fpa.cpp | 34 ++++++++++++++++++++++++---------- src/api/z3_fpa.h | 10 ++++++++++ src/ast/fpa_decl_plugin.h | 1 + 3 files changed, 35 insertions(+), 10 deletions(-) diff --git a/src/api/api_fpa.cpp b/src/api/api_fpa.cpp index dc06bae5b..39294005c 100644 --- a/src/api/api_fpa.cpp +++ b/src/api/api_fpa.cpp @@ -1087,7 +1087,7 @@ extern "C" { mpfm.is_denormal(val) ? mpfm.mk_min_exp(ebits) : mpfm.is_inf(val) ? mpfm.mk_top_exp(ebits) : mpfm.bias_exp(ebits, mpfm.exp(val)); - if (mpfm.is_normal(val) && !biased) + if (mpfm.is_normal(val) && !biased) exp = mpfm.exp(val); std::stringstream ss; ss << exp; @@ -1122,7 +1122,7 @@ extern "C" { mpfm.is_denormal(val) ? mpfm.mk_min_exp(ebits) : mpfm.is_inf(val) ? mpfm.mk_top_exp(ebits) : mpfm.bias_exp(ebits, mpfm.exp(val)); - if (mpfm.is_normal(val) && !biased) + if (mpfm.is_normal(val) && !biased) *n = mpfm.exp(val); return 1; Z3_CATCH_RETURN(0); @@ -1155,10 +1155,10 @@ extern "C" { mpfm.is_inf(val) ? mpfm.mk_top_exp(ebits) : mpfm.bias_exp(ebits, mpfm.exp(val)); if (mpfm.is_normal(val) && !biased) { - std::cout << "unbiassing" << std::endl; + std::cout << "unbiassing" << std::endl; exp = mpfm.exp(val); } - + app * a = mk_c(c)->bvutil().mk_numeral(exp, ebits); mk_c(c)->save_ast_trail(a); RETURN_Z3(of_expr(a)); @@ -1200,7 +1200,7 @@ extern "C" { Z3_bool Z3_API Z3_fpa_is_numeral_nan(Z3_context c, Z3_ast t) { Z3_TRY; - Z3_fpa_is_numeral_nan(c, t); + LOG_Z3_fpa_is_numeral_nan(c, t); RESET_ERROR_CODE(); api::context * ctx = mk_c(c); fpa_util & fu = ctx->fpautil(); @@ -1214,7 +1214,7 @@ extern "C" { Z3_bool Z3_API Z3_fpa_is_numeral_inf(Z3_context c, Z3_ast t) { Z3_TRY; - Z3_fpa_is_numeral_inf(c, t); + LOG_Z3_fpa_is_numeral_inf(c, t); RESET_ERROR_CODE(); api::context * ctx = mk_c(c); fpa_util & fu = ctx->fpautil(); @@ -1228,7 +1228,7 @@ extern "C" { Z3_bool Z3_API Z3_fpa_is_numeral_zero(Z3_context c, Z3_ast t) { Z3_TRY; - Z3_fpa_is_numeral_zero(c, t); + LOG_Z3_fpa_is_numeral_zero(c, t); RESET_ERROR_CODE(); api::context * ctx = mk_c(c); fpa_util & fu = ctx->fpautil(); @@ -1242,7 +1242,7 @@ extern "C" { Z3_bool Z3_API Z3_fpa_is_numeral_normal(Z3_context c, Z3_ast t) { Z3_TRY; - Z3_fpa_is_numeral_normal(c, t); + LOG_Z3_fpa_is_numeral_normal(c, t); RESET_ERROR_CODE(); api::context * ctx = mk_c(c); fpa_util & fu = ctx->fpautil(); @@ -1256,7 +1256,7 @@ extern "C" { Z3_bool Z3_API Z3_fpa_is_numeral_subnormal(Z3_context c, Z3_ast t) { Z3_TRY; - Z3_fpa_is_numeral_subnormal(c, t); + LOG_Z3_fpa_is_numeral_subnormal(c, t); RESET_ERROR_CODE(); api::context * ctx = mk_c(c); fpa_util & fu = ctx->fpautil(); @@ -1270,7 +1270,7 @@ extern "C" { Z3_bool Z3_API Z3_fpa_is_numeral_positive(Z3_context c, Z3_ast t) { Z3_TRY; - Z3_fpa_is_numeral_positive(c, t); + LOG_Z3_fpa_is_numeral_positive(c, t); RESET_ERROR_CODE(); api::context * ctx = mk_c(c); fpa_util & fu = ctx->fpautil(); @@ -1282,4 +1282,18 @@ extern "C" { Z3_CATCH_RETURN(Z3_FALSE); } + Z3_bool Z3_API Z3_fpa_is_numeral_negative(Z3_context c, Z3_ast t) { + Z3_TRY; + LOG_Z3_fpa_is_numeral_negative(c, t); + RESET_ERROR_CODE(); + api::context * ctx = mk_c(c); + fpa_util & fu = ctx->fpautil(); + if (!is_expr(t) || !fu.is_numeral(to_expr(t))) { + SET_ERROR_CODE(Z3_INVALID_ARG); + return 0; + } + return fu.is_negative(to_expr(t)); + Z3_CATCH_RETURN(Z3_FALSE); + } + }; diff --git a/src/api/z3_fpa.h b/src/api/z3_fpa.h index 420106838..70fafe6ea 100644 --- a/src/api/z3_fpa.h +++ b/src/api/z3_fpa.h @@ -882,6 +882,16 @@ extern "C" { */ Z3_bool Z3_API Z3_fpa_is_numeral_positive(Z3_context c, Z3_ast t); + /** + \brief Checks whether a given floating-point numeral is negative. + + \param c logical context + \param t a floating-point numeral + + def_API('Z3_fpa_is_numeral_negative', BOOL, (_in(CONTEXT), _in(AST))) + */ + Z3_bool Z3_API Z3_fpa_is_numeral_negative(Z3_context c, Z3_ast t); + /** \brief Retrieves the sign of a floating-point literal as a bit-vector expression. diff --git a/src/ast/fpa_decl_plugin.h b/src/ast/fpa_decl_plugin.h index 7c9c311a8..cf341a07b 100644 --- a/src/ast/fpa_decl_plugin.h +++ b/src/ast/fpa_decl_plugin.h @@ -297,6 +297,7 @@ public: bool is_normal(expr * n) { scoped_mpf v(fm()); return is_numeral(n, v) && fm().is_normal(v); } bool is_subnormal(expr * n) { scoped_mpf v(fm()); return is_numeral(n, v) && fm().is_denormal(v); } bool is_positive(expr * n) { scoped_mpf v(fm()); return is_numeral(n, v) && fm().is_pos(v); } + bool is_negative(expr * n) { scoped_mpf v(fm()); return is_numeral(n, v) && fm().is_neg(v); } app * mk_fp(expr * sgn, expr * exp, expr * sig) { SASSERT(m_bv_util.is_bv(sgn) && m_bv_util.get_bv_size(sgn) == 1); From 95d7b33ebb2e27e85cc49d8490b3593c1b2e7ec7 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Thu, 27 Oct 2016 15:07:10 +0100 Subject: [PATCH 298/536] Added is_numeral_negative to .NET and Java APIs --- src/api/dotnet/FPNum.cs | 5 +++++ src/api/java/FPNum.java | 11 +++++++++++ 2 files changed, 16 insertions(+) diff --git a/src/api/dotnet/FPNum.cs b/src/api/dotnet/FPNum.cs index 05eda00b3..808752eaa 100644 --- a/src/api/dotnet/FPNum.cs +++ b/src/api/dotnet/FPNum.cs @@ -166,6 +166,11 @@ namespace Microsoft.Z3 /// public bool IsPositive { get { return Native.Z3_fpa_is_numeral_positive(Context.nCtx, NativeObject) != 0; } } + /// + /// Indicates whether the numeral is negative. + /// + public bool IsNegative { get { return Native.Z3_fpa_is_numeral_negative(Context.nCtx, NativeObject) != 0; } } + #region Internal internal FPNum(Context ctx, IntPtr obj) : base(ctx, obj) diff --git a/src/api/java/FPNum.java b/src/api/java/FPNum.java index a8f8af4ff..813e82889 100644 --- a/src/api/java/FPNum.java +++ b/src/api/java/FPNum.java @@ -166,6 +166,17 @@ public class FPNum extends FPExpr { return Native.fpaIsNumeralPositive(getContext().nCtx(), getNativeObject()); } + + /** + * Indicates whether the numeral is negative. + * @throws Z3Exception on error + * @return a boolean + **/ + public boolean isNegative() + { + return Native.fpaIsNumeralNegative(getContext().nCtx(), getNativeObject()); + } + public FPNum(Context ctx, long obj) { From 253cfeb0af93dc06f246db2f71d8877f3555aa68 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Thu, 27 Oct 2016 15:07:34 +0100 Subject: [PATCH 299/536] Added FPA numeral accessors/predicates to Python API --- src/api/python/z3/z3.py | 87 ++++++++++++++++++++++++----------------- 1 file changed, 51 insertions(+), 36 deletions(-) diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index e651fc04f..a2274e97b 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -8432,27 +8432,13 @@ def is_fprm_value(a): ### FP Numerals -class FPNumRef(FPRef): - def isNaN(self): - return self.decl().kind() == Z3_OP_FPA_NAN +class FPNumRef(FPRef): + """The sign of the numeral. - def isInf(self): - return self.decl().kind() == Z3_OP_FPA_PLUS_INF or self.decl().kind() == Z3_OP_FPA_MINUS_INF - - def isZero(self): - return self.decl().kind() == Z3_OP_FPA_PLUS_ZERO or self.decl().kind() == Z3_OP_FPA_MINUS_ZERO - - def isNegative(self): - k = self.decl().kind() - return (self.num_args() == 0 and (k == Z3_OP_FPA_MINUS_INF or k == Z3_OP_FPA_MINUS_ZERO)) or (self.sign() == True) - - """ - The sign of the numeral. - - >>> x = FPNumRef(+1.0, FPSort(8, 24)) + >>> x = FPVal(+1.0, FPSort(8, 24)) >>> x.sign() False - >>> x = FPNumRef(-1.0, FPSort(8, 24)) + >>> x = FPVal(-1.0, FPSort(8, 24)) >>> x.sign() True """ @@ -8462,47 +8448,50 @@ class FPNumRef(FPRef): raise Z3Exception("error retrieving the sign of a numeral.") return l.value != 0 - """ - The sign of a floating-point numeral as a bit-vector expression + """The sign of a floating-point numeral as a bit-vector expression. Remark: NaN's are invalid arguments. """ def sign_as_bv(self): return BitVecNumRef(Z3_fpa_get_numeral_sign_bv(self.ctx.ref(), self.as_ast()), self.ctx) + """The significand of the numeral. - """ - The significand of the numeral. - - >>> x = FPNumRef(2.5, FPSort(8, 24)) + >>> x = FPVal(2.5, FPSort(8, 24)) >>> x.significand() 1.25 """ def significand(self): return Z3_fpa_get_numeral_significand_string(self.ctx.ref(), self.as_ast()) - + + """The significand of the numeral as a long. + + >>> x = FPVal(2.5, FPSort(8, 24)) + >>> x.significand_as_long() + 1.25 """ - The significand of a floating-point numeral as a bit-vector expression + def significand_as_long(self): + return Z3_fpa_get_numeral_significand_uint64(self.ctx.ref(), self.as_ast()) + + """The significand of the numeral as a bit-vector expression. Remark: NaN are invalid arguments. """ def significand_as_bv(self): return BitVecNumRef(Z3_fpa_get_numeral_significand_bv(self.ctx.ref(), self.as_ast()), self.ctx) - """ - The exponent of the numeral. + """The exponent of the numeral. - >>> x = FPNumRef(2.5, FPSort(8, 24)) + >>> x = FPVal(2.5, FPSort(8, 24)) >>> x.exponent() 1 """ def exponent(self, biased=True): return Z3_fpa_get_numeral_exponent_string(self.ctx.ref(), self.as_ast(), biased) - """ - The exponent of the numeral as a long. + """The exponent of the numeral as a long. - >>> x = FPNumRef(2.5, FPSort(8, 24)) + >>> x = FPVal(2.5, FPSort(8, 24)) >>> x.exponent_as_long() 1 """ @@ -8512,19 +8501,45 @@ class FPNumRef(FPRef): raise Z3Exception("error retrieving the exponent of a numeral.") return ptr[0] - """ - The exponent of a floating-point numeral as a bit-vector expression + """The exponent of the numeral as a bit-vector expression. Remark: NaNs are invalid arguments. """ def exponent_as_bv(self, biased=True): return BitVecNumRef(Z3_fpa_get_numeral_exponent_bv(self.ctx.ref(), self.as_ast(), biased), self.ctx) + """Indicates whether the numeral is a NaN.""" + def isNaN(self): + return Z3_fpa_is_numeral_nan(self.ctx.ref(), self.as_ast()) + + """Indicates whether the numeral is +oo or -oo.""" + def isInf(self): + return Z3_fpa_is_numeral_inf(self.ctx.ref(), self.as_ast()) + + """Indicates whether the numeral is +zero or -zero.""" + def isZero(self): + return Z3_fpa_is_numeral_zero(self.ctx.ref(), self.as_ast()) + + """Indicates whether the numeral is normal.""" + def isNormal(self): + return Z3_fpa_is_numeral_normal(self.ctx.ref(), self.as_ast()) + + """Indicates whether the numeral is subnormal.""" + def isSubnormal(self): + return Z3_fpa_is_numeral_subnormal(self.ctx.ref(), self.as_ast()) + + """Indicates whether the numeral is postitive.""" + def isPositive(self): + return Z3_fpa_is_numeral_positive(self.ctx.ref(), self.as_ast()) + + """Indicates whether the numeral is negative.""" + def isNegative(self): + return Z3_fpa_is_numeral_negative(self.ctx.ref(), self.as_ast()) """ The string representation of the numeral. - >>> x = FPNumRef(20, FPSort(8, 24)) + >>> x = FPVal(20, FPSort(8, 24)) >>> x.as_string() 1.25*(2**4) """ @@ -8682,7 +8697,7 @@ def FPVal(sig, exp=None, fps=None, ctx=None): >>> v = FPVal(20.0, FPSort(8, 24)) >>> v 1.25*(2**4) - >>> print("0x%.8x" % v.exponent_as_long()) + >>> print("0x%.8x" % v.exponent_as_long(False)) 0x00000004 >>> v = FPVal(2.25, FPSort(8, 24)) >>> v From 24fc19ed5833ee19b748ab954b890768dd80d114 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 27 Oct 2016 08:15:39 -0700 Subject: [PATCH 300/536] speed up consequence finding by avoiding local search whenver assumption level is reached during the initial phase Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/pb2bv_rewriter.cpp | 7 +++++++ src/ast/rewriter/pb2bv_rewriter.h | 1 + src/cmd_context/cmd_context.cpp | 2 +- src/sat/sat_solver.cpp | 18 ++++++++++++------ src/solver/combined_solver.cpp | 8 +++++++- src/tactic/portfolio/pb2bv_solver.cpp | 2 +- 6 files changed, 29 insertions(+), 9 deletions(-) diff --git a/src/ast/rewriter/pb2bv_rewriter.cpp b/src/ast/rewriter/pb2bv_rewriter.cpp index 0cae3f307..cf5b67793 100644 --- a/src/ast/rewriter/pb2bv_rewriter.cpp +++ b/src/ast/rewriter/pb2bv_rewriter.cpp @@ -433,6 +433,9 @@ struct pb2bv_rewriter::imp { void operator()(expr * e, expr_ref & result, proof_ref & result_proof) { m_rw(e, result, result_proof); } + void assert_expr(expr * e, expr_ref & result, proof_ref & result_proof) { + m_rw(e, result, result_proof); + } void push() { m_fresh_lim.push_back(m_fresh.size()); } @@ -469,9 +472,13 @@ unsigned pb2bv_rewriter::get_num_steps() const { return m_imp->get_num_steps(); void pb2bv_rewriter::cleanup() { ast_manager& mgr = m(); params_ref p = m_imp->m_params; dealloc(m_imp); m_imp = alloc(imp, mgr, p); } func_decl_ref_vector const& pb2bv_rewriter::fresh_constants() const { return m_imp->m_fresh; } void pb2bv_rewriter::operator()(expr * e, expr_ref & result, proof_ref & result_proof) { (*m_imp)(e, result, result_proof); } +void pb2bv_rewriter::assert_expr(expr* e, expr_ref & result, proof_ref & result_proof) { + m_imp->assert_expr(e, result, result_proof); +} void pb2bv_rewriter::push() { m_imp->push(); } void pb2bv_rewriter::pop(unsigned num_scopes) { m_imp->pop(num_scopes); } void pb2bv_rewriter::flush_side_constraints(expr_ref_vector& side_constraints) { m_imp->flush_side_constraints(side_constraints); } unsigned pb2bv_rewriter::num_translated() const { return m_imp->m_num_translated; } + void pb2bv_rewriter::collect_statistics(statistics & st) const { m_imp->collect_statistics(st); } diff --git a/src/ast/rewriter/pb2bv_rewriter.h b/src/ast/rewriter/pb2bv_rewriter.h index 47d8361cb..569eaf07d 100644 --- a/src/ast/rewriter/pb2bv_rewriter.h +++ b/src/ast/rewriter/pb2bv_rewriter.h @@ -36,6 +36,7 @@ public: void cleanup(); func_decl_ref_vector const& fresh_constants() const; void operator()(expr * e, expr_ref & result, proof_ref & result_proof); + void assert_expr(expr* e, expr_ref & result, proof_ref & result_proof); void push(); void pop(unsigned num_scopes); void flush_side_constraints(expr_ref_vector& side_constraints); diff --git a/src/cmd_context/cmd_context.cpp b/src/cmd_context/cmd_context.cpp index b7c80f65a..930a8fc71 100644 --- a/src/cmd_context/cmd_context.cpp +++ b/src/cmd_context/cmd_context.cpp @@ -736,7 +736,7 @@ bool cmd_context::set_logic(symbol const & s) { std::string cmd_context::reason_unknown() const { if (m_check_sat_result.get() == 0) - throw cmd_exception("state of the most recent check-sat command is not unknown"); + throw cmd_exception("state of the most recent check-sat command is not known"); return m_check_sat_result->reason_unknown(); } diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index ab98fd8a0..831eb228f 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -3168,8 +3168,8 @@ namespace sat { ++num_iterations; checkpoint(); literal_set::iterator it = vars.begin(), end = vars.end(); - unsigned chunk_size = 100; - for (; it != end && chunk_size > 0; ++it) { + unsigned num_resolves = 0; + for (; it != end; ++it) { literal lit = *it; if (value(lit) != l_undef) { continue; @@ -3182,16 +3182,22 @@ namespace sat { TRACE("sat", tout << "inconsistent\n";); return l_false; } - propagate(false); - --chunk_size; + propagate(false); + ++num_resolves; + } + if (scope_lvl() == 1) { + break; } } lbool is_sat; while (true) { + if (scope_lvl() == 1 && num_resolves > 0) { + is_sat = l_undef; + break; + } is_sat = bounded_search(); if (is_sat == l_undef) { - restart(); - continue; + restart(); } break; } diff --git a/src/solver/combined_solver.cpp b/src/solver/combined_solver.cpp index 2856315bd..b03de70a2 100644 --- a/src/solver/combined_solver.cpp +++ b/src/solver/combined_solver.cpp @@ -197,7 +197,13 @@ public: virtual lbool get_consequences(expr_ref_vector const& asms, expr_ref_vector const& vars, expr_ref_vector& consequences) { switch_inc_mode(); m_use_solver1_results = false; - return m_solver2->get_consequences(asms, vars, consequences); + try { + return m_solver2->get_consequences(asms, vars, consequences); + } + catch (z3_exception& ex) { + set_reason_unknown(ex.msg()); + } + return l_undef; } virtual lbool check_sat(unsigned num_assumptions, expr * const * assumptions) { diff --git a/src/tactic/portfolio/pb2bv_solver.cpp b/src/tactic/portfolio/pb2bv_solver.cpp index bfd533e8a..d1826e61d 100644 --- a/src/tactic/portfolio/pb2bv_solver.cpp +++ b/src/tactic/portfolio/pb2bv_solver.cpp @@ -113,7 +113,7 @@ private: expr_ref fml(m); expr_ref_vector fmls(m); for (unsigned i = 0; i < m_assertions.size(); ++i) { - m_rewriter(m_assertions[i].get(), fml, proof); + m_rewriter.assert_expr(m_assertions[i].get(), fml, proof); m_solver->assert_expr(fml); } m_rewriter.flush_side_constraints(fmls); From 41deae52c6018076a669739ed7c7b07bff381a21 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 27 Oct 2016 13:35:53 -0700 Subject: [PATCH 301/536] fix enum2bv to handle singleton enumeration types, differentiate disequality conflicts for theories that handle disequalities vs. theories that don't Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/enum2bv_rewriter.cpp | 4 ++-- src/smt/smt_context.cpp | 4 ++-- src/util/sorting_network.h | 25 ------------------------- 3 files changed, 4 insertions(+), 29 deletions(-) diff --git a/src/ast/rewriter/enum2bv_rewriter.cpp b/src/ast/rewriter/enum2bv_rewriter.cpp index bbe07f625..cd0f54503 100644 --- a/src/ast/rewriter/enum2bv_rewriter.cpp +++ b/src/ast/rewriter/enum2bv_rewriter.cpp @@ -126,7 +126,7 @@ struct enum2bv_rewriter::imp { unsigned nc = m_dt.get_datatype_num_constructors(s); result = m.mk_fresh_const(f->get_name().str().c_str(), m_bv.mk_sort(bv_size)); f_fresh = to_app(result)->get_decl(); - if (!is_power_of_two(nc)) { + if (!is_power_of_two(nc) || nc == 1) { m_imp.m_bounds.push_back(m_bv.mk_ule(result, m_bv.mk_numeral(nc-1, bv_size))); } expr_ref f_def(m); @@ -168,7 +168,7 @@ struct enum2bv_rewriter::imp { unsigned bv_size = get_bv_size(s); m_sorts.push_back(m_bv.mk_sort(bv_size)); unsigned nc = m_dt.get_datatype_num_constructors(s); - if (!is_power_of_two(nc)) { + if (!is_power_of_two(nc) || nc == 1) { bounds.push_back(m_bv.mk_ule(m.mk_var(q->get_num_decls()-i-1, m_sorts[i]), m_bv.mk_numeral(nc-1, bv_size))); } found = true; diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index 027790da8..fed6e71bc 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -1111,8 +1111,8 @@ namespace smt { if (r1 == r2) { TRACE("add_diseq_inconsistent", tout << "add_diseq #" << n1->get_owner_id() << " #" << n2->get_owner_id() << " inconsistency, scope_lvl: " << m_scope_lvl << "\n";); - return true; - // return false; // context is inconsistent + theory_id t1 = r1->m_th_var_list.get_th_id(); + return get_theory(t1)->use_diseqs(); } // Propagate disequalities to theories diff --git a/src/util/sorting_network.h b/src/util/sorting_network.h index df3428ef3..33c4f8b61 100644 --- a/src/util/sorting_network.h +++ b/src/util/sorting_network.h @@ -251,15 +251,6 @@ Notes: return result; } -#if 0 - literal mk_and(literal_vector const& lits) { - if (lits.size() == 1) { - return lits[0]; - } - - } -#endif - void mk_implies_or(literal l, unsigned n, literal const* xs) { literal_vector lits(n, xs); lits.push_back(ctx.mk_not(l)); @@ -346,28 +337,12 @@ Notes: ors.push_back(ex); // result => xs[0] + ... + xs[n-1] <= 1 -#if 1 for (unsigned i = 0; i < n; ++i) { for (unsigned j = i + 1; j < n; ++j) { add_clause(ctx.mk_not(result), ctx.mk_not(xs[i]), ctx.mk_not(xs[j])); } } -#else - literal_vector atm; - for (unsigned i = 0; i < n; ++i) { - // at => !xs[1] & .. & !xs[i-1] & !xs[i+1] & ... & !xs[n-1] - literal at = fresh(); - for (unsigned j = 0; j < n; ++j) { - if (i != j) { - add_clause(ctx.mk_not(at), ctx.mk_not(xs[j])); - } - } - atm.push_back(at); - } - atm.push_back(ctx.mk_not(result)); - add_clause(atm); -#endif // xs[0] + ... + xs[n-1] <= 1 => and_x if (full) { literal and_i = fresh(); From 7d7e03e377f1087202a8728fe0ee77b5d88b33ce Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 27 Oct 2016 16:23:33 -0700 Subject: [PATCH 302/536] rewind qhead to ensure re-propagation after cancellation Signed-off-by: Nikolaj Bjorner --- src/smt/smt_consequences.cpp | 1 + src/smt/smt_context.cpp | 8 ++++++-- src/util/rlimit.cpp | 1 + 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/smt/smt_consequences.cpp b/src/smt/smt_consequences.cpp index ef90aac4c..1c1d236ad 100644 --- a/src/smt/smt_consequences.cpp +++ b/src/smt/smt_consequences.cpp @@ -258,6 +258,7 @@ namespace smt { TRACE("context", tout << is_sat << "\n";); return is_sat; } + obj_map var2val; index_set _assumptions; for (unsigned i = 0; i < assumptions.size(); ++i) { diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index fed6e71bc..154f3a6a3 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -1749,8 +1749,10 @@ namespace smt { unsigned qhead = m_qhead; if (!bcp()) return false; - if (get_cancel_flag()) + if (get_cancel_flag()) { + m_qhead = qhead; return true; + } SASSERT(!inconsistent()); propagate_relevancy(qhead); if (inconsistent()) @@ -1768,8 +1770,10 @@ namespace smt { m_qmanager->propagate(); if (inconsistent()) return false; - if (resource_limits_exceeded()) + if (resource_limits_exceeded()) { + m_qhead = qhead; return true; + } if (!can_propagate()) { CASSERT("diseq_bug", inconsistent() || check_missing_diseq_conflict()); CASSERT("eqc_bool", check_eqc_bool_assignment()); diff --git a/src/util/rlimit.cpp b/src/util/rlimit.cpp index 37b1f7904..9f6c692cc 100644 --- a/src/util/rlimit.cpp +++ b/src/util/rlimit.cpp @@ -29,6 +29,7 @@ uint64 reslimit::count() const { return m_count; } + bool reslimit::inc() { ++m_count; return m_cancel == 0 && (m_limit == 0 || m_count <= m_limit); From b1d673e3ebf7125c40144372f4747c71648fcae1 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 27 Oct 2016 16:34:26 -0700 Subject: [PATCH 303/536] catch cancellation exceptions, return undef Signed-off-by: Nikolaj Bjorner --- src/solver/combined_solver.cpp | 8 +++++++- src/solver/solver.cpp | 16 +++++++++++++++- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/src/solver/combined_solver.cpp b/src/solver/combined_solver.cpp index b03de70a2..7f5f6872e 100644 --- a/src/solver/combined_solver.cpp +++ b/src/solver/combined_solver.cpp @@ -21,6 +21,7 @@ Notes: #include"solver.h" #include"scoped_timer.h" #include"combined_solver_params.hpp" +#include"common_msgs.h" #define PS_VB_LVL 15 /** @@ -201,7 +202,12 @@ public: return m_solver2->get_consequences(asms, vars, consequences); } catch (z3_exception& ex) { - set_reason_unknown(ex.msg()); + if (get_manager().canceled()) { + set_reason_unknown(Z3_CANCELED_MSG); + } + else { + set_reason_unknown(ex.msg()); + } } return l_undef; } diff --git a/src/solver/solver.cpp b/src/solver/solver.cpp index 8f32019d5..441ece429 100644 --- a/src/solver/solver.cpp +++ b/src/solver/solver.cpp @@ -21,6 +21,8 @@ Notes: #include"ast_util.h" #include"ast_pp.h" #include"ast_pp_util.h" +#include "common_msgs.h" + unsigned solver::get_num_assertions() const { NOT_IMPLEMENTED_YET(); @@ -56,7 +58,19 @@ struct scoped_assumption_push { }; lbool solver::get_consequences(expr_ref_vector const& asms, expr_ref_vector const& vars, expr_ref_vector& consequences) { - return get_consequences_core(asms, vars, consequences); + try { + return get_consequences_core(asms, vars, consequences); + } + catch (z3_exception& ex) { + if (asms.get_manager().canceled()) { + set_reason_unknown(Z3_CANCELED_MSG); + return l_undef; + } + else { + set_reason_unknown(ex.msg()); + } + throw; + } } lbool solver::get_consequences_core(expr_ref_vector const& asms, expr_ref_vector const& vars, expr_ref_vector& consequences) { From ca309341c3de0e3762acf663263e9cbc8b69eabb Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 27 Oct 2016 22:07:46 -0700 Subject: [PATCH 304/536] fixing cancellation code paths for inc_sat_solver Signed-off-by: Nikolaj Bjorner --- .../bit_blaster/bit_blaster_rewriter.cpp | 9 ++++++ .../bit_blaster/bit_blaster_rewriter.h | 1 + src/sat/sat_solver.cpp | 29 ++++++++++++------- src/sat/sat_solver/inc_sat_solver.cpp | 14 ++++++--- .../portfolio/bounded_int2bv_solver.cpp | 3 +- 5 files changed, 41 insertions(+), 15 deletions(-) diff --git a/src/ast/rewriter/bit_blaster/bit_blaster_rewriter.cpp b/src/ast/rewriter/bit_blaster/bit_blaster_rewriter.cpp index c260178ad..e8d8c4e4b 100644 --- a/src/ast/rewriter/bit_blaster/bit_blaster_rewriter.cpp +++ b/src/ast/rewriter/bit_blaster/bit_blaster_rewriter.cpp @@ -165,6 +165,10 @@ struct blaster_rewriter_cfg : public default_rewriter_cfg { m_keyval_lim.push_back(m_keys.size()); } + unsigned get_num_scopes() const { + return m_keyval_lim.size(); + } + void pop(unsigned num_scopes) { if (num_scopes > 0) { SASSERT(num_scopes <= m_keyval_lim.size()); @@ -637,6 +641,7 @@ struct bit_blaster_rewriter::imp : public rewriter_tpl { } void push() { m_cfg.push(); } void pop(unsigned s) { m_cfg.pop(s); } + unsigned get_num_scopes() const { return m_cfg.get_num_scopes(); } }; bit_blaster_rewriter::bit_blaster_rewriter(ast_manager & m, params_ref const & p): @@ -680,3 +685,7 @@ void bit_blaster_rewriter::operator()(expr * e, expr_ref & result, proof_ref & r m_imp->operator()(e, result, result_proof); } +unsigned bit_blaster_rewriter::get_num_scopes() const { + return m_imp->get_num_scopes(); +} + diff --git a/src/ast/rewriter/bit_blaster/bit_blaster_rewriter.h b/src/ast/rewriter/bit_blaster/bit_blaster_rewriter.h index b23daab3a..8db328ec8 100644 --- a/src/ast/rewriter/bit_blaster/bit_blaster_rewriter.h +++ b/src/ast/rewriter/bit_blaster/bit_blaster_rewriter.h @@ -37,6 +37,7 @@ public: void operator()(expr * e, expr_ref & result, proof_ref & result_proof); void push(); void pop(unsigned num_scopes); + unsigned get_num_scopes() const; }; #endif diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 831eb228f..e70a30a5a 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -3158,7 +3158,14 @@ namespace sat { init_search(); propagate(false); if (inconsistent()) return l_false; - init_assumptions(asms.size(), asms.c_ptr(), 0, 0); + if (asms.empty()) { + bool_var v = mk_var(true, false); + literal lit(v, false); + init_assumptions(1, &lit, 0, 0); + } + else { + init_assumptions(asms.size(), asms.c_ptr(), 0, 0); + } propagate(false); if (check_inconsistent()) return l_false; @@ -3169,6 +3176,7 @@ namespace sat { checkpoint(); literal_set::iterator it = vars.begin(), end = vars.end(); unsigned num_resolves = 0; + lbool is_sat = l_true; for (; it != end; ++it) { literal lit = *it; if (value(lit) != l_undef) { @@ -3179,8 +3187,10 @@ namespace sat { propagate(false); while (inconsistent()) { if (!resolve_conflict()) { - TRACE("sat", tout << "inconsistent\n";); - return l_false; + TRACE("sat", display(tout << "inconsistent\n");); + m_inconsistent = false; + is_sat = l_undef; + break; } propagate(false); ++num_resolves; @@ -3189,17 +3199,16 @@ namespace sat { break; } } - lbool is_sat; - while (true) { + if (is_sat == l_true) { if (scope_lvl() == 1 && num_resolves > 0) { is_sat = l_undef; - break; } - is_sat = bounded_search(); - if (is_sat == l_undef) { - restart(); + else { + is_sat = bounded_search(); + if (is_sat == l_undef) { + restart(); + } } - break; } if (is_sat == l_false) { TRACE("sat", tout << "unsat\n";); diff --git a/src/sat/sat_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp index 592603e53..f5efed726 100644 --- a/src/sat/sat_solver/inc_sat_solver.cpp +++ b/src/sat/sat_solver/inc_sat_solver.cpp @@ -234,6 +234,7 @@ public: } virtual lbool get_consequences_core(expr_ref_vector const& assumptions, expr_ref_vector const& vars, expr_ref_vector& conseq) { + init_preprocess(); TRACE("sat", tout << assumptions << "\n" << vars << "\n";); sat::literal_vector asms; sat::bool_var_vector bvars; @@ -341,7 +342,7 @@ public: mk_bit_blaster_tactic(m, m_bb_rewriter.get()), //mk_aig_tactic(), using_params(mk_simplify_tactic(m), simp2_p)); - for (unsigned i = 0; i < m_num_scopes; ++i) { + while (m_bb_rewriter->get_num_scopes() < m_num_scopes) { m_bb_rewriter->push(); } m_preprocess->reset(); @@ -364,6 +365,7 @@ private: } catch (tactic_exception & ex) { IF_VERBOSE(0, verbose_stream() << "exception in tactic " << ex.msg() << "\n";); + TRACE("sat", tout << "exception: " << ex.msg() << "\n";); m_preprocess = 0; m_bb_rewriter = 0; return l_undef; @@ -518,10 +520,14 @@ private: } dep2asm_t dep2asm; goal_ref g = alloc(goal, m, true, false); // models, maybe cores are enabled - for (; m_fmls_head < m_fmls.size(); ++m_fmls_head) { - g->assert_expr(m_fmls[m_fmls_head].get()); + for (unsigned i = 0 ; i < m_fmls.size(); ++i) { + g->assert_expr(m_fmls[i].get()); } - return internalize_goal(g, dep2asm); + lbool res = internalize_goal(g, dep2asm); + if (res != l_undef) { + m_fmls_head = m_fmls.size(); + } + return res; } void extract_assumptions(unsigned sz, expr* const* asms, dep2asm_t& dep2asm) { diff --git a/src/tactic/portfolio/bounded_int2bv_solver.cpp b/src/tactic/portfolio/bounded_int2bv_solver.cpp index 688d9403a..f8b2f5325 100644 --- a/src/tactic/portfolio/bounded_int2bv_solver.cpp +++ b/src/tactic/portfolio/bounded_int2bv_solver.cpp @@ -247,8 +247,9 @@ private: expr_ref t(m.mk_const(fbv), m); t = m_bv.mk_bv2int(t); if (!offset.is_zero()) { - t = m_arith.mk_add(t, m_arith.mk_numeral(lo, true)); + t = m_arith.mk_add(t, m_arith.mk_numeral(offset, true)); } + TRACE("pb", tout << lo << " <= " << hi << " offset: " << offset << "\n"; tout << mk_pp(e, m) << " |-> " << t << "\n";); sub.insert(e, t); } else { From 9c16d16bc881bdcacbc4374054fce16c3b5bd839 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Fri, 28 Oct 2016 12:22:28 +0100 Subject: [PATCH 305/536] removed debug output --- src/api/api_fpa.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/api/api_fpa.cpp b/src/api/api_fpa.cpp index 39294005c..46234c0d2 100644 --- a/src/api/api_fpa.cpp +++ b/src/api/api_fpa.cpp @@ -1154,10 +1154,8 @@ extern "C" { mpfm.is_denormal(val) ? mpfm.mk_min_exp(ebits) : mpfm.is_inf(val) ? mpfm.mk_top_exp(ebits) : mpfm.bias_exp(ebits, mpfm.exp(val)); - if (mpfm.is_normal(val) && !biased) { - std::cout << "unbiassing" << std::endl; + if (mpfm.is_normal(val) && !biased) exp = mpfm.exp(val); - } app * a = mk_c(c)->bvutil().mk_numeral(exp, ebits); mk_c(c)->save_ast_trail(a); From 6fb358a432ef411341cc18202a52da749dbd76f5 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Fri, 28 Oct 2016 13:45:10 +0100 Subject: [PATCH 306/536] Build fix for libz3.vcxproj. --- scripts/mk_util.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/scripts/mk_util.py b/scripts/mk_util.py index 0fac30e35..84931b47e 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -3076,6 +3076,11 @@ def mk_vs_proj_property_groups(f, name, target_ext, type): f.write(' Unicode\n') f.write(' false\n') f.write(' \n') + f.write(' \n') + f.write(' %s\n' % type) + f.write(' Unicode\n') + f.write(' false\n') + f.write(' \n') f.write(' \n') f.write(' \n') f.write(' \n') From 02e1bae9cbf1dd386c9ee89631958292ad27e7e0 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Fri, 28 Oct 2016 14:22:27 +0100 Subject: [PATCH 307/536] whitespace --- .../portfolio/bounded_int2bv_solver.cpp | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/tactic/portfolio/bounded_int2bv_solver.cpp b/src/tactic/portfolio/bounded_int2bv_solver.cpp index f8b2f5325..8be0788e3 100644 --- a/src/tactic/portfolio/bounded_int2bv_solver.cpp +++ b/src/tactic/portfolio/bounded_int2bv_solver.cpp @@ -14,7 +14,7 @@ Author: Nikolaj Bjorner (nbjorner) 2016-10-23 Notes: - + --*/ #include "bounded_int2bv_solver.h" @@ -76,7 +76,7 @@ public: virtual solver* translate(ast_manager& m, params_ref const& p) { return alloc(bounded_int2bv_solver, m, p, m_solver->translate(m, p)); } - + virtual void assert_expr(expr * t) { m_assertions.push_back(t); } @@ -89,7 +89,7 @@ public: } virtual void pop_core(unsigned n) { - m_assertions.reset(); + m_assertions.reset(); m_solver->pop(n); if (n > 0) { @@ -109,7 +109,7 @@ public: while (n > 0) { dealloc(m_bounds.back()); - m_bounds.pop_back(); + m_bounds.pop_back(); --n; } } @@ -120,25 +120,25 @@ public: } virtual void updt_params(params_ref const & p) { m_solver->updt_params(p); } - virtual void collect_param_descrs(param_descrs & r) { m_solver->collect_param_descrs(r); } + virtual void collect_param_descrs(param_descrs & r) { m_solver->collect_param_descrs(r); } virtual void set_produce_models(bool f) { m_solver->set_produce_models(f); } virtual void set_progress_callback(progress_callback * callback) { m_solver->set_progress_callback(callback); } virtual void collect_statistics(statistics & st) const { m_solver->collect_statistics(st); } virtual void get_unsat_core(ptr_vector & r) { m_solver->get_unsat_core(r); } - virtual void get_model(model_ref & mdl) { + virtual void get_model(model_ref & mdl) { m_solver->get_model(mdl); if (mdl) { extend_model(mdl); - filter_model(mdl); + filter_model(mdl); } - } + } virtual proof * get_proof() { return m_solver->get_proof(); } virtual std::string reason_unknown() const { return m_solver->reason_unknown(); } virtual void set_reason_unknown(char const* msg) { m_solver->set_reason_unknown(msg); } virtual void get_labels(svector & r) { m_solver->get_labels(r); } virtual ast_manager& get_manager() const { return m; } - virtual lbool find_mutexes(expr_ref_vector const& vars, vector& mutexes) { return m_solver->find_mutexes(vars, mutexes); } - virtual lbool get_consequences_core(expr_ref_vector const& asms, expr_ref_vector const& vars, expr_ref_vector& consequences) { + virtual lbool find_mutexes(expr_ref_vector const& vars, vector& mutexes) { return m_solver->find_mutexes(vars, mutexes); } + virtual lbool get_consequences_core(expr_ref_vector const& asms, expr_ref_vector const& vars, expr_ref_vector& consequences) { flush_assertions(); expr_ref_vector bvars(m); for (unsigned i = 0; i < vars.size(); ++i) { @@ -201,7 +201,7 @@ private: value = m_arith.mk_add(value, m_arith.mk_numeral(offset, true)); } TRACE("int2bv", tout << mk_pp(it->m_key, m) << " " << value << "\n";); - ext.insert(it->m_key, value); + ext.insert(it->m_key, value); } ext(mdl, 0); } @@ -224,7 +224,7 @@ private: if (bm.has_lower(e, lo, s1) && bm.has_upper(e, hi, s2) && lo <= hi && !s1 && !s2) { func_decl* fbv; rational offset; - if (!m_int2bv.find(f, fbv)) { + if (!m_int2bv.find(f, fbv)) { rational n = hi - lo + rational::one(); unsigned num_bits = get_num_bits(n); expr_ref b(m); @@ -253,11 +253,11 @@ private: sub.insert(e, t); } else { - IF_VERBOSE(1, + IF_VERBOSE(1, verbose_stream() << "unprocessed entry: " << mk_pp(e, m) << "\n"; if (bm.has_lower(e, lo, s1)) { verbose_stream() << "lower: " << lo << " " << s1 << "\n"; - } + } if (bm.has_upper(e, hi, s2)) { verbose_stream() << "upper: " << hi << " " << s2 << "\n"; }); @@ -284,7 +284,7 @@ private: bm(m_assertions[i].get()); } expr_safe_replace sub(m); - accumulate_sub(sub); + accumulate_sub(sub); proof_ref proof(m); expr_ref fml1(m), fml2(m); if (sub.empty()) { @@ -292,7 +292,7 @@ private: } else { for (unsigned i = 0; i < m_assertions.size(); ++i) { - sub(m_assertions[i].get(), fml1); + sub(m_assertions[i].get(), fml1); m_rewriter(fml1, fml2, proof); m_solver->assert_expr(fml2); TRACE("int2bv", tout << fml2 << "\n";); From f1412d3f3249529224f4180f601652da210b274a Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Fri, 28 Oct 2016 14:23:01 +0100 Subject: [PATCH 308/536] Bugfix for bouned_int2bv_solver --- src/tactic/portfolio/bounded_int2bv_solver.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/tactic/portfolio/bounded_int2bv_solver.cpp b/src/tactic/portfolio/bounded_int2bv_solver.cpp index 8be0788e3..0b136dda7 100644 --- a/src/tactic/portfolio/bounded_int2bv_solver.cpp +++ b/src/tactic/portfolio/bounded_int2bv_solver.cpp @@ -294,6 +294,10 @@ private: for (unsigned i = 0; i < m_assertions.size(); ++i) { sub(m_assertions[i].get(), fml1); m_rewriter(fml1, fml2, proof); + if (m.canceled()) { + m_rewriter.reset(); + return; + } m_solver->assert_expr(fml2); TRACE("int2bv", tout << fml2 << "\n";); } From 2475f3bff59a0e15fbc9560e0896856f817faf87 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 28 Oct 2016 07:41:27 -0700 Subject: [PATCH 309/536] ensure that variables passed to consequence finding have bound constraints, if applicable. Even if those variables do not occur in the constraints Signed-off-by: Nikolaj Bjorner --- src/tactic/portfolio/enum2bv_solver.cpp | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/tactic/portfolio/enum2bv_solver.cpp b/src/tactic/portfolio/enum2bv_solver.cpp index b0f11cb91..e89f9d188 100644 --- a/src/tactic/portfolio/enum2bv_solver.cpp +++ b/src/tactic/portfolio/enum2bv_solver.cpp @@ -102,9 +102,20 @@ public: datatype_util dt(m); bv_util bv(m); + expr_ref_vector bvars(m), conseq(m), bounds(m); + + // ensure that enumeration variables that + // don't occur in the constraints + // are also internalized. + for (unsigned i = 0; i < vars.size(); ++i) { + expr_ref tmp(m.mk_eq(vars[i], vars[i]), m); + proof_ref proof(m); + m_rewriter(tmp, tmp, proof); + } + m_rewriter.flush_side_constraints(bounds); + m_solver->assert_expr(bounds); // translate enumeration constants to bit-vectors. - expr_ref_vector bvars(m), conseq(m); for (unsigned i = 0; i < vars.size(); ++i) { func_decl* f; if (is_app(vars[i]) && is_uninterp_const(vars[i]) && m_rewriter.enum2bv().find(to_app(vars[i])->get_decl(), f)) { From 7764148dd3a247dc1f799dbcdaf67e5a0e7d3443 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 28 Oct 2016 07:42:27 -0700 Subject: [PATCH 310/536] merge Signed-off-by: Nikolaj Bjorner --- src/smt/smt_context.cpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index 459c11a32..154f3a6a3 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -3778,14 +3778,8 @@ namespace smt { #ifdef Z3DEBUG for (unsigned i = 0; i < num_lits; i++) { literal l = lits[i]; -<<<<<<< HEAD - expr* real_atom; - if (expr_signs[i] != l.sign()) { - -======= if (expr_signs[i] != l.sign()) { expr* real_atom; ->>>>>>> f1412d3f3249529224f4180f601652da210b274a VERIFY(m_manager.is_not(expr_lits.get(i), real_atom)); // the sign must have flipped when internalizing CTRACE("resolve_conflict_bug", real_atom != bool_var2expr(l.var()), tout << mk_pp(real_atom, m_manager) << "\n" << mk_pp(bool_var2expr(l.var()), m_manager) << "\n";); From 3714e520bed8e95696bfe9e2e51032eece1a2c73 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 28 Oct 2016 08:27:11 -0700 Subject: [PATCH 311/536] fix performance bottlnecks: gc of literals walk through potentially huge watch-lists, avoid user-push/pop around calls to solver2tactic Signed-off-by: Nikolaj Bjorner --- src/sat/sat_solver.cpp | 17 ++++++++++------- src/solver/solver2tactic.cpp | 21 +++++++++++---------- 2 files changed, 21 insertions(+), 17 deletions(-) diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index e70a30a5a..e0bb0f2a3 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -745,7 +745,7 @@ namespace sat { if (m_config.m_max_conflicts == 0) { - IF_VERBOSE(SAT_VB_LVL, verbose_stream() << "\"abort: max-conflicts = 0\"\n";); + IF_VERBOSE(SAT_VB_LVL, verbose_stream() << "(sat \"abort: max-conflicts = 0\")\n";); return l_undef; } @@ -757,7 +757,7 @@ namespace sat { return r; if (m_conflicts > m_config.m_max_conflicts) { - IF_VERBOSE(SAT_VB_LVL, verbose_stream() << "\"abort: max-conflicts = " << m_conflicts << "\"\n";); + IF_VERBOSE(SAT_VB_LVL, verbose_stream() << "(sat \"abort: max-conflicts = " << m_conflicts << "\")\n";); return l_undef; } @@ -1016,7 +1016,7 @@ namespace sat { set_conflict(justification(), ~lit); m_conflict_lvl = scope_lvl(); resolve_conflict_for_unsat_core(); - IF_VERBOSE(3, verbose_stream() << "core: " << m_core << "\n";); + IF_VERBOSE(3, verbose_stream() << "(sat.core: " << m_core << ")\n";); update_min_core(); SASSERT(m_min_core_valid); m_weight += weights[i]; @@ -1029,7 +1029,7 @@ namespace sat { if (m_core.size() <= 3) { m_inconsistent = true; TRACE("opt", tout << "found small core: " << m_core << "\n";); - IF_VERBOSE(11, verbose_stream() << "small core: " << m_core << "\n";); + IF_VERBOSE(11, verbose_stream() << "(sat.core: " << m_core << ")\n";); return true; } pop_assumption(); @@ -1042,7 +1042,7 @@ namespace sat { } } TRACE("sat", tout << "initialized\n";); - IF_VERBOSE(11, verbose_stream() << "Blocker: " << m_blocker << "\nCore: " << m_min_core << "\n";); + IF_VERBOSE(11, verbose_stream() << "(sat.blocker: " << m_blocker << "\nCore: " << m_min_core << ")\n";); if (m_weight >= max_weight) { // block the current correction set candidate. ++m_stats.m_blocked_corr_sets; @@ -2584,7 +2584,7 @@ namespace sat { // void solver::user_push() { - literal lit; + literal lit; bool_var new_v = mk_var(true, false); lit = literal(new_v, false); m_user_scope_literals.push_back(lit); @@ -2683,6 +2683,9 @@ namespace sat { while (num_scopes > 0) { literal lit = m_user_scope_literals.back(); m_user_scope_literals.pop_back(); + get_wlist(lit).reset(); + get_wlist(~lit).reset(); + gc_lit(m_learned, lit); gc_lit(m_clauses, lit); gc_bin(true, lit); @@ -3218,7 +3221,7 @@ namespace sat { delete_unfixed(vars); } extract_fixed_consequences(num_units, assumptions, vars, conseq); - IF_VERBOSE(1, verbose_stream() << "(get-consequences" + IF_VERBOSE(1, verbose_stream() << "(sat.get-consequences" << " iterations: " << num_iterations << " variables: " << vars.size() << " fixed: " << conseq.size() diff --git a/src/solver/solver2tactic.cpp b/src/solver/solver2tactic.cpp index 8646d4813..76ebf73dd 100644 --- a/src/solver/solver2tactic.cpp +++ b/src/solver/solver2tactic.cpp @@ -84,6 +84,7 @@ class solver2tactic : public tactic { ast_manager& m; ref m_solver; params_ref m_params; + statistics m_st; public: solver2tactic(solver* s): @@ -109,14 +110,14 @@ public: ptr_vector assumptions; ref fmc; extract_clauses_and_dependencies(in, clauses, assumptions, bool2dep, fmc); - m_solver->push(); - m_solver->assert_expr(clauses); - lbool r = m_solver->check_sat(assumptions.size(), assumptions.c_ptr()); + ref local_solver = m_solver->translate(m, m_params); + local_solver->assert_expr(clauses); + lbool r = local_solver->check_sat(assumptions.size(), assumptions.c_ptr()); switch (r) { case l_true: if (in->models_enabled()) { model_ref mdl; - m_solver->get_model(mdl); + local_solver->get_model(mdl); mc = model2model_converter(mdl.get()); mc = concat(fmc.get(), mc.get()); } @@ -130,11 +131,11 @@ public: proof* pr = 0; expr_dependency* lcore = 0; if (in->proofs_enabled()) { - pr = m_solver->get_proof(); + pr = local_solver->get_proof(); } if (in->unsat_core_enabled()) { ptr_vector core; - m_solver->get_unsat_core(core); + local_solver->get_unsat_core(core); for (unsigned i = 0; i < core.size(); ++i) { lcore = m.mk_join(lcore, m.mk_leaf(bool2dep.find(core[i]))); } @@ -150,15 +151,15 @@ public: if (m.canceled()) { throw tactic_exception(Z3_CANCELED_MSG); } - throw tactic_exception(m_solver->reason_unknown().c_str()); + throw tactic_exception(local_solver->reason_unknown().c_str()); } - m_solver->pop(1); + local_solver->collect_statistics(m_st); } virtual void collect_statistics(statistics & st) const { - m_solver->collect_statistics(st); + st.copy(m_st); } - virtual void reset_statistics() {} + virtual void reset_statistics() { m_st.reset(); } virtual void cleanup() { } virtual void reset() { cleanup(); } From ff75f88c4f2222882453d81f5e4294cc6bde8d81 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 31 Oct 2016 22:25:58 +0100 Subject: [PATCH 312/536] fix memory abuse in internalization in inc-sat-solver Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/pb2bv_rewriter.cpp | 43 ++-- src/ast/rewriter/pb2bv_rewriter.h | 1 - src/sat/sat_solver/inc_sat_solver.cpp | 5 +- .../portfolio/bounded_int2bv_solver.cpp | 1 + src/tactic/portfolio/enum2bv_solver.cpp | 1 - src/tactic/portfolio/pb2bv_solver.cpp | 2 +- src/util/sorting_network.h | 202 +++++++++++++----- 7 files changed, 177 insertions(+), 78 deletions(-) diff --git a/src/ast/rewriter/pb2bv_rewriter.cpp b/src/ast/rewriter/pb2bv_rewriter.cpp index cf5b67793..37c87cd5b 100644 --- a/src/ast/rewriter/pb2bv_rewriter.cpp +++ b/src/ast/rewriter/pb2bv_rewriter.cpp @@ -241,37 +241,36 @@ struct pb2bv_rewriter::imp { m_args(m) {} - br_status mk_app_core(func_decl * f, unsigned sz, expr * const* args, expr_ref & result) { + bool mk_app(bool full, func_decl * f, unsigned sz, expr * const* args, expr_ref & result) { if (f->get_family_id() == pb.get_family_id()) { - mk_pb(f, sz, args, result); - ++m_imp.m_num_translated; - return BR_DONE; + mk_pb(full, f, sz, args, result); } else if (au.is_le(f) && is_pb(args[0], args[1])) { - ++m_imp.m_num_translated; result = mk_le_ge(m_args.size(), m_args.c_ptr(), m_k); - return BR_DONE; } else if (au.is_lt(f) && is_pb(args[0], args[1])) { - ++m_imp.m_num_translated; ++m_k; result = mk_le_ge(m_args.size(), m_args.c_ptr(), m_k); - return BR_DONE; } else if (au.is_ge(f) && is_pb(args[1], args[0])) { - ++m_imp.m_num_translated; result = mk_le_ge(m_args.size(), m_args.c_ptr(), m_k); - return BR_DONE; } else if (au.is_gt(f) && is_pb(args[1], args[0])) { - ++m_imp.m_num_translated; ++m_k; result = mk_le_ge(m_args.size(), m_args.c_ptr(), m_k); - return BR_DONE; } else if (m.is_eq(f) && is_pb(args[0], args[1])) { - ++m_imp.m_num_translated; result = mk_le_ge(m_args.size(), m_args.c_ptr(), m_k); + } + else { + return false; + } + ++m_imp.m_num_translated; + return true; + } + + br_status mk_app_core(func_decl * f, unsigned sz, expr * const* args, expr_ref & result) { + if (mk_app(true, f, sz, args, result)) { return BR_DONE; } else { @@ -350,25 +349,25 @@ struct pb2bv_rewriter::imp { return false; } - void mk_pb(func_decl * f, unsigned sz, expr * const* args, expr_ref & result) { + void mk_pb(bool full, func_decl * f, unsigned sz, expr * const* args, expr_ref & result) { SASSERT(f->get_family_id() == pb.get_family_id()); if (is_or(f)) { result = m.mk_or(sz, args); } else if (pb.is_at_most_k(f) && pb.get_k(f).is_unsigned()) { - result = m_sort.le(true, pb.get_k(f).get_unsigned(), sz, args); + result = m_sort.le(full, pb.get_k(f).get_unsigned(), sz, args); } else if (pb.is_at_least_k(f) && pb.get_k(f).is_unsigned()) { - result = m_sort.ge(true, pb.get_k(f).get_unsigned(), sz, args); + result = m_sort.ge(full, pb.get_k(f).get_unsigned(), sz, args); } else if (pb.is_eq(f) && pb.get_k(f).is_unsigned() && pb.has_unit_coefficients(f)) { - result = m_sort.eq(pb.get_k(f).get_unsigned(), sz, args); + result = m_sort.eq(full, pb.get_k(f).get_unsigned(), sz, args); } else if (pb.is_le(f) && pb.get_k(f).is_unsigned() && pb.has_unit_coefficients(f)) { - result = m_sort.le(true, pb.get_k(f).get_unsigned(), sz, args); + result = m_sort.le(full, pb.get_k(f).get_unsigned(), sz, args); } else if (pb.is_ge(f) && pb.get_k(f).is_unsigned() && pb.has_unit_coefficients(f)) { - result = m_sort.ge(true, pb.get_k(f).get_unsigned(), sz, args); + result = m_sort.ge(full, pb.get_k(f).get_unsigned(), sz, args); } else { result = mk_bv(f, sz, args); @@ -433,9 +432,6 @@ struct pb2bv_rewriter::imp { void operator()(expr * e, expr_ref & result, proof_ref & result_proof) { m_rw(e, result, result_proof); } - void assert_expr(expr * e, expr_ref & result, proof_ref & result_proof) { - m_rw(e, result, result_proof); - } void push() { m_fresh_lim.push_back(m_fresh.size()); } @@ -472,9 +468,6 @@ unsigned pb2bv_rewriter::get_num_steps() const { return m_imp->get_num_steps(); void pb2bv_rewriter::cleanup() { ast_manager& mgr = m(); params_ref p = m_imp->m_params; dealloc(m_imp); m_imp = alloc(imp, mgr, p); } func_decl_ref_vector const& pb2bv_rewriter::fresh_constants() const { return m_imp->m_fresh; } void pb2bv_rewriter::operator()(expr * e, expr_ref & result, proof_ref & result_proof) { (*m_imp)(e, result, result_proof); } -void pb2bv_rewriter::assert_expr(expr* e, expr_ref & result, proof_ref & result_proof) { - m_imp->assert_expr(e, result, result_proof); -} void pb2bv_rewriter::push() { m_imp->push(); } void pb2bv_rewriter::pop(unsigned num_scopes) { m_imp->pop(num_scopes); } void pb2bv_rewriter::flush_side_constraints(expr_ref_vector& side_constraints) { m_imp->flush_side_constraints(side_constraints); } diff --git a/src/ast/rewriter/pb2bv_rewriter.h b/src/ast/rewriter/pb2bv_rewriter.h index 569eaf07d..47d8361cb 100644 --- a/src/ast/rewriter/pb2bv_rewriter.h +++ b/src/ast/rewriter/pb2bv_rewriter.h @@ -36,7 +36,6 @@ public: void cleanup(); func_decl_ref_vector const& fresh_constants() const; void operator()(expr * e, expr_ref & result, proof_ref & result_proof); - void assert_expr(expr* e, expr_ref & result, proof_ref & result_proof); void push(); void pop(unsigned num_scopes); void flush_side_constraints(expr_ref_vector& side_constraints); diff --git a/src/sat/sat_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp index f5efed726..d1fae0156 100644 --- a/src/sat/sat_solver/inc_sat_solver.cpp +++ b/src/sat/sat_solver/inc_sat_solver.cpp @@ -34,6 +34,7 @@ Notes: #include "bit_blaster_model_converter.h" #include "ast_translation.h" #include "ast_util.h" +#include "propagate_values_tactic.h" // incremental SAT solver. class inc_sat_solver : public solver { @@ -341,6 +342,7 @@ public: mk_max_bv_sharing_tactic(m), mk_bit_blaster_tactic(m, m_bb_rewriter.get()), //mk_aig_tactic(), + //mk_propagate_values_tactic(m, simp2_p), using_params(mk_simplify_tactic(m), simp2_p)); while (m_bb_rewriter->get_num_scopes() < m_num_scopes) { m_bb_rewriter->push(); @@ -377,6 +379,7 @@ private: g = m_subgoals[0]; expr_ref_vector atoms(m); TRACE("sat", g->display_with_dependencies(tout);); + std::cout << "exprs: " << g->num_exprs() << "\n"; m_goal2sat(*g, m_params, m_solver, m_map, dep2asm, true); m_goal2sat.get_interpreted_atoms(atoms); if (!atoms.empty()) { @@ -520,7 +523,7 @@ private: } dep2asm_t dep2asm; goal_ref g = alloc(goal, m, true, false); // models, maybe cores are enabled - for (unsigned i = 0 ; i < m_fmls.size(); ++i) { + for (unsigned i = m_fmls_head ; i < m_fmls.size(); ++i) { g->assert_expr(m_fmls[i].get()); } lbool res = internalize_goal(g, dep2asm); diff --git a/src/tactic/portfolio/bounded_int2bv_solver.cpp b/src/tactic/portfolio/bounded_int2bv_solver.cpp index 0b136dda7..b6c85c159 100644 --- a/src/tactic/portfolio/bounded_int2bv_solver.cpp +++ b/src/tactic/portfolio/bounded_int2bv_solver.cpp @@ -303,6 +303,7 @@ private: } } m_assertions.reset(); + m_rewriter.reset(); } }; diff --git a/src/tactic/portfolio/enum2bv_solver.cpp b/src/tactic/portfolio/enum2bv_solver.cpp index e89f9d188..f3288d8d6 100644 --- a/src/tactic/portfolio/enum2bv_solver.cpp +++ b/src/tactic/portfolio/enum2bv_solver.cpp @@ -99,7 +99,6 @@ public: virtual lbool find_mutexes(expr_ref_vector const& vars, vector& mutexes) { return m_solver->find_mutexes(vars, mutexes); } virtual lbool get_consequences_core(expr_ref_vector const& asms, expr_ref_vector const& vars, expr_ref_vector& consequences) { - datatype_util dt(m); bv_util bv(m); expr_ref_vector bvars(m), conseq(m), bounds(m); diff --git a/src/tactic/portfolio/pb2bv_solver.cpp b/src/tactic/portfolio/pb2bv_solver.cpp index d1826e61d..bfd533e8a 100644 --- a/src/tactic/portfolio/pb2bv_solver.cpp +++ b/src/tactic/portfolio/pb2bv_solver.cpp @@ -113,7 +113,7 @@ private: expr_ref fml(m); expr_ref_vector fmls(m); for (unsigned i = 0; i < m_assertions.size(); ++i) { - m_rewriter.assert_expr(m_assertions[i].get(), fml, proof); + m_rewriter(m_assertions[i].get(), fml, proof); m_solver->assert_expr(fml); } m_rewriter.flush_side_constraints(fmls); diff --git a/src/util/sorting_network.h b/src/util/sorting_network.h index 33c4f8b61..87d8bbf3f 100644 --- a/src/util/sorting_network.h +++ b/src/util/sorting_network.h @@ -24,7 +24,6 @@ Notes: #ifndef SORTING_NETWORK_H_ #define SORTING_NETWORK_H_ - template class sorting_network { typedef typename Ext::vector vect; @@ -213,17 +212,17 @@ Notes: } } - literal eq(unsigned k, unsigned n, literal const* xs) { + literal eq(bool full, unsigned k, unsigned n, literal const* xs) { if (k > n) { return ctx.mk_false(); } SASSERT(k <= n); literal_vector in, out; if (dualize(k, n, xs, in)) { - return eq(k, n, in.c_ptr()); + return eq(full, k, n, in.c_ptr()); } else if (k == 1) { - return mk_exactly_1(true, n, xs); + return mk_exactly_1(full, n, xs); } else { SASSERT(2*k <= n); @@ -242,34 +241,64 @@ Notes: private: - - literal mk_and(literal l1, literal l2) { - literal result = fresh(); - add_clause(ctx.mk_not(result), l1); - add_clause(ctx.mk_not(result), l2); - add_clause(ctx.mk_not(l1), ctx.mk_not(l2), result); - return result; - } - - void mk_implies_or(literal l, unsigned n, literal const* xs) { + void add_implies_or(literal l, unsigned n, literal const* xs) { literal_vector lits(n, xs); lits.push_back(ctx.mk_not(l)); add_clause(lits); } - void mk_or_implies(literal l, unsigned n, literal const* xs) { + void add_or_implies(literal l, unsigned n, literal const* xs) { for (unsigned j = 0; j < n; ++j) { add_clause(ctx.mk_not(xs[j]), l); } } - literal mk_or(literal_vector const& ors) { - if (ors.size() == 1) { + literal mk_or(unsigned n, literal const* ors) { + if (n == 1) { return ors[0]; } literal result = fresh(); - mk_implies_or(result, ors.size(), ors.c_ptr()); - mk_or_implies(result, ors.size(), ors.c_ptr()); + add_implies_or(result, n, ors); + add_or_implies(result, n, ors); + return result; + } + + literal mk_or(literal l1, literal l2) { + literal ors[2] = { l1, l2 }; + return mk_or(2, ors); + } + literal mk_or(literal_vector const& ors) { + return mk_or(ors.size(), ors.c_ptr()); + } + + void add_implies_and(literal l, literal_vector const& xs) { + for (unsigned j = 0; j < xs.size(); ++j) { + add_clause(ctx.mk_not(l), xs[j]); + } + } + + void add_and_implies(literal l, literal_vector const& xs) { + literal_vector lits; + for (unsigned j = 0; j < xs.size(); ++j) { + lits.push_back(ctx.mk_not(xs[j])); + } + lits.push_back(l); + add_clause(lits); + } + + literal mk_and(literal l1, literal l2) { + literal_vector xs; + xs.push_back(l1); xs.push_back(l2); + return mk_and(xs); + } + + literal mk_and(literal_vector const& ands) { + if (ands.size() == 1) { + return ands[0]; + } + literal result = fresh(); + add_implies_and(result, ands); + add_and_implies(result, ands); return result; } @@ -281,18 +310,19 @@ Notes: r1 = mk_and(r1, mk_or(ors)); } else { - mk_implies_or(r1, ors.size(), ors.c_ptr()); + add_implies_or(r1, ors.size(), ors.c_ptr()); } return r1; } +#if 1 literal mk_at_most_1(bool full, unsigned n, literal const* xs, literal_vector& ors) { TRACE("pb", tout << (full?"full":"partial") << " "; for (unsigned i = 0; i < n; ++i) tout << xs[i] << " "; tout << "\n";); - if (false && !full && n >= 4) { - return mk_at_most_1_bimander(n, xs); + if (n >= 4 && false) { + return mk_at_most_1_bimander(full, n, xs, ors); } literal_vector in(n, xs); literal result = fresh(); @@ -301,17 +331,14 @@ Notes: ands.push_back(result); while (!in.empty()) { ors.reset(); - unsigned i = 0; unsigned n = in.size(); if (n + 1 == inc_size) ++inc_size; - bool last = n <= inc_size; - for (; i + inc_size < n; i += inc_size) { - mk_at_most_1_small(full, last, inc_size, in.c_ptr() + i, result, ands, ors); + for (unsigned i = 0; i < n; i += inc_size) { + unsigned inc = std::min(n - i, inc_size); + mk_at_most_1_small(full, inc, in.c_ptr() + i, result, ands); + ors.push_back(mk_or(inc, in.c_ptr() + i)); } - if (i < n) { - mk_at_most_1_small(full, last, n - i, in.c_ptr() + i, result, ands, ors); - } - if (last) { + if (n <= inc_size) { break; } in.reset(); @@ -322,19 +349,40 @@ Notes: } return result; } +#else + literal mk_at_most_1(bool full, unsigned n, literal const* xs, literal_vector& ors) { + TRACE("pb", tout << (full?"full":"partial") << " "; + for (unsigned i = 0; i < n; ++i) tout << xs[i] << " "; + tout << "\n";); - void mk_at_most_1_small(bool full, bool last, unsigned n, literal const* xs, literal result, literal_vector& ands, literal_vector& ors) { + literal_vector in(n, xs); + unsigned inc_size = 4; + literal_vector ands; + while (!in.empty()) { + ors.reset(); + unsigned i = 0; + unsigned n = in.size(); + if (n + 1 == inc_size) ++inc_size; + for (; i < n; i += inc_size) { + unsigned inc = std::min(inc_size, n - i); + ands.push_back(mk_at_most_1_small(inc, in.c_ptr() + i)); + ors.push_back(mk_or(inc, in.c_ptr() + i)); + } + if (n <= inc_size) { + break; + } + in.reset(); + in.append(ors); + } + return mk_and(ands); + } + +#endif + void mk_at_most_1_small(bool full, unsigned n, literal const* xs, literal result, literal_vector& ands) { SASSERT(n > 0); if (n == 1) { - ors.push_back(xs[0]); return; } - literal ex = fresh(); - mk_or_implies(ex, n, xs); - if (full) { - mk_implies_or(ex, n, xs); - } - ors.push_back(ex); // result => xs[0] + ... + xs[n-1] <= 1 for (unsigned i = 0; i < n; ++i) { @@ -358,19 +406,75 @@ Notes: } } - literal mk_at_most_1_bimander(unsigned n, literal const* xs) { + literal mk_at_most_1_small(unsigned n, literal const* xs) { + SASSERT(n > 0); + if (n == 1) { + return ctx.mk_true(); + } + + +#if 0 + literal result = fresh(); + + // result => xs[0] + ... + xs[n-1] <= 1 + for (unsigned i = 0; i < n; ++i) { + for (unsigned j = i + 1; j < n; ++j) { + add_clause(ctx.mk_not(result), ctx.mk_not(xs[i]), ctx.mk_not(xs[j])); + } + } + + // xs[0] + ... + xs[n-1] <= 1 => result + for (unsigned i = 0; i < n; ++i) { + literal_vector lits; + lits.push_back(result); + for (unsigned j = 0; j < n; ++j) { + if (j != i) lits.push_back(xs[j]); + } + add_clause(lits); + } + + return result; +#endif +#if 1 + // r <=> and( or(!xi,!xj)) + // + literal_vector ands; + for (unsigned i = 0; i < n; ++i) { + for (unsigned j = i + 1; j < n; ++j) { + ands.push_back(mk_or(ctx.mk_not(xs[i]), ctx.mk_not(xs[j]))); + } + } + return mk_and(ands); +#else + // r <=> or (and !x_{j != i}) + + literal_vector ors; + for (unsigned i = 0; i < n; ++i) { + literal_vector ands; + for (unsigned j = 0; j < n; ++j) { + if (j != i) { + ands.push_back(ctx.mk_not(xs[j])); + } + } + ors.push_back(mk_and(ands)); + } + return mk_or(ors); + +#endif + } + + + // + + literal mk_at_most_1_bimander(bool full, unsigned n, literal const* xs, literal_vector& ors) { literal_vector in(n, xs); literal result = fresh(); unsigned inc_size = 2; - bool last = false; - bool full = false; - literal_vector ors, ands; - unsigned i = 0; - for (; i + inc_size < n; i += inc_size) { - mk_at_most_1_small(full, last, inc_size, in.c_ptr() + i, result, ands, ors); - } - if (i < n) { - mk_at_most_1_small(full, last, n - i, in.c_ptr() + i, result, ands, ors); + literal_vector ands; + for (unsigned i = 0; i < n; i += inc_size) { + unsigned inc = std::min(n - i, inc_size); + mk_at_most_1_small(full, inc, in.c_ptr() + i, result, ands); + ors.push_back(mk_or(inc, in.c_ptr() + i)); } unsigned nbits = 0; @@ -381,7 +485,7 @@ Notes: for (unsigned k = 0; k < nbits; ++k) { bits.push_back(fresh()); } - for (i = 0; i < ors.size(); ++i) { + for (unsigned i = 0; i < ors.size(); ++i) { for (unsigned k = 0; k < nbits; ++k) { bool bit_set = (i & (static_cast(1 << k))) != 0; add_clause(ctx.mk_not(result), ctx.mk_not(ors[i]), bit_set ? bits[k] : ctx.mk_not(bits[k])); From fa1a0aa7ba60e2f43d67d111e02317239e541ce0 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 31 Oct 2016 22:59:56 +0100 Subject: [PATCH 313/536] remove buggy and unused equivalence relation plugin. Github issue #770 Signed-off-by: Nikolaj Bjorner --- contrib/cmake/src/muz/rel/CMakeLists.txt | 1 - src/muz/rel/dl_mk_partial_equiv.cpp | 155 -------- src/muz/rel/dl_mk_partial_equiv.h | 50 --- src/muz/rel/dl_table.cpp | 477 ----------------------- src/muz/rel/dl_table.h | 113 ------ src/muz/rel/rel_context.cpp | 3 - 6 files changed, 799 deletions(-) delete mode 100644 src/muz/rel/dl_mk_partial_equiv.cpp delete mode 100644 src/muz/rel/dl_mk_partial_equiv.h diff --git a/contrib/cmake/src/muz/rel/CMakeLists.txt b/contrib/cmake/src/muz/rel/CMakeLists.txt index 720714ed8..f03a90406 100644 --- a/contrib/cmake/src/muz/rel/CMakeLists.txt +++ b/contrib/cmake/src/muz/rel/CMakeLists.txt @@ -12,7 +12,6 @@ z3_add_component(rel dl_interval_relation.cpp dl_lazy_table.cpp dl_mk_explanations.cpp - dl_mk_partial_equiv.cpp dl_mk_similarity_compressor.cpp dl_mk_simple_joins.cpp dl_product_relation.cpp diff --git a/src/muz/rel/dl_mk_partial_equiv.cpp b/src/muz/rel/dl_mk_partial_equiv.cpp deleted file mode 100644 index 94da7851f..000000000 --- a/src/muz/rel/dl_mk_partial_equiv.cpp +++ /dev/null @@ -1,155 +0,0 @@ -/*++ -Copyright (c) 2012 Microsoft Corporation - -Module Name: - - dl_mk_partial_equiv.cpp - -Abstract: - - Rule transformer which identifies predicates that are partial equivalence relations. - -Author: - - Nikolaj Bjorner (nbjorner) 2012-05-14 - -Revision History: - ---*/ - -#include "dl_mk_partial_equiv.h" -#include "dl_relation_manager.h" -#include "ast_pp.h" - -namespace datalog { - - bool mk_partial_equivalence_transformer::is_symmetry(rule const* r) { - func_decl* p = r->get_decl(); - return - p->get_arity() == 2 && - p->get_domain(0) == p->get_domain(1) && - r->get_tail_size() == 1 && - r->get_tail(0)->get_decl() == p && - r->get_head()->get_arg(0) == r->get_tail(0)->get_arg(1) && - r->get_head()->get_arg(1) == r->get_tail(0)->get_arg(0) && - is_var(r->get_head()->get_arg(0)) && - is_var(r->get_head()->get_arg(1)) && - r->get_head()->get_arg(0) != r->get_head()->get_arg(1); - } - - - bool mk_partial_equivalence_transformer::is_transitivity(rule const* r) { - func_decl* p = r->get_decl(); - if (p->get_arity() != 2 || - p->get_domain(0) != p->get_domain(1) || - r->get_tail_size() != 2 || - r->get_tail(0)->get_decl() != p || - r->get_tail(1)->get_decl() != p) { - return false; - } - app* h = r->get_head(); - app* a = r->get_tail(0); - app* b = r->get_tail(1); - expr* x1 = h->get_arg(0); - expr* x2 = h->get_arg(1); - expr* a1 = a->get_arg(0); - expr* a2 = a->get_arg(1); - expr* b1 = b->get_arg(0); - expr* b2 = b->get_arg(1); - - if (!(is_var(x1) && is_var(x2) && is_var(a1) && is_var(a2) && is_var(b1) && is_var(b2))) { - return false; - } - if (x1 == x2 || a1 == a2 || b1 == b2) { - return false; - } - if (a2 == b1) { - if (x1 == b2 && x2 == a1) { - return true; - } - if (x1 == a1 && x2 == b2) { - return true; - } - return false; - } - if (a1 == b2) { - if (x1 == b1 && x2 == a2) { - return true; - } - if (x1 == a2 && x2 == b1) { - return true; - } - return false; - } - - return false; -; - } - - - rule_set * mk_partial_equivalence_transformer::operator()(rule_set const & source) { - // TODO mc - - if (source.get_num_rules() == 0) { - return 0; - } - - if (m_context.get_engine() != DATALOG_ENGINE) { - return 0; - } - - relation_manager & rm = m_context.get_rel_context()->get_rmanager(); - rule_set::decl2rules::iterator it = source.begin_grouped_rules(); - rule_set::decl2rules::iterator end = source.end_grouped_rules(); - - rule_set* res = alloc(rule_set, m_context); - - for (; it != end; ++it) { - func_decl* p = it->m_key; - rule_vector const& rv = *(it->m_value); - bool has_symmetry = false; - bool has_transitivity = false; - unsigned i_symmetry = 0, i_transitivity = 0; - family_id kind = rm.get_requested_predicate_kind(p); - for (unsigned i = 0; i < rv.size(); ++i) { - - if (kind != null_family_id) { - res->add_rule(rv[i]); - } - else if (is_symmetry(rv[i])) { - i_symmetry = i; - has_symmetry = true; - } - else if (is_transitivity(rv[i])) { - i_transitivity = i; - has_transitivity = true; - } - else { - res->add_rule(rv[i]); - } - } - if (has_symmetry && !has_transitivity) { - res->add_rule(rv[i_symmetry]); - } - else if (!has_symmetry && has_transitivity) { - res->add_rule(rv[i_transitivity]); - } - else if (has_symmetry && has_transitivity) { - TRACE("dl", tout << "updating predicate " << mk_pp(p, m) << " to partial equivalence\n";); - SASSERT(kind == null_family_id); - rm.set_predicate_kind(p, rm.get_table_plugin(symbol("equivalence"))->get_kind()); - } - } - - if (res->get_num_rules() == source.get_num_rules()) { - dealloc(res); - return 0; - } - res->inherit_predicates(source); - - return res; - } - -}; - - diff --git a/src/muz/rel/dl_mk_partial_equiv.h b/src/muz/rel/dl_mk_partial_equiv.h deleted file mode 100644 index be871f53e..000000000 --- a/src/muz/rel/dl_mk_partial_equiv.h +++ /dev/null @@ -1,50 +0,0 @@ -/*++ -Copyright (c) 2012 Microsoft Corporation - -Module Name: - - dl_mk_partial_equiv.h - -Abstract: - - Rule transformer which identifies predicates that are partial equivalence relations. - -Author: - - Nikolaj Bjorner (nbjorner) 2012-05-14 - -Revision History: - ---*/ - - -#ifndef DL_MK_PARTIAL_EQUIVALENCE_TRANSFORMER_H_ -#define DL_MK_PARTIAL_EQUIVALENCE_TRANSFORMER_H_ - -#include "dl_context.h" -#include "dl_rule_transformer.h" - -namespace datalog { - - class mk_partial_equivalence_transformer : public rule_transformer::plugin { - ast_manager & m; - context & m_context; - public: - mk_partial_equivalence_transformer(context & ctx, unsigned priority=30000) - : plugin(priority), - m(ctx.get_manager()), - m_context(ctx) {} - - rule_set * operator()(rule_set const & source); - - private: - - bool is_symmetry(rule const* r); - bool is_transitivity(rule const* r); - }; - -}; - -#endif /* DL_MK_PARTIAL_EQUIV_TRANSFORMER_H_ */ - - diff --git a/src/muz/rel/dl_table.cpp b/src/muz/rel/dl_table.cpp index 0b8fc0388..9df9dde5e 100644 --- a/src/muz/rel/dl_table.cpp +++ b/src/muz/rel/dl_table.cpp @@ -292,482 +292,5 @@ namespace datalog { table_base::iterator bitvector_table::end() const { return mk_iterator(alloc(bv_iterator, *this, true)); } - - - - - // ----------------------------------- - // - // equivalence_table - // - // ----------------------------------- - - bool equivalence_table_plugin::can_handle_signature(const table_signature & sig) { - return sig.functional_columns() == 0 && sig.size() == 2 && sig[0] < UINT_MAX && sig[0] == sig[1]; - } - - bool equivalence_table_plugin::is_equivalence_table(table_base const& tbl) const { - if (tbl.get_kind() != get_kind()) return false; - equivalence_table const& t = static_cast(tbl); - return !t.is_sparse(); - } - - table_base * equivalence_table_plugin::mk_empty(const table_signature & s) { - TRACE("dl", for (unsigned i = 0; i < s.size(); ++i) tout << s[i] << " "; tout << "\n";); - SASSERT(can_handle_signature(s)); - return alloc(equivalence_table, *this, s); - } - - class equivalence_table_plugin::select_equal_and_project_fn : public table_transformer_fn { - unsigned m_val; - table_sort m_sort; - public: - select_equal_and_project_fn(const table_signature & sig, table_element val, unsigned col) - : m_val(static_cast(val)), - m_sort(sig[0]) { - SASSERT(val <= UINT_MAX); - SASSERT(col == 0 || col == 1); - SASSERT(sig.functional_columns() == 0); - SASSERT(sig.size() == 2); - SASSERT(sig[0] < UINT_MAX && sig[0] == sig[1]); - } - - virtual table_base* operator()(const table_base& tb) { - TRACE("dl", tout << "\n";); - table_plugin & plugin = tb.get_plugin(); - table_plugin* rp = plugin.get_manager().get_table_plugin(symbol("sparse")); - SASSERT(rp); - table_signature sig; - sig.push_back(m_sort); - table_base* result = rp->mk_empty(sig); - equivalence_table const& eq_table = static_cast(tb); - if (eq_table.is_valid(m_val)) { - table_fact fact; - fact.resize(1); - unsigned r = m_val; - do { - fact[0] = r; - result->add_fact(fact); - r = eq_table.m_uf.next(r); - } - while (r != m_val); - } - TRACE("dl", tb.display(tout << "src:\n"); result->display(tout << "result\n");); - return result; - } - }; - - table_transformer_fn * equivalence_table_plugin::mk_select_equal_and_project_fn( - const table_base & t, const table_element & value, unsigned col) { - return alloc(select_equal_and_project_fn, t.get_signature(), value, col); - } - - class equivalence_table_plugin::union_fn : public table_union_fn { - - equivalence_table_plugin& m_plugin; - - - void mk_union1(equivalence_table & tgt, const equivalence_table & src, table_base * delta) { - unsigned num_vars = src.m_uf.get_num_vars(); - table_fact fact; - fact.resize(2); - for (unsigned i = 0; i < num_vars; ++i) { - if (src.is_valid(i) && src.m_uf.find(i) == i) { - fact[0] = i; - equivalence_table::class_iterator it = src.class_begin(i); - equivalence_table::class_iterator end = src.class_end(i); - for (; it != end; ++it) { - fact[1] = *it; - if (!tgt.contains_fact(fact)) { - tgt.add_fact(fact); - if (delta) { - delta->add_fact(fact); - } - } - } - } - } - } - - void mk_union2(equivalence_table & tgt, const table_base & src, table_base * delta) { - table_fact fact; - table_base::iterator it = src.begin(), end = src.end(); - for (; it != end; ++it) { - it->get_fact(fact); - if (!tgt.contains_fact(fact)) { - tgt.add_fact(fact); - if (delta) { - delta->add_fact(fact); - TRACE("dl", - tout << "Add: "; - for (unsigned i = 0; i < fact.size(); ++i) tout << fact[i] << " "; - tout << "\n";); - } - } - } - } - - public: - union_fn(equivalence_table_plugin& p) : m_plugin(p) {} - - virtual void operator()(table_base & tgt0, const table_base & src, table_base * delta) { - TRACE("dl", tout << "union\n";); - equivalence_table & tgt = static_cast(tgt0); - if (m_plugin.is_equivalence_table(src)) { - mk_union1(tgt, static_cast(src), delta); - } - else { - mk_union2(tgt, src, delta); - } - TRACE("dl", src.display(tout << "src\n"); tgt.display(tout << "tgt\n"); - if (delta) delta->display(tout << "delta\n");); - } - }; - - table_union_fn * equivalence_table_plugin::mk_union_fn( - const table_base & tgt, const table_base & src, const table_base * delta) { - if (!is_equivalence_table(tgt) || - tgt.get_signature() != src.get_signature() || - (delta && delta->get_signature() != tgt.get_signature())) { - return 0; - } - return alloc(union_fn,*this); - } - - class equivalence_table_plugin::join_project_fn : public convenient_table_join_project_fn { - equivalence_table_plugin& m_plugin; - public: - join_project_fn( - equivalence_table_plugin& plugin, const table_signature & t1_sig, const table_signature & t2_sig, unsigned col_cnt, - const unsigned * cols1, const unsigned * cols2, unsigned removed_col_cnt, - const unsigned * removed_cols) - : convenient_table_join_project_fn(t1_sig, t2_sig, col_cnt, cols1, cols2, removed_col_cnt, removed_cols), - m_plugin(plugin) { - m_removed_cols.push_back(UINT_MAX); - } - - virtual table_base * operator()(const table_base & tb1, const table_base & tb2) { - SASSERT(m_cols1.size() == 1); - const table_signature & res_sign = get_result_signature(); - table_plugin * plugin = &tb1.get_plugin(); - if (!plugin->can_handle_signature(res_sign)) { - plugin = &tb2.get_plugin(); - if (!plugin->can_handle_signature(res_sign)) { - plugin = &tb1.get_manager().get_appropriate_plugin(res_sign); - } - } - SASSERT(plugin->can_handle_signature(res_sign)); - table_base * result = plugin->mk_empty(res_sign); - - if (m_plugin.is_equivalence_table(tb1)) { - mk_join(0, m_cols1[0], static_cast(tb1), - 2, m_cols2[0], tb2, result); - } - else if (m_plugin.is_equivalence_table(tb2)) { - mk_join(tb1.get_signature().size(), m_cols2[0], static_cast(tb2), - 0, m_cols1[0], tb1, result); - } - else { - UNREACHABLE(); - } - TRACE("dl", tb1.display(tout << "tb1\n"); tb2.display(tout << "tb2\n"); result->display(tout << "result\n");); - return result; - } - - private: - table_base * mk_join(unsigned offs1, unsigned col1, equivalence_table const & t1, - unsigned offs2, unsigned col2, table_base const& t2, table_base* res) { - table_base::iterator els2it = t2.begin(); - table_base::iterator els2end = t2.end(); - - table_fact acc, proj; - acc.resize(t1.get_signature().size() + t2.get_signature().size()); - - for(; els2it != els2end; ++els2it) { - const table_base::row_interface & row2 = *els2it; - table_element const& e2 = row2[col2]; - equivalence_table::class_iterator it = t1.class_begin(e2); - equivalence_table::class_iterator end = t1.class_end(e2); - if (it != end) { - for (unsigned i = 0; i < row2.size(); ++i) { - acc[i+offs2] = row2[i]; - } - } - for (; it != end; ++it) { - acc[offs1+col1] = e2; - acc[offs1+1-col1] = *it; - mk_project(acc, proj); - TRACE("dl", for (unsigned i = 0; i < proj.size(); ++i) tout << proj[i] << " "; tout << "\n";); - res->add_fact(proj); - } - } - return res; - } - - virtual void mk_project(table_fact const & f, table_fact & p) const { - unsigned sz = f.size(); - p.reset(); - for (unsigned i = 0, r = 0; i < sz; ++i) { - if (r < m_removed_cols.size() && m_removed_cols[r] == i) { - ++r; - } - else { - p.push_back(f[i]); - } - } - } - - - }; - - table_join_fn * equivalence_table_plugin::mk_join_project_fn( - const table_base & t1, const table_base & t2, - unsigned col_cnt, const unsigned * cols1, const unsigned * cols2, unsigned removed_col_cnt, - const unsigned * removed_cols) { - if (col_cnt != 1) { - TRACE("dl", tout << "WARNING: join_project on multiple columns is not implemented\n";); - return 0; - } - if (is_equivalence_table(t1) || is_equivalence_table(t2)) { - return alloc(join_project_fn, *this, t1.get_signature(), t2.get_signature(), col_cnt, cols1, cols2, - removed_col_cnt, removed_cols); - } - return 0; - } - - class equivalence_table::eq_iterator : public iterator_core { - - equivalence_table const& m_eq; - unsigned m_last; - unsigned m_current; - unsigned m_next; - - class our_row : public caching_row_interface { - const eq_iterator& m_parent; - public: - our_row(const eq_iterator & p) : caching_row_interface(p.m_eq), m_parent(p) {} - - virtual void get_fact(table_fact& result) const { - if (result.size() < size()) { - result.resize(size(), 0); - } - result[0] = m_parent.m_current; - result[1] = m_parent.m_next; - } - - virtual table_element operator[](unsigned col) const { - if (col == 0) return m_parent.m_current; - if (col == 1) return m_parent.m_next; - UNREACHABLE(); - return 0; - } - - }; - our_row m_row_obj; - - public: - eq_iterator(const equivalence_table& eq, bool end): - m_eq(eq), - m_last(eq.m_uf.get_num_vars()), - m_current(end?m_last:0), - m_next(0), - m_row_obj(*this) - { - while (m_current < m_last && !m_eq.is_valid(m_current)) { - m_current++; - m_next = m_current; - } - } - - virtual bool is_finished() const { - return m_current == m_last; - } - - virtual row_interface & operator*() { - SASSERT(!is_finished()); - return m_row_obj; - } - - virtual void operator++() { - SASSERT(!is_finished()); - m_next = m_eq.m_uf.next(m_next); - if (m_next == m_current) { - do { - m_current++; - m_next = m_current; - } - while (m_current < m_last && !m_eq.is_valid(m_current)); - } - } - }; - - equivalence_table::equivalence_table(equivalence_table_plugin & plugin, const table_signature & sig) - : table_base(plugin, sig), m_uf(m_ctx), m_sparse(0) { - SASSERT(plugin.can_handle_signature(sig)); - } - - equivalence_table::~equivalence_table() { - if (is_sparse()) { - m_sparse->deallocate(); - } - } - - - void equivalence_table::add_fact(const table_fact & f) { - if (is_sparse()) { - add_fact_sparse(f); - } - else { - TRACE("dl_verbose", for (unsigned i = 0; i < f.size(); ++i) tout << f[i] << " "; tout << "\n";); - while (first(f) >= m_uf.get_num_vars()) m_uf.mk_var(); - while (second(f) >= m_uf.get_num_vars()) m_uf.mk_var(); - m_uf.merge(first(f), second(f)); - m_valid.reserve(m_uf.get_num_vars()); - m_valid.set(first(f)); - m_valid.set(second(f)); - } - } - - void equivalence_table::remove_fact(const table_element* fact) { - mk_sparse(); - m_sparse->remove_fact(fact); - } - - void equivalence_table::mk_sparse() { - if (m_sparse) return; - - TRACE("dl",tout << "\n";); - table_plugin & plugin = get_plugin(); - table_plugin* rp = plugin.get_manager().get_table_plugin(symbol("sparse")); - SASSERT(rp); - table_base* result = rp->mk_empty(get_signature()); - table_base::iterator it = begin(), e = end(); - table_fact fact; - for (; it != e; ++it) { - it->get_fact(fact); - result->add_fact(fact); - } - m_sparse = result; - } - - void equivalence_table::add_fact_sparse(table_fact const& f) { - table_base::iterator it = m_sparse->begin(), end = m_sparse->end(); - vector to_add; - to_add.push_back(f); - table_fact f1(f); - - f1[0] = f[1]; - f1[1] = f[0]; - to_add.push_back(f1); - - f1[0] = f[1]; - f1[1] = f[1]; - to_add.push_back(f1); - - f1[0] = f[0]; - f1[1] = f[0]; - to_add.push_back(f1); - - for (; it != end; ++it) { - if ((*it)[0] == f[0]) { - f1[0] = f[1]; - f1[1] = (*it)[1]; - to_add.push_back(f1); - std::swap(f1[0],f1[1]); - to_add.push_back(f1); - } - } - for (unsigned i = 0; i < to_add.size(); ++i) { - m_sparse->add_fact(to_add[i]); - } - } - - bool equivalence_table::contains_fact(const table_fact & f) const { - TRACE("dl_verbose", for (unsigned i = 0; i < f.size(); ++i) tout << f[i] << " "; tout << "\n";); - if (is_sparse()) { - return m_sparse->contains_fact(f); - } - return - is_valid(first(f)) && - is_valid(second(f)) && - m_uf.find(first(f)) == m_uf.find(second(f)); - } - - table_base* equivalence_table::clone() const { - if (is_sparse()) { - return m_sparse->clone(); - } - TRACE("dl",tout << "\n";); - table_plugin & plugin = get_plugin(); - table_base* result = plugin.mk_empty(get_signature()); - table_fact fact; - fact.resize(2); - for (unsigned i = 0; i < m_uf.get_num_vars(); ++i) { - if (m_valid.get(i) && m_uf.find(i) == i) { - unsigned n = m_uf.next(i); - fact[0] = i; - while (n != i) { - fact[1] = n; - result->add_fact(fact); - n = m_uf.next(n); - } - } - } - return result; - } - - table_base::iterator equivalence_table::begin() const { - if (is_sparse()) return m_sparse->begin(); - return mk_iterator(alloc(eq_iterator, *this, false)); - } - - table_base::iterator equivalence_table::end() const { - if (is_sparse()) return m_sparse->end(); - return mk_iterator(alloc(eq_iterator, *this, true)); - } - - equivalence_table::class_iterator equivalence_table::class_begin(table_element const& _e) const { - SASSERT(!is_sparse()); - unsigned e = static_cast(_e); - return class_iterator(*this, e, !is_valid(e)); - } - - equivalence_table::class_iterator equivalence_table::class_end(table_element const& _e) const { - SASSERT(!is_sparse()); - unsigned e = static_cast(_e); - return class_iterator(*this, e, true); - } - - void equivalence_table::display(std::ostream& out) const { - if (is_sparse()) { - m_sparse->display(out); - return; - } - for (unsigned i = 0; i < m_uf.get_num_vars(); ++i) { - if (is_valid(i) && m_uf.find(i) == i) { - unsigned j = i, last = i; - do { - out << "<" << i << " " << j << ">\n"; - j = m_uf.next(j); - } - while (last != j); - } - } - } - - unsigned equivalence_table::get_size_estimate_rows() const { - if (is_sparse()) return m_sparse->get_size_estimate_rows(); - return static_cast(get_signature()[0]); - } - - unsigned equivalence_table::get_size_estimate_bytes() const { - if (is_sparse()) return m_sparse->get_size_estimate_bytes(); - return static_cast(get_signature()[0]); - } - - bool equivalence_table::knows_exact_size() const { - return (!is_sparse() || m_sparse->knows_exact_size()); - } - }; diff --git a/src/muz/rel/dl_table.h b/src/muz/rel/dl_table.h index b77e860d6..d25aa31bc 100644 --- a/src/muz/rel/dl_table.h +++ b/src/muz/rel/dl_table.h @@ -144,119 +144,6 @@ namespace datalog { virtual iterator end() const; }; - // ------------------------------------------- - // Equivalence table. - // Really: partial equivalence relation table. - // ------------------------------------------- - - class equivalence_table; - - class equivalence_table_plugin : public table_plugin { - class union_fn; - class select_equal_and_project_fn; - class join_project_fn; - - bool is_equivalence_table(table_base const& tbl) const; - - public: - typedef equivalence_table table; - - equivalence_table_plugin(relation_manager & manager) - : table_plugin(symbol("equivalence"), manager) {} - - virtual bool can_handle_signature(const table_signature & s); - - virtual table_base * mk_empty(const table_signature & s); - - protected: - virtual table_union_fn * mk_union_fn(const table_base & tgt, const table_base & src, - const table_base * delta); - virtual table_transformer_fn * mk_select_equal_and_project_fn( - const table_base & t, - const table_element & value, unsigned col); - virtual table_join_fn * mk_join_project_fn(const table_base & t1, const table_base & t2, - unsigned col_cnt, const unsigned * cols1, const unsigned * cols2, unsigned removed_col_cnt, - const unsigned * removed_cols); - - -#if 0 - virtual table_join_fn * mk_join_fn(const table_base & t1, const table_base & t2, - unsigned col_cnt, const unsigned * cols1, const unsigned * cols2); - virtual table_transformer_fn * mk_project_fn(const table_base & t, unsigned col_cnt, - const unsigned * removed_cols); - virtual table_transformer_fn * mk_rename_fn(const table_base & t, unsigned permutation_cycle_len, - const unsigned * permutation_cycle); - const table_element & value, unsigned col); - virtual table_intersection_filter_fn * mk_filter_by_negation_fn(const table_base & t, - const table_base & negated_obj, unsigned joined_col_cnt, - const unsigned * t_cols, const unsigned * negated_cols); -#endif - }; - - class equivalence_table : public table_base { - friend class equivalence_table_plugin; - - class eq_iterator; - union_find_default_ctx m_ctx; - bit_vector m_valid; - union_find<> m_uf; - table_base* m_sparse; - - equivalence_table(equivalence_table_plugin & plugin, const table_signature & sig); - virtual ~equivalence_table(); - - unsigned first(table_fact const& f) const { return static_cast(f[0]); } - unsigned second(table_fact const& f) const { return static_cast(f[1]); } - - bool is_valid(unsigned entry) const { return entry < m_valid.size() && m_valid.get(entry); } - bool is_sparse() const { return m_sparse != 0; } - - // iterator over equivalence class of 'n'. - class class_iterator { - equivalence_table const& m_parent; - unsigned m_current; - unsigned m_last; - bool m_end; - public: - class_iterator(equivalence_table const& s, unsigned n, bool end): - m_parent(s), m_current(n), m_last(n), m_end(end) {} - - unsigned operator*() { return m_current; } - - class_iterator& operator++() { - m_current = m_parent.m_uf.next(m_current); - m_end = (m_current == m_last); - return *this; - } - - bool operator==(const class_iterator & it) const { - return - (m_end && it.m_end) || - (!m_end && !it.m_end && m_current == it.m_current); - } - bool operator!=(const class_iterator & it) const { return !operator==(it); } - - }; - class_iterator class_begin(table_element const& e) const; - class_iterator class_end(table_element const& e) const; - - void add_fact_sparse(table_fact const& f); - void mk_sparse(); - - - public: - virtual void add_fact(const table_fact & f); - virtual void remove_fact(const table_element* fact); - virtual bool contains_fact(const table_fact & f) const; - virtual table_base* clone() const; - virtual iterator begin() const; - virtual iterator end() const; - virtual unsigned get_size_estimate_rows() const; - virtual unsigned get_size_estimate_bytes() const; - virtual bool knows_exact_size() const; - virtual void display(std::ostream & out) const; - - }; }; diff --git a/src/muz/rel/rel_context.cpp b/src/muz/rel/rel_context.cpp index 6d167dfec..abaf88f32 100644 --- a/src/muz/rel/rel_context.cpp +++ b/src/muz/rel/rel_context.cpp @@ -43,7 +43,6 @@ Revision History: #include"dl_mk_similarity_compressor.h" #include"dl_mk_unbound_compressor.h" #include"dl_mk_subsumption_checker.h" -#include"dl_mk_partial_equiv.h" #include"dl_mk_coi_filter.h" #include"dl_mk_filter_rules.h" #include"dl_mk_rule_inliner.h" @@ -108,7 +107,6 @@ namespace datalog { rm.register_plugin(alloc(sparse_table_plugin, rm)); rm.register_plugin(alloc(hashtable_table_plugin, rm)); rm.register_plugin(alloc(bitvector_table_plugin, rm)); - rm.register_plugin(alloc(equivalence_table_plugin, rm)); rm.register_plugin(lazy_table_plugin::mk_sparse(rm)); // register plugins for builtin relations @@ -308,7 +306,6 @@ namespace datalog { transf.register_plugin(alloc(mk_similarity_compressor, m_context)); } transf.register_plugin(alloc(mk_rule_inliner, m_context)); - transf.register_plugin(alloc(mk_partial_equivalence_transformer, m_context)); transf.register_plugin(alloc(mk_interp_tail_simplifier, m_context)); transf.register_plugin(alloc(mk_separate_negated_tails, m_context)); From ba942af5a8492615886c8cba4cabefeb03ed6922 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 31 Oct 2016 23:27:39 +0100 Subject: [PATCH 314/536] disable sat solver when proofs are turned on. Fixes issue #768 Signed-off-by: Nikolaj Bjorner --- src/opt/opt_context.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 1335685ff..624671e2b 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -42,7 +42,6 @@ Notes: #include "ast_smt_pp.h" #include "filter_model_converter.h" #include "ast_pp_util.h" -#include "inc_sat_solver.h" #include "qsat.h" namespace opt { @@ -595,6 +594,9 @@ namespace opt { if (opt_params(m_params).priority() == symbol("pareto")) { return; } + if (m.proofs_enabled()) { + return; + } m_params.set_bool("minimize_core_partial", true); m_params.set_bool("minimize_core", true); m_sat_solver = mk_inc_sat_solver(m, m_params); From 84172302a28a013c7c4d3b5e18cc8cb8f22ca5f6 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 1 Nov 2016 00:16:16 +0100 Subject: [PATCH 315/536] fix bug in mutex extraction, reported by Patrick Trentin Signed-off-by: Nikolaj Bjorner --- src/opt/maxres.cpp | 29 ++++++++++++++++----------- src/sat/sat_solver/inc_sat_solver.cpp | 1 - 2 files changed, 17 insertions(+), 13 deletions(-) diff --git a/src/opt/maxres.cpp b/src/opt/maxres.cpp index d8b166924..e6b452603 100644 --- a/src/opt/maxres.cpp +++ b/src/opt/maxres.cpp @@ -155,7 +155,7 @@ public: void add_soft(expr* e, rational const& w) { - TRACE("opt", tout << mk_pp(e, m) << "\n";); + TRACE("opt", tout << mk_pp(e, m) << " |-> " << w << "\n";); expr_ref asum(m), fml(m); app_ref cls(m); rational weight(0); @@ -290,7 +290,10 @@ public: } void process_mutex(expr_ref_vector& mutex) { - TRACE("opt", tout << mutex << "\n";); + TRACE("opt", + for (unsigned i = 0; i < mutex.size(); ++i) { + tout << mk_pp(mutex[i].get(), m) << " |-> " << get_weight(mutex[i].get()) << "\n"; + }); if (mutex.size() <= 1) { return; } @@ -298,20 +301,22 @@ public: ptr_vector core(mutex.size(), mutex.c_ptr()); remove_soft(core, m_asms); rational weight(0), sum1(0), sum2(0); + vector weights; for (unsigned i = 0; i < mutex.size(); ++i) { - sum1 += get_weight(mutex[i].get()); + rational w = get_weight(mutex[i].get()); + weights.push_back(w); + sum1 += w; + m_asm2weight.remove(mutex[i].get()); } - while (!mutex.empty()) { - expr_ref soft = mk_or(mutex); - rational w = get_weight(mutex.back()); + for (unsigned i = mutex.size(); i > 0; ) { + --i; + expr_ref soft(m.mk_or(i+1, mutex.c_ptr()), m); + rational w = weights[i]; weight = w - weight; - m_lower += weight*rational(mutex.size()-1); - sum2 += weight*rational(mutex.size()); + m_lower += weight*rational(i); + sum2 += weight*rational(i+1); add_soft(soft, weight); - mutex.pop_back(); - while (!mutex.empty() && get_weight(mutex.back()) == w) { - mutex.pop_back(); - } + for (; i > 0 && weights[i-1] == w; --i) {} weight = w; } SASSERT(sum1 == sum2); diff --git a/src/sat/sat_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp index d1fae0156..682978287 100644 --- a/src/sat/sat_solver/inc_sat_solver.cpp +++ b/src/sat/sat_solver/inc_sat_solver.cpp @@ -379,7 +379,6 @@ private: g = m_subgoals[0]; expr_ref_vector atoms(m); TRACE("sat", g->display_with_dependencies(tout);); - std::cout << "exprs: " << g->num_exprs() << "\n"; m_goal2sat(*g, m_params, m_solver, m_map, dep2asm, true); m_goal2sat.get_interpreted_atoms(atoms); if (!atoms.empty()) { From ed5137ffd22b9dd0721869e7547b06bb8d4479ab Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Tue, 1 Nov 2016 11:23:42 +0000 Subject: [PATCH 316/536] build fix --- src/test/sorting_network.cpp | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/test/sorting_network.cpp b/src/test/sorting_network.cpp index a64d3a70f..81340651a 100644 --- a/src/test/sorting_network.cpp +++ b/src/test/sorting_network.cpp @@ -22,7 +22,7 @@ struct ast_ext { ast_ext(ast_manager& m):m(m) {} typedef expr* T; typedef expr_ref_vector vector; - T mk_ite(T a, T b, T c) { + T mk_ite(T a, T b, T c) { return m.mk_ite(a, b, c); } T mk_le(T a, T b) { @@ -34,7 +34,7 @@ struct ast_ext { } T mk_default() { return m.mk_false(); - } + } }; @@ -164,17 +164,17 @@ struct ast_ext2 { literal mk_false() { return m.mk_false(); } literal mk_true() { return m.mk_true(); } - literal mk_max(literal a, literal b) { - return trail(m.mk_or(a, b)); + literal mk_max(literal a, literal b) { + return trail(m.mk_or(a, b)); } literal mk_min(literal a, literal b) { return trail(m.mk_and(a, b)); } - literal mk_not(literal a) { if (m.is_not(a,a)) return a; - return trail(m.mk_not(a)); + literal mk_not(literal a) { if (m.is_not(a,a)) return a; + return trail(m.mk_not(a)); } std::ostream& pp(std::ostream& out, literal lit) { return out << mk_pp(lit, m); } - literal fresh() { + literal fresh() { return trail(m.mk_fresh_const("x", m.mk_bool_sort())); } void mk_clause(unsigned n, literal const* lits) { @@ -200,7 +200,7 @@ static void test_sorting_eq(unsigned n, unsigned k) { // equality: std::cout << "eq " << k << "\n"; solver.push(); - result = sn.eq(k, in.size(), in.c_ptr()); + result = sn.eq(true, k, in.size(), in.c_ptr()); solver.assert_expr(result); for (unsigned i = 0; i < ext.m_clauses.size(); ++i) { solver.assert_expr(ext.m_clauses[i].get()); @@ -210,7 +210,7 @@ static void test_sorting_eq(unsigned n, unsigned k) { solver.push(); for (unsigned i = 0; i < k; ++i) { - solver.assert_expr(in[i].get()); + solver.assert_expr(in[i].get()); } res = solver.check(); SASSERT(res == l_true); @@ -256,7 +256,7 @@ static void test_sorting_le(unsigned n, unsigned k) { SASSERT(res == l_true); for (unsigned i = 0; i < k; ++i) { - solver.assert_expr(in[i].get()); + solver.assert_expr(in[i].get()); } res = solver.check(); SASSERT(res == l_true); @@ -304,7 +304,7 @@ void test_sorting_ge(unsigned n, unsigned k) { solver.push(); for (unsigned i = 0; i < n - k; ++i) { - solver.assert_expr(m.mk_not(in[i].get())); + solver.assert_expr(m.mk_not(in[i].get())); } res = solver.check(); SASSERT(res == l_true); @@ -350,10 +350,10 @@ void test_at_most_1(unsigned n, bool full) { for (unsigned i = 0; i < n; ++i) { in.push_back(m.mk_fresh_const("a",m.mk_bool_sort())); } - + ast_ext2 ext(m); psort_nw sn(ext); - expr_ref result1(m), result2(m); + expr_ref result1(m), result2(m); result1 = sn.le(full, 1, in.size(), in.c_ptr()); result2 = naive_at_most1(in); @@ -368,12 +368,12 @@ void test_at_most_1(unsigned n, bool full) { if (full) { solver.push(); solver.assert_expr(m.mk_not(m.mk_eq(result1, result2))); - + std::cout << result1 << "\n"; - + res = solver.check(); SASSERT(res == l_false); - + solver.pop(1); } From 026309a325e0357bf62f63f690702ce676bdf000 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Tue, 1 Nov 2016 14:21:06 +0000 Subject: [PATCH 317/536] bugfix for disequality propagation in smt_context --- src/smt/smt_context.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index 154f3a6a3..6b3d92602 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -1112,6 +1112,7 @@ namespace smt { if (r1 == r2) { TRACE("add_diseq_inconsistent", tout << "add_diseq #" << n1->get_owner_id() << " #" << n2->get_owner_id() << " inconsistency, scope_lvl: " << m_scope_lvl << "\n";); theory_id t1 = r1->m_th_var_list.get_th_id(); + if (t1 == null_theory_id) return false; return get_theory(t1)->use_diseqs(); } From 305e080239a4824e13ed25ce9c8a31433d176442 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 1 Nov 2016 17:57:28 +0100 Subject: [PATCH 318/536] enable unsat core extraction in nlsat_tactic Signed-off-by: Nikolaj Bjorner --- src/nlsat/nlsat_solver.cpp | 10 +++++++++- src/nlsat/nlsat_solver.h | 8 ++++++++ src/nlsat/tactic/nlsat_tactic.cpp | 15 +++++++++++++-- src/sat/tactic/sat_tactic.cpp | 7 ++++--- src/smt/tactic/smt_tactic.cpp | 9 ++------- src/solver/solver2tactic.cpp | 8 +++----- src/solver/tactic2solver.cpp | 4 +++- src/tactic/goal.cpp | 3 +++ src/test/sorting_network.cpp | 2 +- 9 files changed, 46 insertions(+), 20 deletions(-) diff --git a/src/nlsat/nlsat_solver.cpp b/src/nlsat/nlsat_solver.cpp index 4f9854d87..7582c8389 100644 --- a/src/nlsat/nlsat_solver.cpp +++ b/src/nlsat/nlsat_solver.cpp @@ -1283,7 +1283,7 @@ namespace nlsat { if (r == l_false) { // collect used literals from m_lemma_assumptions vector deps; - m_asm.linearize(m_lemma_assumptions.get(), deps); + get_core(deps); for (unsigned i = 0; i < deps.size(); ++i) { literal const* lp = (literal const*)(deps[i]); if (ptr <= lp && lp < ptr + sz) { @@ -1299,6 +1299,10 @@ namespace nlsat { return r; } + void get_core(vector& deps) { + m_asm.linearize(m_lemma_assumptions.get(), deps); + } + void collect(literal_vector const& assumptions, clause_vector& clauses) { unsigned n = clauses.size(); unsigned j = 0; @@ -2712,6 +2716,10 @@ namespace nlsat { return m_imp->check(assumptions); } + void solver::get_core(vector& assumptions) { + return m_imp->get_core(assumptions); + } + void solver::reset() { m_imp->reset(); } diff --git a/src/nlsat/nlsat_solver.h b/src/nlsat/nlsat_solver.h index eec5ba19f..3668629cd 100644 --- a/src/nlsat/nlsat_solver.h +++ b/src/nlsat/nlsat_solver.h @@ -195,6 +195,14 @@ namespace nlsat { lbool value(literal l) const; + // ----------------------- + // + // Core + // + // ----------------------- + + void get_core(vector& deps); + // ----------------------- // // Misc diff --git a/src/nlsat/tactic/nlsat_tactic.cpp b/src/nlsat/tactic/nlsat_tactic.cpp index 14b2a6d32..b648866ef 100644 --- a/src/nlsat/tactic/nlsat_tactic.cpp +++ b/src/nlsat/tactic/nlsat_tactic.cpp @@ -147,6 +147,7 @@ class nlsat_tactic : public tactic { TRACE("nlsat", g->display(tout);); expr2var a2b(m); expr2var t2x(m); + m_g2nl(*g, m_params, m_solver, a2b, t2x); m_display_var.m_var2expr.reset(); @@ -172,9 +173,19 @@ class nlsat_tactic : public tactic { } } else { - // TODO: extract unsat core - g->assert_expr(m.mk_false(), 0, 0); + expr_dependency* lcore = 0; + if (g->unsat_core_enabled()) { + vector assumptions; + m_solver.get_core(assumptions); + for (unsigned i = 0; i < assumptions.size(); ++i) { + expr_dependency* d = static_cast(assumptions[i]); + lcore = m.mk_join(lcore, d); + } + } + g->assert_expr(m.mk_false(), 0, lcore); + core = lcore; } + g->inc_depth(); result.push_back(g.get()); TRACE("nlsat", g->display(tout);); diff --git a/src/sat/tactic/sat_tactic.cpp b/src/sat/tactic/sat_tactic.cpp index da513d97b..e28f64f23 100644 --- a/src/sat/tactic/sat_tactic.cpp +++ b/src/sat/tactic/sat_tactic.cpp @@ -73,14 +73,15 @@ class sat_tactic : public tactic { if (r == l_false) { expr_dependency * lcore = 0; if (produce_core) { - sat::literal_vector const& core = m_solver.get_core(); + sat::literal_vector const& ucore = m_solver.get_core(); u_map asm2dep; mk_asm2dep(dep2asm, asm2dep); - for (unsigned i = 0; i < core.size(); ++i) { - sat::literal lit = core[i]; + for (unsigned i = 0; i < ucore.size(); ++i) { + sat::literal lit = ucore[i]; expr* dep = asm2dep.find(lit.index()); lcore = m.mk_join(lcore, m.mk_leaf(dep)); } + core = lcore; } g->assert_expr(m.mk_false(), 0, lcore); } diff --git a/src/smt/tactic/smt_tactic.cpp b/src/smt/tactic/smt_tactic.cpp index 2909d8848..dd0eff889 100644 --- a/src/smt/tactic/smt_tactic.cpp +++ b/src/smt/tactic/smt_tactic.cpp @@ -138,6 +138,7 @@ public: proof_converter_ref & pc, expr_dependency_ref & core) { try { + mc = 0; pc = 0; core = 0; SASSERT(in->is_well_sorted()); ast_manager & m = in->m(); TRACE("smt_tactic", tout << this << "\nAUTO_CONFIG: " << fparams().m_auto_config << " HIDIV0: " << fparams().m_hi_div0 << " " @@ -206,8 +207,6 @@ public: mc = model2model_converter(md.get()); mc = concat(fmc.get(), mc.get()); } - pc = 0; - core = 0; return; } case l_false: { @@ -229,12 +228,10 @@ public: expr * d = bool2dep.find(b); lcore = m.mk_join(lcore, m.mk_leaf(d)); } + core = lcore; } in->assert_expr(m.mk_false(), pr, lcore); result.push_back(in.get()); - mc = 0; - pc = 0; - core = 0; return; } case l_undef: @@ -257,8 +254,6 @@ public: m_ctx->get_model(md); mc = model2model_converter(md.get()); } - pc = 0; - core = 0; return; default: break; diff --git a/src/solver/solver2tactic.cpp b/src/solver/solver2tactic.cpp index 76ebf73dd..21ecdec32 100644 --- a/src/solver/solver2tactic.cpp +++ b/src/solver/solver2tactic.cpp @@ -105,6 +105,7 @@ public: /* out */ model_converter_ref & mc, /* out */ proof_converter_ref & pc, /* out */ expr_dependency_ref & core) { + pc = 0; mc = 0; core = 0; expr_ref_vector clauses(m); expr2expr_map bool2dep; ptr_vector assumptions; @@ -123,8 +124,6 @@ public: } in->reset(); result.push_back(in.get()); - pc = 0; - core = 0; break; case l_false: { in->reset(); @@ -132,6 +131,7 @@ public: expr_dependency* lcore = 0; if (in->proofs_enabled()) { pr = local_solver->get_proof(); + pc = proof2proof_converter(m, pr); } if (in->unsat_core_enabled()) { ptr_vector core; @@ -142,9 +142,7 @@ public: } in->assert_expr(m.mk_false(), pr, lcore); result.push_back(in.get()); - mc = 0; - pc = 0; - core = 0; + core = lcore; break; } case l_undef: diff --git a/src/solver/tactic2solver.cpp b/src/solver/tactic2solver.cpp index 213ba5c1c..34d2edd3c 100644 --- a/src/solver/tactic2solver.cpp +++ b/src/solver/tactic2solver.cpp @@ -137,7 +137,9 @@ lbool tactic2solver::check_sat_core(unsigned num_assumptions, expr * const * ass g->assert_expr(m_assertions.get(i)); } for (unsigned i = 0; i < num_assumptions; i++) { - g->assert_expr(assumptions[i], m.mk_asserted(assumptions[i]), m.mk_leaf(assumptions[i])); + proof_ref pr(m.mk_asserted(assumptions[i]), m); + expr_dependency_ref ans(m.mk_leaf(assumptions[i]), m); + g->assert_expr(assumptions[i], pr, ans); } model_ref md; diff --git a/src/tactic/goal.cpp b/src/tactic/goal.cpp index 8897a83f8..b14d2676c 100644 --- a/src/tactic/goal.cpp +++ b/src/tactic/goal.cpp @@ -237,6 +237,9 @@ void goal::slow_process(expr * f, proof * pr, expr_dependency * d) { } void goal::assert_expr(expr * f, proof * pr, expr_dependency * d) { + expr_ref _f(f, m()); + proof_ref _pr(pr, m()); + expr_dependency_ref _d(d, m()); SASSERT(proofs_enabled() == (pr != 0 && !m().is_undef_proof(pr))); if (m_inconsistent) return; diff --git a/src/test/sorting_network.cpp b/src/test/sorting_network.cpp index a64d3a70f..090770d0b 100644 --- a/src/test/sorting_network.cpp +++ b/src/test/sorting_network.cpp @@ -200,7 +200,7 @@ static void test_sorting_eq(unsigned n, unsigned k) { // equality: std::cout << "eq " << k << "\n"; solver.push(); - result = sn.eq(k, in.size(), in.c_ptr()); + result = sn.eq(true, k, in.size(), in.c_ptr()); solver.assert_expr(result); for (unsigned i = 0; i < ext.m_clauses.size(); ++i) { solver.assert_expr(ext.m_clauses[i].get()); From c81ee050982ee8e2d6de2ea681df1635a5666611 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Wed, 2 Nov 2016 13:36:29 +0000 Subject: [PATCH 319/536] Fixes for .NET Core build --- src/api/dotnet/Z3Exception.cs | 10 ++++++---- src/api/dotnet/core/README.txt | 9 +++++++++ src/api/dotnet/core/project.json | 3 ++- 3 files changed, 17 insertions(+), 5 deletions(-) create mode 100644 src/api/dotnet/core/README.txt diff --git a/src/api/dotnet/Z3Exception.cs b/src/api/dotnet/Z3Exception.cs index 71e4fef1a..b0e05900c 100644 --- a/src/api/dotnet/Z3Exception.cs +++ b/src/api/dotnet/Z3Exception.cs @@ -21,11 +21,13 @@ using System; namespace Microsoft.Z3 { - /// - /// The exception base class for error reporting from Z3 - /// + /// + /// The exception base class for error reporting from Z3 + /// +#if !DOTNET_CORE [Serializable] - public class Z3Exception : Exception +#endif + public class Z3Exception : Exception { /// /// Constructor. diff --git a/src/api/dotnet/core/README.txt b/src/api/dotnet/core/README.txt new file mode 100644 index 000000000..72331d7f9 --- /dev/null +++ b/src/api/dotnet/core/README.txt @@ -0,0 +1,9 @@ +Z3 API for .NET Core + +Z3's .NET API uses Code Contracts, which are not included in .NET Core. The +enclosed file called DummyContracts.cs provides stubs for the Code Contracts +functions, so that the API will compile, but not perform any contract +checking. To build this using .NET core, run (in this directory): + +dotnet restore +dotnet build project.json diff --git a/src/api/dotnet/core/project.json b/src/api/dotnet/core/project.json index afe281a50..d54b6877b 100644 --- a/src/api/dotnet/core/project.json +++ b/src/api/dotnet/core/project.json @@ -4,7 +4,8 @@ "debugType": "portable", "emitEntryPoint": false, "outputName": "Microsoft.Z3", - "compile": [ "../*.cs", "*.cs" ] + "compile": [ "../*.cs", "*.cs" ], + "define": ["DOTNET_CORE"] }, "dependencies": { }, "frameworks": { From f61600d1d833fff241376ad340244068fe7ece21 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 2 Nov 2016 14:14:55 +0000 Subject: [PATCH 320/536] fixing unsat core extraction for tactics Signed-off-by: Nikolaj Bjorner --- src/cmd_context/tactic_cmds.cpp | 2 -- src/nlsat/tactic/nlsat_tactic.cpp | 1 - src/sat/tactic/sat_tactic.cpp | 1 - src/smt/tactic/smt_tactic.cpp | 1 - src/solver/combined_solver.cpp | 8 ++--- src/tactic/core/cofactor_term_ite_tactic.cpp | 2 +- src/tactic/core/pb_preprocess_tactic.cpp | 30 +++++++++++-------- src/tactic/smtlogics/qfuf_tactic.cpp | 2 +- src/tactic/tactical.cpp | 5 ++-- src/tactic/ufbv/ufbv_tactic.cpp | 31 ++++++++++---------- 10 files changed, 42 insertions(+), 41 deletions(-) diff --git a/src/cmd_context/tactic_cmds.cpp b/src/cmd_context/tactic_cmds.cpp index 86900e175..91963fa0d 100644 --- a/src/cmd_context/tactic_cmds.cpp +++ b/src/cmd_context/tactic_cmds.cpp @@ -288,9 +288,7 @@ public: #endif p.insert("print_model_converter", CPK_BOOL, "(default: false) print model converter."); p.insert("print_benchmark", CPK_BOOL, "(default: false) display resultant goals as a SMT2 benchmark."); -#ifndef _EXTERNAL_RELEASE p.insert("print_dependencies", CPK_BOOL, "(default: false) print dependencies when displaying the resultant set of goals."); -#endif exec_given_tactic_cmd::init_pdescrs(ctx, p); } diff --git a/src/nlsat/tactic/nlsat_tactic.cpp b/src/nlsat/tactic/nlsat_tactic.cpp index b648866ef..4ecdade38 100644 --- a/src/nlsat/tactic/nlsat_tactic.cpp +++ b/src/nlsat/tactic/nlsat_tactic.cpp @@ -183,7 +183,6 @@ class nlsat_tactic : public tactic { } } g->assert_expr(m.mk_false(), 0, lcore); - core = lcore; } g->inc_depth(); diff --git a/src/sat/tactic/sat_tactic.cpp b/src/sat/tactic/sat_tactic.cpp index e28f64f23..f99e46851 100644 --- a/src/sat/tactic/sat_tactic.cpp +++ b/src/sat/tactic/sat_tactic.cpp @@ -81,7 +81,6 @@ class sat_tactic : public tactic { expr* dep = asm2dep.find(lit.index()); lcore = m.mk_join(lcore, m.mk_leaf(dep)); } - core = lcore; } g->assert_expr(m.mk_false(), 0, lcore); } diff --git a/src/smt/tactic/smt_tactic.cpp b/src/smt/tactic/smt_tactic.cpp index dd0eff889..c9e0ddc69 100644 --- a/src/smt/tactic/smt_tactic.cpp +++ b/src/smt/tactic/smt_tactic.cpp @@ -228,7 +228,6 @@ public: expr * d = bool2dep.find(b); lcore = m.mk_join(lcore, m.mk_leaf(d)); } - core = lcore; } in->assert_expr(m.mk_false(), pr, lcore); result.push_back(in.get()); diff --git a/src/solver/combined_solver.cpp b/src/solver/combined_solver.cpp index 7f5f6872e..1eb6be08e 100644 --- a/src/solver/combined_solver.cpp +++ b/src/solver/combined_solver.cpp @@ -217,7 +217,7 @@ public: m_use_solver1_results = false; if (get_num_assumptions() != 0 || - num_assumptions > 0 || // assumptions were provided + num_assumptions > 0 || // assumptions were provided m_ignore_solver1) { // must use incremental solver switch_inc_mode(); @@ -227,7 +227,7 @@ public: if (m_inc_mode) { if (m_inc_timeout == UINT_MAX) { IF_VERBOSE(PS_VB_LVL, verbose_stream() << "(combined-solver \"using solver 2 (without a timeout)\")\n";); - lbool r = m_solver2->check_sat(0, 0); + lbool r = m_solver2->check_sat(num_assumptions, assumptions); if (r != l_undef || !use_solver1_when_undef()) { return r; } @@ -238,7 +238,7 @@ public: lbool r = l_undef; try { scoped_timer timer(m_inc_timeout, &eh); - r = m_solver2->check_sat(0, 0); + r = m_solver2->check_sat(num_assumptions, assumptions); } catch (z3_exception&) { if (!eh.m_canceled) { @@ -254,7 +254,7 @@ public: IF_VERBOSE(PS_VB_LVL, verbose_stream() << "(combined-solver \"using solver 1\")\n";); m_use_solver1_results = true; - return m_solver1->check_sat(0, 0); + return m_solver1->check_sat(num_assumptions, assumptions); } virtual void set_progress_callback(progress_callback * callback) { diff --git a/src/tactic/core/cofactor_term_ite_tactic.cpp b/src/tactic/core/cofactor_term_ite_tactic.cpp index 24b381476..2286281f4 100644 --- a/src/tactic/core/cofactor_term_ite_tactic.cpp +++ b/src/tactic/core/cofactor_term_ite_tactic.cpp @@ -36,7 +36,7 @@ class cofactor_term_ite_tactic : public tactic { expr * f = g.form(i); expr_ref new_f(m); m_elim_ite(f, new_f); - g.update(i, new_f); + g.update(i, new_f, 0, g.dep(i)); } } diff --git a/src/tactic/core/pb_preprocess_tactic.cpp b/src/tactic/core/pb_preprocess_tactic.cpp index b4f335db5..a7e381576 100644 --- a/src/tactic/core/pb_preprocess_tactic.cpp +++ b/src/tactic/core/pb_preprocess_tactic.cpp @@ -151,9 +151,6 @@ public: SASSERT(g->is_well_sorted()); pc = 0; core = 0; - if (g->unsat_core_enabled()) { - throw tactic_exception("pb-preprocess does not support cores"); - } if (g->proofs_enabled()) { throw tactic_exception("pb-preprocess does not support proofs"); } @@ -202,6 +199,7 @@ public: while (it != m_vars.end()) { app * e = it->m_key; rec const& r = it->m_value; + TRACE("pb", tout << mk_pp(e, m) << " " << r.pos.size() << " " << r.neg.size() << "\n";); if (r.pos.empty()) { replace(r.neg, e, m.mk_false(), g); mc.set_value(e, false); @@ -249,11 +247,11 @@ public: unsigned_vector const& pos = neg?r.neg:r.pos; for (unsigned j = 0; j < pos.size(); ++j) { unsigned k = pos[j]; - if (k == i) continue; + if (k == m_ge[i]) continue; if (!to_ge(g->form(k), args2, coeffs2, k2)) continue; if (subsumes(args1, coeffs1, k1, args2, coeffs2, k2)) { IF_VERBOSE(3, verbose_stream() << "replace " << mk_pp(g->form(k), m) << "\n";); - g->update(k, m.mk_true()); + g->update(k, m.mk_true(), 0, m.mk_join(g->dep(m_ge[i]), g->dep(k))); m_progress = true; } } @@ -299,7 +297,7 @@ private: args.push_back(negate(to_app(r)->get_arg(j))); } tmp = pb.mk_ge(args.size(), coeffs.c_ptr(), args.c_ptr(), sum - k + rational::one()); - g->update(i, tmp); + g->update(i, tmp, g->pr(i), g->dep(i)); } } } @@ -331,12 +329,12 @@ private: for (unsigned j = 0; j < cuts.size(); ++j) { unsigned end = cuts[j]; fml1 = decompose_cut(a, start, end, cut_args, cut_coeffs); - g->assert_expr(fml1); + g->assert_expr(fml1, 0, g->dep(i)); start = end; TRACE("pb", tout << fml1 << "\n";); } fml2 = pb.mk_ge(cut_args.size(), cut_coeffs.c_ptr(), cut_args.c_ptr(), pb.get_k(e)); - g->update(i, fml2); + g->update(i, fml2, 0, g->dep(i)); TRACE("pb", tout << fml2 << "\n";); } } @@ -577,8 +575,12 @@ private: verbose_stream() << "resolve: " << mk_pp(fml1, m) << "\n" << mk_pp(fml2, m) << "\n" << tmp1 << "\n"; verbose_stream() << "to\n" << mk_pp(fml2, m) << " -> " << tmp2 << "\n";); - g->update(idx1, m.mk_true()); // proof & dependencies - g->update(idx2, tmp2); // proof & dependencies + TRACE("pb", + tout << "resolve: " << mk_pp(fml1, m) << "\n" << mk_pp(fml2, m) << "\n" << tmp1 << "\n"; + tout << "to\n" << mk_pp(fml2, m) << " -> " << tmp2 << "\n";); + + g->update(idx2, tmp2, 0, m.mk_join(g->dep(idx1), g->dep(idx2))); + g->update(idx1, m.mk_true(), 0, 0); m_progress = true; //IF_VERBOSE(0, if (!g->inconsistent()) display_annotation(verbose_stream(), g);); } @@ -634,14 +636,18 @@ private: for (unsigned i = 0; i < positions.size(); ++i) { unsigned idx = positions[i]; expr_ref f(m); + proof_ref new_pr(m); f = g->form(idx); if (!m.is_true(f)) { - m_r(f, tmp); + m_r(f, tmp, new_pr); if (tmp != f) { TRACE("pb", tout << mk_pp(f, m) << " -> " << tmp << " by " << mk_pp(e, m) << " |-> " << mk_pp(v, m) << "\n";); IF_VERBOSE(3, verbose_stream() << "replace " << mk_pp(f, m) << " -> " << tmp << "\n";); - g->update(idx, tmp); // proof & dependencies. + if (g->proofs_enabled()) { + new_pr = m.mk_modus_ponens(g->pr(idx), new_pr); + } + g->update(idx, tmp, new_pr, g->dep(idx)); m_progress = true; } } diff --git a/src/tactic/smtlogics/qfuf_tactic.cpp b/src/tactic/smtlogics/qfuf_tactic.cpp index 567325f6a..7648e20fe 100644 --- a/src/tactic/smtlogics/qfuf_tactic.cpp +++ b/src/tactic/smtlogics/qfuf_tactic.cpp @@ -33,7 +33,7 @@ tactic * mk_qfuf_tactic(ast_manager & m, params_ref const & p) { mk_propagate_values_tactic(m, p), mk_solve_eqs_tactic(m, p), using_params(mk_simplify_tactic(m, p), s2_p), - mk_symmetry_reduce_tactic(m, p), + if_no_proofs(if_no_unsat_cores(mk_symmetry_reduce_tactic(m, p))), mk_smt_tactic(p)); } diff --git a/src/tactic/tactical.cpp b/src/tactic/tactical.cpp index 0d276ba72..4cb212265 100644 --- a/src/tactic/tactical.cpp +++ b/src/tactic/tactical.cpp @@ -132,8 +132,7 @@ public: if (r1_size == 1) { if (r1[0]->is_decided()) { result.push_back(r1[0]); - if (models_enabled) mc = mc1; - SASSERT(!pc); SASSERT(!core); + if (models_enabled) mc = mc1; return; } goal_ref r1_0 = r1[0]; @@ -964,7 +963,7 @@ class repeat_tactical : public unary_tactical { pc = 0; core = 0; { - goal orig_in(in->m()); + goal orig_in(in->m(), proofs_enabled, models_enabled, cores_enabled); orig_in.copy_from(*(in.get())); m_t->operator()(in, r1, mc1, pc1, core1); if (is_equal(orig_in, *(in.get()))) { diff --git a/src/tactic/ufbv/ufbv_tactic.cpp b/src/tactic/ufbv/ufbv_tactic.cpp index b5a4ca3a3..7a185c854 100644 --- a/src/tactic/ufbv/ufbv_tactic.cpp +++ b/src/tactic/ufbv/ufbv_tactic.cpp @@ -41,21 +41,22 @@ tactic * mk_ufbv_preprocessor_tactic(ast_manager & m, params_ref const & p) { return and_then( mk_trace_tactic("ufbv_pre"), - and_then(mk_simplify_tactic(m, p), - mk_propagate_values_tactic(m, p), - and_then(using_params(mk_macro_finder_tactic(m, no_elim_and), no_elim_and), - mk_simplify_tactic(m, p)), - and_then(mk_snf_tactic(m, p), mk_simplify_tactic(m, p)), - mk_elim_and_tactic(m, p), - mk_solve_eqs_tactic(m, p), - and_then(mk_der_fp_tactic(m, p), mk_simplify_tactic(m, p)), - and_then(mk_distribute_forall_tactic(m, p), mk_simplify_tactic(m, p))), - and_then(and_then(mk_reduce_args_tactic(m, p), mk_simplify_tactic(m, p)), - and_then(mk_macro_finder_tactic(m, p), mk_simplify_tactic(m, p)), - and_then(mk_ufbv_rewriter_tactic(m, p), mk_simplify_tactic(m, p)), - and_then(mk_quasi_macros_tactic(m, p), mk_simplify_tactic(m, p)), - and_then(mk_der_fp_tactic(m, p), mk_simplify_tactic(m, p)), - mk_simplify_tactic(m, p)), + and_then(mk_simplify_tactic(m, p), + mk_propagate_values_tactic(m, p), + and_then(if_no_proofs(if_no_unsat_cores(using_params(mk_macro_finder_tactic(m, no_elim_and), no_elim_and))), + mk_simplify_tactic(m, p)), + and_then(mk_snf_tactic(m, p), mk_simplify_tactic(m, p)), + mk_elim_and_tactic(m, p), + mk_solve_eqs_tactic(m, p), + and_then(mk_der_fp_tactic(m, p), mk_simplify_tactic(m, p)), + and_then(mk_distribute_forall_tactic(m, p), mk_simplify_tactic(m, p))), + if_no_unsat_cores( + and_then(and_then(mk_reduce_args_tactic(m, p), mk_simplify_tactic(m, p)), + and_then(mk_macro_finder_tactic(m, p), mk_simplify_tactic(m, p)), + and_then(mk_ufbv_rewriter_tactic(m, p), mk_simplify_tactic(m, p)), + and_then(mk_quasi_macros_tactic(m, p), mk_simplify_tactic(m, p)))), + and_then(mk_der_fp_tactic(m, p), mk_simplify_tactic(m, p)), + mk_simplify_tactic(m, p), mk_trace_tactic("ufbv_post")); } From be9d5c7088b01019399ea4fc4e23de1049790695 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 2 Nov 2016 21:33:24 +0000 Subject: [PATCH 321/536] fix evaluator for array store expressions Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/array_rewriter.cpp | 12 ++++++++++++ src/ast/rewriter/array_rewriter.h | 3 +++ src/model/model_evaluator.cpp | 21 ++++++++++++++++++++- src/smt/theory_array.cpp | 2 +- src/smt/theory_array_base.cpp | 2 +- 5 files changed, 37 insertions(+), 3 deletions(-) diff --git a/src/ast/rewriter/array_rewriter.cpp b/src/ast/rewriter/array_rewriter.cpp index 1f4418fd5..6f6b5b62e 100644 --- a/src/ast/rewriter/array_rewriter.cpp +++ b/src/ast/rewriter/array_rewriter.cpp @@ -26,6 +26,7 @@ void array_rewriter::updt_params(params_ref const & _p) { m_sort_store = p.sort_store(); m_expand_select_store = p.expand_select_store(); m_expand_store_eq = p.expand_store_eq(); + m_expand_select_ite = false; } void array_rewriter::get_param_descrs(param_descrs & r) { @@ -201,6 +202,17 @@ br_status array_rewriter::mk_select_core(unsigned num_args, expr * const * args, result = m().mk_app(f, num_args - 1, args + 1); return BR_REWRITE1; } + + expr* c, *th, *el; + if (m_expand_select_ite && m().is_ite(args[0], c, th, el)) { + ptr_vector args1, args2; + args1.push_back(th); + args1.append(num_args-1, args + 1); + args2.push_back(el); + args2.append(num_args-1, args + 1); + result = m().mk_ite(c, m_util.mk_select(num_args, args1.c_ptr()), m_util.mk_select(num_args, args2.c_ptr())); + return BR_REWRITE2; + } return BR_FAILED; } diff --git a/src/ast/rewriter/array_rewriter.h b/src/ast/rewriter/array_rewriter.h index 10b7bcfda..4ff48d496 100644 --- a/src/ast/rewriter/array_rewriter.h +++ b/src/ast/rewriter/array_rewriter.h @@ -32,6 +32,7 @@ class array_rewriter { bool m_sort_store; bool m_expand_select_store; bool m_expand_store_eq; + bool m_expand_select_ite; template lbool compare_args(unsigned num_args, expr * const * args1, expr * const * args2); public: @@ -43,6 +44,8 @@ public: ast_manager & m() const { return m_util.get_manager(); } family_id get_fid() const { return m_util.get_family_id(); } + void set_expand_select_store(bool f) { m_expand_select_store = f; } + void set_expand_select_ite(bool f) { m_expand_select_ite = f; } void updt_params(params_ref const & p); static void get_param_descrs(param_descrs & r); diff --git a/src/model/model_evaluator.cpp b/src/model/model_evaluator.cpp index eb2b2f5dd..ef1fab97e 100644 --- a/src/model/model_evaluator.cpp +++ b/src/model/model_evaluator.cpp @@ -32,6 +32,7 @@ Revision History: #include"cooperate.h" #include"ast_pp.h" #include"ast_util.h" +#include"model_smt2_pp.h" struct evaluator_cfg : public default_rewriter_cfg { @@ -69,6 +70,8 @@ struct evaluator_cfg : public default_rewriter_cfg { m_a_rw.set_flat(flat); m_bv_rw.set_flat(flat); m_bv_rw.set_mkbv2num(true); + m_ar_rw.set_expand_select_store(true); + m_ar_rw.set_expand_select_ite(true); updt_params(p); } @@ -400,6 +403,7 @@ struct evaluator_cfg : public default_rewriter_cfg { SASSERT(m_ar.is_array(a)); bool are_values = true; are_unique = true; + TRACE("model_evaluator", tout << mk_pp(a, m()) << "\n";); while (m_ar.is_store(a)) { expr_ref_vector store(m()); @@ -438,13 +442,28 @@ struct evaluator_cfg : public default_rewriter_cfg { } else_case = g->get_else(); if (!else_case) { - TRACE("model_evaluator", tout << "no else case " << mk_pp(a, m()) << "\n";); + TRACE("model_evaluator", tout << "no else case " << mk_pp(a, m()) << "\n"; + /*model_smt2_pp(tout, m(), m_model, 0);*/ + ); return false; } if (!is_ground(else_case)) { TRACE("model_evaluator", tout << "non-ground else case " << mk_pp(a, m()) << "\n" << else_case << "\n";); return false; } + if (m_ar.is_as_array(else_case)) { + bool are_unique1 = true; + expr_ref tmp(m()); + unsigned num_stores = stores.size(); + if (!extract_array_func_interp(else_case, stores, tmp, are_unique1)) { + stores.shrink(num_stores); + } + else { + sort* srt = m().get_sort(else_case); + else_case = m_ar.mk_const_array(srt, tmp); + are_unique &= are_unique1; + } + } for (unsigned i = stores.size(); are_values && i > 0; ) { --i; if (m().are_equal(else_case, stores[i].back())) { diff --git a/src/smt/theory_array.cpp b/src/smt/theory_array.cpp index 5e0539787..b06e50d2a 100644 --- a/src/smt/theory_array.cpp +++ b/src/smt/theory_array.cpp @@ -404,7 +404,7 @@ namespace smt { r = assert_delayed_axioms(); } } - TRACE("as_array", tout << "m_found_unsupported_op: " << m_found_unsupported_op << " " << r << "\n";); + TRACE("array", tout << "m_found_unsupported_op: " << m_found_unsupported_op << " " << r << "\n";); if (r == FC_DONE && m_found_unsupported_op) r = FC_GIVEUP; return r; diff --git a/src/smt/theory_array_base.cpp b/src/smt/theory_array_base.cpp index 498f8aeec..fa48fea57 100644 --- a/src/smt/theory_array_base.cpp +++ b/src/smt/theory_array_base.cpp @@ -33,7 +33,7 @@ namespace smt { } void theory_array_base::found_unsupported_op(expr * n) { - TRACE("theory_array_unsup", tout << mk_ll_pp(n, get_manager()) << "\n";); + TRACE("array", tout << mk_ll_pp(n, get_manager()) << "\n";); if (!m_found_unsupported_op) { get_context().push_trail(value_trail(m_found_unsupported_op)); m_found_unsupported_op = true; From c0fb2eafe552670fe24010f358bc9d23fda54a8c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 2 Nov 2016 23:08:10 +0000 Subject: [PATCH 322/536] remove recursive expansion of else-case Signed-off-by: Nikolaj Bjorner --- src/model/model_evaluator.cpp | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/src/model/model_evaluator.cpp b/src/model/model_evaluator.cpp index ef1fab97e..af2253801 100644 --- a/src/model/model_evaluator.cpp +++ b/src/model/model_evaluator.cpp @@ -451,19 +451,6 @@ struct evaluator_cfg : public default_rewriter_cfg { TRACE("model_evaluator", tout << "non-ground else case " << mk_pp(a, m()) << "\n" << else_case << "\n";); return false; } - if (m_ar.is_as_array(else_case)) { - bool are_unique1 = true; - expr_ref tmp(m()); - unsigned num_stores = stores.size(); - if (!extract_array_func_interp(else_case, stores, tmp, are_unique1)) { - stores.shrink(num_stores); - } - else { - sort* srt = m().get_sort(else_case); - else_case = m_ar.mk_const_array(srt, tmp); - are_unique &= are_unique1; - } - } for (unsigned i = stores.size(); are_values && i > 0; ) { --i; if (m().are_equal(else_case, stores[i].back())) { From 6e0369036ea1fe38d11990854593e8a49c8050d2 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Thu, 3 Nov 2016 17:13:02 +0000 Subject: [PATCH 323/536] fixed log output typo --- scripts/mk_util.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/mk_util.py b/scripts/mk_util.py index 84931b47e..868f9b9c1 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -1591,7 +1591,7 @@ class DotNetDLLComponent(Component): elif os.path.isfile(os.path.join(self.src_dir, self.key_file)): self.key_file = os.path.abspath(os.path.join(self.src_dir, self.key_file)) else: - print("Keyfile '%s' could not be found; %s.dll will be unsigned." % (self.dll_name, self.key_file)) + print("Keyfile '%s' could not be found; %s.dll will be unsigned." % (self.key_file, self.dll_name)) self.key_file = None if not self.key_file is None: From 7bbdb7714fa5cd6d82f573a0f14292b5543f9aea Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Thu, 3 Nov 2016 17:20:39 +0000 Subject: [PATCH 324/536] Added signed .NET assemblies in unix builds --- scripts/mk_util.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/mk_util.py b/scripts/mk_util.py index 868f9b9c1..873af8432 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -82,7 +82,7 @@ Z3PY_SRC_DIR=None VS_PROJ = False TRACE = False DOTNET_ENABLED=False -DOTNET_KEY_FILE=None +DOTNET_KEY_FILE=getenv("Z3_DOTNET_KEY_FILE", None) JAVA_ENABLED=False ML_ENABLED=False PYTHON_INSTALL_ENABLED=False From a3e915fbea00c30d6614824405086d7fc348905e Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Fri, 4 Nov 2016 13:37:14 +0000 Subject: [PATCH 325/536] Whitespace --- src/ast/rewriter/bool_rewriter.cpp | 6 +-- src/tactic/core/ctx_simplify_tactic.cpp | 58 ++++++++++++------------- 2 files changed, 32 insertions(+), 32 deletions(-) diff --git a/src/ast/rewriter/bool_rewriter.cpp b/src/ast/rewriter/bool_rewriter.cpp index 66c5e66bc..a914d6a0a 100644 --- a/src/ast/rewriter/bool_rewriter.cpp +++ b/src/ast/rewriter/bool_rewriter.cpp @@ -581,15 +581,15 @@ br_status bool_rewriter::try_ite_value(app * ite, app * val, expr_ref & result) TRACE("try_ite_value", tout << mk_ismt2_pp(t, m()) << " " << mk_ismt2_pp(e, m()) << " " << mk_ismt2_pp(val, m()) << "\n"; tout << t << " " << e << " " << val << "\n";); result = m().mk_false(); - } + } else if (t == val && e == val) { result = m().mk_true(); - } + } else if (t == val) { result = cond; } else { - SASSERT(e == val); + SASSERT(e == val); mk_not(cond, result); } return BR_DONE; diff --git a/src/tactic/core/ctx_simplify_tactic.cpp b/src/tactic/core/ctx_simplify_tactic.cpp index 1cda9cc6f..5258f8c5c 100644 --- a/src/tactic/core/ctx_simplify_tactic.cpp +++ b/src/tactic/core/ctx_simplify_tactic.cpp @@ -46,7 +46,7 @@ public: ctx_propagate_assertions::ctx_propagate_assertions(ast_manager& m): m(m), m_trail(m) {} bool ctx_propagate_assertions::assert_expr(expr * t, bool sign) { - + expr * p = t; while (m.is_not(t, t)) { sign = !sign; @@ -83,8 +83,8 @@ void ctx_propagate_assertions::assert_eq_core(expr * t, app * val) { // because the simplifier stopped at depth m_max_depth return; } - - CTRACE("assert_eq_bug", m_assertions.contains(t), + + CTRACE("assert_eq_bug", m_assertions.contains(t), tout << "t:\n" << mk_ismt2_pp(t, m) << "\nval:\n" << mk_ismt2_pp(val, m) << "\n"; expr * old_val = 0; m_assertions.find(t, old_val); @@ -114,11 +114,11 @@ void ctx_propagate_assertions::pop(unsigned num_scopes) { m_trail.pop_back(); } SASSERT(m_trail.size() == old_trail_size); - m_scopes.shrink(scope_lvl - num_scopes); + m_scopes.shrink(scope_lvl - num_scopes); } -bool ctx_simplify_tactic::simplifier::shared(expr * t) const { +bool ctx_simplify_tactic::simplifier::shared(expr * t) const { SASSERT(m_occs); return t->get_ref_count() > 1 && m_occs->get_num_occs(t) > 1; } @@ -139,7 +139,7 @@ struct ctx_simplify_tactic::imp { unsigned m_lvl; cached_result * m_next; cached_result(expr * t, unsigned lvl, cached_result * next): - m_to(t), + m_to(t), m_lvl(lvl), m_next(next) { } @@ -156,7 +156,7 @@ struct ctx_simplify_tactic::imp { small_object_allocator m_allocator; svector m_cache; vector > m_cache_undo; - unsigned m_depth; + unsigned m_depth; unsigned m_num_steps; goal_num_occurs m_occs; mk_simplified_app m_mk_app; @@ -183,7 +183,7 @@ struct ctx_simplify_tactic::imp { dealloc(m_simp); DEBUG_CODE({ for (unsigned i = 0; i < m_cache.size(); i++) { - CTRACE("ctx_simplify_tactic_bug", m_cache[i].m_from, + CTRACE("ctx_simplify_tactic_bug", m_cache[i].m_from, tout << "i: " << i << "\n" << mk_ismt2_pp(m_cache[i].m_from, m) << "\n"; tout << "m_result: " << m_cache[i].m_result << "\n"; if (m_cache[i].m_result) tout << "lvl: " << m_cache[i].m_result->m_lvl << "\n";); @@ -209,7 +209,7 @@ struct ctx_simplify_tactic::imp { throw tactic_exception(m.limit().get_cancel_msg()); } - bool shared(expr * t) const { + bool shared(expr * t) const { TRACE("ctx_simplify_tactic_bug", tout << mk_pp(t, m) << "\n";); return t->get_ref_count() > 1 && m_occs.get_num_occs(t) > 1; } @@ -233,7 +233,7 @@ struct ctx_simplify_tactic::imp { unsigned id = from->get_id(); TRACE("ctx_simplify_tactic_cache", tout << "caching " << id << " @ " << scope_level() << "\n" << mk_ismt2_pp(from, m) << "\n--->\n" << mk_ismt2_pp(to, m) << "\n";); m_cache.reserve(id+1); - cache_cell & cell = m_cache[id]; + cache_cell & cell = m_cache[id]; void * mem = m_allocator.allocate(sizeof(cached_result)); if (cell.m_from == 0) { // new_entry @@ -243,7 +243,7 @@ struct ctx_simplify_tactic::imp { m.inc_ref(to); } else { - // update + // update cell.m_result = new (mem) cached_result(to, scope_level(), cell.m_result); m.inc_ref(to); } @@ -255,7 +255,7 @@ struct ctx_simplify_tactic::imp { if (shared(from)) cache_core(from, to); } - + unsigned scope_level() const { return m_simp->scope_level(); } @@ -276,7 +276,7 @@ struct ctx_simplify_tactic::imp { m.dec_ref(cell.m_result->m_to); cached_result * to_delete = cell.m_result; SASSERT(to_delete->m_lvl == lvl); - TRACE("ctx_simplify_tactic_cache", tout << "uncaching: " << to_delete->m_lvl << "\n" << + TRACE("ctx_simplify_tactic_cache", tout << "uncaching: " << to_delete->m_lvl << "\n" << mk_ismt2_pp(key, m) << "\n--->\n" << mk_ismt2_pp(to_delete->m_to, m) << "\nrestoring:\n"; if (to_delete->m_next) tout << mk_ismt2_pp(to_delete->m_next->m_to, m); else tout << ""; tout << "\n";); @@ -287,7 +287,7 @@ struct ctx_simplify_tactic::imp { } m_allocator.deallocate(sizeof(cached_result), to_delete); } - keys.reset(); + keys.reset(); } void pop(unsigned num_scopes) { @@ -295,7 +295,7 @@ struct ctx_simplify_tactic::imp { return; SASSERT(num_scopes <= scope_level()); - unsigned lvl = scope_level(); + unsigned lvl = scope_level(); m_simp->pop(num_scopes); // restore cache @@ -339,7 +339,7 @@ struct ctx_simplify_tactic::imp { } m_num_steps++; m_depth++; - if (m.is_or(t)) + if (m.is_or(t)) simplify_or_and(to_app(t), r); else if (m.is_and(t)) simplify_or_and(to_app(t), r); @@ -351,7 +351,7 @@ struct ctx_simplify_tactic::imp { SASSERT(r.get() != 0); TRACE("ctx_simplify_tactic_detail", tout << "result:\n" << mk_bounded_pp(t, m) << "\n---->\n" << mk_bounded_pp(r, m) << "\n";); } - + template void simplify_or_and(app * t, expr_ref & r) { // go forwards @@ -374,7 +374,7 @@ struct ctx_simplify_tactic::imp { continue; } if ((OR && m.is_true(new_arg)) || - (!OR && m.is_false(new_arg))) { + (!OR && m.is_false(new_arg))) { r = new_arg; pop(scope_level() - old_lvl); cache(t, r); @@ -403,7 +403,7 @@ struct ctx_simplify_tactic::imp { continue; } if ((OR && m.is_true(new_arg)) || - (!OR && m.is_false(new_arg))) { + (!OR && m.is_false(new_arg))) { r = new_arg; pop(scope_level() - old_lvl); cache(t, r); @@ -428,7 +428,7 @@ struct ctx_simplify_tactic::imp { } cache(t, r); } - + void simplify_ite(app * ite, expr_ref & r) { expr * c = ite->get_arg(0); expr * t = ite->get_arg(1); @@ -467,8 +467,8 @@ struct ctx_simplify_tactic::imp { } else { expr * args[3] = { new_c.get(), new_t.get(), new_e.get() }; - TRACE("ctx_simplify_tactic_ite_bug", - tout << "mk_ite\n" << mk_ismt2_pp(new_c.get(), m) << "\n" << mk_ismt2_pp(new_t.get(), m) + TRACE("ctx_simplify_tactic_ite_bug", + tout << "mk_ite\n" << mk_ismt2_pp(new_c.get(), m) << "\n" << mk_ismt2_pp(new_t.get(), m) << "\n" << mk_ismt2_pp(new_e.get(), m) << "\n";); m_mk_app(ite->get_decl(), 3, args, r); } @@ -529,7 +529,7 @@ struct ctx_simplify_tactic::imp { unsigned sz = g.size(); expr_ref r(m); for (unsigned i = 0; !g.inconsistent() && i < sz; ++i) { - m_depth = 0; + m_depth = 0; simplify(g.form(i), r); if (i < sz - 1 && !m.is_true(r) && !m.is_false(r) && !g.dep(i) && !assert_expr(r, false)) { r = m.mk_false(); @@ -590,7 +590,7 @@ struct ctx_simplify_tactic::imp { IF_VERBOSE(TACTIC_VERBOSITY_LVL, verbose_stream() << "(ctx-simplify :num-steps " << m_num_steps << ")\n";); SASSERT(g.is_well_sorted()); } - + }; ctx_simplify_tactic::ctx_simplify_tactic(ast_manager & m, simplifier* simp, params_ref const & p): @@ -618,9 +618,9 @@ void ctx_simplify_tactic::get_param_descrs(param_descrs & r) { r.insert("propagate_eq", CPK_BOOL, "(default: false) enable equality propagation from bounds."); } -void ctx_simplify_tactic::operator()(goal_ref const & in, - goal_ref_buffer & result, - model_converter_ref & mc, +void ctx_simplify_tactic::operator()(goal_ref const & in, + goal_ref_buffer & result, + model_converter_ref & mc, proof_converter_ref & pc, expr_dependency_ref & core) { mc = 0; pc = 0; core = 0; @@ -628,12 +628,12 @@ void ctx_simplify_tactic::operator()(goal_ref const & in, in->inc_depth(); result.push_back(in.get()); } - + void ctx_simplify_tactic::cleanup() { ast_manager & m = m_imp->m; imp * d = alloc(imp, m, m_imp->m_simp->translate(m), m_params); - std::swap(d, m_imp); + std::swap(d, m_imp); dealloc(d); } From 824ba1497744f0c646d4a6d9056b2d3108828854 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Fri, 4 Nov 2016 13:39:53 +0000 Subject: [PATCH 326/536] Disabled some ITE rewrite rules that were applied by default, but too expensive. Added re-computation of subterm occurrences in ctx_simplify_tactic. (Performance fixes for QF_LIA benchmarks). --- src/ast/rewriter/bool_rewriter.cpp | 36 +++++++++++++------------ src/tactic/core/ctx_simplify_tactic.cpp | 2 ++ 2 files changed, 21 insertions(+), 17 deletions(-) diff --git a/src/ast/rewriter/bool_rewriter.cpp b/src/ast/rewriter/bool_rewriter.cpp index a914d6a0a..ce3eb5844 100644 --- a/src/ast/rewriter/bool_rewriter.cpp +++ b/src/ast/rewriter/bool_rewriter.cpp @@ -594,25 +594,27 @@ br_status bool_rewriter::try_ite_value(app * ite, app * val, expr_ref & result) } return BR_DONE; } - if (m().is_value(t)) { - if (val == t) { - result = m().mk_or(cond, m().mk_eq(val, e)); + if (m_ite_extra_rules) { + if (m().is_value(t)) { + if (val == t) { + result = m().mk_or(cond, m().mk_eq(val, e)); + } + else { + mk_not(cond, result); + result = m().mk_and(result, m().mk_eq(val, e)); + } + return BR_REWRITE2; } - else { - mk_not(cond, result); - result = m().mk_and(result, m().mk_eq(val, e)); + if (m().is_value(e)) { + if (val == e) { + mk_not(cond, result); + result = m().mk_or(result, m().mk_eq(val, t)); + } + else { + result = m().mk_and(cond, m().mk_eq(val, t)); + } + return BR_REWRITE2; } - return BR_REWRITE2; - } - if (m().is_value(e)) { - if (val == e) { - mk_not(cond, result); - result = m().mk_or(result, m().mk_eq(val, t)); - } - else { - result = m().mk_and(cond, m().mk_eq(val, t)); - } - return BR_REWRITE2; } expr* cond2, *t2, *e2; if (m().is_ite(t, cond2, t2, e2) && m().is_value(t2) && m().is_value(e2)) { diff --git a/src/tactic/core/ctx_simplify_tactic.cpp b/src/tactic/core/ctx_simplify_tactic.cpp index 5258f8c5c..3e2790fe3 100644 --- a/src/tactic/core/ctx_simplify_tactic.cpp +++ b/src/tactic/core/ctx_simplify_tactic.cpp @@ -538,6 +538,8 @@ struct ctx_simplify_tactic::imp { } pop(scope_level() - old_lvl); + m_occs(g); + // go backwards sz = g.size(); for (unsigned i = sz; !g.inconsistent() && i > 0; ) { From 51a40859103e671dd7bea8d7568b64e79818c4fc Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 4 Nov 2016 15:19:11 +0000 Subject: [PATCH 327/536] check for logic in solver Signed-off-by: Nikolaj Bjorner --- contrib/cmake/src/solver/CMakeLists.txt | 1 + src/api/api_solver.cpp | 17 ++- src/cmd_context/cmd_context.cpp | 127 ++------------------ src/cmd_context/cmd_context.h | 7 -- src/solver/smt_logics.cpp | 149 ++++++++++++++++++++++++ src/solver/smt_logics.h | 40 +++++++ 6 files changed, 213 insertions(+), 128 deletions(-) create mode 100644 src/solver/smt_logics.cpp create mode 100644 src/solver/smt_logics.h diff --git a/contrib/cmake/src/solver/CMakeLists.txt b/contrib/cmake/src/solver/CMakeLists.txt index 7f54e7745..56864a691 100644 --- a/contrib/cmake/src/solver/CMakeLists.txt +++ b/contrib/cmake/src/solver/CMakeLists.txt @@ -3,6 +3,7 @@ z3_add_component(solver check_sat_result.cpp combined_solver.cpp mus.cpp + smt_logics.cpp solver.cpp solver_na2as.cpp solver2tactic.cpp diff --git a/src/api/api_solver.cpp b/src/api/api_solver.cpp index 786a7c4ba..6dc41efb2 100644 --- a/src/api/api_solver.cpp +++ b/src/api/api_solver.cpp @@ -32,6 +32,7 @@ Revision History: #include"smt_strategic_solver.h" #include"smt_solver.h" #include"smt_implied_equalities.h" +#include"smt_logics.h" extern "C" { @@ -80,10 +81,18 @@ extern "C" { Z3_TRY; LOG_Z3_mk_solver_for_logic(c, logic); RESET_ERROR_CODE(); - Z3_solver_ref * s = alloc(Z3_solver_ref, *mk_c(c), mk_smt_strategic_solver_factory(to_symbol(logic))); - mk_c(c)->save_object(s); - Z3_solver r = of_solver(s); - RETURN_Z3(r); + if (!smt_logics::supported_logic(to_symbol(logic))) { + std::ostringstream strm; + strm << "logic '" << to_symbol(logic) << "' is not recognized"; + throw default_exception(strm.str()); + RETURN_Z3(0); + } + else { + Z3_solver_ref * s = alloc(Z3_solver_ref, *mk_c(c), mk_smt_strategic_solver_factory(to_symbol(logic))); + mk_c(c)->save_object(s); + Z3_solver r = of_solver(s); + RETURN_Z3(r); + } Z3_CATCH_RETURN(0); } diff --git a/src/cmd_context/cmd_context.cpp b/src/cmd_context/cmd_context.cpp index 930a8fc71..3cf00c154 100644 --- a/src/cmd_context/cmd_context.cpp +++ b/src/cmd_context/cmd_context.cpp @@ -45,6 +45,7 @@ Notes: #include"model_params.hpp" #include"th_rewriter.h" #include"tactic_exception.h" +#include"smt_logics.h" func_decls::func_decls(ast_manager & m, func_decl * f): m_decls(TAG(func_decl*, f, 0)) { @@ -503,128 +504,32 @@ void cmd_context::load_plugin(symbol const & name, bool install, svector Date: Fri, 4 Nov 2016 15:51:35 +0000 Subject: [PATCH 328/536] fix generation of fresh constants for uninterpreted sort in EPR, Issue #649 Signed-off-by: Nikolaj Bjorner --- src/smt/smt_model_finder.cpp | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/src/smt/smt_model_finder.cpp b/src/smt/smt_model_finder.cpp index 5dc0dd8ec..b8320f329 100644 --- a/src/smt/smt_model_finder.cpp +++ b/src/smt/smt_model_finder.cpp @@ -315,6 +315,7 @@ namespace smt { void mk_instantiation_set(ast_manager & m) { SASSERT(is_root()); + SASSERT(!m_set); m_set = alloc(instantiation_set, m); } @@ -1001,10 +1002,13 @@ namespace smt { void add_elem_to_empty_inst_sets() { ptr_vector::const_iterator it = m_root_nodes.begin(); ptr_vector::const_iterator end = m_root_nodes.end(); + obj_map sort2elems; + ptr_vector need_fresh; for (; it != end; ++it) { node * n = *it; SASSERT(n->is_root()); instantiation_set const * s = n->get_instantiation_set(); + TRACE("model_finder", s->display(tout);); obj_map const & elems = s->get_elems(); if (elems.empty()) { // The method get_some_value cannot be used if n->get_sort() is an uninterpreted sort or is a sort built using uninterpreted sorts @@ -1013,11 +1017,29 @@ namespace smt { // If these module values "leak" inside the logical context, they may affect satisfiability. // sort * ns = n->get_sort(); - if (m_manager.is_fully_interp(ns)) + if (m_manager.is_fully_interp(ns)) { n->insert(m_model->get_some_value(ns), 0); - else - n->insert(m_manager.mk_fresh_const("elem", ns), 0); + } + else { + need_fresh.push_back(n); + } } + else { + sort2elems.insert(n->get_sort(), elems.begin()->m_key); + } + } + expr_ref_vector trail(m_manager); + for (unsigned i = 0; i < need_fresh.size(); ++i) { + expr * e; + node* n = need_fresh[i]; + sort* s = n->get_sort(); + if (!sort2elems.find(s, e)) { + e = m_manager.mk_fresh_const("elem", s); + trail.push_back(e); + sort2elems.insert(s, e); + } + n->insert(e, 0); + TRACE("model_finder", tout << "fresh constant: " << mk_pp(e, m_manager) << "\n";); } } From 19858c44b2999e8a14eb4febb4a53fc72756d333 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Fri, 4 Nov 2016 19:39:53 +0000 Subject: [PATCH 329/536] Added release notes for the upcoming 4.5.0 release --- RELEASE_NOTES | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/RELEASE_NOTES b/RELEASE_NOTES index 6746c1a54..38b6d9f6c 100644 --- a/RELEASE_NOTES +++ b/RELEASE_NOTES @@ -1,5 +1,22 @@ RELEASE NOTES +Version 4.5.0 +============= + +- New features: + - New theories of strings and sequences. + - Incremental consequence finder for finite domains. + - CMake build system (thanks @delcypher). + - Updated and improved OCaml API (thanks @martin-neuhaeusser). + - Updated and improved Java API (thanks @cheshire). + - New resource limit facilities to avoid non-deterministic timeout behaviour. + - New bit-vector simplification and ackermannization tactics (thanks @MikolasJanota, @nunoplopes). + - QSAT: a new solver for quantified arithmetic problems. See: + Bjorner, Janota: Playing with Quantified Satisfaction, LPAR 2016. + +- A multitude of bugs has been fixed. + + Version 4.4.1 ============= From 152321bce6c5feeab5f0debb9acd2cf2aed098cb Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 4 Nov 2016 20:29:12 +0000 Subject: [PATCH 330/536] fix crash in poly normalizer exposed by qe. Issue #775 Signed-off-by: Nikolaj Bjorner --- .../simplifier/arith_simplifier_plugin.cpp | 3 +-- src/ast/simplifier/poly_simplifier_plugin.cpp | 25 ++++++++++++++----- src/smt/theory_seq.cpp | 17 ++++++++----- 3 files changed, 31 insertions(+), 14 deletions(-) diff --git a/src/ast/simplifier/arith_simplifier_plugin.cpp b/src/ast/simplifier/arith_simplifier_plugin.cpp index 588508f4f..ef320578a 100644 --- a/src/ast/simplifier/arith_simplifier_plugin.cpp +++ b/src/ast/simplifier/arith_simplifier_plugin.cpp @@ -43,8 +43,7 @@ bool arith_simplifier_plugin::is_neg_poly(expr * t) const { if (m_util.is_mul(t)) { t = to_app(t)->get_arg(0); rational r; - bool is_int; - if (m_util.is_numeral(t, r, is_int)) + if (is_numeral(t, r)) return r.is_neg(); } return false; diff --git a/src/ast/simplifier/poly_simplifier_plugin.cpp b/src/ast/simplifier/poly_simplifier_plugin.cpp index c5dc275fd..e5e74ca56 100644 --- a/src/ast/simplifier/poly_simplifier_plugin.cpp +++ b/src/ast/simplifier/poly_simplifier_plugin.cpp @@ -607,12 +607,25 @@ void poly_simplifier_plugin::append_to_monomial(expr * n, numeral & k, ptr_buffe k *= val; n = get_monomial_body(n); - if (is_mul(n)) { - for (unsigned i = 0; i < to_app(n)->get_num_args(); i++) - result.push_back(to_app(n)->get_arg(i)); - } - else { - result.push_back(n); + unsigned hd = result.size(); + result.push_back(n); + while (hd < result.size()) { + n = result[hd]; + if (is_mul(n)) { + result[hd] = result.back(); + result.pop_back(); + for (unsigned i = 0; i < to_app(n)->get_num_args(); i++) { + result.push_back(to_app(n)->get_arg(i)); + } + } + else if (is_numeral(n, val)) { + k *= val; + result[hd] = result.back(); + result.pop_back(); + } + else { + ++hd; + } } } diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index 641b9c053..071167872 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -1815,7 +1815,10 @@ bool theory_seq::solve_ne(unsigned idx) { for (unsigned i = 0; i < n.lits().size(); ++i) { switch (ctx.get_assignment(n.lits(i))) { case l_false: - TRACE("seq", display_disequation(tout << "has false literal\n", n);); + TRACE("seq", display_disequation(tout << "has false literal\n", n); + ctx.display_literal_verbose(tout, n.lits(i)); + tout << "\n" << n.lits(i) << " " << ctx.is_relevant(n.lits(i)) << "\n"; + ); return true; case l_true: break; @@ -1841,7 +1844,10 @@ bool theory_seq::solve_ne(unsigned idx) { change = canonize(n.rs(i), rs, deps) || change; if (!m_seq_rewrite.reduce_eq(ls, rs, lhs, rhs, change)) { - TRACE("seq", display_disequation(tout << "reduces to false: ", n);); + TRACE("seq", display_disequation(tout << "reduces to false: ", n); + tout << n.ls(i) << " -> " << ls << "\n"; + tout << n.rs(i) << " -> " << rs << "\n";); + return true; } else if (!change) { @@ -3720,30 +3726,29 @@ void theory_seq::new_diseq_eh(theory_var v1, theory_var v2) { expr_ref e2(n2->get_owner(), m); m_exclude.update(e1, e2); expr_ref eq(m.mk_eq(e1, e2), m); + TRACE("seq", tout << "new disequality " << get_context().get_scope_level() << ": " << eq << "\n";); m_rewrite(eq); if (!m.is_false(eq)) { - TRACE("seq", tout << "new disequality " << get_context().get_scope_level() << ": " << eq << "\n";); literal lit = mk_eq(e1, e2, false); - // propagate x != "" into x = (++ (unit (nth x 0) (tail x 0))) if (m_util.str.is_empty(e2)) { std::swap(e1, e2); } +#if 0 if (false && m_util.str.is_empty(e1)) { expr_ref head(m), tail(m), conc(m); mk_decompose(e2, head, tail); conc = mk_concat(head, tail); propagate_eq(~lit, e2, conc, true); } -#if 0 + // (e1 = "" & e2 = xdz) or (e2 = "" & e1 = xcy) or (e1 = xcy & e2 = xdz & c != d) or (e1 = x & e2 = xdz) or (e2 = x & e1 = xcy) // e1 = "" or e1 = xcy or e1 = x // e2 = "" or e2 = xdz or e2 = x // e1 = xcy or e2 = xdz // c != d - literal lit = mk_seq_eq(e1, e2); sort* char_sort = 0; expr_ref emp(m); VERIFY(m_util.is_seq(m.get_sort(e1), char_sort)); From 81fce55d784e173b1eb31f384f1a5ed8750dccdc Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Fri, 4 Nov 2016 21:22:01 +0000 Subject: [PATCH 331/536] Updated optimization ML API. Addresses #776. --- src/api/ml/z3.ml | 8 ++++++-- src/api/ml/z3.mli | 40 ++++++++++++++++++++++++++++------------ 2 files changed, 34 insertions(+), 14 deletions(-) diff --git a/src/api/ml/z3.ml b/src/api/ml/z3.ml index b7016c4c8..245fd460b 100644 --- a/src/api/ml/z3.ml +++ b/src/api/ml/z3.ml @@ -1906,13 +1906,17 @@ struct let q = Z3native.optimize_get_model (gc x) x in if Z3native.is_null_model q then None else Some q - let get_lower (x:handle) (idx:int) = Z3native.optimize_get_lower (gc x.opt) x.opt idx - let get_upper (x:handle) (idx:int) = Z3native.optimize_get_upper (gc x.opt) x.opt idx + let get_lower (x:handle) = Z3native.optimize_get_lower (gc x.opt) x.opt x.h + let get_upper (x:handle) = Z3native.optimize_get_upper (gc x.opt) x.opt x.h let push (x:optimize) = Z3native.optimize_push (gc x) x let pop (x:optimize) = Z3native.optimize_pop (gc x) x let get_reason_unknown (x:optimize) = Z3native.optimize_get_reason_unknown (gc x) x let to_string (x:optimize) = Z3native.optimize_to_string (gc x) x let get_statistics (x:optimize) = Z3native.optimize_get_statistics (gc x) x + let from_file (x:optimize) (s:string) = Z3native.optimize_from_file (gc x) x s + let from_string (x:optimize) (s:string) = Z3native.optimize_from_string (gc x) x s + let get_assertions (x:optimize) = AST.ASTVector.to_expr_list (Z3native.optimize_get_assertions (gc x) x) + let get_objectives (x:optimize) = AST.ASTVector.to_expr_list (Z3native.optimize_get_statistics (gc x) x) end diff --git a/src/api/ml/z3.mli b/src/api/ml/z3.mli index 1c91b28aa..594472030 100644 --- a/src/api/ml/z3.mli +++ b/src/api/ml/z3.mli @@ -3236,33 +3236,28 @@ sig (** Asssert a soft constraint. Supply integer weight and string that identifies a group - of soft constraints. - *) + of soft constraints. *) val add_soft : optimize -> Expr.expr -> string -> Symbol.symbol -> handle - (** Add maximization objective. - *) + (** Add maximization objective. *) val maximize : optimize -> Expr.expr -> handle - (** Add minimization objective. - *) + (** Add minimization objective. *) val minimize : optimize -> Expr.expr -> handle - (** Checks whether the assertions in the context are satisfiable and solves objectives. - *) + (** Checks whether the assertions in the context are satisfiable and solves objectives. *) val check : optimize -> Solver.status (** Retrieve model from satisfiable context *) val get_model : optimize -> Model.model option (** Retrieve lower bound in current model for handle *) - val get_lower : handle -> int -> Expr.expr + val get_lower : handle -> Expr.expr (** Retrieve upper bound in current model for handle *) - val get_upper : handle -> int -> Expr.expr + val get_upper : handle -> Expr.expr - (** Creates a backtracking point. - {!pop} *) + (** Creates a backtracking point. {!pop} *) val push : optimize -> unit (** Backtrack one backtracking point. @@ -3278,6 +3273,27 @@ sig (** Retrieve statistics information from the last call to check *) val get_statistics : optimize -> Statistics.statistics + + (** Parse an SMT-LIB2 file with assertions, soft constraints and optimization + objectives. Add the parsed constraints and objectives to the optimization + context. *) + val from_file : optimize -> string -> unit + + (** Parse an SMT-LIB2 string with assertions, soft constraints and optimization + objectives. Add the parsed constraints and objectives to the optimization + context. *) + val from_string : optimize -> string -> unit + + (** Return the set of asserted formulas on the optimization context. *) + val get_assertions : optimize -> Expr.expr list + + (** Return objectives on the optimization context. If the objective function + is a max-sat objective it is returned as a Pseudo-Boolean (minimization) + sum of the form (+ (if f1 w1 0) (if f2 w2 0) ...). If the objective + function is entered as a maximization objective, then return the + corresponding minimization objective. In this way the resulting + objective function is always returned as a minimization objective. *) + val get_objectives : optimize -> Expr.expr list end From ac7e1b145caafc1187dc8929b6ece762ecb3872e Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Fri, 4 Nov 2016 21:27:10 +0000 Subject: [PATCH 332/536] Whitespace, typo --- src/api/z3_optimization.h | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/src/api/z3_optimization.h b/src/api/z3_optimization.h index 219f3ede8..f7a9a8fe9 100644 --- a/src/api/z3_optimization.h +++ b/src/api/z3_optimization.h @@ -71,7 +71,6 @@ extern "C" { */ unsigned Z3_API Z3_optimize_assert_soft(Z3_context c, Z3_optimize o, Z3_ast a, Z3_string weight, Z3_symbol id); - /** \brief Add a maximization constraint. \param c - context @@ -91,7 +90,6 @@ extern "C" { */ unsigned Z3_API Z3_optimize_minimize(Z3_context c, Z3_optimize o, Z3_ast t); - /** \brief Create a backtracking point. @@ -198,7 +196,7 @@ extern "C" { Z3_string Z3_API Z3_optimize_to_string(Z3_context c, Z3_optimize o); /** - \brief Parse an SMT-LIB2 string with assertions, + \brief Parse an SMT-LIB2 string with assertions, soft constraints and optimization objectives. Add the parsed constraints and objectives to the optimization context. @@ -210,13 +208,11 @@ extern "C" { */ void Z3_API Z3_optimize_from_string(Z3_context c, Z3_optimize o, Z3_string s); - /** - \brief Parse an SMT-LIB2 file with assertions, + \brief Parse an SMT-LIB2 file with assertions, soft constraints and optimization objectives. Add the parsed constraints and objectives to the optimization context. - \param c - context. \param o - optimize context. \param s - string containing SMT2 specification. @@ -225,7 +221,6 @@ extern "C" { */ void Z3_API Z3_optimize_from_file(Z3_context c, Z3_optimize o, Z3_string s); - /** \brief Return a string containing a description of parameters accepted by optimize. @@ -240,7 +235,6 @@ extern "C" { */ Z3_stats Z3_API Z3_optimize_get_statistics(Z3_context c, Z3_optimize d); - /** \brief Return the set of asserted formulas on the optimization context. @@ -251,15 +245,14 @@ extern "C" { /** \brief Return objectives on the optimization context. If the objective function is a max-sat objective it is returned - as a Pseudo-Boolean (minimization) sum of the form (+ (if f1 w1 0) (if f2 w2 0) ...) - If the objective function is entered as a maximization objective, then return the corresponding minimizaiton - objective. In this way the resulting objective function is always returned as a minimization objective. + as a Pseudo-Boolean (minimization) sum of the form (+ (if f1 w1 0) (if f2 w2 0) ...) + If the objective function is entered as a maximization objective, then return + the corresponding minimization objective. In this way the resulting objective + function is always returned as a minimization objective. def_API('Z3_optimize_get_objectives', AST_VECTOR, (_in(CONTEXT), _in(OPTIMIZE))) */ Z3_ast_vector Z3_API Z3_optimize_get_objectives(Z3_context c, Z3_optimize o); - - /*@}*/ /*@}*/ From b1f7c6ac979f91afbb15ad951d2a2d2a4d34a0f2 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Fri, 4 Nov 2016 22:08:49 +0000 Subject: [PATCH 333/536] eliminated unnecessary variable --- src/tactic/portfolio/bounded_int2bv_solver.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/tactic/portfolio/bounded_int2bv_solver.cpp b/src/tactic/portfolio/bounded_int2bv_solver.cpp index b6c85c159..53c20b253 100644 --- a/src/tactic/portfolio/bounded_int2bv_solver.cpp +++ b/src/tactic/portfolio/bounded_int2bv_solver.cpp @@ -183,7 +183,6 @@ private: return; } filter_model_converter filter(m); - func_decl_ref_vector const& fns = m_bv_fns; for (unsigned i = 0; i < m_bv_fns.size(); ++i) { filter.insert(m_bv_fns[i]); } From caf0a1e80dbfb2e6d917851676de49ea35b806ee Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 5 Nov 2016 07:22:27 +0000 Subject: [PATCH 334/536] fix breaking change to theory-seq Signed-off-by: Nikolaj Bjorner --- src/smt/theory_seq.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index 071167872..afb6d21b3 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -1847,7 +1847,7 @@ bool theory_seq::solve_ne(unsigned idx) { TRACE("seq", display_disequation(tout << "reduces to false: ", n); tout << n.ls(i) << " -> " << ls << "\n"; tout << n.rs(i) << " -> " << rs << "\n";); - + return true; } else if (!change) { @@ -3732,16 +3732,18 @@ void theory_seq::new_diseq_eh(theory_var v1, theory_var v2) { literal lit = mk_eq(e1, e2, false); + if (m_util.str.is_empty(e2)) { std::swap(e1, e2); } -#if 0 + if (false && m_util.str.is_empty(e1)) { expr_ref head(m), tail(m), conc(m); mk_decompose(e2, head, tail); conc = mk_concat(head, tail); propagate_eq(~lit, e2, conc, true); } +#if 0 // (e1 = "" & e2 = xdz) or (e2 = "" & e1 = xcy) or (e1 = xcy & e2 = xdz & c != d) or (e1 = x & e2 = xdz) or (e2 = x & e1 = xcy) // e1 = "" or e1 = xcy or e1 = x From 50c323dc74c0947236f28c16514517924cf1f753 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Sat, 5 Nov 2016 14:35:48 +0000 Subject: [PATCH 335/536] Whitespace --- src/smt/smt_quantifier.h | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/src/smt/smt_quantifier.h b/src/smt/smt_quantifier.h index e814afcb1..bc731bf9c 100644 --- a/src/smt/smt_quantifier.h +++ b/src/smt/smt_quantifier.h @@ -37,7 +37,7 @@ namespace smt { public: quantifier_manager(context & ctx, smt_params & fp, params_ref const & p); ~quantifier_manager(); - + context & get_context() const; void set_plugin(quantifier_manager_plugin * plugin); @@ -51,12 +51,12 @@ namespace smt { quantifier_stat * get_stat(quantifier * q) const; unsigned get_generation(quantifier * q) const; - bool add_instance(quantifier * q, app * pat, - unsigned num_bindings, - enode * const * bindings, - unsigned max_generation, - unsigned min_top_generation, - unsigned max_top_generation, + bool add_instance(quantifier * q, app * pat, + unsigned num_bindings, + enode * const * bindings, + unsigned max_generation, + unsigned min_top_generation, + unsigned max_top_generation, ptr_vector & used_enodes); bool add_instance(quantifier * q, unsigned num_bindings, enode * const * bindings, unsigned generation = 0); @@ -78,11 +78,11 @@ namespace smt { bool mbqi_enabled(quantifier *q) const; // can mbqi instantiate this quantifier? void adjust_model(proto_model * m); check_model_result check_model(proto_model * m, obj_map const & root2value); - + void push(); void pop(unsigned num_scopes); void reset(); - + void display(std::ostream & out) const; void display_stats(std::ostream & out, quantifier * q) const; @@ -97,7 +97,7 @@ namespace smt { public: quantifier_manager_plugin() {} virtual ~quantifier_manager_plugin() {} - + virtual void set_manager(quantifier_manager & qm) = 0; virtual quantifier_manager_plugin * mk_fresh() = 0; @@ -106,7 +106,7 @@ namespace smt { virtual void del(quantifier * q) = 0; virtual bool is_shared(enode * n) const = 0; - + /** \brief This method is invoked whenever q is assigned to true. */ @@ -131,9 +131,9 @@ namespace smt { \brief This method is invoked whenever the solver restarts. */ virtual void restart_eh() = 0; - + /** - \brief Return true if the quantifier_manager can propagate information + \brief Return true if the quantifier_manager can propagate information information back into the core. */ virtual bool can_propagate() const = 0; @@ -143,11 +143,11 @@ namespace smt { \brief Return true if the plugin is "model based" */ virtual bool model_based() const = 0; - + /** \brief Is "model based" instantiate allowed to instantiate this quantifier? */ - virtual bool mbqi_enabled(quantifier *q) const {return true;} + virtual bool mbqi_enabled(quantifier *q) const {return true;} /** \brief Give a change to the plugin to adjust the interpretation of unintepreted functions. @@ -161,10 +161,10 @@ namespace smt { It also provides a mapping from enodes to their interpretations. */ virtual quantifier_manager::check_model_result check_model(proto_model * m, obj_map const & root2value) = 0; - + virtual void push() = 0; virtual void pop(unsigned num_scopes) = 0; - + }; }; From 5ef7d38d728a77f6825fe6526523dce7a157a459 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Sat, 5 Nov 2016 14:39:23 +0000 Subject: [PATCH 336/536] Whitespace --- src/smt/smt_quantifier.cpp | 97 ++++++++++++++++++-------------------- 1 file changed, 47 insertions(+), 50 deletions(-) diff --git a/src/smt/smt_quantifier.cpp b/src/smt/smt_quantifier.cpp index a5e15a201..5787d6732 100644 --- a/src/smt/smt_quantifier.cpp +++ b/src/smt/smt_quantifier.cpp @@ -27,7 +27,7 @@ Revision History: #include"ast_smt2_pp.h" namespace smt { - + quantifier_manager_plugin * mk_default_plugin(); struct quantifier_manager::imp { @@ -40,7 +40,7 @@ namespace smt { ptr_vector m_quantifiers; scoped_ptr m_plugin; unsigned m_num_instances; - + imp(quantifier_manager & wrapper, context & ctx, smt_params & p, quantifier_manager_plugin * plugin): m_wrapper(wrapper), m_context(ctx), @@ -85,7 +85,7 @@ namespace smt { out << max_generation << " : " << max_cost << "\n"; } } - + void del(quantifier * q) { if (m_params.m_qi_profile) { display_stats(verbose_stream(), q); @@ -99,15 +99,15 @@ namespace smt { } bool is_shared(enode * n) const { - return m_plugin->is_shared(n); + return m_plugin->is_shared(n); } - bool add_instance(quantifier * q, app * pat, - unsigned num_bindings, - enode * const * bindings, - unsigned max_generation, - unsigned min_top_generation, - unsigned max_top_generation, + bool add_instance(quantifier * q, app * pat, + unsigned num_bindings, + enode * const * bindings, + unsigned max_generation, + unsigned min_top_generation, + unsigned max_top_generation, ptr_vector & used_enodes) { max_generation = std::max(max_generation, get_generation(q)); if (m_num_instances > m_params.m_qi_max_instances) @@ -136,7 +136,7 @@ namespace smt { } return false; } - + void init_search_eh() { m_num_instances = 0; ptr_vector::iterator it2 = m_quantifiers.begin(); @@ -149,7 +149,7 @@ namespace smt { m_plugin->init_search_eh(); TRACE("smt_params", m_params.display(tout); ); } - + void assign_eh(quantifier * q) { m_plugin->assign_eh(q); } @@ -175,7 +175,7 @@ namespace smt { m_plugin->pop(num_scopes); m_qi_queue.pop_scope(num_scopes); } - + bool can_propagate() { return m_qi_queue.has_work() || m_plugin->can_propagate(); } @@ -184,7 +184,7 @@ namespace smt { m_plugin->propagate(); m_qi_queue.instantiate(); } - + bool check_quantifier(quantifier* q) { return m_context.is_relevant(q) && m_context.get_assignment(q) == l_true; // TBD: && !m_context->get_manager().is_rec_fun_def(q); } @@ -251,7 +251,7 @@ namespace smt { quantifier_manager::~quantifier_manager() { dealloc(m_imp); } - + context & quantifier_manager::get_context() const { return m_imp->m_context; } @@ -285,16 +285,16 @@ namespace smt { return m_imp->get_generation(q); } - bool quantifier_manager::add_instance(quantifier * q, app * pat, - unsigned num_bindings, - enode * const * bindings, - unsigned max_generation, - unsigned min_top_generation, - unsigned max_top_generation, + bool quantifier_manager::add_instance(quantifier * q, app * pat, + unsigned num_bindings, + enode * const * bindings, + unsigned max_generation, + unsigned min_top_generation, + unsigned max_top_generation, ptr_vector & used_enodes) { return m_imp->add_instance(q, pat, num_bindings, bindings, max_generation, min_top_generation, max_generation, used_enodes); } - + bool quantifier_manager::add_instance(quantifier * q, unsigned num_bindings, enode * const * bindings, unsigned generation) { ptr_vector tmp; return add_instance(q, 0, num_bindings, bindings, generation, generation, generation, tmp); @@ -347,7 +347,7 @@ namespace smt { quantifier_manager::check_model_result quantifier_manager::check_model(proto_model * m, obj_map const & root2value) { return m_imp->check_model(m, root2value); } - + void quantifier_manager::push() { m_imp->push(); } @@ -367,7 +367,7 @@ namespace smt { plugin->set_manager(*this); } } - + void quantifier_manager::display(std::ostream & out) const { } @@ -382,12 +382,12 @@ namespace smt { m_imp->display_stats(out, q); } - ptr_vector::const_iterator quantifier_manager::begin_quantifiers() const { - return m_imp->m_quantifiers.begin(); + ptr_vector::const_iterator quantifier_manager::begin_quantifiers() const { + return m_imp->m_quantifiers.begin(); } - - ptr_vector::const_iterator quantifier_manager::end_quantifiers() const { - return m_imp->m_quantifiers.end(); + + ptr_vector::const_iterator quantifier_manager::end_quantifiers() const { + return m_imp->m_quantifiers.end(); } // The default plugin uses E-matching, MBQI and quick-checker @@ -404,13 +404,13 @@ namespace smt { bool m_active; public: default_qm_plugin(): - m_qm(0), - m_context(0), - m_new_enode_qhead(0), + m_qm(0), + m_context(0), + m_new_enode_qhead(0), m_lazy_matching_idx(0), m_active(false) { } - + virtual ~default_qm_plugin() { } @@ -434,20 +434,18 @@ namespace smt { virtual bool model_based() const { return m_fparams->m_mbqi; } - virtual bool mbqi_enabled(quantifier *q) const { - if(!m_fparams->m_mbqi_id) return true; + virtual bool mbqi_enabled(quantifier *q) const { + if (!m_fparams->m_mbqi_id) return true; const symbol &s = q->get_qid(); size_t len = strlen(m_fparams->m_mbqi_id); - if(s == symbol::null || s.is_numerical()) + if (s == symbol::null || s.is_numerical()) return len == 0; - return strncmp(s.bare_str(),m_fparams->m_mbqi_id,len) == 0; - } + return strncmp(s.bare_str(), m_fparams->m_mbqi_id, len) == 0; + } - /* Quantifier id's must begin with the prefix specified by - parameter mbqi.id to be instantiated with MBQI. The default - value is the empty string, so all quantifiers are - instantiated. - */ + /* Quantifier id's must begin with the prefix specified by parameter + mbqi.id to be instantiated with MBQI. The default value is the + empty string, so all quantifiers are instantiated. */ virtual void add(quantifier * q) { if (m_fparams->m_mbqi && mbqi_enabled(q)) { m_active = true; @@ -455,8 +453,7 @@ namespace smt { } } - virtual void del(quantifier * q) { - } + virtual void del(quantifier * q) { } virtual void push() { m_mam->push_scope(); @@ -465,7 +462,7 @@ namespace smt { m_model_finder->push_scope(); } } - + virtual void pop(unsigned num_scopes) { m_mam->pop_scope(num_scopes); m_lazy_mam->pop_scope(num_scopes); @@ -473,7 +470,7 @@ namespace smt { m_model_finder->pop_scope(num_scopes); } } - + virtual void init_search_eh() { m_lazy_matching_idx = 0; if (m_fparams->m_mbqi) { @@ -516,7 +513,7 @@ namespace smt { } } } - + bool use_ematching() const { return m_fparams->m_ematching && !m_qm->empty(); } @@ -538,7 +535,7 @@ namespace smt { } virtual void restart_eh() { - if (m_fparams->m_mbqi) { + if (m_fparams->m_mbqi) { m_model_finder->restart_eh(); m_model_checker->restart_eh(); } @@ -613,7 +610,7 @@ namespace smt { } return FC_DONE; } - + }; quantifier_manager_plugin * mk_default_plugin() { From 0909832cbfe2536c79056714e8ddb33cf13d60ec Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 6 Nov 2016 02:11:45 +0100 Subject: [PATCH 337/536] updated release notes Signed-off-by: Nikolaj Bjorner --- RELEASE_NOTES | 34 ++++++++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/RELEASE_NOTES b/RELEASE_NOTES index 38b6d9f6c..357c17e78 100644 --- a/RELEASE_NOTES +++ b/RELEASE_NOTES @@ -5,14 +5,40 @@ Version 4.5.0 - New features: - New theories of strings and sequences. - - Incremental consequence finder for finite domains. + - Consequence finding API "get-consequences" to compute + set of consequences modulo hard constraints and set of + assumptions. Optimized implementations provided for finite + domains (QF_FD) and for most SMT logics. - CMake build system (thanks @delcypher). + - New API functions, including accessing assertions, parsing SMT-LIB benchmarks. - Updated and improved OCaml API (thanks @martin-neuhaeusser). - Updated and improved Java API (thanks @cheshire). - New resource limit facilities to avoid non-deterministic timeout behaviour. - - New bit-vector simplification and ackermannization tactics (thanks @MikolasJanota, @nunoplopes). - - QSAT: a new solver for quantified arithmetic problems. See: - Bjorner, Janota: Playing with Quantified Satisfaction, LPAR 2016. + You can enable it from the command-line using the switch rlimit=. + - New bit-vector simplification and ackermannization + tactics (thanks @MikolasJanota, @nunoplopes). + - QSAT: a new solver for satisfiability of quantified arithmetic formulas. + See: Bjorner, Janota: Playing with Quantified Satisfaction, LPAR 2016. + This is the new default solver for logics LIA, LRA, NRA. It furthermore + can be applied as a tactic on quantified formulas using algebraic + data-types (but excluding selector sub-terms because Z3 does not + specify the semantics of applying a selector to a non-matching + constructor term). + - A specialized logic QF_FD and associated incremental solver + (that supports push/pop). + The QF_FD domain comprises of bit-vectors, enumeration data-types + used only in equalities, and bounded integers: Integers used in + QF_FD problems have to be constrained by a finite bound. + - Queries in the fixedpoint engine are now function symbols and not + formulas with free variables. This makes the association of + free variables in the answers unambiguous. To emulate queries + over compound formulas, introduce a fresh predicate whose + arguments are the relevant free variables in the formula and add a rule + that uses the fresh predicate in the head and formula in the body. + - minimization of unsat cores is avaialble as an option for the SAT and SMT cores. + By setting smt.core.minimize=true resp. sat.core.minimize=true + cores produced by these modules are minimized. + - A multitude of bugs has been fixed. From 9ebea09d05fab108f8adff2ec8ca9d7c3095859b Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Mon, 7 Nov 2016 10:28:39 +0000 Subject: [PATCH 338/536] added is_numeral_negative to ML API. --- src/api/ml/z3.ml | 1 + src/api/ml/z3.mli | 3 +++ 2 files changed, 4 insertions(+) diff --git a/src/api/ml/z3.ml b/src/api/ml/z3.ml index 565adf976..2051a2c48 100644 --- a/src/api/ml/z3.ml +++ b/src/api/ml/z3.ml @@ -1338,6 +1338,7 @@ struct let is_numeral_normal = Z3native.fpa_is_numeral_normal let is_numeral_subnormal = Z3native.fpa_is_numeral_subnormal let is_numeral_positive = Z3native.fpa_is_numeral_positive + let is_numeral_negative = Z3native.fpa_is_numeral_negative let mk_to_ieee_bv = Z3native.mk_fpa_to_ieee_bv let mk_to_fp_int_real = Z3native.mk_fpa_to_fp_int_real let numeral_to_string x = Z3native.get_numeral_string (Expr.gc x) x diff --git a/src/api/ml/z3.mli b/src/api/ml/z3.mli index a2ecf54c2..979e0cfab 100644 --- a/src/api/ml/z3.mli +++ b/src/api/ml/z3.mli @@ -2185,6 +2185,9 @@ sig (** Indicates whether a floating-point numeral is positive. *) val is_numeral_positive : context -> Expr.expr -> bool + + (** Indicates whether a floating-point numeral is negative. *) + val is_numeral_negative : context -> Expr.expr -> bool (** Conversion of a floating-point term into a bit-vector term in IEEE 754-2008 format. *) val mk_to_ieee_bv : context -> Expr.expr -> Expr.expr From 758a6d98fb82cd9559a000a9c94b64d94800e296 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Mon, 7 Nov 2016 12:35:48 +0000 Subject: [PATCH 339/536] FPA API clarification --- src/api/z3_fpa.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/api/z3_fpa.h b/src/api/z3_fpa.h index 70fafe6ea..e92b728d7 100644 --- a/src/api/z3_fpa.h +++ b/src/api/z3_fpa.h @@ -253,9 +253,9 @@ extern "C" { This is the operator named `fp' in the SMT FP theory definition. Note that \c sign is required to be a bit-vector of size 1. Significand and exponent - are required to be greater than 1 and 2 respectively. The FloatingPoint sort + are required to be longer than 1 and 2 respectively. The FloatingPoint sort of the resulting expression is automatically determined from the bit-vector sizes - of the arguments. + of the arguments. The exponent is assumed to be in IEEE-754 biased representation. \param c logical context \param sgn sign From 4e7077db7039114a3b5ecb20cd04d2d65ceb9c44 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Mon, 7 Nov 2016 12:38:12 +0000 Subject: [PATCH 340/536] Bugfix for denormal numeral exponents --- src/api/api_fpa.cpp | 56 +++++++++++++++++++++++++++++---------------- 1 file changed, 36 insertions(+), 20 deletions(-) diff --git a/src/api/api_fpa.cpp b/src/api/api_fpa.cpp index 46234c0d2..35c8d8fc1 100644 --- a/src/api/api_fpa.cpp +++ b/src/api/api_fpa.cpp @@ -990,7 +990,7 @@ extern "C" { scoped_mpq q(mpqm); mpqm.set(q, mpfm.sig(val)); if (mpfm.is_inf(val)) mpqm.set(q, 0); - app * a = mk_c(c)->bvutil().mk_numeral(q.get(), sbits); + app * a = mk_c(c)->bvutil().mk_numeral(q.get(), sbits-1); mk_c(c)->save_ast_trail(a); RETURN_Z3(of_expr(a)); Z3_CATCH_RETURN(0); @@ -1083,12 +1083,18 @@ extern "C" { return ""; } unsigned ebits = val.get().get_ebits(); - mpf_exp_t exp = mpfm.is_zero(val) ? 0 : - mpfm.is_denormal(val) ? mpfm.mk_min_exp(ebits) : - mpfm.is_inf(val) ? mpfm.mk_top_exp(ebits) : - mpfm.bias_exp(ebits, mpfm.exp(val)); - if (mpfm.is_normal(val) && !biased) - exp = mpfm.exp(val); + mpf_exp_t exp; + if (biased) { + exp = mpfm.is_zero(val) ? 0 : + mpfm.is_inf(val) ? mpfm.mk_top_exp(ebits) : + mpfm.bias_exp(ebits, mpfm.exp(val)) + } + else { + exp = mpfm.is_zero(val) ? 0 : + mpfm.is_inf(val) ? mpfm.mk_top_exp(ebits) : + mpfm.is_denormal(val) ? mpfm.mk_min_exp(ebits) : + mpfm.exp(val); + } std::stringstream ss; ss << exp; return mk_c(c)->mk_external_string(ss.str()); @@ -1118,12 +1124,17 @@ extern "C" { return 0; } unsigned ebits = val.get().get_ebits(); - *n = mpfm.is_zero(val) ? 0 : - mpfm.is_denormal(val) ? mpfm.mk_min_exp(ebits) : - mpfm.is_inf(val) ? mpfm.mk_top_exp(ebits) : - mpfm.bias_exp(ebits, mpfm.exp(val)); - if (mpfm.is_normal(val) && !biased) - *n = mpfm.exp(val); + if (biased) { + *n = mpfm.is_zero(val) ? 0 : + mpfm.is_inf(val) ? mpfm.mk_top_exp(ebits) : + mpfm.bias_exp(ebits, mpfm.exp(val)); + } + else { + *n = mpfm.is_zero(val) ? 0 : + mpfm.is_inf(val) ? mpfm.mk_top_exp(ebits) : + mpfm.is_denormal(val) ? mpfm.mk_min_exp(ebits) : + mpfm.exp(val); + } return 1; Z3_CATCH_RETURN(0); } @@ -1150,13 +1161,18 @@ extern "C" { RETURN_Z3(0); } unsigned ebits = val.get().get_ebits(); - mpf_exp_t exp = mpfm.is_zero(val) ? 0 : - mpfm.is_denormal(val) ? mpfm.mk_min_exp(ebits) : - mpfm.is_inf(val) ? mpfm.mk_top_exp(ebits) : - mpfm.bias_exp(ebits, mpfm.exp(val)); - if (mpfm.is_normal(val) && !biased) - exp = mpfm.exp(val); - + mpf_exp_t exp; + if (biased) { + exp = mpfm.is_zero(val) ? 0 : + mpfm.is_inf(val) ? mpfm.mk_top_exp(ebits) : + mpfm.bias_exp(ebits, mpfm.exp(val)); + } + else { + exp = mpfm.is_zero(val) ? 0 : + mpfm.is_inf(val) ? mpfm.mk_top_exp(ebits) : + mpfm.is_denormal(val) ? mpfm.mk_min_exp(ebits) : + mpfm.exp(val); + } app * a = mk_c(c)->bvutil().mk_numeral(exp, ebits); mk_c(c)->save_ast_trail(a); RETURN_Z3(of_expr(a)); From 80e136f09097b9fa1b274255a163f78507c7a178 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Mon, 7 Nov 2016 13:51:09 +0000 Subject: [PATCH 341/536] build fix --- src/api/api_fpa.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/api_fpa.cpp b/src/api/api_fpa.cpp index 35c8d8fc1..4454cc577 100644 --- a/src/api/api_fpa.cpp +++ b/src/api/api_fpa.cpp @@ -1087,7 +1087,7 @@ extern "C" { if (biased) { exp = mpfm.is_zero(val) ? 0 : mpfm.is_inf(val) ? mpfm.mk_top_exp(ebits) : - mpfm.bias_exp(ebits, mpfm.exp(val)) + mpfm.bias_exp(ebits, mpfm.exp(val)); } else { exp = mpfm.is_zero(val) ? 0 : From 75cfd14e5a6cfe43eca6f273988360507f46d47e Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Mon, 7 Nov 2016 14:14:45 +0000 Subject: [PATCH 342/536] bugfix for macro finder --- src/ast/macros/macro_util.cpp | 118 +++++++++++++++++----------------- 1 file changed, 60 insertions(+), 58 deletions(-) diff --git a/src/ast/macros/macro_util.cpp b/src/ast/macros/macro_util.cpp index 166b9c4b0..e1f44e927 100644 --- a/src/ast/macros/macro_util.cpp +++ b/src/ast/macros/macro_util.cpp @@ -34,7 +34,7 @@ macro_util::macro_util(ast_manager & m, simplifier & s): m_simplifier(s), m_arith_simp(0), m_bv_simp(0), - m_basic_simp(0), + m_basic_simp(0), m_forbidden_set(0), m_curr_clause(0) { } @@ -64,23 +64,23 @@ basic_simplifier_plugin * macro_util::get_basic_simp() const { } bool macro_util::is_bv(expr * n) const { - return get_bv_simp()->is_bv(n); + return get_bv_simp()->is_bv(n); } bool macro_util::is_bv_sort(sort * s) const { - return get_bv_simp()->is_bv_sort(s); + return get_bv_simp()->is_bv_sort(s); } bool macro_util::is_add(expr * n) const { - return get_arith_simp()->is_add(n) || get_bv_simp()->is_add(n); + return get_arith_simp()->is_add(n) || get_bv_simp()->is_add(n); } bool macro_util::is_times_minus_one(expr * n, expr * & arg) const { return get_arith_simp()->is_times_minus_one(n, arg) || get_bv_simp()->is_times_minus_one(n, arg); } -bool macro_util::is_le(expr * n) const { - return get_arith_simp()->is_le(n) || get_bv_simp()->is_le(n); +bool macro_util::is_le(expr * n) const { + return get_arith_simp()->is_le(n) || get_bv_simp()->is_le(n); } bool macro_util::is_le_ge(expr * n) const { @@ -130,7 +130,7 @@ void macro_util::mk_add(unsigned num_args, expr * const * args, sort * s, expr_r /** \brief Return true if \c n is an application of the form - + (f x_{k_1}, ..., x_{k_n}) where f is uninterpreted @@ -147,7 +147,7 @@ bool macro_util::is_macro_head(expr * n, unsigned num_decls) const { var2pos.resize(num_decls, -1); for (unsigned i = 0; i < num_decls; i++) { expr * c = to_app(n)->get_arg(i); - if (!is_var(c)) + if (!is_var(c)) return false; unsigned idx = to_var(c)->get_idx(); if (idx >= num_decls || var2pos[idx] != -1) @@ -161,12 +161,12 @@ bool macro_util::is_macro_head(expr * n, unsigned num_decls) const { /** \brief Return true if n is of the form - + (= (f x_{k_1}, ..., x_{k_n}) t) OR - (iff (f x_{k_1}, ..., x_{k_n}) t) + (iff (f x_{k_1}, ..., x_{k_n}) t) where - + is_macro_head((f x_{k_1}, ..., x_{k_n})) returns true AND t does not contain f AND f is not in forbidden_set @@ -180,7 +180,8 @@ bool macro_util::is_left_simple_macro(expr * n, unsigned num_decls, app_ref & he if (m_manager.is_eq(n) || m_manager.is_iff(n)) { expr * lhs = to_app(n)->get_arg(0); expr * rhs = to_app(n)->get_arg(1); - if (is_macro_head(lhs, num_decls) && !is_forbidden(to_app(lhs)->get_decl()) && !occurs(to_app(lhs)->get_decl(), rhs)) { + if (is_macro_head(lhs, num_decls) && !is_forbidden(to_app(lhs)->get_decl()) && + !occurs(to_app(lhs)->get_decl(), rhs) && !has_quantifiers(rhs)) { head = to_app(lhs); def = rhs; return true; @@ -192,12 +193,12 @@ bool macro_util::is_left_simple_macro(expr * n, unsigned num_decls, app_ref & he /** \brief Return true if n is of the form - + (= t (f x_{k_1}, ..., x_{k_n})) OR (iff t (f x_{k_1}, ..., x_{k_n})) where - + is_macro_head((f x_{k_1}, ..., x_{k_n})) returns true AND t does not contain f AND f is not in forbidden_set @@ -211,7 +212,8 @@ bool macro_util::is_right_simple_macro(expr * n, unsigned num_decls, app_ref & h if (m_manager.is_eq(n) || m_manager.is_iff(n)) { expr * lhs = to_app(n)->get_arg(0); expr * rhs = to_app(n)->get_arg(1); - if (is_macro_head(rhs, num_decls) && !is_forbidden(to_app(rhs)->get_decl()) && !occurs(to_app(rhs)->get_decl(), lhs)) { + if (is_macro_head(rhs, num_decls) && !is_forbidden(to_app(rhs)->get_decl()) && + !occurs(to_app(rhs)->get_decl(), lhs) && !has_quantifiers(lhs)) { head = to_app(rhs); def = lhs; return true; @@ -254,7 +256,7 @@ bool macro_util::is_arith_macro(expr * n, unsigned num_decls, app_ref & head, ex if (!as->is_numeral(rhs)) return false; - + inv = false; ptr_buffer args; expr * h = 0; @@ -271,15 +273,15 @@ bool macro_util::is_arith_macro(expr * n, unsigned num_decls, app_ref & head, ex for (unsigned i = 0; i < lhs_num_args; i++) { expr * arg = lhs_args[i]; expr * neg_arg; - if (h == 0 && - is_macro_head(arg, num_decls) && - !is_forbidden(to_app(arg)->get_decl()) && + if (h == 0 && + is_macro_head(arg, num_decls) && + !is_forbidden(to_app(arg)->get_decl()) && !poly_contains_head(lhs, to_app(arg)->get_decl(), arg)) { h = arg; } else if (h == 0 && as->is_times_minus_one(arg, neg_arg) && - is_macro_head(neg_arg, num_decls) && - !is_forbidden(to_app(neg_arg)->get_decl()) && + is_macro_head(neg_arg, num_decls) && + !is_forbidden(to_app(neg_arg)->get_decl()) && !poly_contains_head(lhs, to_app(neg_arg)->get_decl(), arg)) { h = neg_arg; inv = true; @@ -304,7 +306,7 @@ bool macro_util::is_arith_macro(expr * n, unsigned num_decls, app_ref & head, ex \brief Auxiliary function for is_pseudo_predicate_macro. It detects the pattern (= (f X) t) */ bool macro_util::is_pseudo_head(expr * n, unsigned num_decls, app_ref & head, app_ref & t) { - if (!m_manager.is_eq(n)) + if (!m_manager.is_eq(n)) return false; expr * lhs = to_app(n)->get_arg(0); expr * rhs = to_app(n)->get_arg(1); @@ -331,7 +333,7 @@ bool macro_util::is_pseudo_head(expr * n, unsigned num_decls, app_ref & head, ap /** \brief Returns true if n if of the form (forall (X) (iff (= (f X) t) def[X])) - where t is a ground term, (f X) is the head. + where t is a ground term, (f X) is the head. */ bool macro_util::is_pseudo_predicate_macro(expr * n, app_ref & head, app_ref & t, expr_ref & def) { if (!is_quantifier(n) || !to_quantifier(n)->is_forall()) @@ -343,14 +345,14 @@ bool macro_util::is_pseudo_predicate_macro(expr * n, app_ref & head, app_ref & t return false; expr * lhs = to_app(body)->get_arg(0); expr * rhs = to_app(body)->get_arg(1); - if (is_pseudo_head(lhs, num_decls, head, t) && - !is_forbidden(head->get_decl()) && + if (is_pseudo_head(lhs, num_decls, head, t) && + !is_forbidden(head->get_decl()) && !occurs(head->get_decl(), rhs)) { def = rhs; return true; } - if (is_pseudo_head(rhs, num_decls, head, t) && - !is_forbidden(head->get_decl()) && + if (is_pseudo_head(rhs, num_decls, head, t) && + !is_forbidden(head->get_decl()) && !occurs(head->get_decl(), lhs)) { def = lhs; return true; @@ -361,7 +363,7 @@ bool macro_util::is_pseudo_predicate_macro(expr * n, app_ref & head, app_ref & t /** \brief A quasi-macro head is of the form f[X_1, ..., X_n], where n == num_decls, f[X_1, ..., X_n] is a term starting with symbol f, f is uninterpreted, - contains all universally quantified variables as arguments. + contains all universally quantified variables as arguments. Note that, some arguments of f[X_1, ..., X_n] may not be variables. Examples of quasi-macros: @@ -477,16 +479,16 @@ void macro_util::normalize_expr(app * head, expr * t, expr_ref & norm_t) const { else var_mapping.setx(max_var_idx - i, v); } - + for (unsigned i = num_args; i <= max_var_idx; i++) - // CMW: Won't be used, but dictates a larger binding size, + // CMW: Won't be used, but dictates a larger binding size, // so that the indexes between here and in the rewriter match. // It's possible that we don't see the true max idx of all vars here. - var_mapping.setx(max_var_idx - i, 0); + var_mapping.setx(max_var_idx - i, 0); if (changed) { // REMARK: t may have nested quantifiers... So, I must use the std order for variable substitution. - var_subst subst(m_manager, true); + var_subst subst(m_manager, true); TRACE("macro_util_bug", tout << "head: " << mk_pp(head, m_manager) << "\n"; tout << "applying substitution to:\n" << mk_ll_pp(t, m_manager) << "\nsubstitution:\n"; @@ -503,8 +505,8 @@ void macro_util::normalize_expr(app * head, expr * t, expr_ref & norm_t) const { // ----------------------------- // -// "Hint" support -// See comment at is_hint_atom +// "Hint" support +// See comment at is_hint_atom // for a definition of what a hint is. // // ----------------------------- @@ -516,7 +518,7 @@ bool is_hint_head(expr * n, ptr_buffer & vars) { return false; unsigned num_args = to_app(n)->get_num_args(); for (unsigned i = 0; i < num_args; i++) { - expr * arg = to_app(n)->get_arg(i); + expr * arg = to_app(n)->get_arg(i); if (is_var(arg)) vars.push_back(to_var(arg)); } @@ -552,7 +554,7 @@ bool vars_of_is_subset(expr * n, ptr_buffer const & vars) { } } else { - SASSERT(is_quantifier(curr)); + SASSERT(is_quantifier(curr)); return false; // do no support nested quantifier... being conservative. } } @@ -560,7 +562,7 @@ bool vars_of_is_subset(expr * n, ptr_buffer const & vars) { } /** - \brief (= lhs rhs) is a hint atom if + \brief (= lhs rhs) is a hint atom if lhs is of the form (f t_1 ... t_n) and all variables occurring in rhs are direct arguments of lhs. */ @@ -598,7 +600,7 @@ void hint_to_macro_head(ast_manager & m, app * head, unsigned num_decls, app_ref /** \brief Return true if n can be viewed as a polynomial "hint" based on head. That is, n (but the monomial exception) only uses the variables in head, and does not use - head->get_decl(). + head->get_decl(). is_hint_head(head, vars) must also return true */ bool macro_util::is_poly_hint(expr * n, app * head, expr * exception) { @@ -630,7 +632,7 @@ bool macro_util::is_poly_hint(expr * n, app * head, expr * exception) { } TRACE("macro_util_hint", tout << "succeeded\n";); return true; - + } // ----------------------------- @@ -681,7 +683,7 @@ void macro_util::insert_macro(app * head, expr * def, expr * cond, bool ineq, bo r.insert(head->get_decl(), norm_def.get(), norm_cond.get(), ineq, satisfy_atom, hint); } -void macro_util::insert_quasi_macro(app * head, unsigned num_decls, expr * def, expr * cond, bool ineq, bool satisfy_atom, +void macro_util::insert_quasi_macro(app * head, unsigned num_decls, expr * def, expr * cond, bool ineq, bool satisfy_atom, bool hint, macro_candidates & r) { if (!is_macro_head(head, head->get_num_args())) { app_ref new_head(m_manager); @@ -783,8 +785,8 @@ void macro_util::collect_arith_macro_candidates(expr * lhs, expr * rhs, expr * a if (!is_app(arg)) continue; func_decl * f = to_app(arg)->get_decl(); - - bool _is_arith_macro = + + bool _is_arith_macro = is_quasi_macro_head(arg, num_decls) && !is_forbidden(f) && !poly_contains_head(lhs, f, arg) && @@ -805,14 +807,14 @@ void macro_util::collect_arith_macro_candidates(expr * lhs, expr * rhs, expr * a } else if (is_times_minus_one(arg, neg_arg) && is_app(neg_arg)) { f = to_app(neg_arg)->get_decl(); - bool _is_arith_macro = + bool _is_arith_macro = is_quasi_macro_head(neg_arg, num_decls) && !is_forbidden(f) && !poly_contains_head(lhs, f, arg) && !occurs(f, rhs) && !rest_contains_decl(f, atom); bool _is_poly_hint = !_is_arith_macro && is_poly_hint(lhs, to_app(neg_arg), arg); - + if (_is_arith_macro || _is_poly_hint) { collect_poly_args(lhs, arg, args); expr_ref rest(m_manager); @@ -842,34 +844,34 @@ void macro_util::collect_arith_macro_candidates(expr * atom, unsigned num_decls, /** \brief Collect macro candidates for atom \c atom. The candidates are stored in \c r. - + The following post-condition holds: for each i in [0, r.size() - 1] we have a conditional macro of the form - + r.get_cond(i) IMPLIES f(x_1, ..., x_n) = r.get_def(i) - + where f == r.get_fs(i) .., x_n), f is uninterpreted and x_1, ..., x_n are variables. r.get_cond(i) and r.get_defs(i) do not contain f or variables not in {x_1, ..., x_n} The idea is to use r.get_defs(i) as the interpretation for f in a model M whenever r.get_cond(i) - - Given a model M and values { v_1, ..., v_n } + + Given a model M and values { v_1, ..., v_n } Let M' be M{x_1 -> v_1, ..., v_n -> v_n} - + Note that M'(f(x_1, ..., x_n)) = M(f)(v_1, ..., v_n) - + Then, IF we have that M(f)(v_1, ..., v_n) = M'(r.get_def(i)) AND M'(r.get_cond(i)) = true THEN M'(atom) = true That is, if the conditional macro is used then the atom is satisfied when M'(r.get_cond(i)) = true - + IF r.is_ineq(i) = false, then M(f)(v_1, ..., v_n) ***MUST BE*** M'(r.get_def(i)) whenever M'(r.get_cond(i)) = true - + IF r.satisfy_atom(i) = true, then we have the stronger property: Then, IF we have that (M'(r.get_cond(i)) = true IMPLIES M(f)(v_1, ..., v_n) = M'(r.get_def(i))) @@ -878,8 +880,8 @@ void macro_util::collect_arith_macro_candidates(expr * atom, unsigned num_decls, void macro_util::collect_macro_candidates_core(expr * atom, unsigned num_decls, macro_candidates & r) { expr* lhs, *rhs; if (m_manager.is_eq(atom, lhs, rhs) || m_manager.is_iff(atom, lhs, rhs)) { - if (is_quasi_macro_head(lhs, num_decls) && - !is_forbidden(to_app(lhs)->get_decl()) && + if (is_quasi_macro_head(lhs, num_decls) && + !is_forbidden(to_app(lhs)->get_decl()) && !occurs(to_app(lhs)->get_decl(), rhs) && !rest_contains_decl(to_app(lhs)->get_decl(), atom)) { expr_ref cond(m_manager); @@ -889,9 +891,9 @@ void macro_util::collect_macro_candidates_core(expr * atom, unsigned num_decls, else if (is_hint_atom(lhs, rhs)) { insert_quasi_macro(to_app(lhs), num_decls, rhs, 0, false, true, true, r); } - - if (is_quasi_macro_head(rhs, num_decls) && - !is_forbidden(to_app(rhs)->get_decl()) && + + if (is_quasi_macro_head(rhs, num_decls) && + !is_forbidden(to_app(rhs)->get_decl()) && !occurs(to_app(rhs)->get_decl(), lhs) && !rest_contains_decl(to_app(rhs)->get_decl(), atom)) { expr_ref cond(m_manager); From ef9230d8f8ae1a39efa6c4d2e45c9ce9b72fd754 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 7 Nov 2016 06:56:36 -0800 Subject: [PATCH 343/536] detect quantifiers in model expressions to quiet down failing model validation Signed-off-by: Nikolaj Bjorner --- src/ast/macros/macro_util.cpp | 4 ++-- src/cmd_context/cmd_context.cpp | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/ast/macros/macro_util.cpp b/src/ast/macros/macro_util.cpp index e1f44e927..91bff5ab5 100644 --- a/src/ast/macros/macro_util.cpp +++ b/src/ast/macros/macro_util.cpp @@ -181,7 +181,7 @@ bool macro_util::is_left_simple_macro(expr * n, unsigned num_decls, app_ref & he expr * lhs = to_app(n)->get_arg(0); expr * rhs = to_app(n)->get_arg(1); if (is_macro_head(lhs, num_decls) && !is_forbidden(to_app(lhs)->get_decl()) && - !occurs(to_app(lhs)->get_decl(), rhs) && !has_quantifiers(rhs)) { + !occurs(to_app(lhs)->get_decl(), rhs)) { head = to_app(lhs); def = rhs; return true; @@ -213,7 +213,7 @@ bool macro_util::is_right_simple_macro(expr * n, unsigned num_decls, app_ref & h expr * lhs = to_app(n)->get_arg(0); expr * rhs = to_app(n)->get_arg(1); if (is_macro_head(rhs, num_decls) && !is_forbidden(to_app(rhs)->get_decl()) && - !occurs(to_app(rhs)->get_decl(), lhs) && !has_quantifiers(lhs)) { + !occurs(to_app(rhs)->get_decl(), lhs)) { head = to_app(rhs); def = lhs; return true; diff --git a/src/cmd_context/cmd_context.cpp b/src/cmd_context/cmd_context.cpp index 3cf00c154..eb7b3ff44 100644 --- a/src/cmd_context/cmd_context.cpp +++ b/src/cmd_context/cmd_context.cpp @@ -1568,6 +1568,9 @@ void cmd_context::validate_model() { // If r contains as_array/store/map/const expressions, then we do not generate the error. // TODO: improve evaluator for model expressions. // Note that, if "a" evaluates to false, then the error will be generated. + if (has_quantifiers(r)) { + continue; + } try { for_each_expr(contains_array, r); } From 7f923c6a33cde36fc162e859a9c327545dc2b80e Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Mon, 7 Nov 2016 16:16:55 +0000 Subject: [PATCH 344/536] Include Python API files in distributions. --- examples/python/example.py | 28 +++++++++++++++++++- scripts/mk_project.py | 1 + scripts/mk_unix_dist.py | 10 ++++++- scripts/mk_util.py | 53 +++++++++++++++++++++++++++++++++----- scripts/mk_win_dist.py | 12 +++++++-- 5 files changed, 94 insertions(+), 10 deletions(-) diff --git a/examples/python/example.py b/examples/python/example.py index e0c9374e7..a17668506 100644 --- a/examples/python/example.py +++ b/examples/python/example.py @@ -1,4 +1,30 @@ -# Copyright (c) Microsoft Corporation 2015 +# Copyright (c) Microsoft Corporation 2015, 2016 + +# The Z3 Python API requires libz3.dll/.so/.dylib in the +# PATH/LD_LIBRARY_PATH/DYLD_LIBRARY_PATH +# environment variable and the PYTHON_PATH environment variable +# needs to point to the `python' directory that contains `z3/z3.py' +# (which is at bin/python in our binary releases). + +# If you obtained example.py as part of our binary release zip files, +# which you unzipped into a directory called `MYZ3', then follow these +# instructions to run the example: + +# Running this example on Windows: +# set PATH=%PATH%;MYZ3\bin +# set PYTHONPATH=MYZ3\bin\python +# python example.py + +# Running this example on Linux: +# export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:MYZ3/bin +# export PYTHONPATH=MYZ3/bin/python +# python example.py + +# Running this example on OSX: +# export DYLD_LIBRARY_PATH=$DYLD_LIBRARY_PATH:MYZ3/bin +# export PYTHONPATH=MYZ3/bin/python +# python example.py + from z3 import * diff --git a/scripts/mk_project.py b/scripts/mk_project.py index c03d76b5f..b18e7801b 100644 --- a/scripts/mk_project.py +++ b/scripts/mk_project.py @@ -94,6 +94,7 @@ def init_project_def(): add_ml_lib('ml', ['api_dll'], 'api/ml', lib_name='libz3ml') add_hlib('cpp', 'api/c++', includes2install=['z3++.h']) set_z3py_dir('api/python') + add_python(_libz3Component) add_python_install(_libz3Component) # Examples add_cpp_example('cpp_example', 'c++') diff --git a/scripts/mk_unix_dist.py b/scripts/mk_unix_dist.py index 4905a7141..527797e66 100644 --- a/scripts/mk_unix_dist.py +++ b/scripts/mk_unix_dist.py @@ -26,6 +26,7 @@ DOTNET_ENABLED=True DOTNET_KEY_FILE=None JAVA_ENABLED=True GIT_HASH=False +PYTHON_ENABLED=True def set_verbose(flag): global VERBOSE @@ -55,6 +56,7 @@ def display_help(): print(" --nodotnet do not include .NET bindings in the binary distribution files.") print(" --dotnet-key= sign the .NET assembly with the private key in .") print(" --nojava do not include Java bindings in the binary distribution files.") + print(" --nopython do not include Python bindings in the binary distribution files.") print(" --githash include git hash in the Zip file.") exit(0) @@ -69,7 +71,8 @@ def parse_options(): 'nojava', 'nodotnet', 'dotnet-key=', - 'githash' + 'githash', + 'nopython' ]) for opt, arg in options: if opt in ('-b', '--build'): @@ -84,6 +87,8 @@ def parse_options(): FORCE_MK = True elif opt == '--nodotnet': DOTNET_ENABLED = False + elif opt == '--nopython': + PYTHON_ENABLED = False elif opt == '--dotnet-key': DOTNET_KEY_FILE = arg elif opt == '--nojava': @@ -111,6 +116,8 @@ def mk_build_dir(path): if GIT_HASH: opts.append('--githash=%s' % mk_util.git_hash()) opts.append('--git-describe') + if PYTHON_ENABLED: + opts.append('--python') if subprocess.call(opts) != 0: raise MKException("Failed to generate build directory at '%s'" % path) @@ -181,6 +188,7 @@ def mk_dist_dir(): mk_util.DOTNET_ENABLED = DOTNET_ENABLED mk_util.DOTNET_KEY_FILE = DOTNET_KEY_FILE mk_util.JAVA_ENABLED = JAVA_ENABLED + mk_util.PYTHON_ENABLED = PYTHON_ENABLED mk_unix_dist(build_path, dist_path) if is_verbose(): print("Generated distribution folder at '%s'" % dist_path) diff --git a/scripts/mk_util.py b/scripts/mk_util.py index 873af8432..cf06a10a7 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -63,6 +63,7 @@ DOTNET_COMPONENT='dotnet' JAVA_COMPONENT='java' ML_COMPONENT='ml' CPP_COMPONENT='cpp' +PYTHON_COMPONENT='python' ##################### IS_WINDOWS=False IS_LINUX=False @@ -81,6 +82,7 @@ ONLY_MAKEFILES = False Z3PY_SRC_DIR=None VS_PROJ = False TRACE = False +PYTHON_ENABLED=False DOTNET_ENABLED=False DOTNET_KEY_FILE=getenv("Z3_DOTNET_KEY_FILE", None) JAVA_ENABLED=False @@ -675,7 +677,7 @@ def display_help(exit_code): # Parse configuration option for mk_make script def parse_options(): global VERBOSE, DEBUG_MODE, IS_WINDOWS, VS_X64, ONLY_MAKEFILES, SHOW_CPPS, VS_PROJ, TRACE, VS_PAR, VS_PAR_NUM - global DOTNET_ENABLED, DOTNET_KEY_FILE, JAVA_ENABLED, ML_ENABLED, STATIC_LIB, STATIC_BIN, PREFIX, GMP, FOCI2, FOCI2LIB, PYTHON_PACKAGE_DIR, GPROF, GIT_HASH, GIT_DESCRIBE, PYTHON_INSTALL_ENABLED + global DOTNET_ENABLED, DOTNET_KEY_FILE, JAVA_ENABLED, ML_ENABLED, STATIC_LIB, STATIC_BIN, PREFIX, GMP, FOCI2, FOCI2LIB, PYTHON_PACKAGE_DIR, GPROF, GIT_HASH, GIT_DESCRIBE, PYTHON_INSTALL_ENABLED, PYTHON_ENABLED global LINUX_X64, SLOW_OPTIMIZE, USE_OMP try: options, remainder = getopt.gnu_getopt(sys.argv[1:], @@ -748,6 +750,7 @@ def parse_options(): elif opt in ('', '--noomp'): USE_OMP = False elif opt in ('--python'): + PYTHON_ENABLED = True PYTHON_INSTALL_ENABLED = True else: print("ERROR: Invalid command line option '%s'" % opt) @@ -844,6 +847,9 @@ def is_ml_enabled(): def is_dotnet_enabled(): return DOTNET_ENABLED +def is_python_enabled(): + return PYTHON_ENABLED + def is_python_install_enabled(): return PYTHON_INSTALL_ENABLED @@ -1382,6 +1388,32 @@ class DLLComponent(Component): shutil.copy('%s.a' % os.path.join(build_path, self.dll_name), '%s.a' % os.path.join(dist_path, INSTALL_BIN_DIR, self.dll_name)) +class PythonComponent(Component): + def __init__(self, name, libz3Component): + assert isinstance(libz3Component, DLLComponent) + global PYTHON_ENABLED + Component.__init__(self, name, None, []) + self.libz3Component = libz3Component + + def main_component(self): + return False + + def mk_win_dist(self, build_path, dist_path): + if not is_python_enabled(): + return + + src = os.path.join(build_path, 'python', 'z3') + dst = os.path.join(dist_path, INSTALL_BIN_DIR, 'python', 'z3') + if os.path.exists(dst): + shutil.rmtree(dst) + shutil.copytree(src, dst) + + def mk_unix_dist(self, build_path, dist_path): + self.mk_win_dist(build_path, dist_path) + + def mk_makefile(self, out): + return + class PythonInstallComponent(Component): def __init__(self, name, libz3Component): assert isinstance(libz3Component, DLLComponent) @@ -1484,6 +1516,7 @@ class PythonInstallComponent(Component): os.path.join('python', 'z3', '*.pyc'), os.path.join(self.pythonPkgDir,'z3'), in_prefix=self.in_prefix_install) + if PYTHON_PACKAGE_DIR != distutils.sysconfig.get_python_lib(): out.write('\t@echo Z3Py was installed at \'%s\', make sure this directory is in your PYTHONPATH environment variable.' % PYTHON_PACKAGE_DIR) @@ -2173,6 +2206,15 @@ class PythonExampleComponent(ExampleComponent): print("Copied Z3Py example '%s' to '%s'" % (py, os.path.join(BUILD_DIR, 'python'))) out.write('_ex_%s: \n\n' % self.name) + def mk_win_dist(self, build_path, dist_path): + full = os.path.join(EXAMPLE_DIR, self.path) + py = 'example.py' + shutil.copyfile(os.path.join(full, py), + os.path.join(dist_path, INSTALL_BIN_DIR, 'python', py)) + + def mk_unix_dist(self, build_path, dist_path): + self.mk_win_dist(build_path, dist_path) + def reg_component(name, c): global _Id, _Components, _ComponentNames, _Name2Component @@ -2213,6 +2255,10 @@ def add_java_dll(name, deps=[], path=None, dll_name=None, package_name=None, man c = JavaDLLComponent(name, dll_name, package_name, manifest_file, path, deps) reg_component(name, c) +def add_python(libz3Component): + name = 'python' + reg_component(name, PythonComponent(name, libz3Component)) + def add_python_install(libz3Component): name = 'python_install' reg_component(name, PythonInstallComponent(name, libz3Component)) @@ -3230,11 +3276,6 @@ def mk_vs_proj_dll(name, components): def mk_win_dist(build_path, dist_path): for c in get_components(): c.mk_win_dist(build_path, dist_path) - # Add Z3Py to bin directory - print("Adding to %s\n" % dist_path) - for pyc in filter(lambda f: f.endswith('.pyc') or f.endswith('.py'), os.listdir(build_path)): - shutil.copy(os.path.join(build_path, pyc), - os.path.join(dist_path, INSTALL_BIN_DIR, pyc)) def mk_unix_dist(build_path, dist_path): for c in get_components(): diff --git a/scripts/mk_win_dist.py b/scripts/mk_win_dist.py index 145e356fb..65d780f0d 100644 --- a/scripts/mk_win_dist.py +++ b/scripts/mk_win_dist.py @@ -28,6 +28,7 @@ DOTNET_ENABLED=True DOTNET_KEY_FILE=None JAVA_ENABLED=True GIT_HASH=False +PYTHON_ENABLED=True def set_verbose(flag): global VERBOSE @@ -60,12 +61,13 @@ def display_help(): print(" --nodotnet do not include .NET bindings in the binary distribution files.") print(" --dotnet-key= sign the .NET assembly with the private key in .") print(" --nojava do not include Java bindings in the binary distribution files.") + print(" --nopython do not include Python bindings in the binary distribution files.") print(" --githash include git hash in the Zip file.") exit(0) # Parse configuration option for mk_make script def parse_options(): - global FORCE_MK, JAVA_ENABLED, GIT_HASH, DOTNET_ENABLED, DOTNET_KEY_FILE + global FORCE_MK, JAVA_ENABLED, GIT_HASH, DOTNET_ENABLED, DOTNET_KEY_FILE, PYTHON_ENABLED path = BUILD_DIR options, remainder = getopt.gnu_getopt(sys.argv[1:], 'b:hsf', ['build=', 'help', @@ -74,7 +76,8 @@ def parse_options(): 'nojava', 'nodotnet', 'dotnet-key=', - 'githash' + 'githash', + 'nopython' ]) for opt, arg in options: if opt in ('-b', '--build'): @@ -89,6 +92,8 @@ def parse_options(): FORCE_MK = True elif opt == '--nodotnet': DOTNET_ENABLED = False + elif opt == '--nopython': + PYTHON_ENABLED = False elif opt == '--dotnet-key': DOTNET_KEY_FILE = arg elif opt == '--nojava': @@ -118,6 +123,8 @@ def mk_build_dir(path, x64): if GIT_HASH: opts.append('--githash=%s' % mk_util.git_hash()) opts.append('--git-describe') + if PYTHON_ENABLED: + opts.append('--python') if subprocess.call(opts) != 0: raise MKException("Failed to generate build directory at '%s'" % path) @@ -192,6 +199,7 @@ def mk_dist_dir_core(x64): mk_util.DOTNET_ENABLED = DOTNET_ENABLED mk_util.DOTNET_KEY_FILE = DOTNET_KEY_FILE mk_util.JAVA_ENABLED = JAVA_ENABLED + mk_util.PYTHON_ENABLED = PYTHON_ENABLED mk_win_dist(build_path, dist_path) if is_verbose(): print("Generated %s distribution folder at '%s'" % (platform, dist_path)) From d57a2a6dce9291acf9c71a561252f3e133f0c894 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Mon, 7 Nov 2016 15:32:52 +0000 Subject: [PATCH 345/536] Bumped version to 4.5.0 --- scripts/mk_project.py | 2 +- src/api/python/setup.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/mk_project.py b/scripts/mk_project.py index b18e7801b..986e92bde 100644 --- a/scripts/mk_project.py +++ b/scripts/mk_project.py @@ -9,7 +9,7 @@ from mk_util import * # Z3 Project definition def init_project_def(): - set_version(4, 4, 2, 1) + set_version(4, 5, 0, 0) add_lib('util', []) add_lib('polynomial', ['util'], 'math/polynomial') add_lib('sat', ['util']) diff --git a/src/api/python/setup.py b/src/api/python/setup.py index 95843aac0..d7d3722b3 100644 --- a/src/api/python/setup.py +++ b/src/api/python/setup.py @@ -139,7 +139,7 @@ class sdist(_sdist): setup( name='z3-solver', - version='4.4.2.1', + version='4.5.0.0', description='an efficient SMT solver library', long_description='Z3 is a theorem prover from Microsoft Research with support for bitvectors, booleans, arrays, floating point numbers, strings, and other data types.\n\nFor documentation, please read http://z3prover.github.io/api/html/z3.html\n\nIn the event of technical difficulties related to configuration, compiliation, or installation, please submit issues to https://github.com/angr/angr-z3', author="The Z3 Theorem Prover Project", From 00ada5305ff672448576c61525cef3958f9457de Mon Sep 17 00:00:00 2001 From: Dominic Chen Date: Mon, 7 Nov 2016 17:42:44 -0500 Subject: [PATCH 346/536] Standardize on __uint64 instead of unsigned __int64 --- src/api/api_datalog.cpp | 4 ++-- src/api/z3_api.h | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/api/api_datalog.cpp b/src/api/api_datalog.cpp index 903fedd0f..cc512c08e 100644 --- a/src/api/api_datalog.cpp +++ b/src/api/api_datalog.cpp @@ -189,7 +189,7 @@ extern "C" { Z3_CATCH_RETURN(0); } - Z3_sort Z3_API Z3_mk_finite_domain_sort(Z3_context c, Z3_symbol name, unsigned __int64 size) { + Z3_sort Z3_API Z3_mk_finite_domain_sort(Z3_context c, Z3_symbol name, __uint64 size) { Z3_TRY; LOG_Z3_mk_finite_domain_sort(c, name, size); RESET_ERROR_CODE(); @@ -199,7 +199,7 @@ extern "C" { Z3_CATCH_RETURN(0); } - Z3_bool Z3_API Z3_get_finite_domain_sort_size(Z3_context c, Z3_sort s, unsigned __int64 * out) { + Z3_bool Z3_API Z3_get_finite_domain_sort_size(Z3_context c, Z3_sort s, __uint64 * out) { Z3_TRY; if (out) { *out = 0; diff --git a/src/api/z3_api.h b/src/api/z3_api.h index 069f83340..c7749ebef 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -1807,7 +1807,7 @@ extern "C" { def_API('Z3_mk_finite_domain_sort', SORT, (_in(CONTEXT), _in(SYMBOL), _in(UINT64))) */ - Z3_sort Z3_API Z3_mk_finite_domain_sort(Z3_context c, Z3_symbol name, unsigned __int64 size); + Z3_sort Z3_API Z3_mk_finite_domain_sort(Z3_context c, Z3_symbol name, __uint64 size); /** \brief Create an array type. @@ -3143,14 +3143,14 @@ extern "C" { /** \brief Create a numeral of a int, bit-vector, or finite-domain sort. - This function can be use to create numerals that fit in a machine unsigned __int64 integer. + This function can be use to create numerals that fit in a machine __uint64 integer. It is slightly faster than #Z3_mk_numeral since it is not necessary to parse a string. \sa Z3_mk_numeral def_API('Z3_mk_unsigned_int64', AST, (_in(CONTEXT), _in(UINT64), _in(SORT))) */ - Z3_ast Z3_API Z3_mk_unsigned_int64(Z3_context c, unsigned __int64 v, Z3_sort ty); + Z3_ast Z3_API Z3_mk_unsigned_int64(Z3_context c, __uint64 v, Z3_sort ty); /*@}*/ @@ -3722,7 +3722,7 @@ extern "C" { def_API('Z3_get_finite_domain_sort_size', BOOL, (_in(CONTEXT), _in(SORT), _out(UINT64))) */ - Z3_bool_opt Z3_API Z3_get_finite_domain_sort_size(Z3_context c, Z3_sort s, unsigned __int64* r); + Z3_bool_opt Z3_API Z3_get_finite_domain_sort_size(Z3_context c, Z3_sort s, __uint64* r); /** \brief Return the domain of the given array sort. @@ -4288,7 +4288,7 @@ extern "C" { /** \brief Similar to #Z3_get_numeral_string, but only succeeds if - the value can fit in a machine unsigned __int64 int. Return Z3_TRUE if the call succeeded. + the value can fit in a machine __uint64 int. Return Z3_TRUE if the call succeeded. \pre Z3_get_ast_kind(c, v) == Z3_NUMERAL_AST @@ -4296,7 +4296,7 @@ extern "C" { def_API('Z3_get_numeral_uint64', BOOL, (_in(CONTEXT), _in(AST), _out(UINT64))) */ - Z3_bool Z3_API Z3_get_numeral_uint64(Z3_context c, Z3_ast v, unsigned __int64* u); + Z3_bool Z3_API Z3_get_numeral_uint64(Z3_context c, Z3_ast v, __uint64* u); /** \brief Similar to #Z3_get_numeral_string, but only succeeds if From 889e5e93884699a972c2c644701e1d63b897dc9e Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Mon, 7 Nov 2016 23:19:59 +0000 Subject: [PATCH 347/536] Bumped version number. --- scripts/mk_project.py | 2 +- src/api/python/setup.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/mk_project.py b/scripts/mk_project.py index 986e92bde..7ba88c1b3 100644 --- a/scripts/mk_project.py +++ b/scripts/mk_project.py @@ -9,7 +9,7 @@ from mk_util import * # Z3 Project definition def init_project_def(): - set_version(4, 5, 0, 0) + set_version(4, 5, 1, 0) add_lib('util', []) add_lib('polynomial', ['util'], 'math/polynomial') add_lib('sat', ['util']) diff --git a/src/api/python/setup.py b/src/api/python/setup.py index d7d3722b3..9c18da01e 100644 --- a/src/api/python/setup.py +++ b/src/api/python/setup.py @@ -139,7 +139,7 @@ class sdist(_sdist): setup( name='z3-solver', - version='4.5.0.0', + version='4.5.1.0', description='an efficient SMT solver library', long_description='Z3 is a theorem prover from Microsoft Research with support for bitvectors, booleans, arrays, floating point numbers, strings, and other data types.\n\nFor documentation, please read http://z3prover.github.io/api/html/z3.html\n\nIn the event of technical difficulties related to configuration, compiliation, or installation, please submit issues to https://github.com/angr/angr-z3', author="The Z3 Theorem Prover Project", From 18e7b2d28e6bcea76b7b3bd9414d15caf21a5a6f Mon Sep 17 00:00:00 2001 From: Dan Liew Date: Tue, 8 Nov 2016 08:29:38 +0000 Subject: [PATCH 348/536] [CMake] Bump the version number in the CMake build. --- CMakeLists.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6a2ed0ebd..1ca94689e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -32,9 +32,9 @@ project(Z3 C CXX) # Project version ################################################################################ set(Z3_VERSION_MAJOR 4) -set(Z3_VERSION_MINOR 4) -set(Z3_VERSION_PATCH 2) -set(Z3_VERSION_TWEAK 1) +set(Z3_VERSION_MINOR 5) +set(Z3_VERSION_PATCH 1) +set(Z3_VERSION_TWEAK 0) set(Z3_FULL_VERSION 0) set(Z3_VERSION "${Z3_VERSION_MAJOR}.${Z3_VERSION_MINOR}.${Z3_VERSION_PATCH}.${Z3_VERSION_TWEAK}") message(STATUS "Z3 version ${Z3_VERSION}") From a3e4629996df0a9cc126e420db912fdf567e37a1 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Tue, 8 Nov 2016 15:12:04 +0000 Subject: [PATCH 349/536] fixed hard-coded version number in setup.py --- src/api/python/setup.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/api/python/setup.py b/src/api/python/setup.py index 9c18da01e..ff3b0736d 100644 --- a/src/api/python/setup.py +++ b/src/api/python/setup.py @@ -4,6 +4,7 @@ import shutil import platform import subprocess import multiprocessing +import re from setuptools import setup from distutils.errors import LibError from distutils.command.build import build as _build @@ -43,6 +44,16 @@ def _clean_bins(): shutil.rmtree(BINS_DIR, ignore_errors=True) shutil.rmtree(HEADERS_DIR, ignore_errors=True) +def _z3_version(): + fn = os.path.join(SRC_DIR, 'scripts', 'mk_project.py') + if os.path.exists(fn): + with open(fn) as f: + for line in f: + n = re.match(".*set_version\((.*), (.*), (.*), (.*)\).*", line) + if not n is None: + return n.group(1) + '.' + n.group(2) + '.' + n.group(3) + '.' + n.group(4) + return "?.?.?.?" + def _configure_z3(): # bail out early if we don't need to do this - it forces a rebuild every time otherwise if os.path.exists(BUILD_DIR): @@ -139,7 +150,7 @@ class sdist(_sdist): setup( name='z3-solver', - version='4.5.1.0', + version=_z3_version(), description='an efficient SMT solver library', long_description='Z3 is a theorem prover from Microsoft Research with support for bitvectors, booleans, arrays, floating point numbers, strings, and other data types.\n\nFor documentation, please read http://z3prover.github.io/api/html/z3.html\n\nIn the event of technical difficulties related to configuration, compiliation, or installation, please submit issues to https://github.com/angr/angr-z3', author="The Z3 Theorem Prover Project", From e22a67c12c23923a93ea46256f43087e2bce5b8c Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Tue, 8 Nov 2016 15:27:46 +0000 Subject: [PATCH 350/536] Whitespace --- src/api/z3_replayer.cpp | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/api/z3_replayer.cpp b/src/api/z3_replayer.cpp index 651cb730f..56f6d7bb6 100644 --- a/src/api/z3_replayer.cpp +++ b/src/api/z3_replayer.cpp @@ -14,7 +14,7 @@ Author: Leonardo de Moura (leonardo) 2011-09-22 Notes: - + --*/ #include"vector.h" #include"map.h" @@ -76,13 +76,13 @@ struct z3_replayer::imp { } if (m_args[pos].m_kind != k) { std::stringstream strm; - strm << "expecting " << kind2string(k) << " at position " + strm << "expecting " << kind2string(k) << " at position " << pos << " but got " << kind2string(m_args[pos].m_kind); throw z3_replayer_exception(strm.str().c_str()); } } - struct value { + struct value { value_kind m_kind; union { __int64 m_int; @@ -129,7 +129,7 @@ struct z3_replayer::imp { break; case DOUBLE: out << v.m_double; - break; + break; case STRING: out << v.m_str; break; @@ -160,7 +160,7 @@ struct z3_replayer::imp { char curr() const { return m_curr; } void new_line() { m_line++; } void next() { m_curr = m_stream.get(); } - + void read_string_core(char delimiter) { if (curr() != delimiter) throw z3_replayer_exception("invalid string/symbol"); @@ -258,7 +258,7 @@ struct z3_replayer::imp { } bool is_double_char() const { - return curr() == '-' || curr() == '.' || ('0' <= curr() && curr() <= '9') || curr() == 'e' || curr() == 'E'; + return curr() == '-' || curr() == '.' || ('0' <= curr() && curr() <= '9') || curr() == 'e' || curr() == 'E'; } #if (!defined(strtof)) @@ -376,7 +376,7 @@ struct z3_replayer::imp { } } else if (k == OBJECT) { - TRACE("z3_replayer_bug", + TRACE("z3_replayer_bug", tout << "args: "; display_args(tout); tout << "\n"; tout << "push_back, sz: " << sz << ", m_obj_arrays.size(): " << m_obj_arrays.size() << "\n"; for (unsigned i = asz - sz; i < asz; i++) { @@ -421,7 +421,7 @@ struct z3_replayer::imp { break; case 'R': // reset - next(); + next(); TRACE("z3_replayer", tout << "[" << m_line << "] " << "R\n";); reset(); break; @@ -432,7 +432,7 @@ struct z3_replayer::imp { if (m_ptr == 0) { m_args.push_back(0); } - else { + else { void * obj = 0; if (!m_heap.find(m_ptr, obj)) throw z3_replayer_exception("invalid pointer"); @@ -493,7 +493,7 @@ struct z3_replayer::imp { next(); skip_blank(); read_double(); TRACE("z3_replayer", tout << "[" << m_line << "] " << "D " << m_double << "\n";); m_args.push_back(value(DOUBLE, m_double)); - break; + break; case 'p': case 's': case 'u': @@ -696,15 +696,15 @@ struct z3_replayer::imp { m_unsigned_arrays.reset(); m_int_arrays.reset(); } - - + + }; z3_replayer::z3_replayer(std::istream & in) { m_imp = alloc(imp, *this, in); register_z3_replayer_cmds(*this); } - + z3_replayer::~z3_replayer() { dealloc(m_imp); } From 1188e6df47f3d284910313911bf9e95a326abc23 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Tue, 8 Nov 2016 15:28:20 +0000 Subject: [PATCH 351/536] Typo --- src/api/z3_replayer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/z3_replayer.cpp b/src/api/z3_replayer.cpp index 56f6d7bb6..277fedb4a 100644 --- a/src/api/z3_replayer.cpp +++ b/src/api/z3_replayer.cpp @@ -72,7 +72,7 @@ struct z3_replayer::imp { void check_arg(unsigned pos, value_kind k) const { if (pos >= m_args.size()) { TRACE("z3_replayer", tout << "too few arguments " << m_args.size() << " expecting " << kind2string(k) << "\n";); - throw z3_replayer_exception("invalid argument reference2"); + throw z3_replayer_exception("invalid argument reference"); } if (m_args[pos].m_kind != k) { std::stringstream strm; From b47c67dee3df0502e8bb5a61b6a2e60ac9a379d6 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Thu, 10 Nov 2016 21:15:43 +0000 Subject: [PATCH 352/536] Bugfix for Z3_fpa_get_numeral_*_uint64. Relates to #570. --- src/api/api_fpa.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/api/api_fpa.cpp b/src/api/api_fpa.cpp index 5d423c725..a039de63c 100644 --- a/src/api/api_fpa.cpp +++ b/src/api/api_fpa.cpp @@ -968,6 +968,10 @@ extern "C" { Z3_TRY; LOG_Z3_fpa_get_numeral_significand_uint64(c, t, n); RESET_ERROR_CODE(); + if (n == 0) { + SET_ERROR_CODE(Z3_INVALID_ARG); + return 0; + } ast_manager & m = mk_c(c)->m(); mpf_manager & mpfm = mk_c(c)->fpautil().fm(); unsynch_mpz_manager & mpzm = mpfm.mpz_manager(); @@ -1028,6 +1032,10 @@ extern "C" { Z3_TRY; LOG_Z3_fpa_get_numeral_exponent_int64(c, t, n); RESET_ERROR_CODE(); + if (n == 0) { + SET_ERROR_CODE(Z3_INVALID_ARG); + return 0; + } ast_manager & m = mk_c(c)->m(); mpf_manager & mpfm = mk_c(c)->fpautil().fm(); family_id fid = mk_c(c)->get_fpa_fid(); From ca81e803cbd2524741be48ea9d27d1cb647842dd Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Thu, 10 Nov 2016 21:33:42 +0000 Subject: [PATCH 353/536] Bugfix for Z3_fpa_get_numeral_sign. Relates to #570. --- src/api/api_fpa.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/api/api_fpa.cpp b/src/api/api_fpa.cpp index a039de63c..8e122ff01 100644 --- a/src/api/api_fpa.cpp +++ b/src/api/api_fpa.cpp @@ -909,6 +909,10 @@ extern "C" { Z3_TRY; LOG_Z3_fpa_get_numeral_sign(c, t, sgn); RESET_ERROR_CODE(); + if (sgn == 0) { + SET_ERROR_CODE(Z3_INVALID_ARG); + return 0; + } ast_manager & m = mk_c(c)->m(); mpf_manager & mpfm = mk_c(c)->fpautil().fm(); fpa_decl_plugin * plugin = (fpa_decl_plugin*)m.get_plugin(mk_c(c)->get_fpa_fid()); From 44d05e537548d01e31ab49dab81bf24701a610e0 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Wed, 9 Nov 2016 18:00:15 +0000 Subject: [PATCH 354/536] Fix cleanup/initialization of sat::simplifier. Relates to #570. --- src/sat/sat_clause.h | 6 +- src/sat/sat_probing.cpp | 18 ++--- src/sat/sat_simplifier.cpp | 36 ++++++---- src/sat/sat_simplifier.h | 21 ++++-- src/sat/sat_solver.cpp | 130 ++++++++++++++++++------------------- src/sat/sat_types.h | 4 +- 6 files changed, 119 insertions(+), 96 deletions(-) diff --git a/src/sat/sat_clause.h b/src/sat/sat_clause.h index 1662b429f..1aededbb6 100644 --- a/src/sat/sat_clause.h +++ b/src/sat/sat_clause.h @@ -102,10 +102,14 @@ namespace sat { unsigned m_val1; unsigned m_val2; public: - bin_clause(literal l1, literal l2, bool learned):m_val1(l1.to_uint()), m_val2((l2.to_uint() << 1) + static_cast(learned)) {} + bin_clause(literal l1, literal l2, bool learned) :m_val1(l1.to_uint()), m_val2((l2.to_uint() << 1) + static_cast(learned)) {} literal get_literal1() const { return to_literal(m_val1); } literal get_literal2() const { return to_literal(m_val2 >> 1); } bool is_learned() const { return (m_val2 & 1) == 1; } + bool operator==(const bin_clause & other) const { + return m_val1 == other.m_val1 && m_val2 == other.m_val2 || + m_val1 == other.m_val2 && m_val2 == other.m_val1; + } }; class tmp_clause { diff --git a/src/sat/sat_probing.cpp b/src/sat/sat_probing.cpp index 165d39ad8..c00b68ac2 100644 --- a/src/sat/sat_probing.cpp +++ b/src/sat/sat_probing.cpp @@ -95,7 +95,7 @@ namespace sat { if (updt_cache) cache_bins(l, old_tr_sz); s.pop(1); - + literal_vector::iterator it = m_to_assert.begin(); literal_vector::iterator end = m_to_assert.end(); for (; it != end; ++it) { @@ -178,10 +178,10 @@ namespace sat { m_num_assigned(p.m_num_assigned) { m_watch.start(); } - + ~report() { m_watch.stop(); - IF_VERBOSE(SAT_VB_LVL, + IF_VERBOSE(SAT_VB_LVL, verbose_stream() << " (sat-probing :probing-assigned " << (m_probing.m_num_assigned - m_num_assigned) << " :cost " << m_probing.m_counter; @@ -189,7 +189,7 @@ namespace sat { verbose_stream() << mem_stat() << " :time " << std::fixed << std::setprecision(2) << m_watch.get_seconds() << ")\n";); } }; - + bool probing::operator()(bool force) { if (!m_probing) return true; @@ -200,8 +200,8 @@ namespace sat { CASSERT("probing", s.check_invariant()); if (!force && m_counter > 0) return true; - - if (m_probing_cache && memory::get_allocation_size() > m_probing_cache_limit) + + if (m_probing_cache && memory::get_allocation_size() > m_probing_cache_limit) m_cached_bins.finalize(); report rpt(*this); @@ -256,14 +256,14 @@ namespace sat { } void probing::free_memory() { - m_assigned.cleanup(); + m_assigned.finalize(); m_to_assert.finalize(); } - + void probing::collect_statistics(statistics & st) const { st.update("probing assigned", m_num_assigned); } - + void probing::reset_statistics() { m_num_assigned = 0; } diff --git a/src/sat/sat_simplifier.cpp b/src/sat/sat_simplifier.cpp index b200524e7..151bdf45b 100644 --- a/src/sat/sat_simplifier.cpp +++ b/src/sat/sat_simplifier.cpp @@ -63,6 +63,7 @@ namespace sat { } simplifier::~simplifier() { + free_memory(); } inline watch_list & simplifier::get_wlist(literal l) { return s.get_wlist(l); } @@ -96,7 +97,7 @@ namespace sat { inline void simplifier::remove_clause_core(clause & c) { unsigned sz = c.size(); for (unsigned i = 0; i < sz; i++) - insert_todo(c[i].var()); + insert_elim_todo(c[i].var()); m_sub_todo.erase(c); c.set_removed(true); TRACE("resolution_bug", tout << "del_clause: " << c << "\n";); @@ -116,6 +117,7 @@ namespace sat { inline void simplifier::remove_bin_clause_half(literal l1, literal l2, bool learned) { SASSERT(s.get_wlist(~l1).contains(watched(l2, learned))); s.get_wlist(~l1).erase(watched(l2, learned)); + m_sub_bin_todo.erase(bin_clause(l1, l2, learned)); } void simplifier::init_visited() { @@ -127,27 +129,36 @@ namespace sat { m_use_list.finalize(); m_sub_todo.finalize(); m_sub_bin_todo.finalize(); + m_elim_todo.finalize(); m_visited.finalize(); m_bs_cs.finalize(); m_bs_ls.finalize(); } + void simplifier::initialize() { + m_need_cleanup = false; + s.m_cleaner(true); + m_last_sub_trail_sz = s.m_trail.size(); + m_use_list.init(s.num_vars()); + m_sub_todo.reset(); + m_sub_bin_todo.reset(); + m_elim_todo.reset(); + init_visited(); + TRACE("after_cleanup", s.display(tout);); + CASSERT("sat_solver", s.check_invariant()); + } + void simplifier::operator()(bool learned) { if (s.inconsistent()) return; if (!m_subsumption && !m_elim_blocked_clauses && !m_resolution) return; + initialize(); + CASSERT("sat_solver", s.check_invariant()); TRACE("before_simplifier", s.display(tout);); - s.m_cleaner(true); - m_last_sub_trail_sz = s.m_trail.size(); - TRACE("after_cleanup", s.display(tout);); - CASSERT("sat_solver", s.check_invariant()); - m_need_cleanup = false; - m_use_list.init(s.num_vars()); - init_visited(); bool learned_in_use_lists = false; if (learned) { register_clauses(s.m_learned); @@ -158,7 +169,6 @@ namespace sat { if (!learned && (m_elim_blocked_clauses || m_elim_blocked_clauses_at == m_num_calls)) elim_blocked_clauses(); - if (!learned) m_num_calls++; @@ -617,7 +627,7 @@ namespace sat { TRACE("elim_lit", tout << "processing: " << c << "\n";); m_need_cleanup = true; m_num_elim_lits++; - insert_todo(l.var()); + insert_elim_todo(l.var()); c.elim(l); clause_use_list & occurs = m_use_list.get(l); occurs.erase_not_removed(c); @@ -920,7 +930,7 @@ namespace sat { void process(literal l) { TRACE("blocked_clause", tout << "processing: " << l << "\n";); model_converter::entry * new_entry = 0; - if (s.is_external(l.var()) || s.was_eliminated(l.var())) + if (s.is_external(l.var()) || s.was_eliminated(l.var())) return; { @@ -1235,12 +1245,14 @@ namespace sat { for (; it2 != end2; ++it2) { if (it2->is_binary_clause() && it2->get_literal() == l) { TRACE("bin_clause_bug", tout << "removing: " << l << " " << it2->get_literal() << "\n";); + m_sub_bin_todo.erase(bin_clause(l2, l, it2->is_learned())); continue; } *itprev = *it2; itprev++; } wlist2.set_end(itprev); + m_sub_bin_todo.erase(bin_clause(l, l2, it->is_learned())); } } TRACE("bin_clause_bug", tout << "collapsing watch_list of: " << l << "\n";); @@ -1343,7 +1355,7 @@ namespace sat { } TRACE("resolution", tout << "found var to eliminate, before: " << before_clauses << " after: " << after_clauses << "\n";); - + // eliminate variable model_converter::entry & mc_entry = s.m_mc.mk(model_converter::ELIM_VAR, v); save_clauses(mc_entry, m_pos_cls); diff --git a/src/sat/sat_simplifier.h b/src/sat/sat_simplifier.h index 85922cf7c..f0f78b9c2 100644 --- a/src/sat/sat_simplifier.h +++ b/src/sat/sat_simplifier.h @@ -9,7 +9,7 @@ Abstract: SAT simplification procedures that use a "full" occurrence list: Subsumption, Blocked Clause Removal, Variable Elimination, ... - + Author: @@ -83,7 +83,7 @@ namespace sat { bool m_subsumption; unsigned m_subsumption_limit; bool m_elim_vars; - + // stats unsigned m_num_blocked_clauses; unsigned m_num_subsumed; @@ -97,6 +97,8 @@ namespace sat { void checkpoint(); + void initialize(); + void init_visited(); void mark_visited(literal l) { m_visited[l.index()] = true; } void unmark_visited(literal l) { m_visited[l.index()] = false; } @@ -135,7 +137,7 @@ namespace sat { void mark_as_not_learned_core(watch_list & wlist, literal l2); void mark_as_not_learned(literal l1, literal l2); void subsume(); - + void cleanup_watches(); void cleanup_clauses(clause_vector & cs, bool learned, bool vars_eliminated, bool in_use_lists); @@ -145,7 +147,7 @@ namespace sat { lbool value(literal l) const; watch_list & get_wlist(literal l); watch_list const & get_wlist(literal l) const; - + struct blocked_clause_elim; void elim_blocked_clauses(); @@ -172,14 +174,19 @@ namespace sat { simplifier(solver & s, params_ref const & p); ~simplifier(); - void insert_todo(bool_var v) { m_elim_todo.insert(v); } - void reset_todo() { m_elim_todo.reset(); } + void insert_elim_todo(bool_var v) { m_elim_todo.insert(v); } + + void reset_todos() { + m_elim_todo.reset(); + m_sub_todo.reset(); + m_sub_bin_todo.reset(); + } void operator()(bool learned); void updt_params(params_ref const & p); static void collect_param_descrs(param_descrs & d); - + void free_memory(); void collect_statistics(statistics & st) const; diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index e0bb0f2a3..1aede522a 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -141,7 +141,7 @@ namespace sat { m_prev_phase.push_back(PHASE_NOT_AVAILABLE); m_assigned_since_gc.push_back(false); m_case_split_queue.mk_var_eh(v); - m_simplifier.insert_todo(v); + m_simplifier.insert_elim_todo(v); SASSERT(!was_eliminated(v)); return v; } @@ -151,7 +151,7 @@ namespace sat { for (unsigned i = 0; i < num_lits; i++) SASSERT(m_eliminated[lits[i].var()] == false); }); - + if (m_user_scope_literals.empty()) { mk_clause_core(num_lits, lits, false); } @@ -175,8 +175,8 @@ namespace sat { void solver::del_clause(clause& c) { if (!c.is_learned()) m_stats.m_non_learned_generation++; - m_cls_allocator.del_clause(&c); - m_stats.m_del_clause++; + m_cls_allocator.del_clause(&c); + m_stats.m_del_clause++; } clause * solver::mk_clause_core(unsigned num_lits, literal * lits, bool learned) { @@ -188,7 +188,7 @@ namespace sat { return 0; // clause is equivalent to true. } ++m_stats.m_non_learned_generation; - } + } switch (num_lits) { case 0: @@ -739,10 +739,10 @@ namespace sat { m_restart_threshold = m_config.m_restart_initial; } - // iff3_finder(*this)(); + // iff3_finder(*this)(); simplify_problem(); if (check_inconsistent()) return l_false; - + if (m_config.m_max_conflicts == 0) { IF_VERBOSE(SAT_VB_LVL, verbose_stream() << "(sat \"abort: max-conflicts = 0\")\n";); @@ -763,7 +763,7 @@ namespace sat { restart(); simplify_problem(); - if (check_inconsistent()) return l_false; + if (check_inconsistent()) return l_false; gc(); } } @@ -891,7 +891,7 @@ namespace sat { else { mk_model(); return l_true; - } + } } @@ -920,8 +920,8 @@ namespace sat { return; } - TRACE("sat", - for (unsigned i = 0; i < num_lits; ++i) + TRACE("sat", + for (unsigned i = 0; i < num_lits; ++i) tout << lits[i] << " "; tout << "\n"; if (!m_user_scope_literals.empty()) { @@ -932,7 +932,7 @@ namespace sat { for (unsigned i = 0; !inconsistent() && i < m_user_scope_literals.size(); ++i) { literal nlit = ~m_user_scope_literals[i]; - assign(nlit, justification()); + assign(nlit, justification()); } if (weights && !inconsistent()) { @@ -947,9 +947,9 @@ namespace sat { for (unsigned i = 0; !inconsistent() && i < num_lits; ++i) { literal lit = lits[i]; - SASSERT(is_external(lit.var())); - add_assumption(lit); - assign(lit, justification()); + SASSERT(is_external(lit.var())); + add_assumption(lit); + assign(lit, justification()); } } @@ -962,10 +962,10 @@ namespace sat { unsigned num_cores = 0; for (unsigned i = 0; !inconsistent() && i < num_lits; ++i) { literal lit = lits[i]; - SASSERT(is_external(lit.var())); + SASSERT(is_external(lit.var())); TRACE("sat", tout << "propagate: " << lit << " " << value(lit) << "\n";); SASSERT(m_scope_lvl == 1); - add_assumption(lit); + add_assumption(lit); switch(value(lit)) { case l_undef: values.push_back(l_true); @@ -973,10 +973,10 @@ namespace sat { if (num_cores*2 >= num_lits) { break; } - propagate(false); + propagate(false); if (inconsistent()) { flet _init(m_initializing_preferred, true); - while (inconsistent()) { + while (inconsistent()) { if (!resolve_conflict()) { return true; } @@ -1001,15 +1001,15 @@ namespace sat { for (unsigned k = i; k >= j; --k) { if (is_assumption(lits[k])) { pop_assumption(); - } + } } values.resize(j); TRACE("sat", tout << "backjump " << (i - j + 1) << " steps " << num_cores << "\n";); i = j - 1; } - break; - - case l_false: + break; + + case l_false: ++num_cores; values.push_back(l_false); SASSERT(!inconsistent()); @@ -1028,14 +1028,14 @@ namespace sat { SASSERT(m_assumptions.size() <= i+1); if (m_core.size() <= 3) { m_inconsistent = true; - TRACE("opt", tout << "found small core: " << m_core << "\n";); + TRACE("opt", tout << "found small core: " << m_core << "\n";); IF_VERBOSE(11, verbose_stream() << "(sat.core: " << m_core << ")\n";); return true; } pop_assumption(); - m_inconsistent = false; + m_inconsistent = false; break; - case l_true: + case l_true: values.push_back(l_true); SASSERT(m_justification[lit.var()].get_kind() != justification::NONE || lvl(lit) == 0); break; @@ -1046,7 +1046,7 @@ namespace sat { if (m_weight >= max_weight) { // block the current correction set candidate. ++m_stats.m_blocked_corr_sets; - TRACE("opt", tout << "blocking soft correction set: " << m_blocker << "\n";); + TRACE("opt", tout << "blocking soft correction set: " << m_blocker << "\n";); IF_VERBOSE(11, verbose_stream() << "blocking " << m_blocker << "\n";); pop_to_base_level(); mk_clause_core(m_blocker); @@ -1062,17 +1062,17 @@ namespace sat { m_min_core.reset(); m_min_core.append(m_core); m_min_core_valid = true; - } + } } void solver::reset_assumptions() { m_assumptions.reset(); - m_assumption_set.reset(); + m_assumption_set.reset(); } void solver::add_assumption(literal lit) { - m_assumption_set.insert(lit); - m_assumptions.push_back(lit); + m_assumption_set.insert(lit); + m_assumptions.push_back(lit); } void solver::pop_assumption() { @@ -1089,8 +1089,8 @@ namespace sat { for (unsigned i = 0; i < m_min_core.size(); ++i) { literal lit = m_min_core[i]; SASSERT(is_external(lit.var())); - add_assumption(lit); - assign(lit, justification()); + add_assumption(lit); + assign(lit, justification()); } propagate(false); SASSERT(inconsistent()); @@ -1132,7 +1132,7 @@ namespace sat { m_min_core_valid = false; m_min_core.reset(); TRACE("sat", display(tout);); - + if (m_config.m_bcd) { bceq bc(*this); bc(); @@ -1149,11 +1149,11 @@ namespace sat { } IF_VERBOSE(2, verbose_stream() << "(sat.simplify)\n";); - // Disable simplification during MUS computation. + // Disable simplification during MUS computation. // if (m_mus.is_active()) return; TRACE("sat", tout << "simplify\n";); - pop(scope_lvl()); + pop(scope_lvl()); SASSERT(scope_lvl() == 0); @@ -1166,7 +1166,7 @@ namespace sat { m_simplifier(false); CASSERT("sat_simplify_bug", check_invariant()); CASSERT("sat_missed_prop", check_missed_propagation()); - + if (!m_learned.empty()) { m_simplifier(true); CASSERT("sat_missed_prop", check_missed_propagation()); @@ -1260,7 +1260,7 @@ namespace sat { TRACE("sat", tout << "failed: " << c << "\n"; tout << "assumptions: " << m_assumptions << "\n"; tout << "trail: " << m_trail << "\n"; - tout << "model: " << m << "\n"; + tout << "model: " << m << "\n"; m_mc.display(tout); ); ok = false; @@ -1289,10 +1289,10 @@ namespace sat { } for (unsigned i = 0; i < m_assumptions.size(); ++i) { if (value_at(m_assumptions[i], m) != l_true) { - TRACE("sat", + TRACE("sat", tout << m_assumptions[i] << " does not model check\n"; tout << "trail: " << m_trail << "\n"; - tout << "model: " << m << "\n"; + tout << "model: " << m << "\n"; m_mc.display(tout); ); ok = false; @@ -1664,7 +1664,7 @@ namespace sat { resolve_conflict_for_unsat_core(); return false; } - + if (m_conflict_lvl == 0) { return false; } @@ -1849,11 +1849,11 @@ namespace sat { bool solver::resolve_conflict_for_init() { if (m_conflict_lvl == 0) { return false; - } + } m_lemma.reset(); m_lemma.push_back(null_literal); // asserted literal if (m_not_l != null_literal) { - TRACE("sat", tout << "not_l: " << m_not_l << "\n";); + TRACE("sat", tout << "not_l: " << m_not_l << "\n";); process_antecedent_for_init(m_not_l); } literal consequent = m_not_l; @@ -1988,7 +1988,7 @@ namespace sat { SASSERT(!is_marked(m_trail[i].var())); }}); - unsigned old_size = m_unmark.size(); + unsigned old_size = m_unmark.size(); int idx = skip_literals_above_conflict_level(); if (m_not_l != null_literal) { @@ -2005,7 +2005,7 @@ namespace sat { process_consequent_for_unsat_core(m_not_l, js); } } - + literal consequent = m_not_l; justification js = m_conflict; @@ -2031,7 +2031,7 @@ namespace sat { SASSERT(lvl(consequent) == m_conflict_lvl); js = m_justification[c_var]; idx--; - } + } reset_unmark(old_size); if (m_config.m_core_minimize) { if (m_min_core_valid && m_min_core.size() < m_core.size()) { @@ -2039,7 +2039,7 @@ namespace sat { m_core.reset(); m_core.append(m_min_core); } - // TBD: + // TBD: // apply optional clause minimization by detecting subsumed literals. // initial experiment suggests it has no effect. m_mus(); // ignore return value on cancelation. @@ -2511,7 +2511,7 @@ namespace sat { void solver::pop_reinit(unsigned num_scopes) { pop(num_scopes); - reinit_assumptions(); + reinit_assumptions(); } void solver::pop(unsigned num_scopes) { @@ -2578,13 +2578,13 @@ namespace sat { m_clauses_to_reinit.shrink(j); } - // + // // All new clauses that are added to the solver // are relative to the user-scope literals. - // + // void solver::user_push() { - literal lit; + literal lit; bool_var new_v = mk_var(true, false); lit = literal(new_v, false); m_user_scope_literals.push_back(lit); @@ -2674,7 +2674,7 @@ namespace sat { m_phase.shrink(v); m_prev_phase.shrink(v); m_assigned_since_gc.shrink(v); - m_simplifier.reset_todo(); + m_simplifier.reset_todos(); } } @@ -2698,7 +2698,7 @@ namespace sat { unassign_vars(i); break; } - } + } gc_var(lit.var()); } } @@ -3080,10 +3080,10 @@ namespace sat { } bool non_empty = true; m_seen[0].reset(); - while (non_empty) { + while (non_empty) { literal_vector mutex; bool turn = false; - m_reachable[turn] = ps; + m_reachable[turn] = ps; while (!m_reachable[turn].empty()) { literal p = m_reachable[turn].pop(); if (m_seen[0].contains(p)) { @@ -3100,7 +3100,7 @@ namespace sat { turn = !turn; } if (mutex.size() > 1) { - mutexes.push_back(mutex); + mutexes.push_back(mutex); } non_empty = !mutex.empty(); } @@ -3144,7 +3144,7 @@ namespace sat { switch (get_model()[v]) { case l_true: lits.push_back(literal(v, false)); break; case l_false: lits.push_back(literal(v, true)); break; - default: break; + default: break; } } is_sat = get_consequences(asms, lits, conseq); @@ -3171,7 +3171,7 @@ namespace sat { } propagate(false); if (check_inconsistent()) return l_false; - + unsigned num_units = 0, num_iterations = 0; extract_fixed_consequences(num_units, assumptions, vars, conseq); while (!vars.empty()) { @@ -3188,14 +3188,14 @@ namespace sat { push(); assign(~lit, justification()); propagate(false); - while (inconsistent()) { + while (inconsistent()) { if (!resolve_conflict()) { TRACE("sat", display(tout << "inconsistent\n");); m_inconsistent = false; is_sat = l_undef; break; } - propagate(false); + propagate(false); ++num_resolves; } if (scope_lvl() == 1) { @@ -3209,7 +3209,7 @@ namespace sat { else { is_sat = bounded_search(); if (is_sat == l_undef) { - restart(); + restart(); } } } @@ -3220,7 +3220,7 @@ namespace sat { if (is_sat == l_true) { delete_unfixed(vars); } - extract_fixed_consequences(num_units, assumptions, vars, conseq); + extract_fixed_consequences(num_units, assumptions, vars, conseq); IF_VERBOSE(1, verbose_stream() << "(sat.get-consequences" << " iterations: " << num_iterations << " variables: " << vars.size() @@ -3240,10 +3240,10 @@ namespace sat { if (value(lit) == l_true) { to_keep.insert(lit); } - } + } unfixed = to_keep; } - + void solver::extract_fixed_consequences(unsigned& start, literal_set const& assumptions, literal_set& unfixed, vector& conseq) { if (scope_lvl() > 1) { pop(scope_lvl() - 1); @@ -3293,7 +3293,7 @@ namespace sat { } void solver::extract_fixed_consequences(literal lit, literal_set const& assumptions, literal_set& unfixed, vector& conseq) { - index_set s; + index_set s; if (assumptions.contains(lit)) { s.insert(lit.index()); } diff --git a/src/sat/sat_types.h b/src/sat/sat_types.h index 00edaa593..509cc58ba 100644 --- a/src/sat/sat_types.h +++ b/src/sat/sat_types.h @@ -200,7 +200,7 @@ namespace sat { iterator begin() const { return m_set.begin(); } iterator end() const { return m_set.end(); } void reset() { m_set.reset(); m_in_set.reset(); } - void cleanup() { m_set.finalize(); m_in_set.finalize(); } + void finalize() { m_set.finalize(); m_in_set.finalize(); } uint_set& operator&=(uint_set const& other) { unsigned j = 0; for (unsigned i = 0; i < m_set.size(); ++i) { @@ -259,7 +259,7 @@ namespace sat { bool empty() const { return m_set.empty(); } unsigned size() const { return m_set.size(); } void reset() { m_set.reset(); } - void cleanup() { m_set.cleanup(); } + void finalize() { m_set.finalize(); } class iterator { uint_set::iterator m_it; public: From 22c9b9a79756b47196dca1f5c22e3a14881a04d7 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Wed, 9 Nov 2016 18:06:53 +0000 Subject: [PATCH 355/536] Fixed compiler warning --- src/sat/sat_clause.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sat/sat_clause.h b/src/sat/sat_clause.h index 1aededbb6..27a0ed739 100644 --- a/src/sat/sat_clause.h +++ b/src/sat/sat_clause.h @@ -107,8 +107,8 @@ namespace sat { literal get_literal2() const { return to_literal(m_val2 >> 1); } bool is_learned() const { return (m_val2 & 1) == 1; } bool operator==(const bin_clause & other) const { - return m_val1 == other.m_val1 && m_val2 == other.m_val2 || - m_val1 == other.m_val2 && m_val2 == other.m_val1; + return (m_val1 == other.m_val1 && m_val2 == other.m_val2) || + (m_val1 == other.m_val2 && m_val2 == other.m_val1); } }; From 40d90a951c56c273764897ec7dad051ecb5326ba Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Thu, 10 Nov 2016 16:52:56 +0000 Subject: [PATCH 356/536] Fixed interruption cleanup bug in sat_solver. Relates to #570. --- src/sat/sat_solver.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index 85836b889..c0d736ebf 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -237,7 +237,10 @@ namespace sat { lbool status(clause const & c) const; clause_offset get_offset(clause const & c) const { return m_cls_allocator.get_offset(&c); } void checkpoint() { - if (!m_rlimit.inc()) { throw solver_exception(Z3_CANCELED_MSG); } + if (!m_rlimit.inc()) { + m_mc.reset(); + throw solver_exception(Z3_CANCELED_MSG); + } ++m_num_checkpoints; if (m_num_checkpoints < 10) return; m_num_checkpoints = 0; From d66530a11291700b02fb465d2536dd2e2576eb70 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Thu, 10 Nov 2016 17:06:55 +0000 Subject: [PATCH 357/536] Fixed potential SAT solver cleanup problem. Renamed functions for consistency. Relates to #570. --- src/sat/sat_probing.cpp | 5 +++-- src/sat/sat_probing.h | 2 +- src/sat/sat_simplifier.cpp | 10 ++++++---- src/sat/sat_simplifier.h | 2 +- src/sat/sat_solver.cpp | 2 +- src/sat/sat_solver.h | 1 + 6 files changed, 13 insertions(+), 9 deletions(-) diff --git a/src/sat/sat_probing.cpp b/src/sat/sat_probing.cpp index c00b68ac2..0b5edb2c9 100644 --- a/src/sat/sat_probing.cpp +++ b/src/sat/sat_probing.cpp @@ -239,7 +239,7 @@ namespace sat { m_counter *= 2; } CASSERT("probing", s.check_invariant()); - free_memory(); + finalize(); return r; } @@ -255,9 +255,10 @@ namespace sat { // TODO } - void probing::free_memory() { + void probing::finalize() { m_assigned.finalize(); m_to_assert.finalize(); + m_cached_bins.finalize(); } void probing::collect_statistics(statistics & st) const { diff --git a/src/sat/sat_probing.h b/src/sat/sat_probing.h index daf6817e3..cce165a34 100644 --- a/src/sat/sat_probing.h +++ b/src/sat/sat_probing.h @@ -69,7 +69,7 @@ namespace sat { void updt_params(params_ref const & p); static void collect_param_descrs(param_descrs & d); - void free_memory(); + void finalize(); void collect_statistics(statistics & st) const; void reset_statistics(); diff --git a/src/sat/sat_simplifier.cpp b/src/sat/sat_simplifier.cpp index 151bdf45b..f46540b89 100644 --- a/src/sat/sat_simplifier.cpp +++ b/src/sat/sat_simplifier.cpp @@ -63,7 +63,7 @@ namespace sat { } simplifier::~simplifier() { - free_memory(); + finalize(); } inline watch_list & simplifier::get_wlist(literal l) { return s.get_wlist(l); } @@ -125,7 +125,7 @@ namespace sat { m_visited.resize(2*s.num_vars(), false); } - void simplifier::free_memory() { + void simplifier::finalize() { m_use_list.finalize(); m_sub_todo.finalize(); m_sub_bin_todo.finalize(); @@ -154,6 +154,7 @@ namespace sat { if (!m_subsumption && !m_elim_blocked_clauses && !m_resolution) return; + initialize(); CASSERT("sat_solver", s.check_invariant()); @@ -166,6 +167,7 @@ namespace sat { } register_clauses(s.m_clauses); + if (!learned && (m_elim_blocked_clauses || m_elim_blocked_clauses_at == m_num_calls)) elim_blocked_clauses(); @@ -207,7 +209,7 @@ namespace sat { } CASSERT("sat_solver", s.check_invariant()); TRACE("after_simplifier", s.display(tout); tout << "model_converter:\n"; s.m_mc.display(tout);); - free_memory(); + finalize(); } /** @@ -932,8 +934,8 @@ namespace sat { model_converter::entry * new_entry = 0; if (s.is_external(l.var()) || s.was_eliminated(l.var())) return; - { + { m_to_remove.reset(); { clause_use_list & occs = s.m_use_list.get(l); diff --git a/src/sat/sat_simplifier.h b/src/sat/sat_simplifier.h index f0f78b9c2..9ee239083 100644 --- a/src/sat/sat_simplifier.h +++ b/src/sat/sat_simplifier.h @@ -187,7 +187,7 @@ namespace sat { void updt_params(params_ref const & p); static void collect_param_descrs(param_descrs & d); - void free_memory(); + void finalize(); void collect_statistics(statistics & st) const; void reset_statistics(); diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 1aede522a..f1f6a6aa8 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -3042,7 +3042,7 @@ namespace sat { if (scope_lvl() > 0 || inconsistent()) return; m_simplifier(learned); - m_simplifier.free_memory(); + m_simplifier.finalize(); if (m_ext) m_ext->clauses_modifed(); } diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index c0d736ebf..a44f07a23 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -239,6 +239,7 @@ namespace sat { void checkpoint() { if (!m_rlimit.inc()) { m_mc.reset(); + m_model_is_current = false; throw solver_exception(Z3_CANCELED_MSG); } ++m_num_checkpoints; From 2df5a4e3f9df926b5d29eab0b5aaddbe4827aeb3 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Sat, 12 Nov 2016 15:01:54 +0000 Subject: [PATCH 358/536] typo --- src/api/z3_replayer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/z3_replayer.cpp b/src/api/z3_replayer.cpp index 277fedb4a..e5fbf5720 100644 --- a/src/api/z3_replayer.cpp +++ b/src/api/z3_replayer.cpp @@ -30,7 +30,7 @@ void register_z3_replayer_cmds(z3_replayer & in); void throw_invalid_reference() { TRACE("z3_replayer", tout << "invalid argument reference\n";); - throw z3_replayer_exception("invalid argument reference1"); + throw z3_replayer_exception("invalid argument reference"); } struct z3_replayer::imp { From e0613b673749538807d66fb5e0bb99299af4a767 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 12 Nov 2016 08:58:03 -0800 Subject: [PATCH 359/536] fix crash reported in #784 Signed-off-by: Nikolaj Bjorner --- src/sat/sat_simplifier.cpp | 2 ++ src/sat/sat_solver.cpp | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/src/sat/sat_simplifier.cpp b/src/sat/sat_simplifier.cpp index b200524e7..2a1930f4f 100644 --- a/src/sat/sat_simplifier.cpp +++ b/src/sat/sat_simplifier.cpp @@ -141,6 +141,8 @@ namespace sat { CASSERT("sat_solver", s.check_invariant()); TRACE("before_simplifier", s.display(tout);); + m_sub_todo.reset(); + m_sub_bin_todo.reset(); s.m_cleaner(true); m_last_sub_trail_sz = s.m_trail.size(); TRACE("after_cleanup", s.display(tout);); diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index e0bb0f2a3..68c42f712 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -3078,6 +3078,10 @@ namespace sat { m_binary_clause_graph[l1.index()].push_back(l2); m_binary_clause_graph[l2.index()].push_back(l1); } + for (unsigned i = 0; i < lits.size(); ++i) { + m_binary_clause_graph.reserve(lits[i].index() + 1); + m_binary_clause_graph.reserve((~lits[i]).index() + 1); + } bool non_empty = true; m_seen[0].reset(); while (non_empty) { From 6204f67d38e63273d501e6c9eed435d2e7ec6c32 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Mon, 14 Nov 2016 17:40:09 +0000 Subject: [PATCH 360/536] Fixed problems with aborted rewriters in theory_fpa. Relates to #570. --- src/smt/theory_fpa.cpp | 96 ++++++++++++++++++++++++++++++++++-------- 1 file changed, 79 insertions(+), 17 deletions(-) diff --git a/src/smt/theory_fpa.cpp b/src/smt/theory_fpa.cpp index b0b8ffff5..89acc0ecf 100644 --- a/src/smt/theory_fpa.cpp +++ b/src/smt/theory_fpa.cpp @@ -238,7 +238,14 @@ namespace smt { 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); + + try { + m_th_rw((expr_ref&)res); + } + catch (rewriter_exception &) { + m_th_rw.reset(); + throw; + } } else { sort * es = m.get_sort(e); @@ -295,8 +302,15 @@ namespace smt { 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); - m_th_rw(res, res); + try { + m_rw(e, res); + m_th_rw(res, res); + } + catch (rewriter_exception &) { + m_rw.reset(); + m_th_rw.reset(); + throw; + } SASSERT(is_app(res)); SASSERT(m.is_bool(res)); return res; @@ -308,7 +322,14 @@ namespace smt { expr_ref e_conv(m), res(m); proof_ref pr(m); - m_rw(e, e_conv); + + try { + m_rw(e, e_conv); + } + catch (rewriter_exception &) { + m_rw.reset(); + throw; + } 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;); @@ -338,8 +359,15 @@ namespace smt { SASSERT(to_app(e)->get_family_id() == get_family_id()); /* This is for the conversion functions fp.to_* */ expr_ref res(get_manager()); - m_rw(e, res); - m_th_rw(res, res); + try { + m_rw(e, res); + m_th_rw(res, res); + } + catch (rewriter_exception &) { + m_rw.reset(); + m_th_rw.reset(); + throw; + } return res; } @@ -396,7 +424,14 @@ namespace smt { res = m.mk_and(res, t); } m_converter.m_extra_assertions.reset(); - m_th_rw(res); + + try { + m_th_rw(res); + } + catch (rewriter_exception &) { + m_th_rw.reset(); + throw; + } CTRACE("t_fpa", !m.is_true(res), tout << "side condition: " << mk_ismt2_pp(res, m) << std::endl;); return res; @@ -439,7 +474,15 @@ namespace smt { expr_ref bv_atom(convert_atom(atom)); expr_ref bv_atom_w_side_c(m), atom_eq(m); bv_atom_w_side_c = m.mk_and(bv_atom, mk_side_conditions()); - m_th_rw(bv_atom_w_side_c); + + try { + m_th_rw(bv_atom_w_side_c); + } + catch (rewriter_exception &) { + m_th_rw.reset(); + throw; + } + atom_eq = m.mk_eq(atom, bv_atom_w_side_c); assert_cnstr(atom_eq); return true; @@ -550,7 +593,14 @@ namespace smt { else c = m.mk_eq(xc, yc); - m_th_rw(c); + try { + m_th_rw(c); + } + catch (rewriter_exception &) { + m_th_rw.reset(); + throw; + } + expr_ref xe_eq_ye(m), c_eq_iff(m); xe_eq_ye = m.mk_eq(xe, ye); c_eq_iff = m.mk_iff(xe_eq_ye, c); @@ -595,7 +645,13 @@ namespace smt { c = m.mk_not(xc_eq_yc); } - m_th_rw(c); + try { + m_th_rw(c); + } + catch (rewriter_exception &) { + m_th_rw.reset(); + throw; + } expr_ref xe_eq_ye(m), not_xe_eq_ye(m), c_eq_iff(m); xe_eq_ye = m.mk_eq(xe, ye); @@ -634,7 +690,13 @@ namespace smt { expr_ref cnstr(m); cnstr = (is_true) ? m.mk_implies(e, converted) : m.mk_implies(converted, e); - m_th_rw(cnstr); + try { + m_th_rw(cnstr); + } + catch (rewriter_exception &) { + m_th_rw.reset(); + throw; + } assert_cnstr(cnstr); } @@ -802,30 +864,30 @@ namespace smt { ast_manager & m = get_manager(); proto_model & mdl = mg.get_model(); proto_model new_model(m); - + bv2fpa_converter bv2fp(m, m_converter); - + obj_hashtable seen; bv2fp.convert_min_max_specials(&mdl, &new_model, seen); bv2fp.convert_uf2bvuf(&mdl, &new_model, seen); - + for (obj_hashtable::iterator it = seen.begin(); it != seen.end(); it++) mdl.unregister_decl(*it); - + for (unsigned i = 0; i < new_model.get_num_constants(); i++) { func_decl * f = new_model.get_constant(i); mdl.register_decl(f, new_model.get_const_interp(f)); } - + for (unsigned i = 0; i < new_model.get_num_functions(); i++) { func_decl * f = new_model.get_function(i); func_interp * fi = new_model.get_func_interp(f)->copy(); mdl.register_decl(f, fi); } } - + void theory_fpa::display(std::ostream & out) const { ast_manager & m = get_manager(); From 890142ef9677e7eb3fcfa2efc7c2ca278e073e3c Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Wed, 9 Nov 2016 18:00:15 +0000 Subject: [PATCH 361/536] Fix cleanup/initialization of sat::simplifier. Relates to #570. --- src/sat/sat_clause.h | 6 +- src/sat/sat_probing.cpp | 18 ++--- src/sat/sat_simplifier.cpp | 29 +++++++-- src/sat/sat_simplifier.h | 21 ++++-- src/sat/sat_solver.cpp | 130 ++++++++++++++++++------------------- src/sat/sat_types.h | 4 +- 6 files changed, 119 insertions(+), 89 deletions(-) diff --git a/src/sat/sat_clause.h b/src/sat/sat_clause.h index 1662b429f..1aededbb6 100644 --- a/src/sat/sat_clause.h +++ b/src/sat/sat_clause.h @@ -102,10 +102,14 @@ namespace sat { unsigned m_val1; unsigned m_val2; public: - bin_clause(literal l1, literal l2, bool learned):m_val1(l1.to_uint()), m_val2((l2.to_uint() << 1) + static_cast(learned)) {} + bin_clause(literal l1, literal l2, bool learned) :m_val1(l1.to_uint()), m_val2((l2.to_uint() << 1) + static_cast(learned)) {} literal get_literal1() const { return to_literal(m_val1); } literal get_literal2() const { return to_literal(m_val2 >> 1); } bool is_learned() const { return (m_val2 & 1) == 1; } + bool operator==(const bin_clause & other) const { + return m_val1 == other.m_val1 && m_val2 == other.m_val2 || + m_val1 == other.m_val2 && m_val2 == other.m_val1; + } }; class tmp_clause { diff --git a/src/sat/sat_probing.cpp b/src/sat/sat_probing.cpp index 165d39ad8..c00b68ac2 100644 --- a/src/sat/sat_probing.cpp +++ b/src/sat/sat_probing.cpp @@ -95,7 +95,7 @@ namespace sat { if (updt_cache) cache_bins(l, old_tr_sz); s.pop(1); - + literal_vector::iterator it = m_to_assert.begin(); literal_vector::iterator end = m_to_assert.end(); for (; it != end; ++it) { @@ -178,10 +178,10 @@ namespace sat { m_num_assigned(p.m_num_assigned) { m_watch.start(); } - + ~report() { m_watch.stop(); - IF_VERBOSE(SAT_VB_LVL, + IF_VERBOSE(SAT_VB_LVL, verbose_stream() << " (sat-probing :probing-assigned " << (m_probing.m_num_assigned - m_num_assigned) << " :cost " << m_probing.m_counter; @@ -189,7 +189,7 @@ namespace sat { verbose_stream() << mem_stat() << " :time " << std::fixed << std::setprecision(2) << m_watch.get_seconds() << ")\n";); } }; - + bool probing::operator()(bool force) { if (!m_probing) return true; @@ -200,8 +200,8 @@ namespace sat { CASSERT("probing", s.check_invariant()); if (!force && m_counter > 0) return true; - - if (m_probing_cache && memory::get_allocation_size() > m_probing_cache_limit) + + if (m_probing_cache && memory::get_allocation_size() > m_probing_cache_limit) m_cached_bins.finalize(); report rpt(*this); @@ -256,14 +256,14 @@ namespace sat { } void probing::free_memory() { - m_assigned.cleanup(); + m_assigned.finalize(); m_to_assert.finalize(); } - + void probing::collect_statistics(statistics & st) const { st.update("probing assigned", m_num_assigned); } - + void probing::reset_statistics() { m_num_assigned = 0; } diff --git a/src/sat/sat_simplifier.cpp b/src/sat/sat_simplifier.cpp index 2a1930f4f..3e817b2a9 100644 --- a/src/sat/sat_simplifier.cpp +++ b/src/sat/sat_simplifier.cpp @@ -63,6 +63,7 @@ namespace sat { } simplifier::~simplifier() { + free_memory(); } inline watch_list & simplifier::get_wlist(literal l) { return s.get_wlist(l); } @@ -96,7 +97,7 @@ namespace sat { inline void simplifier::remove_clause_core(clause & c) { unsigned sz = c.size(); for (unsigned i = 0; i < sz; i++) - insert_todo(c[i].var()); + insert_elim_todo(c[i].var()); m_sub_todo.erase(c); c.set_removed(true); TRACE("resolution_bug", tout << "del_clause: " << c << "\n";); @@ -116,6 +117,7 @@ namespace sat { inline void simplifier::remove_bin_clause_half(literal l1, literal l2, bool learned) { SASSERT(s.get_wlist(~l1).contains(watched(l2, learned))); s.get_wlist(~l1).erase(watched(l2, learned)); + m_sub_bin_todo.erase(bin_clause(l1, l2, learned)); } void simplifier::init_visited() { @@ -127,17 +129,33 @@ namespace sat { m_use_list.finalize(); m_sub_todo.finalize(); m_sub_bin_todo.finalize(); + m_elim_todo.finalize(); m_visited.finalize(); m_bs_cs.finalize(); m_bs_ls.finalize(); } + void simplifier::initialize() { + m_need_cleanup = false; + s.m_cleaner(true); + m_last_sub_trail_sz = s.m_trail.size(); + m_use_list.init(s.num_vars()); + m_sub_todo.reset(); + m_sub_bin_todo.reset(); + m_elim_todo.reset(); + init_visited(); + TRACE("after_cleanup", s.display(tout);); + CASSERT("sat_solver", s.check_invariant()); + } + void simplifier::operator()(bool learned) { if (s.inconsistent()) return; if (!m_subsumption && !m_elim_blocked_clauses && !m_resolution) return; + initialize(); + CASSERT("sat_solver", s.check_invariant()); TRACE("before_simplifier", s.display(tout);); @@ -160,7 +178,6 @@ namespace sat { if (!learned && (m_elim_blocked_clauses || m_elim_blocked_clauses_at == m_num_calls)) elim_blocked_clauses(); - if (!learned) m_num_calls++; @@ -619,7 +636,7 @@ namespace sat { TRACE("elim_lit", tout << "processing: " << c << "\n";); m_need_cleanup = true; m_num_elim_lits++; - insert_todo(l.var()); + insert_elim_todo(l.var()); c.elim(l); clause_use_list & occurs = m_use_list.get(l); occurs.erase_not_removed(c); @@ -922,7 +939,7 @@ namespace sat { void process(literal l) { TRACE("blocked_clause", tout << "processing: " << l << "\n";); model_converter::entry * new_entry = 0; - if (s.is_external(l.var()) || s.was_eliminated(l.var())) + if (s.is_external(l.var()) || s.was_eliminated(l.var())) return; { @@ -1237,12 +1254,14 @@ namespace sat { for (; it2 != end2; ++it2) { if (it2->is_binary_clause() && it2->get_literal() == l) { TRACE("bin_clause_bug", tout << "removing: " << l << " " << it2->get_literal() << "\n";); + m_sub_bin_todo.erase(bin_clause(l2, l, it2->is_learned())); continue; } *itprev = *it2; itprev++; } wlist2.set_end(itprev); + m_sub_bin_todo.erase(bin_clause(l, l2, it->is_learned())); } } TRACE("bin_clause_bug", tout << "collapsing watch_list of: " << l << "\n";); @@ -1345,7 +1364,7 @@ namespace sat { } TRACE("resolution", tout << "found var to eliminate, before: " << before_clauses << " after: " << after_clauses << "\n";); - + // eliminate variable model_converter::entry & mc_entry = s.m_mc.mk(model_converter::ELIM_VAR, v); save_clauses(mc_entry, m_pos_cls); diff --git a/src/sat/sat_simplifier.h b/src/sat/sat_simplifier.h index 85922cf7c..f0f78b9c2 100644 --- a/src/sat/sat_simplifier.h +++ b/src/sat/sat_simplifier.h @@ -9,7 +9,7 @@ Abstract: SAT simplification procedures that use a "full" occurrence list: Subsumption, Blocked Clause Removal, Variable Elimination, ... - + Author: @@ -83,7 +83,7 @@ namespace sat { bool m_subsumption; unsigned m_subsumption_limit; bool m_elim_vars; - + // stats unsigned m_num_blocked_clauses; unsigned m_num_subsumed; @@ -97,6 +97,8 @@ namespace sat { void checkpoint(); + void initialize(); + void init_visited(); void mark_visited(literal l) { m_visited[l.index()] = true; } void unmark_visited(literal l) { m_visited[l.index()] = false; } @@ -135,7 +137,7 @@ namespace sat { void mark_as_not_learned_core(watch_list & wlist, literal l2); void mark_as_not_learned(literal l1, literal l2); void subsume(); - + void cleanup_watches(); void cleanup_clauses(clause_vector & cs, bool learned, bool vars_eliminated, bool in_use_lists); @@ -145,7 +147,7 @@ namespace sat { lbool value(literal l) const; watch_list & get_wlist(literal l); watch_list const & get_wlist(literal l) const; - + struct blocked_clause_elim; void elim_blocked_clauses(); @@ -172,14 +174,19 @@ namespace sat { simplifier(solver & s, params_ref const & p); ~simplifier(); - void insert_todo(bool_var v) { m_elim_todo.insert(v); } - void reset_todo() { m_elim_todo.reset(); } + void insert_elim_todo(bool_var v) { m_elim_todo.insert(v); } + + void reset_todos() { + m_elim_todo.reset(); + m_sub_todo.reset(); + m_sub_bin_todo.reset(); + } void operator()(bool learned); void updt_params(params_ref const & p); static void collect_param_descrs(param_descrs & d); - + void free_memory(); void collect_statistics(statistics & st) const; diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 68c42f712..5bc9e4ed9 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -141,7 +141,7 @@ namespace sat { m_prev_phase.push_back(PHASE_NOT_AVAILABLE); m_assigned_since_gc.push_back(false); m_case_split_queue.mk_var_eh(v); - m_simplifier.insert_todo(v); + m_simplifier.insert_elim_todo(v); SASSERT(!was_eliminated(v)); return v; } @@ -151,7 +151,7 @@ namespace sat { for (unsigned i = 0; i < num_lits; i++) SASSERT(m_eliminated[lits[i].var()] == false); }); - + if (m_user_scope_literals.empty()) { mk_clause_core(num_lits, lits, false); } @@ -175,8 +175,8 @@ namespace sat { void solver::del_clause(clause& c) { if (!c.is_learned()) m_stats.m_non_learned_generation++; - m_cls_allocator.del_clause(&c); - m_stats.m_del_clause++; + m_cls_allocator.del_clause(&c); + m_stats.m_del_clause++; } clause * solver::mk_clause_core(unsigned num_lits, literal * lits, bool learned) { @@ -188,7 +188,7 @@ namespace sat { return 0; // clause is equivalent to true. } ++m_stats.m_non_learned_generation; - } + } switch (num_lits) { case 0: @@ -739,10 +739,10 @@ namespace sat { m_restart_threshold = m_config.m_restart_initial; } - // iff3_finder(*this)(); + // iff3_finder(*this)(); simplify_problem(); if (check_inconsistent()) return l_false; - + if (m_config.m_max_conflicts == 0) { IF_VERBOSE(SAT_VB_LVL, verbose_stream() << "(sat \"abort: max-conflicts = 0\")\n";); @@ -763,7 +763,7 @@ namespace sat { restart(); simplify_problem(); - if (check_inconsistent()) return l_false; + if (check_inconsistent()) return l_false; gc(); } } @@ -891,7 +891,7 @@ namespace sat { else { mk_model(); return l_true; - } + } } @@ -920,8 +920,8 @@ namespace sat { return; } - TRACE("sat", - for (unsigned i = 0; i < num_lits; ++i) + TRACE("sat", + for (unsigned i = 0; i < num_lits; ++i) tout << lits[i] << " "; tout << "\n"; if (!m_user_scope_literals.empty()) { @@ -932,7 +932,7 @@ namespace sat { for (unsigned i = 0; !inconsistent() && i < m_user_scope_literals.size(); ++i) { literal nlit = ~m_user_scope_literals[i]; - assign(nlit, justification()); + assign(nlit, justification()); } if (weights && !inconsistent()) { @@ -947,9 +947,9 @@ namespace sat { for (unsigned i = 0; !inconsistent() && i < num_lits; ++i) { literal lit = lits[i]; - SASSERT(is_external(lit.var())); - add_assumption(lit); - assign(lit, justification()); + SASSERT(is_external(lit.var())); + add_assumption(lit); + assign(lit, justification()); } } @@ -962,10 +962,10 @@ namespace sat { unsigned num_cores = 0; for (unsigned i = 0; !inconsistent() && i < num_lits; ++i) { literal lit = lits[i]; - SASSERT(is_external(lit.var())); + SASSERT(is_external(lit.var())); TRACE("sat", tout << "propagate: " << lit << " " << value(lit) << "\n";); SASSERT(m_scope_lvl == 1); - add_assumption(lit); + add_assumption(lit); switch(value(lit)) { case l_undef: values.push_back(l_true); @@ -973,10 +973,10 @@ namespace sat { if (num_cores*2 >= num_lits) { break; } - propagate(false); + propagate(false); if (inconsistent()) { flet _init(m_initializing_preferred, true); - while (inconsistent()) { + while (inconsistent()) { if (!resolve_conflict()) { return true; } @@ -1001,15 +1001,15 @@ namespace sat { for (unsigned k = i; k >= j; --k) { if (is_assumption(lits[k])) { pop_assumption(); - } + } } values.resize(j); TRACE("sat", tout << "backjump " << (i - j + 1) << " steps " << num_cores << "\n";); i = j - 1; } - break; - - case l_false: + break; + + case l_false: ++num_cores; values.push_back(l_false); SASSERT(!inconsistent()); @@ -1028,14 +1028,14 @@ namespace sat { SASSERT(m_assumptions.size() <= i+1); if (m_core.size() <= 3) { m_inconsistent = true; - TRACE("opt", tout << "found small core: " << m_core << "\n";); + TRACE("opt", tout << "found small core: " << m_core << "\n";); IF_VERBOSE(11, verbose_stream() << "(sat.core: " << m_core << ")\n";); return true; } pop_assumption(); - m_inconsistent = false; + m_inconsistent = false; break; - case l_true: + case l_true: values.push_back(l_true); SASSERT(m_justification[lit.var()].get_kind() != justification::NONE || lvl(lit) == 0); break; @@ -1046,7 +1046,7 @@ namespace sat { if (m_weight >= max_weight) { // block the current correction set candidate. ++m_stats.m_blocked_corr_sets; - TRACE("opt", tout << "blocking soft correction set: " << m_blocker << "\n";); + TRACE("opt", tout << "blocking soft correction set: " << m_blocker << "\n";); IF_VERBOSE(11, verbose_stream() << "blocking " << m_blocker << "\n";); pop_to_base_level(); mk_clause_core(m_blocker); @@ -1062,17 +1062,17 @@ namespace sat { m_min_core.reset(); m_min_core.append(m_core); m_min_core_valid = true; - } + } } void solver::reset_assumptions() { m_assumptions.reset(); - m_assumption_set.reset(); + m_assumption_set.reset(); } void solver::add_assumption(literal lit) { - m_assumption_set.insert(lit); - m_assumptions.push_back(lit); + m_assumption_set.insert(lit); + m_assumptions.push_back(lit); } void solver::pop_assumption() { @@ -1089,8 +1089,8 @@ namespace sat { for (unsigned i = 0; i < m_min_core.size(); ++i) { literal lit = m_min_core[i]; SASSERT(is_external(lit.var())); - add_assumption(lit); - assign(lit, justification()); + add_assumption(lit); + assign(lit, justification()); } propagate(false); SASSERT(inconsistent()); @@ -1132,7 +1132,7 @@ namespace sat { m_min_core_valid = false; m_min_core.reset(); TRACE("sat", display(tout);); - + if (m_config.m_bcd) { bceq bc(*this); bc(); @@ -1149,11 +1149,11 @@ namespace sat { } IF_VERBOSE(2, verbose_stream() << "(sat.simplify)\n";); - // Disable simplification during MUS computation. + // Disable simplification during MUS computation. // if (m_mus.is_active()) return; TRACE("sat", tout << "simplify\n";); - pop(scope_lvl()); + pop(scope_lvl()); SASSERT(scope_lvl() == 0); @@ -1166,7 +1166,7 @@ namespace sat { m_simplifier(false); CASSERT("sat_simplify_bug", check_invariant()); CASSERT("sat_missed_prop", check_missed_propagation()); - + if (!m_learned.empty()) { m_simplifier(true); CASSERT("sat_missed_prop", check_missed_propagation()); @@ -1260,7 +1260,7 @@ namespace sat { TRACE("sat", tout << "failed: " << c << "\n"; tout << "assumptions: " << m_assumptions << "\n"; tout << "trail: " << m_trail << "\n"; - tout << "model: " << m << "\n"; + tout << "model: " << m << "\n"; m_mc.display(tout); ); ok = false; @@ -1289,10 +1289,10 @@ namespace sat { } for (unsigned i = 0; i < m_assumptions.size(); ++i) { if (value_at(m_assumptions[i], m) != l_true) { - TRACE("sat", + TRACE("sat", tout << m_assumptions[i] << " does not model check\n"; tout << "trail: " << m_trail << "\n"; - tout << "model: " << m << "\n"; + tout << "model: " << m << "\n"; m_mc.display(tout); ); ok = false; @@ -1664,7 +1664,7 @@ namespace sat { resolve_conflict_for_unsat_core(); return false; } - + if (m_conflict_lvl == 0) { return false; } @@ -1849,11 +1849,11 @@ namespace sat { bool solver::resolve_conflict_for_init() { if (m_conflict_lvl == 0) { return false; - } + } m_lemma.reset(); m_lemma.push_back(null_literal); // asserted literal if (m_not_l != null_literal) { - TRACE("sat", tout << "not_l: " << m_not_l << "\n";); + TRACE("sat", tout << "not_l: " << m_not_l << "\n";); process_antecedent_for_init(m_not_l); } literal consequent = m_not_l; @@ -1988,7 +1988,7 @@ namespace sat { SASSERT(!is_marked(m_trail[i].var())); }}); - unsigned old_size = m_unmark.size(); + unsigned old_size = m_unmark.size(); int idx = skip_literals_above_conflict_level(); if (m_not_l != null_literal) { @@ -2005,7 +2005,7 @@ namespace sat { process_consequent_for_unsat_core(m_not_l, js); } } - + literal consequent = m_not_l; justification js = m_conflict; @@ -2031,7 +2031,7 @@ namespace sat { SASSERT(lvl(consequent) == m_conflict_lvl); js = m_justification[c_var]; idx--; - } + } reset_unmark(old_size); if (m_config.m_core_minimize) { if (m_min_core_valid && m_min_core.size() < m_core.size()) { @@ -2039,7 +2039,7 @@ namespace sat { m_core.reset(); m_core.append(m_min_core); } - // TBD: + // TBD: // apply optional clause minimization by detecting subsumed literals. // initial experiment suggests it has no effect. m_mus(); // ignore return value on cancelation. @@ -2511,7 +2511,7 @@ namespace sat { void solver::pop_reinit(unsigned num_scopes) { pop(num_scopes); - reinit_assumptions(); + reinit_assumptions(); } void solver::pop(unsigned num_scopes) { @@ -2578,13 +2578,13 @@ namespace sat { m_clauses_to_reinit.shrink(j); } - // + // // All new clauses that are added to the solver // are relative to the user-scope literals. - // + // void solver::user_push() { - literal lit; + literal lit; bool_var new_v = mk_var(true, false); lit = literal(new_v, false); m_user_scope_literals.push_back(lit); @@ -2674,7 +2674,7 @@ namespace sat { m_phase.shrink(v); m_prev_phase.shrink(v); m_assigned_since_gc.shrink(v); - m_simplifier.reset_todo(); + m_simplifier.reset_todos(); } } @@ -2698,7 +2698,7 @@ namespace sat { unassign_vars(i); break; } - } + } gc_var(lit.var()); } } @@ -3084,10 +3084,10 @@ namespace sat { } bool non_empty = true; m_seen[0].reset(); - while (non_empty) { + while (non_empty) { literal_vector mutex; bool turn = false; - m_reachable[turn] = ps; + m_reachable[turn] = ps; while (!m_reachable[turn].empty()) { literal p = m_reachable[turn].pop(); if (m_seen[0].contains(p)) { @@ -3104,7 +3104,7 @@ namespace sat { turn = !turn; } if (mutex.size() > 1) { - mutexes.push_back(mutex); + mutexes.push_back(mutex); } non_empty = !mutex.empty(); } @@ -3148,7 +3148,7 @@ namespace sat { switch (get_model()[v]) { case l_true: lits.push_back(literal(v, false)); break; case l_false: lits.push_back(literal(v, true)); break; - default: break; + default: break; } } is_sat = get_consequences(asms, lits, conseq); @@ -3175,7 +3175,7 @@ namespace sat { } propagate(false); if (check_inconsistent()) return l_false; - + unsigned num_units = 0, num_iterations = 0; extract_fixed_consequences(num_units, assumptions, vars, conseq); while (!vars.empty()) { @@ -3192,14 +3192,14 @@ namespace sat { push(); assign(~lit, justification()); propagate(false); - while (inconsistent()) { + while (inconsistent()) { if (!resolve_conflict()) { TRACE("sat", display(tout << "inconsistent\n");); m_inconsistent = false; is_sat = l_undef; break; } - propagate(false); + propagate(false); ++num_resolves; } if (scope_lvl() == 1) { @@ -3213,7 +3213,7 @@ namespace sat { else { is_sat = bounded_search(); if (is_sat == l_undef) { - restart(); + restart(); } } } @@ -3224,7 +3224,7 @@ namespace sat { if (is_sat == l_true) { delete_unfixed(vars); } - extract_fixed_consequences(num_units, assumptions, vars, conseq); + extract_fixed_consequences(num_units, assumptions, vars, conseq); IF_VERBOSE(1, verbose_stream() << "(sat.get-consequences" << " iterations: " << num_iterations << " variables: " << vars.size() @@ -3244,10 +3244,10 @@ namespace sat { if (value(lit) == l_true) { to_keep.insert(lit); } - } + } unfixed = to_keep; } - + void solver::extract_fixed_consequences(unsigned& start, literal_set const& assumptions, literal_set& unfixed, vector& conseq) { if (scope_lvl() > 1) { pop(scope_lvl() - 1); @@ -3297,7 +3297,7 @@ namespace sat { } void solver::extract_fixed_consequences(literal lit, literal_set const& assumptions, literal_set& unfixed, vector& conseq) { - index_set s; + index_set s; if (assumptions.contains(lit)) { s.insert(lit.index()); } diff --git a/src/sat/sat_types.h b/src/sat/sat_types.h index 00edaa593..509cc58ba 100644 --- a/src/sat/sat_types.h +++ b/src/sat/sat_types.h @@ -200,7 +200,7 @@ namespace sat { iterator begin() const { return m_set.begin(); } iterator end() const { return m_set.end(); } void reset() { m_set.reset(); m_in_set.reset(); } - void cleanup() { m_set.finalize(); m_in_set.finalize(); } + void finalize() { m_set.finalize(); m_in_set.finalize(); } uint_set& operator&=(uint_set const& other) { unsigned j = 0; for (unsigned i = 0; i < m_set.size(); ++i) { @@ -259,7 +259,7 @@ namespace sat { bool empty() const { return m_set.empty(); } unsigned size() const { return m_set.size(); } void reset() { m_set.reset(); } - void cleanup() { m_set.cleanup(); } + void finalize() { m_set.finalize(); } class iterator { uint_set::iterator m_it; public: From d099e2634247b128d50e357fb361b3808c19dbde Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Wed, 9 Nov 2016 18:06:53 +0000 Subject: [PATCH 362/536] Fixed compiler warning --- src/sat/sat_clause.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sat/sat_clause.h b/src/sat/sat_clause.h index 1aededbb6..27a0ed739 100644 --- a/src/sat/sat_clause.h +++ b/src/sat/sat_clause.h @@ -107,8 +107,8 @@ namespace sat { literal get_literal2() const { return to_literal(m_val2 >> 1); } bool is_learned() const { return (m_val2 & 1) == 1; } bool operator==(const bin_clause & other) const { - return m_val1 == other.m_val1 && m_val2 == other.m_val2 || - m_val1 == other.m_val2 && m_val2 == other.m_val1; + return (m_val1 == other.m_val1 && m_val2 == other.m_val2) || + (m_val1 == other.m_val2 && m_val2 == other.m_val1); } }; From 520e868adde0e5dae12cb575a15883c4c2a7b3e8 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Thu, 10 Nov 2016 16:52:56 +0000 Subject: [PATCH 363/536] Fixed interruption cleanup bug in sat_solver. Relates to #570. --- src/sat/sat_solver.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index 85836b889..c0d736ebf 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -237,7 +237,10 @@ namespace sat { lbool status(clause const & c) const; clause_offset get_offset(clause const & c) const { return m_cls_allocator.get_offset(&c); } void checkpoint() { - if (!m_rlimit.inc()) { throw solver_exception(Z3_CANCELED_MSG); } + if (!m_rlimit.inc()) { + m_mc.reset(); + throw solver_exception(Z3_CANCELED_MSG); + } ++m_num_checkpoints; if (m_num_checkpoints < 10) return; m_num_checkpoints = 0; From bfaa9ddf633b542a0aa01bd925a7c3d1a5b3097d Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Thu, 10 Nov 2016 17:06:55 +0000 Subject: [PATCH 364/536] Fixed potential SAT solver cleanup problem. Renamed functions for consistency. Relates to #570. --- src/sat/sat_probing.cpp | 5 +++-- src/sat/sat_probing.h | 2 +- src/sat/sat_simplifier.cpp | 10 ++++++---- src/sat/sat_simplifier.h | 2 +- src/sat/sat_solver.cpp | 2 +- src/sat/sat_solver.h | 1 + 6 files changed, 13 insertions(+), 9 deletions(-) diff --git a/src/sat/sat_probing.cpp b/src/sat/sat_probing.cpp index c00b68ac2..0b5edb2c9 100644 --- a/src/sat/sat_probing.cpp +++ b/src/sat/sat_probing.cpp @@ -239,7 +239,7 @@ namespace sat { m_counter *= 2; } CASSERT("probing", s.check_invariant()); - free_memory(); + finalize(); return r; } @@ -255,9 +255,10 @@ namespace sat { // TODO } - void probing::free_memory() { + void probing::finalize() { m_assigned.finalize(); m_to_assert.finalize(); + m_cached_bins.finalize(); } void probing::collect_statistics(statistics & st) const { diff --git a/src/sat/sat_probing.h b/src/sat/sat_probing.h index daf6817e3..cce165a34 100644 --- a/src/sat/sat_probing.h +++ b/src/sat/sat_probing.h @@ -69,7 +69,7 @@ namespace sat { void updt_params(params_ref const & p); static void collect_param_descrs(param_descrs & d); - void free_memory(); + void finalize(); void collect_statistics(statistics & st) const; void reset_statistics(); diff --git a/src/sat/sat_simplifier.cpp b/src/sat/sat_simplifier.cpp index 3e817b2a9..c42572f1e 100644 --- a/src/sat/sat_simplifier.cpp +++ b/src/sat/sat_simplifier.cpp @@ -63,7 +63,7 @@ namespace sat { } simplifier::~simplifier() { - free_memory(); + finalize(); } inline watch_list & simplifier::get_wlist(literal l) { return s.get_wlist(l); } @@ -125,7 +125,7 @@ namespace sat { m_visited.resize(2*s.num_vars(), false); } - void simplifier::free_memory() { + void simplifier::finalize() { m_use_list.finalize(); m_sub_todo.finalize(); m_sub_bin_todo.finalize(); @@ -154,6 +154,7 @@ namespace sat { if (!m_subsumption && !m_elim_blocked_clauses && !m_resolution) return; + initialize(); CASSERT("sat_solver", s.check_invariant()); @@ -175,6 +176,7 @@ namespace sat { } register_clauses(s.m_clauses); + if (!learned && (m_elim_blocked_clauses || m_elim_blocked_clauses_at == m_num_calls)) elim_blocked_clauses(); @@ -216,7 +218,7 @@ namespace sat { } CASSERT("sat_solver", s.check_invariant()); TRACE("after_simplifier", s.display(tout); tout << "model_converter:\n"; s.m_mc.display(tout);); - free_memory(); + finalize(); } /** @@ -941,8 +943,8 @@ namespace sat { model_converter::entry * new_entry = 0; if (s.is_external(l.var()) || s.was_eliminated(l.var())) return; - { + { m_to_remove.reset(); { clause_use_list & occs = s.m_use_list.get(l); diff --git a/src/sat/sat_simplifier.h b/src/sat/sat_simplifier.h index f0f78b9c2..9ee239083 100644 --- a/src/sat/sat_simplifier.h +++ b/src/sat/sat_simplifier.h @@ -187,7 +187,7 @@ namespace sat { void updt_params(params_ref const & p); static void collect_param_descrs(param_descrs & d); - void free_memory(); + void finalize(); void collect_statistics(statistics & st) const; void reset_statistics(); diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 5bc9e4ed9..7acfda822 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -3042,7 +3042,7 @@ namespace sat { if (scope_lvl() > 0 || inconsistent()) return; m_simplifier(learned); - m_simplifier.free_memory(); + m_simplifier.finalize(); if (m_ext) m_ext->clauses_modifed(); } diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index c0d736ebf..a44f07a23 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -239,6 +239,7 @@ namespace sat { void checkpoint() { if (!m_rlimit.inc()) { m_mc.reset(); + m_model_is_current = false; throw solver_exception(Z3_CANCELED_MSG); } ++m_num_checkpoints; From e21bd8dacc58b95c2d207092b1ec4a932b260086 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 15 Nov 2016 15:07:05 +0200 Subject: [PATCH 365/536] fix lexicographic combinations for wmax: pb constrsaints were not interpreted in Boolean benchmarks. #782 Signed-off-by: Nikolaj Bjorner --- src/ast/pb_decl_plugin.h | 2 ++ src/muz/pdr/pdr_context.cpp | 1 + src/opt/maxsmt.cpp | 8 ++++++++ src/smt/theory_pb.h | 1 + 4 files changed, 12 insertions(+) diff --git a/src/ast/pb_decl_plugin.h b/src/ast/pb_decl_plugin.h index 2ed14a4ce..0750dcac7 100644 --- a/src/ast/pb_decl_plugin.h +++ b/src/ast/pb_decl_plugin.h @@ -73,6 +73,8 @@ public: unsigned arity, sort * const * domain, sort * range); virtual void get_op_names(svector & op_names, symbol const & logic); + virtual bool is_considered_uninterpreted(func_decl * f) { return false; } + }; diff --git a/src/muz/pdr/pdr_context.cpp b/src/muz/pdr/pdr_context.cpp index b6a889756..6d3a57581 100644 --- a/src/muz/pdr/pdr_context.cpp +++ b/src/muz/pdr/pdr_context.cpp @@ -1760,6 +1760,7 @@ namespace pdr { smt::kernel solver(m, get_fparams()); solver.assert_expr(tmp); lbool res = solver.check(); + TRACE("pdr", tout << tmp << " " << res << "\n";); if (res != l_false) { msg << "rule validation failed when checking: " << mk_pp(tmp, m); IF_VERBOSE(0, verbose_stream() << msg.str() << "\n";); diff --git a/src/opt/maxsmt.cpp b/src/opt/maxsmt.cpp index fa4897046..7d3e8eda9 100644 --- a/src/opt/maxsmt.cpp +++ b/src/opt/maxsmt.cpp @@ -25,6 +25,7 @@ Notes: #include "uint_set.h" #include "opt_context.h" #include "theory_wmaxsat.h" +#include "theory_pb.h" #include "ast_util.h" #include "pb_decl_plugin.h" @@ -124,6 +125,13 @@ namespace opt { wth = alloc(smt::theory_wmaxsat, m, m_c.fm()); m_c.smt_context().register_plugin(wth); } + smt::theory_id th_pb = m.get_family_id("pb"); + smt::theory_pb* pb = dynamic_cast(m_c.smt_context().get_theory(th_pb)); + if (!pb) { + theory_pb_params params; + pb = alloc(smt::theory_pb, m, params); + m_c.smt_context().register_plugin(pb); + } return wth; } diff --git a/src/smt/theory_pb.h b/src/smt/theory_pb.h index b9fddba38..1a08b7b61 100644 --- a/src/smt/theory_pb.h +++ b/src/smt/theory_pb.h @@ -316,6 +316,7 @@ namespace smt { virtual void collect_statistics(::statistics & st) const; virtual model_value_proc * mk_value(enode * n, model_generator & mg); virtual void init_model(model_generator & m); + virtual bool include_func_interp(func_decl* f) { return false; } static literal assert_ge(context& ctx, unsigned k, unsigned n, literal const* xs); }; From e65d80dedd3ef33a3279d0a0abaea6b0631174d9 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 15 Nov 2016 18:29:51 +0200 Subject: [PATCH 366/536] make semantics of extract/substr deterministic. Issue #781 Signed-off-by: Nikolaj Bjorner --- src/smt/theory_seq.cpp | 37 ++++++++++++++++++++++--------------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index afb6d21b3..245ffe438 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -3259,15 +3259,18 @@ bool theory_seq::get_length(expr* e, rational& val) const { let e = extract(s, i, l) - 0 <= i <= len(s) -> prefix(xe,s) - 0 <= i <= len(s) -> len(x) = i - 0 <= i <= len(s) & 0 <= l <= len(s) - i -> len(e) = l - 0 <= i <= len(s) & len(s) < l + i -> len(e) = len(s) - i - 0 <= i <= len(s) & l < 0 -> len(e) = 0 - * i < 0 -> e = empty - * i > len(s) -> e = empty + 0 <= i <= |s| -> prefix(xe,s) + 0 <= i <= |s| -> len(x) = i + 0 <= i <= |s| & 0 <= l <= |s| - i -> |e| = l + 0 <= i <= |s| & |s| < l + i -> |e| = |s| - i + 0 <= i <= |s| & l < 0 -> |e| = 0 + i >= |s| => |e| = 0 + i < 0 => |e| = 0 + l <= 0 => |e| = 0 + + It follows that: + |e| = min(l, |s| - i) for 0 <= i < |s| and 0 < |l| - */ @@ -3301,16 +3304,20 @@ void theory_seq::add_extract_axiom(expr* e) { expr_ref zero(m_autil.mk_int(0), m); literal i_ge_0 = mk_literal(m_autil.mk_ge(i, zero)); - literal i_le_ls = mk_literal(m_autil.mk_le(mk_sub(i, ls), zero)); + literal ls_le_i = mk_literal(m_autil.mk_le(mk_sub(i, ls), zero)); literal li_ge_ls = mk_literal(m_autil.mk_ge(ls_minus_i_l, zero)); literal l_ge_zero = mk_literal(m_autil.mk_ge(l, zero)); + literal ls_le_0 = mk_literal(m_autil.mk_le(ls, zero)); -// add_axiom(~i_ge_0, ~i_le_ls, mk_literal(m_util.str.mk_prefix(xe, s))); - add_axiom(~i_ge_0, ~i_le_ls, mk_seq_eq(xey, s)); - add_axiom(~i_ge_0, ~i_le_ls, mk_eq(lx, i, false)); - add_axiom(~i_ge_0, ~i_le_ls, ~l_ge_zero, ~li_ge_ls, mk_eq(le, l, false)); - add_axiom(~i_ge_0, ~i_le_ls, li_ge_ls, mk_eq(le, mk_sub(ls, i), false)); - add_axiom(~i_ge_0, ~i_le_ls, l_ge_zero, mk_eq(le, zero, false)); +// add_axiom(~i_ge_0, ~ls_le_i, mk_literal(m_util.str.mk_prefix(xe, s))); + add_axiom(~i_ge_0, ~ls_le_i, mk_seq_eq(xey, s)); + add_axiom(~i_ge_0, ~ls_le_i, mk_eq(lx, i, false)); + add_axiom(~i_ge_0, ~ls_le_i, ~l_ge_zero, ~li_ge_ls, mk_eq(le, l, false)); + add_axiom(~i_ge_0, ~ls_le_i, li_ge_ls, mk_eq(le, mk_sub(ls, i), false)); + add_axiom(~i_ge_0, ~ls_le_i, l_ge_zero, mk_eq(le, zero, false)); + add_axiom(i_ge_0, mk_eq(le, zero, false)); + add_axiom(ls_le_i, mk_eq(le, zero, false)); + add_axiom(~ls_le_0, mk_eq(le, zero, false)); } void theory_seq::add_tail_axiom(expr* e, expr* s) { From 014815a6408a1c54ee6c324353880fe46e46bf0a Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Tue, 15 Nov 2016 08:59:18 -0800 Subject: [PATCH 367/536] Fixed Windows distribution script. --- scripts/mk_win_dist.py | 26 ++++++++++---------------- 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/scripts/mk_win_dist.py b/scripts/mk_win_dist.py index 65d780f0d..92d89480f 100644 --- a/scripts/mk_win_dist.py +++ b/scripts/mk_win_dist.py @@ -236,23 +236,9 @@ def mk_zip(): VS_RUNTIME_PATS = [re.compile('vcomp.*\.dll'), re.compile('msvcp.*\.dll'), re.compile('msvcr.*\.dll')] - -VS_RUNTIME_FILES = [] -def cp_vs_runtime_visitor(pattern, dir, files): - global VS_RUNTIME_FILES - for filename in files: - for pat in VS_RUNTIME_PATS: - if pat.match(filename): - if fnmatch(filename, pattern): - fname = os.path.join(dir, filename) - if not os.path.isdir(fname): - VS_RUNTIME_FILES.append(fname) - break - # Copy Visual Studio Runtime libraries -def cp_vs_runtime_core(x64): - global VS_RUNTIME_FILES +def cp_vs_runtime_core(x64): if x64: platform = "x64" @@ -261,7 +247,15 @@ def cp_vs_runtime_core(x64): vcdir = os.environ['VCINSTALLDIR'] path = '%sredist\\%s' % (vcdir, platform) VS_RUNTIME_FILES = [] - os.walk(path, cp_vs_runtime_visitor, '*.dll') + for root, dirs, files in os.walk(path): + for filename in files: + if fnmatch(filename, '*.dll'): + for pat in VS_RUNTIME_PATS: + if pat.match(filename): + fname = os.path.join(root, filename) + if not os.path.isdir(fname): + VS_RUNTIME_FILES.append(fname) + bin_dist_path = os.path.join(DIST_DIR, get_dist_path(x64), 'bin') for f in VS_RUNTIME_FILES: shutil.copy(f, bin_dist_path) From ee60ba824f0a116ec0bb5e9e615dd4fe2e9802db Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Tue, 15 Nov 2016 19:59:08 +0000 Subject: [PATCH 368/536] Bugfix for rewriter exceptions in theory_fpa. Relates to #570. --- src/smt/theory_fpa.cpp | 37 ++++++++++++++++++++++--------------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/src/smt/theory_fpa.cpp b/src/smt/theory_fpa.cpp index 89acc0ecf..4b53c1341 100644 --- a/src/smt/theory_fpa.cpp +++ b/src/smt/theory_fpa.cpp @@ -334,23 +334,30 @@ namespace smt { TRACE("t_fpa_detail", tout << "term: " << mk_ismt2_pp(e, get_manager()) << std::endl; tout << "converted term: " << mk_ismt2_pp(e_conv, get_manager()) << std::endl;); - if (m_fpa_util.is_rm(e)) { - 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_bv2rm(bv_rm); + try { + 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_bv2rm(bv_rm); + } + else if (m_fpa_util.is_float(e)) { + 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); + m_th_rw(exp); + m_th_rw(sig); + res = m_fpa_util.mk_fp(sgn, exp, sig); + } + else + UNREACHABLE(); } - else if (m_fpa_util.is_float(e)) { - 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); - m_th_rw(exp); - m_th_rw(sig); - res = m_fpa_util.mk_fp(sgn, exp, sig); + catch (rewriter_exception &) + { + m_th_rw.reset(); + throw; } - else - UNREACHABLE(); return res; } From c7787feebb5ed79b2274741b4f24299aa87a2057 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Tue, 15 Nov 2016 19:59:22 +0000 Subject: [PATCH 369/536] Assertion fix for theory_fpa. Relates to #570. --- src/smt/theory_fpa.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/smt/theory_fpa.cpp b/src/smt/theory_fpa.cpp index 4b53c1341..57cd6a914 100644 --- a/src/smt/theory_fpa.cpp +++ b/src/smt/theory_fpa.cpp @@ -750,8 +750,15 @@ namespace smt { // These are the conversion functions fp.to_* */ SASSERT(!m_fpa_util.is_float(n) && !m_fpa_util.is_rm(n)); } - else - UNREACHABLE(); + else { + /* Theory variables can be merged when (= bv-term (bvwrap fp-term)), + in which case context::relevant_eh may call theory_fpa::relevant_eh + after theory_bv::relevant_eh, regardless of whether theory_fpa is + interested in this term. But, this can only happen because of + (bvwrap ...) terms, i.e., `n' must be a bit-vector expression, + which we can safely ignore. */ + SASSERT(m_bv_util.is_bv(n)); + } } void theory_fpa::reset_eh() { From e9db934f1a3199cc69748333bdc115f4010d0eda Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 17 Nov 2016 04:26:17 +0200 Subject: [PATCH 370/536] improving perf of mutex finding, revert semantics of 0 timeout to no-timeout. Issue #791 Signed-off-by: Nikolaj Bjorner --- src/muz/pdr/pdr_dl_interface.cpp | 6 +++ src/opt/maxres.cpp | 67 +++++----------------------- src/opt/maxsmt.cpp | 65 ++++++++++++++++++++++++++- src/opt/maxsmt.h | 6 +++ src/opt/wmax.cpp | 25 +++++++---- src/smt/params/smt_params_helper.pyg | 2 +- src/smt/smt_consequences.cpp | 13 +++--- src/smt/smt_context.h | 2 +- src/smt/theory_pb.cpp | 2 +- src/util/scoped_timer.cpp | 2 +- 10 files changed, 116 insertions(+), 74 deletions(-) diff --git a/src/muz/pdr/pdr_dl_interface.cpp b/src/muz/pdr/pdr_dl_interface.cpp index 37f708009..dfc15636c 100644 --- a/src/muz/pdr/pdr_dl_interface.cpp +++ b/src/muz/pdr/pdr_dl_interface.cpp @@ -145,6 +145,11 @@ lbool dl_interface::query(expr * query) { query_pred = rules.get_output_predicate(); + TRACE("pdr", + tout << "rules:\n"; + m_ctx.display_rules(tout); + ); + IF_VERBOSE(2, m_ctx.display_rules(verbose_stream());); m_pdr_rules.replace_rules(rules); m_pdr_rules.close(); @@ -152,6 +157,7 @@ lbool dl_interface::query(expr * query) { m_ctx.reopen(); m_ctx.replace_rules(old_rules); + scoped_restore_proof _sc(m); // update_rules may overwrite the proof mode. m_context->set_proof_converter(m_ctx.get_proof_converter()); diff --git a/src/opt/maxres.cpp b/src/opt/maxres.cpp index e6b452603..016f1ee0e 100644 --- a/src/opt/maxres.cpp +++ b/src/opt/maxres.cpp @@ -192,9 +192,8 @@ public: lbool mus_solver() { lbool is_sat = l_true; if (!init()) return l_undef; - init_local(); + is_sat = init_local(); trace(); - is_sat = process_mutex(); if (is_sat != l_true) return is_sat; while (m_lower < m_upper) { if (m_lower >= m_upper) break; @@ -233,10 +232,9 @@ public: lbool primal_dual_solver() { if (!init()) return l_undef; - init_local(); + lbool is_sat = init_local(); trace(); exprs cs; - lbool is_sat = process_mutex(); if (is_sat != l_true) return is_sat; while (m_lower < m_upper) { is_sat = check_sat_hill_climb(m_asms); @@ -274,54 +272,6 @@ public: return l_true; } - lbool process_mutex() { - vector mutexes; - lbool is_sat = s().find_mutexes(m_asms, mutexes); - if (is_sat != l_true) { - return is_sat; - } - for (unsigned i = 0; i < mutexes.size(); ++i) { - process_mutex(mutexes[i]); - } - if (!mutexes.empty()) { - trace(); - } - return l_true; - } - - void process_mutex(expr_ref_vector& mutex) { - TRACE("opt", - for (unsigned i = 0; i < mutex.size(); ++i) { - tout << mk_pp(mutex[i].get(), m) << " |-> " << get_weight(mutex[i].get()) << "\n"; - }); - if (mutex.size() <= 1) { - return; - } - sort_assumptions(mutex); - ptr_vector core(mutex.size(), mutex.c_ptr()); - remove_soft(core, m_asms); - rational weight(0), sum1(0), sum2(0); - vector weights; - for (unsigned i = 0; i < mutex.size(); ++i) { - rational w = get_weight(mutex[i].get()); - weights.push_back(w); - sum1 += w; - m_asm2weight.remove(mutex[i].get()); - } - for (unsigned i = mutex.size(); i > 0; ) { - --i; - expr_ref soft(m.mk_or(i+1, mutex.c_ptr()), m); - rational w = weights[i]; - weight = w - weight; - m_lower += weight*rational(i); - sum2 += weight*rational(i+1); - add_soft(soft, weight); - for (; i > 0 && weights[i-1] == w; --i) {} - weight = w; - } - SASSERT(sum1 == sum2); - } - lbool check_sat_hill_climb(expr_ref_vector& asms1) { expr_ref_vector asms(asms1); lbool is_sat = l_true; @@ -854,12 +804,18 @@ public: m_dump_benchmarks = _p.dump_benchmarks(); } - void init_local() { + lbool init_local() { m_upper.reset(); m_lower.reset(); m_trail.reset(); - for (unsigned i = 0; i < m_soft.size(); ++i) { - add_soft(m_soft[i], m_weights[i]); + obj_map new_soft; + lbool is_sat = find_mutexes(new_soft); + if (is_sat != l_true) { + return is_sat; + } + obj_map::iterator it = new_soft.begin(), end = new_soft.end(); + for (; it != end; ++it) { + add_soft(it->m_key, it->m_value); } m_max_upper = m_upper; m_found_feasible_optimum = false; @@ -867,6 +823,7 @@ public: add_upper_bound_block(); m_csmodel = 0; m_correction_set_size = 0; + return l_true; } virtual void commit_assignment() { diff --git a/src/opt/maxsmt.cpp b/src/opt/maxsmt.cpp index 7d3e8eda9..97ce28166 100644 --- a/src/opt/maxsmt.cpp +++ b/src/opt/maxsmt.cpp @@ -38,7 +38,8 @@ namespace opt { m_c(c), m_soft(soft), m_weights(ws), - m_assertions(m) { + m_assertions(m), + m_trail(m) { c.get_base_model(m_model); SASSERT(m_model); updt_params(c.params()); @@ -152,6 +153,67 @@ namespace opt { verbose_stream() << "(opt." << solver << " [" << l << ":" << u << "])\n";); } + lbool maxsmt_solver_base::find_mutexes(obj_map& new_soft) { + m_lower.reset(); + for (unsigned i = 0; i < m_soft.size(); ++i) { + new_soft.insert(m_soft[i], m_weights[i]); + } + vector mutexes; + lbool is_sat = s().find_mutexes(m_soft, mutexes); + if (is_sat != l_true) { + return is_sat; + } + for (unsigned i = 0; i < mutexes.size(); ++i) { + process_mutex(mutexes[i], new_soft); + } + return l_true; + } + + struct maxsmt_compare_soft { + obj_map const& m_soft; + maxsmt_compare_soft(obj_map const& soft): m_soft(soft) {} + bool operator()(expr* a, expr* b) const { + return m_soft.find(a) > m_soft.find(b); + } + }; + + void maxsmt_solver_base::process_mutex(expr_ref_vector& mutex, obj_map& new_soft) { + TRACE("opt", + for (unsigned i = 0; i < mutex.size(); ++i) { + tout << mk_pp(mutex[i].get(), m) << " |-> " << new_soft.find(mutex[i].get()) << "\n"; + }); + if (mutex.size() <= 1) { + return; + } + maxsmt_compare_soft cmp(new_soft); + ptr_vector _mutex(mutex.size(), mutex.c_ptr()); + std::sort(_mutex.begin(), _mutex.end(), cmp); + mutex.reset(); + mutex.append(_mutex.size(), _mutex.c_ptr()); + + rational weight(0), sum1(0), sum2(0); + vector weights; + for (unsigned i = 0; i < mutex.size(); ++i) { + rational w = new_soft.find(mutex[i].get()); + weights.push_back(w); + sum1 += w; + new_soft.remove(mutex[i].get()); + } + for (unsigned i = mutex.size(); i > 0; ) { + --i; + expr_ref soft(m.mk_or(i+1, mutex.c_ptr()), m); + m_trail.push_back(soft); + rational w = weights[i]; + weight = w - weight; + m_lower += weight*rational(i); + sum2 += weight*rational(i+1); + new_soft.insert(soft, weight); + for (; i > 0 && weights[i-1] == w; --i) {} + weight = w; + } + SASSERT(sum1 == sum2); + } + maxsmt::maxsmt(maxsat_context& c, unsigned index): @@ -310,4 +372,5 @@ namespace opt { } + }; diff --git a/src/opt/maxsmt.h b/src/opt/maxsmt.h index 57fe12b59..5ecb023f6 100644 --- a/src/opt/maxsmt.h +++ b/src/opt/maxsmt.h @@ -62,6 +62,7 @@ namespace opt { const expr_ref_vector m_soft; vector m_weights; expr_ref_vector m_assertions; + expr_ref_vector m_trail; rational m_lower; rational m_upper; model_ref m_model; @@ -95,12 +96,17 @@ namespace opt { ~scoped_ensure_theory(); smt::theory_wmaxsat& operator()(); }; + + lbool find_mutexes(obj_map& new_soft); protected: void enable_sls(bool force); void trace_bounds(char const* solver); + void process_mutex(expr_ref_vector& mutex, obj_map& new_soft); + + }; /** diff --git a/src/opt/wmax.cpp b/src/opt/wmax.cpp index ef4989cee..d3ceb9a3b 100644 --- a/src/opt/wmax.cpp +++ b/src/opt/wmax.cpp @@ -40,19 +40,28 @@ namespace opt { lbool operator()() { TRACE("opt", tout << "weighted maxsat\n";); scoped_ensure_theory wth(*this); - lbool is_sat = l_true; - bool was_sat = false; - for (unsigned i = 0; i < m_soft.size(); ++i) { - wth().assert_weighted(m_soft[i], m_weights[i]); + obj_map soft; + lbool is_sat = find_mutexes(soft); + if (is_sat != l_true) { + return is_sat; } - while (l_true == is_sat) { - is_sat = s().check_sat(0,0); + rational offset = m_lower; + m_upper = offset; + bool was_sat = false; + obj_map::iterator it = soft.begin(), end = soft.end(); + for (; it != end; ++it) { + wth().assert_weighted(it->m_key, it->m_value); + m_upper += it->m_value; + } + trace_bounds("wmax"); + while (l_true == is_sat && m_lower < m_upper) { + is_sat = s().check_sat(0, 0); if (m.canceled()) { is_sat = l_undef; } if (is_sat == l_true) { if (wth().is_optimal()) { - m_upper = wth().get_min_cost(); + m_upper = offset + wth().get_min_cost(); s().get_model(m_model); } expr_ref fml = wth().mk_block(); @@ -63,11 +72,11 @@ namespace opt { } if (was_sat) { wth().get_assignment(m_assignment); + m_upper = offset + wth().get_min_cost(); } if (is_sat == l_false && was_sat) { is_sat = l_true; } - m_upper = wth().get_min_cost(); if (is_sat == l_true) { m_lower = m_upper; } diff --git a/src/smt/params/smt_params_helper.pyg b/src/smt/params/smt_params_helper.pyg index 35652608c..739af8bfe 100644 --- a/src/smt/params/smt_params_helper.pyg +++ b/src/smt/params/smt_params_helper.pyg @@ -16,7 +16,7 @@ def_module_params(module_name='smt', ('delay_units_threshold', UINT, 32, 'maximum number of learned unit clauses before restarting, ignored if delay_units is false'), ('pull_nested_quantifiers', BOOL, False, 'pull nested quantifiers'), ('refine_inj_axioms', BOOL, True, 'refine injectivity axioms'), - ('timeout', UINT, UINT_MAX, 'timeout (in milliseconds) (0 means immediate timeout)'), + ('timeout', UINT, UINT_MAX, 'timeout (in milliseconds) (UINT_MAX and 0 mean no timeout)'), ('rlimit', UINT, 0, 'resource limit (0 means no limit)'), ('max_conflicts', UINT, UINT_MAX, 'maximum number of conflicts before giving up.'), ('mbqi', BOOL, True, 'model based quantifier instantiation (MBQI)'), diff --git a/src/smt/smt_consequences.cpp b/src/smt/smt_consequences.cpp index 1c1d236ad..667411be5 100644 --- a/src/smt/smt_consequences.cpp +++ b/src/smt/smt_consequences.cpp @@ -369,7 +369,7 @@ namespace smt { lbool context::find_mutexes(expr_ref_vector const& vars, vector& mutexes) { - index_set lits; + uint_set lits; for (unsigned i = 0; i < vars.size(); ++i) { expr* n = vars[i]; bool neg = m_manager.is_not(n, n); @@ -379,11 +379,11 @@ namespace smt { } while (!lits.empty()) { literal_vector mutex; - index_set other(lits); + uint_set other(lits); while (!other.empty()) { - index_set conseq; + uint_set conseq; literal p = to_literal(*other.begin()); - other.erase(p.index()); + other.remove(p.index()); mutex.push_back(p); if (other.empty()) { break; @@ -407,11 +407,12 @@ namespace smt { return l_true; } - void context::get_reachable(literal p, index_set& goal, index_set& reachable) { - index_set seen; + void context::get_reachable(literal p, uint_set& goal, uint_set& reachable) { + uint_set seen; literal_vector todo; todo.push_back(p); while (!todo.empty()) { + // std::cout << "todo: " << todo.size() << "\n"; p = todo.back(); todo.pop_back(); if (seen.contains(p.index())) { diff --git a/src/smt/smt_context.h b/src/smt/smt_context.h index d9f24ddf6..84459d272 100644 --- a/src/smt/smt_context.h +++ b/src/smt/smt_context.h @@ -1371,7 +1371,7 @@ namespace smt { \brief Auxiliry function for mutex finding. */ - void get_reachable(literal p, index_set& goal, index_set& reached); + void get_reachable(literal p, uint_set& goal, uint_set& reached); public: context(ast_manager & m, smt_params & fp, params_ref const & p = params_ref()); diff --git a/src/smt/theory_pb.cpp b/src/smt/theory_pb.cpp index 73e427b0b..a2f8ceba9 100644 --- a/src/smt/theory_pb.cpp +++ b/src/smt/theory_pb.cpp @@ -1289,7 +1289,7 @@ namespace smt { m_stats.m_num_compiled_vars += sortnw.m_stats.m_num_compiled_vars; m_stats.m_num_compiled_clauses += sortnw.m_stats.m_num_compiled_clauses; - IF_VERBOSE(1, verbose_stream() + IF_VERBOSE(2, verbose_stream() << "(smt.pb compile sorting network bound: " << k << " literals: " << in.size() << " clauses: " << sortnw.m_stats.m_num_compiled_clauses diff --git a/src/util/scoped_timer.cpp b/src/util/scoped_timer.cpp index bf3ca9b67..335b2c3bb 100644 --- a/src/util/scoped_timer.cpp +++ b/src/util/scoped_timer.cpp @@ -231,7 +231,7 @@ struct scoped_timer::imp { }; scoped_timer::scoped_timer(unsigned ms, event_handler * eh) { - if (ms != UINT_MAX) + if (ms != UINT_MAX && ms != 0) m_imp = alloc(imp, ms, eh); else m_imp = 0; From 1600823435a0058851368eda73582e3f89a66361 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 17 Nov 2016 05:38:52 +0200 Subject: [PATCH 371/536] fix perf bug reported in #790 Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/bool_rewriter.cpp | 36 +++++++++++++++++++----------- src/ast/rewriter/bool_rewriter.h | 2 ++ 2 files changed, 25 insertions(+), 13 deletions(-) diff --git a/src/ast/rewriter/bool_rewriter.cpp b/src/ast/rewriter/bool_rewriter.cpp index ce3eb5844..05f47ada7 100644 --- a/src/ast/rewriter/bool_rewriter.cpp +++ b/src/ast/rewriter/bool_rewriter.cpp @@ -456,6 +456,22 @@ bool bool_rewriter::simp_nested_eq_ite(expr * t, expr_fast_mark1 & neg_lits, exp return false; } +void bool_rewriter::push_new_arg(expr* arg, expr_ref_vector& new_args, expr_fast_mark1& neg_lits, expr_fast_mark2& pos_lits) { + expr* narg; + if (m().is_not(arg, narg)) { + if (!neg_lits.is_marked(narg)) { + neg_lits.mark(narg); + new_args.push_back(arg); + } + } + else { + if (!pos_lits.is_marked(arg)) { + pos_lits.mark(arg); + new_args.push_back(arg); + } + } +} + /** \brief Apply local context simplification at (OR args[0] ... args[num_args-1]) Basic idea: @@ -473,6 +489,7 @@ bool bool_rewriter::local_ctx_simp(unsigned num_args, expr * const * args, expr_ bool modified = false; bool forward = true; unsigned rounds = 0; + expr* narg; while (true) { rounds++; @@ -481,20 +498,13 @@ bool bool_rewriter::local_ctx_simp(unsigned num_args, expr * const * args, expr_ verbose_stream() << "rounds: " << rounds << "\n"; #endif -#define PUSH_NEW_ARG(ARG) { \ - new_args.push_back(ARG); \ - if (m().is_not(ARG)) \ - neg_lits.mark(to_app(ARG)->get_arg(0)); \ - else \ - pos_lits.mark(ARG); \ -} #define PROCESS_ARG() \ { \ expr * arg = args[i]; \ - if (m().is_not(arg) && m().is_or(to_app(arg)->get_arg(0)) && \ - simp_nested_not_or(to_app(to_app(arg)->get_arg(0))->get_num_args(), \ - to_app(to_app(arg)->get_arg(0))->get_args(), \ + if (m().is_not(arg, narg) && m().is_or(narg) && \ + simp_nested_not_or(to_app(narg)->get_num_args(), \ + to_app(narg)->get_args(), \ neg_lits, \ pos_lits, \ new_arg)) { \ @@ -515,11 +525,11 @@ bool bool_rewriter::local_ctx_simp(unsigned num_args, expr * const * args, expr_ unsigned sz = to_app(arg)->get_num_args(); \ for (unsigned j = 0; j < sz; j++) { \ expr * arg_arg = to_app(arg)->get_arg(j); \ - PUSH_NEW_ARG(arg_arg); \ + push_new_arg(arg_arg, new_args, neg_lits, pos_lits); \ } \ } \ else { \ - PUSH_NEW_ARG(arg); \ + push_new_arg(arg, new_args, neg_lits, pos_lits); \ } \ } @@ -528,7 +538,7 @@ bool bool_rewriter::local_ctx_simp(unsigned num_args, expr * const * args, expr_ static unsigned counter = 0; counter++; if (counter % 10000 == 0) - verbose_stream() << "local-ctx-cost: " << m_local_ctx_cost << "\n"; + verbose_stream() << "local-ctx-cost: " << m_local_ctx_cost << " " << num_args << "\n"; #endif if (forward) { diff --git a/src/ast/rewriter/bool_rewriter.h b/src/ast/rewriter/bool_rewriter.h index b309f8032..b1d2dec53 100644 --- a/src/ast/rewriter/bool_rewriter.h +++ b/src/ast/rewriter/bool_rewriter.h @@ -75,6 +75,8 @@ class bool_rewriter { bool local_ctx_simp(unsigned num_args, expr * const * args, expr_ref & result); br_status try_ite_value(app * ite, app * val, expr_ref & result); + void push_new_arg(expr* arg, expr_ref_vector& new_args, expr_fast_mark1& neg_lits, expr_fast_mark2& pos_lits); + public: bool_rewriter(ast_manager & m, params_ref const & p = params_ref()):m_manager(m), m_local_ctx_cost(0) { updt_params(p); } ast_manager & m() const { return m_manager; } From a97358965be476b2e2fae224002ba4890646cf34 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Thu, 17 Nov 2016 16:28:49 +0000 Subject: [PATCH 372/536] Fixed interruption/cancelation issue in rewriter. --- src/ast/rewriter/rewriter_def.h | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/src/ast/rewriter/rewriter_def.h b/src/ast/rewriter/rewriter_def.h index cd6a63acc..61d177809 100644 --- a/src/ast/rewriter/rewriter_def.h +++ b/src/ast/rewriter/rewriter_def.h @@ -27,7 +27,7 @@ void rewriter_tpl::process_var(var * v) { SASSERT(v->get_sort() == m().get_sort(m_r)); if (ProofGen) { result_pr_stack().push_back(m_pr); - m_pr = 0; + m_pr = 0; } set_new_child_flag(v); TRACE("rewriter", tout << mk_ismt2_pp(v, m()) << " -> " << m_r << "\n";); @@ -43,7 +43,7 @@ void rewriter_tpl::process_var(var * v) { if (r != 0) { SASSERT(v->get_sort() == m().get_sort(r)); if (!is_ground(r) && m_shifts[index] != m_bindings.size()) { - + unsigned shift_amount = m_bindings.size() - m_shifts[index]; expr_ref tmp(m()); m_shifter(r, shift_amount, tmp); @@ -195,9 +195,9 @@ void rewriter_tpl::process_app(app * t, frame & fr) { // this optimization is only used when Proof generation is disabled. if (f->is_associative() && t->get_ref_count() <= 1 && frame_stack().size() > 1) { frame & prev_fr = frame_stack()[frame_stack().size() - 2]; - if (is_app(prev_fr.m_curr) && - to_app(prev_fr.m_curr)->get_decl() == f && - prev_fr.m_state == PROCESS_CHILDREN && + if (is_app(prev_fr.m_curr) && + to_app(prev_fr.m_curr)->get_decl() == f && + prev_fr.m_state == PROCESS_CHILDREN && flat_assoc(f)) { frame_stack().pop_back(); set_new_child_flag(t); @@ -223,7 +223,7 @@ void rewriter_tpl::process_app(app * t, frame & fr) { } br_status st = m_cfg.reduce_app(f, new_num_args, new_args, m_r, m_pr2); SASSERT(st != BR_DONE || m().get_sort(m_r) == m().get_sort(t)); - TRACE("reduce_app", + TRACE("reduce_app", tout << mk_ismt2_pp(t, m()) << "\n"; tout << "st: " << st; if (m_r) tout << " --->\n" << mk_ismt2_pp(m_r, m()); @@ -296,11 +296,11 @@ void rewriter_tpl::process_app(app * t, frame & fr) { expr * def; proof * def_pr; quantifier * def_q; - // When get_macro succeeds, then + // When get_macro succeeds, then // we know that: // forall X. f(X) = def[X] // and def_pr is a proof for this quantifier. - // + // // Remark: def_q is only used for proof generation. // It is the quantifier forall X. f(X) = def[X] if (get_macro(f, def, def_q, def_pr)) { @@ -318,7 +318,7 @@ void rewriter_tpl::process_app(app * t, frame & fr) { if (ProofGen) { NOT_IMPLEMENTED_YET(); // We do not support the use of bindings in proof generation mode. - // Thus we have to apply the subsitution here, and + // Thus we have to apply the subsitution here, and // beta_reducer subst(m()); // subst.set_bindings(new_num_args, new_args); // expr_ref r2(m()); @@ -333,7 +333,7 @@ void rewriter_tpl::process_app(app * t, frame & fr) { unsigned i = num_args; while (i > 0) { --i; - m_bindings.push_back(new_args[i]); // num_args - i - 1]); + m_bindings.push_back(new_args[i]); // num_args - i - 1]); m_shifts.push_back(sz); } result_stack().push_back(def); @@ -465,7 +465,7 @@ void rewriter_tpl::process_quantifier(quantifier * q, frame & fr) { } else { new_pats = q->get_patterns(); - new_no_pats = q->get_no_patterns(); + new_no_pats = q->get_no_patterns(); } if (ProofGen) { quantifier * new_q = m().update_quantifier(q, q->get_num_patterns(), new_pats, q->get_num_no_patterns(), new_no_pats, new_body); @@ -559,7 +559,7 @@ template void rewriter_tpl::display_bindings(std::ostream& out) { out << "bindings:\n"; for (unsigned i = 0; i < m_bindings.size(); i++) { - if (m_bindings[i]) + if (m_bindings[i]) out << i << ": " << mk_ismt2_pp(m_bindings[i], m()) << "\n"; } } @@ -596,6 +596,7 @@ template template void rewriter_tpl::main_loop(expr * t, expr_ref & result, proof_ref & result_pr) { if (m_cancel_check && m().canceled()) { + reset(); throw rewriter_exception(m().limit().get_cancel_msg()); } SASSERT(!ProofGen || result_stack().size() == result_pr_stack().size()); @@ -630,6 +631,7 @@ void rewriter_tpl::resume_core(expr_ref & result, proof_ref & result_pr) SASSERT(!frame_stack().empty()); while (!frame_stack().empty()) { if (m_cancel_check && m().canceled()) { + reset(); throw rewriter_exception(m().limit().get_cancel_msg()); } SASSERT(!ProofGen || result_stack().size() == result_pr_stack().size()); From b138a0f6d3f5c309f330c4e7969b520a6ff0e0c8 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Thu, 17 Nov 2016 16:36:39 +0000 Subject: [PATCH 373/536] Cleaned up hacky rewriter cancelation fix in theory_fpa. --- src/smt/theory_fpa.cpp | 118 +++++++++-------------------------------- 1 file changed, 26 insertions(+), 92 deletions(-) diff --git a/src/smt/theory_fpa.cpp b/src/smt/theory_fpa.cpp index 57cd6a914..a3bf77180 100644 --- a/src/smt/theory_fpa.cpp +++ b/src/smt/theory_fpa.cpp @@ -238,14 +238,7 @@ namespace smt { 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); - - try { - m_th_rw((expr_ref&)res); - } - catch (rewriter_exception &) { - m_th_rw.reset(); - throw; - } + m_th_rw((expr_ref&)res); } else { sort * es = m.get_sort(e); @@ -302,15 +295,8 @@ namespace smt { TRACE("t_fpa_detail", tout << "converting atom: " << mk_ismt2_pp(e, get_manager()) << std::endl;); expr_ref res(m); proof_ref pr(m); - try { - m_rw(e, res); - m_th_rw(res, res); - } - catch (rewriter_exception &) { - m_rw.reset(); - m_th_rw.reset(); - throw; - } + m_rw(e, res); + m_th_rw(res, res); SASSERT(is_app(res)); SASSERT(m.is_bool(res)); return res; @@ -323,41 +309,28 @@ namespace smt { expr_ref e_conv(m), res(m); proof_ref pr(m); - try { - m_rw(e, e_conv); - } - catch (rewriter_exception &) { - m_rw.reset(); - throw; - } + m_rw(e, e_conv); 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;); - try { - 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_bv2rm(bv_rm); - } - else if (m_fpa_util.is_float(e)) { - 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); - m_th_rw(exp); - m_th_rw(sig); - res = m_fpa_util.mk_fp(sgn, exp, sig); - } - else - UNREACHABLE(); + 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_bv2rm(bv_rm); } - catch (rewriter_exception &) - { - m_th_rw.reset(); - throw; + else if (m_fpa_util.is_float(e)) { + 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); + m_th_rw(exp); + m_th_rw(sig); + res = m_fpa_util.mk_fp(sgn, exp, sig); } + else + UNREACHABLE(); return res; } @@ -366,15 +339,8 @@ namespace smt { SASSERT(to_app(e)->get_family_id() == get_family_id()); /* This is for the conversion functions fp.to_* */ expr_ref res(get_manager()); - try { - m_rw(e, res); - m_th_rw(res, res); - } - catch (rewriter_exception &) { - m_rw.reset(); - m_th_rw.reset(); - throw; - } + m_rw(e, res); + m_th_rw(res, res); return res; } @@ -432,13 +398,7 @@ namespace smt { } m_converter.m_extra_assertions.reset(); - try { - m_th_rw(res); - } - catch (rewriter_exception &) { - m_th_rw.reset(); - throw; - } + m_th_rw(res); CTRACE("t_fpa", !m.is_true(res), tout << "side condition: " << mk_ismt2_pp(res, m) << std::endl;); return res; @@ -481,15 +441,7 @@ namespace smt { expr_ref bv_atom(convert_atom(atom)); expr_ref bv_atom_w_side_c(m), atom_eq(m); bv_atom_w_side_c = m.mk_and(bv_atom, mk_side_conditions()); - - try { - m_th_rw(bv_atom_w_side_c); - } - catch (rewriter_exception &) { - m_th_rw.reset(); - throw; - } - + m_th_rw(bv_atom_w_side_c); atom_eq = m.mk_eq(atom, bv_atom_w_side_c); assert_cnstr(atom_eq); return true; @@ -600,13 +552,7 @@ namespace smt { else c = m.mk_eq(xc, yc); - try { - m_th_rw(c); - } - catch (rewriter_exception &) { - m_th_rw.reset(); - throw; - } + m_th_rw(c); expr_ref xe_eq_ye(m), c_eq_iff(m); xe_eq_ye = m.mk_eq(xe, ye); @@ -652,13 +598,7 @@ namespace smt { c = m.mk_not(xc_eq_yc); } - try { - m_th_rw(c); - } - catch (rewriter_exception &) { - m_th_rw.reset(); - throw; - } + m_th_rw(c); expr_ref xe_eq_ye(m), not_xe_eq_ye(m), c_eq_iff(m); xe_eq_ye = m.mk_eq(xe, ye); @@ -697,13 +637,7 @@ namespace smt { expr_ref cnstr(m); cnstr = (is_true) ? m.mk_implies(e, converted) : m.mk_implies(converted, e); - try { - m_th_rw(cnstr); - } - catch (rewriter_exception &) { - m_th_rw.reset(); - throw; - } + m_th_rw(cnstr); assert_cnstr(cnstr); } From ea601dd403dc17819ad79b44e76ea6f62f43ccc2 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 19 Nov 2016 03:55:48 -0800 Subject: [PATCH 374/536] fix and coallesce clique functionality Signed-off-by: Nikolaj Bjorner --- contrib/cmake/src/opt/CMakeLists.txt | 1 + src/muz/pdr/pdr_context.cpp | 9 +- src/opt/maxres.cpp | 3 - src/opt/maxsmt.cpp | 3 + src/opt/sortmax.cpp | 141 +++++++++++++++++++++++++++ src/opt/wmax.cpp | 5 +- src/opt/wmax.h | 2 + src/sat/sat_solver.cpp | 75 +++++--------- src/sat/sat_solver.h | 5 - src/sat/sat_types.h | 1 + src/smt/params/qi_params.cpp | 2 +- src/smt/smt_consequences.cpp | 75 ++++++-------- src/smt/smt_context.h | 5 - src/smt/smt_model_checker.cpp | 1 + src/util/max_cliques.h | 140 ++++++++++++++++++++++++++ src/util/sorting_network.h | 4 +- src/util/uint_set.h | 8 +- 17 files changed, 361 insertions(+), 119 deletions(-) create mode 100644 src/opt/sortmax.cpp create mode 100644 src/util/max_cliques.h diff --git a/contrib/cmake/src/opt/CMakeLists.txt b/contrib/cmake/src/opt/CMakeLists.txt index b8d17ec89..05a62b6c2 100644 --- a/contrib/cmake/src/opt/CMakeLists.txt +++ b/contrib/cmake/src/opt/CMakeLists.txt @@ -9,6 +9,7 @@ z3_add_component(opt optsmt.cpp opt_solver.cpp pb_sls.cpp + sortmax.cpp wmax.cpp COMPONENT_DEPENDENCIES sat_solver diff --git a/src/muz/pdr/pdr_context.cpp b/src/muz/pdr/pdr_context.cpp index 6d3a57581..01a9a4416 100644 --- a/src/muz/pdr/pdr_context.cpp +++ b/src/muz/pdr/pdr_context.cpp @@ -584,6 +584,7 @@ namespace pdr { init_atom(pts, rule.get_head(), var_reprs, conj, UINT_MAX); for (unsigned i = 0; i < ut_size; ++i) { if (rule.is_neg_tail(i)) { + dealloc(&var_reprs); throw default_exception("PDR does not support negated predicates in rule tails"); } init_atom(pts, rule.get_tail(i), var_reprs, conj, i); @@ -602,7 +603,13 @@ namespace pdr { var_subst(m, false)(tail[i].get(), var_reprs.size(), (expr*const*)var_reprs.c_ptr(), tmp); conj.push_back(tmp); TRACE("pdr", tout << mk_pp(tail[i].get(), m) << "\n" << mk_pp(tmp, m) << "\n";); - SASSERT(is_ground(tmp)); + if (!is_ground(tmp)) { + std::stringstream msg; + msg << "PDR cannot solve non-ground tails: " << tmp; + IF_VERBOSE(0, verbose_stream() << msg.str() << "\n";); + dealloc(&var_reprs); + throw default_exception(msg.str()); + } } expr_ref fml = pm.mk_and(conj); th_rewriter rw(m); diff --git a/src/opt/maxres.cpp b/src/opt/maxres.cpp index 016f1ee0e..7f9183d9a 100644 --- a/src/opt/maxres.cpp +++ b/src/opt/maxres.cpp @@ -162,7 +162,6 @@ public: if (m_asm2weight.find(e, weight)) { weight += w; m_asm2weight.insert(e, weight); - m_upper += w; return; } if (is_literal(e)) { @@ -174,7 +173,6 @@ public: s().assert_expr(fml); } new_assumption(asum, w); - m_upper += w; } void new_assumption(expr* e, rational const& w) { @@ -805,7 +803,6 @@ public: } lbool init_local() { - m_upper.reset(); m_lower.reset(); m_trail.reset(); obj_map new_soft; diff --git a/src/opt/maxsmt.cpp b/src/opt/maxsmt.cpp index 97ce28166..85b19e427 100644 --- a/src/opt/maxsmt.cpp +++ b/src/opt/maxsmt.cpp @@ -235,6 +235,9 @@ namespace opt { else if (maxsat_engine == symbol("wmax")) { m_msolver = mk_wmax(m_c, m_weights, m_soft_constraints); } + else if (maxsat_engine == symbol("sortmax")) { + m_msolver = mk_sortmax(m_c, m_weights, m_soft_constraints); + } else { warning_msg("solver %s is not recognized, using default 'maxres'", maxsat_engine.str().c_str()); m_msolver = mk_maxres(m_c, m_index, m_weights, m_soft_constraints); diff --git a/src/opt/sortmax.cpp b/src/opt/sortmax.cpp new file mode 100644 index 000000000..6df827896 --- /dev/null +++ b/src/opt/sortmax.cpp @@ -0,0 +1,141 @@ +/*++ +Copyright (c) 2014 Microsoft Corporation + +Module Name: + + sortmax.cpp + +Abstract: + + Theory based MaxSAT. + +Author: + + Nikolaj Bjorner (nbjorner) 2016-11-18 + +Notes: + +--*/ +#include "maxsmt.h" +#include "uint_set.h" +#include "ast_pp.h" +#include "model_smt2_pp.h" +#include "smt_theory.h" +#include "smt_context.h" +#include "opt_context.h" +#include "sorting_network.h" +#include "filter_model_converter.h" + +namespace opt { + + class sortmax : public maxsmt_solver_base { + public: + typedef expr* literal; + typedef ptr_vector literal_vector; + psort_nw m_sort; + expr_ref_vector m_trail; + func_decl_ref_vector m_fresh; + ref m_filter; + sortmax(maxsat_context& c, weights_t& ws, expr_ref_vector const& soft): + maxsmt_solver_base(c, ws, soft), m_sort(*this), m_trail(m), m_fresh(m) {} + + virtual ~sortmax() {} + + lbool operator()() { + obj_map soft; + if (!init()) { + return l_false; + } + lbool is_sat = find_mutexes(soft); + if (is_sat != l_true) { + return is_sat; + } + m_filter = alloc(filter_model_converter, m); + rational offset = m_lower; + m_upper = offset; + expr_ref_vector in(m); + expr_ref tmp(m); + ptr_vector out; + obj_map::iterator it = soft.begin(), end = soft.end(); + for (; it != end; ++it) { + unsigned n = it->m_value.get_unsigned(); + while (n > 0) { + in.push_back(it->m_key); + --n; + } + m_upper += it->m_value; + } + m_sort.sorting(in.size(), in.c_ptr(), out); + unsigned first = 0; + while (l_true == is_sat && first < out.size() && m_lower < m_upper) { + trace_bounds("sortmax"); + s().assert_expr(out[first]); + is_sat = s().check_sat(0, 0); + TRACE("opt", tout << is_sat << "\n"; s().display(tout); tout << "\n";); + if (m.canceled()) { + is_sat = l_undef; + } + if (is_sat == l_true) { + ++first; + s().get_model(m_model); + update_assignment(); + for (; first < out.size() && is_true(out[first]); ++first) { + s().assert_expr(out[first]); + } + TRACE("opt", model_smt2_pp(tout, m, *m_model.get(), 0);); + m_upper = m_lower + rational(out.size() - first); + (*m_filter)(m_model); + } + } + if (is_sat == l_false) { + is_sat = l_true; + m_lower = m_upper; + } + TRACE("opt", tout << "min cost: " << m_upper << "\n";); + return is_sat; + } + + void update_assignment() { + for (unsigned i = 0; i < m_soft.size(); ++i) { + m_assignment[i] = is_true(m_soft[i]); + } + } + + bool is_true(expr* e) { + expr_ref tmp(m); + return m_model->eval(e, tmp) && m.is_true(tmp); + } + + // definitions used for sorting network + literal mk_false() { return m.mk_false(); } + literal mk_true() { return m.mk_true(); } + literal mk_max(literal a, literal b) { return trail(m.mk_or(a, b)); } + literal mk_min(literal a, literal b) { return trail(m.mk_and(a, b)); } + literal mk_not(literal a) { if (m.is_not(a,a)) return a; return trail(m.mk_not(a)); } + + std::ostream& pp(std::ostream& out, literal lit) { return out << mk_pp(lit, m); } + + literal trail(literal l) { + m_trail.push_back(l); + return l; + } + literal fresh() { + expr_ref fr(m.mk_fresh_const("sn", m.mk_bool_sort()), m); + func_decl* f = to_app(fr)->get_decl(); + m_fresh.push_back(f); + m_filter->insert(f); + return trail(fr); + } + + void mk_clause(unsigned n, literal const* lits) { + s().assert_expr(mk_or(m, n, lits)); + } + + }; + + + maxsmt_solver_base* mk_sortmax(maxsat_context& c, weights_t& ws, expr_ref_vector const& soft) { + return alloc(sortmax, c, ws, soft); + } + +} diff --git a/src/opt/wmax.cpp b/src/opt/wmax.cpp index d3ceb9a3b..7e0e796ca 100644 --- a/src/opt/wmax.cpp +++ b/src/opt/wmax.cpp @@ -51,7 +51,10 @@ namespace opt { obj_map::iterator it = soft.begin(), end = soft.end(); for (; it != end; ++it) { wth().assert_weighted(it->m_key, it->m_value); - m_upper += it->m_value; + expr_ref tmp(m); + if (!m_model->eval(it->m_key, tmp) || !m.is_true(tmp)) { + m_upper += it->m_value; + } } trace_bounds("wmax"); while (l_true == is_sat && m_lower < m_upper) { diff --git a/src/opt/wmax.h b/src/opt/wmax.h index 094bb8644..3d9d206ad 100644 --- a/src/opt/wmax.h +++ b/src/opt/wmax.h @@ -25,5 +25,7 @@ Notes: namespace opt { maxsmt_solver_base* mk_wmax(maxsat_context& c, weights_t & ws, expr_ref_vector const& soft); + maxsmt_solver_base* mk_sortmax(maxsat_context& c, weights_t & ws, expr_ref_vector const& soft); + } #endif diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 7acfda822..9cf13afe4 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -21,6 +21,7 @@ Revision History: #include"luby.h" #include"trace.h" #include"sat_bceq.h" +#include"max_cliques.h" // define to update glue during propagation #define UPDATE_GLUE @@ -3062,74 +3063,44 @@ namespace sat { // // ----------------------- + struct neg_literal { + unsigned negate(unsigned idx) { + return (~to_literal(idx)).index(); + } + }; + lbool solver::find_mutexes(literal_vector const& lits, vector & mutexes) { - literal_vector ps(lits); + max_cliques mc; m_user_bin_clauses.reset(); m_binary_clause_graph.reset(); collect_bin_clauses(m_user_bin_clauses, true); collect_bin_clauses(m_user_bin_clauses, false); + hashtable, default_eq > seen_bc; for (unsigned i = 0; i < m_user_bin_clauses.size(); ++i) { literal l1 = m_user_bin_clauses[i].first; literal l2 = m_user_bin_clauses[i].second; - m_binary_clause_graph.reserve(l1.index() + 1); - m_binary_clause_graph.reserve(l2.index() + 1); - m_binary_clause_graph.reserve((~l1).index() + 1); - m_binary_clause_graph.reserve((~l2).index() + 1); - m_binary_clause_graph[l1.index()].push_back(l2); - m_binary_clause_graph[l2.index()].push_back(l1); + literal_pair p(l1, l2); + if (!seen_bc.contains(p)) { + seen_bc.insert(p); + mc.add_edge(l1.index(), l2.index()); + } } + vector _mutexes; + unsigned_vector ps; for (unsigned i = 0; i < lits.size(); ++i) { - m_binary_clause_graph.reserve(lits[i].index() + 1); - m_binary_clause_graph.reserve((~lits[i]).index() + 1); + ps.push_back(lits[i].index()); } - bool non_empty = true; - m_seen[0].reset(); - while (non_empty) { - literal_vector mutex; - bool turn = false; - m_reachable[turn] = ps; - while (!m_reachable[turn].empty()) { - literal p = m_reachable[turn].pop(); - if (m_seen[0].contains(p)) { - continue; - } - m_reachable[turn].remove(p); - m_seen[0].insert(p); - mutex.push_back(p); - if (m_reachable[turn].empty()) { - break; - } - m_reachable[!turn].reset(); - get_reachable(p, m_reachable[turn], m_reachable[!turn]); - turn = !turn; + mc.cliques(ps, _mutexes); + for (unsigned i = 0; i < _mutexes.size(); ++i) { + literal_vector lits; + for (unsigned j = 0; j < _mutexes[i].size(); ++j) { + lits.push_back(to_literal(_mutexes[i][j])); } - if (mutex.size() > 1) { - mutexes.push_back(mutex); - } - non_empty = !mutex.empty(); + mutexes.push_back(lits); } return l_true; } - void solver::get_reachable(literal p, literal_set const& goal, literal_set& reachable) { - m_seen[1].reset(); - m_todo.reset(); - m_todo.push_back(p); - while (!m_todo.empty()) { - p = m_todo.back(); - m_todo.pop_back(); - if (m_seen[1].contains(p)) { - continue; - } - m_seen[1].insert(p); - literal np = ~p; - if (goal.contains(np)) { - reachable.insert(np); - } - m_todo.append(m_binary_clause_graph[np.index()]); - } - } - // ----------------------- // // Consequence generation. diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index a44f07a23..bcd9a66d2 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -451,14 +451,9 @@ namespace sat { u_map m_antecedents; vector m_binary_clause_graph; - literal_set m_reachable[2]; - literal_set m_seen[2]; - literal_vector m_todo; void extract_assumptions(literal lit, index_set& s); - void get_reachable(literal p, literal_set const& goal, literal_set& reachable); - lbool get_consequences(literal_vector const& assms, literal_vector const& lits, vector& conseq); void delete_unfixed(literal_set& unfixed); diff --git a/src/sat/sat_types.h b/src/sat/sat_types.h index 509cc58ba..28d8d761a 100644 --- a/src/sat/sat_types.h +++ b/src/sat/sat_types.h @@ -96,6 +96,7 @@ namespace sat { }; const literal null_literal; + struct literal_hash : obj_hash {}; inline literal to_literal(unsigned x) { return literal(x); } inline bool operator<(literal const & l1, literal const & l2) { return l1.m_val < l2.m_val; } diff --git a/src/smt/params/qi_params.cpp b/src/smt/params/qi_params.cpp index a341040ce..8182222e4 100644 --- a/src/smt/params/qi_params.cpp +++ b/src/smt/params/qi_params.cpp @@ -62,4 +62,4 @@ void qi_params::display(std::ostream & out) const { DISPLAY_PARAM(m_mbqi_trace); DISPLAY_PARAM(m_mbqi_force_template); DISPLAY_PARAM(m_mbqi_id); -} \ No newline at end of file +} diff --git a/src/smt/smt_consequences.cpp b/src/smt/smt_consequences.cpp index 667411be5..e6edbf87e 100644 --- a/src/smt/smt_consequences.cpp +++ b/src/smt/smt_consequences.cpp @@ -20,6 +20,8 @@ Revision History: #include "ast_util.h" #include "datatype_decl_plugin.h" #include "model_pp.h" +#include "max_cliques.h" +#include "stopwatch.h" namespace smt { @@ -367,67 +369,46 @@ namespace smt { << ")\n"; } + struct neg_literal { + unsigned negate(unsigned i) { + return (~to_literal(i)).index(); + } + }; lbool context::find_mutexes(expr_ref_vector const& vars, vector& mutexes) { - uint_set lits; + unsigned_vector ps; + max_cliques mc; + expr_ref lit(m_manager); for (unsigned i = 0; i < vars.size(); ++i) { expr* n = vars[i]; bool neg = m_manager.is_not(n, n); if (b_internalized(n)) { - lits.insert(literal(get_bool_var(n), neg).index()); + ps.push_back(literal(get_bool_var(n), neg).index()); } } - while (!lits.empty()) { - literal_vector mutex; - uint_set other(lits); - while (!other.empty()) { - uint_set conseq; - literal p = to_literal(*other.begin()); - other.remove(p.index()); - mutex.push_back(p); - if (other.empty()) { - break; + for (unsigned i = 0; i < m_watches.size(); ++i) { + watch_list & w = m_watches[i]; + for (literal const* it = w.begin_literals(), *end = w.end_literals(); it != end; ++it) { + unsigned idx1 = (~to_literal(i)).index(); + unsigned idx2 = it->index(); + if (idx1 < idx2) { + mc.add_edge(idx1, idx2); } - get_reachable(p, other, conseq); - other = conseq; - } - if (mutex.size() > 1) { - expr_ref_vector mux(m_manager); - for (unsigned i = 0; i < mutex.size(); ++i) { - expr_ref e(m_manager); - literal2expr(mutex[i], e); - mux.push_back(e); - } - mutexes.push_back(mux); - } - for (unsigned i = 0; i < mutex.size(); ++i) { - lits.remove(mutex[i].index()); } } + vector _mutexes; + mc.cliques(ps, _mutexes); + for (unsigned i = 0; i < _mutexes.size(); ++i) { + expr_ref_vector lits(m_manager); + for (unsigned j = 0; j < _mutexes[i].size(); ++j) { + literal2expr(to_literal(_mutexes[i][j]), lit); + lits.push_back(lit); + } + mutexes.push_back(lits); + } return l_true; } - void context::get_reachable(literal p, uint_set& goal, uint_set& reachable) { - uint_set seen; - literal_vector todo; - todo.push_back(p); - while (!todo.empty()) { - // std::cout << "todo: " << todo.size() << "\n"; - p = todo.back(); - todo.pop_back(); - if (seen.contains(p.index())) { - continue; - } - seen.insert(p.index()); - literal np = ~p; - if (goal.contains(np.index())) { - reachable.insert(np.index()); - } - watch_list & w = m_watches[np.index()]; - todo.append(static_cast(w.end_literals() - w.begin_literals()), w.begin_literals()); - } - } - // // Validate, in a slow pass, that the current consequences are correctly // extracted. diff --git a/src/smt/smt_context.h b/src/smt/smt_context.h index 84459d272..21d628e1a 100644 --- a/src/smt/smt_context.h +++ b/src/smt/smt_context.h @@ -1367,11 +1367,6 @@ namespace smt { void validate_consequences(expr_ref_vector const& assumptions, expr_ref_vector const& vars, expr_ref_vector const& conseq, expr_ref_vector const& unfixed); - /* - \brief Auxiliry function for mutex finding. - */ - - void get_reachable(literal p, uint_set& goal, uint_set& reached); public: context(ast_manager & m, smt_params & fp, params_ref const & p = params_ref()); diff --git a/src/smt/smt_model_checker.cpp b/src/smt/smt_model_checker.cpp index c17211664..a7f415aad 100644 --- a/src/smt/smt_model_checker.cpp +++ b/src/smt/smt_model_checker.cpp @@ -194,6 +194,7 @@ namespace smt { } tout << "\n";); + max_generation = std::max(m_qm->get_generation(q), max_generation); add_instance(q, bindings, max_generation); return true; } diff --git a/src/util/max_cliques.h b/src/util/max_cliques.h new file mode 100644 index 000000000..8668b9931 --- /dev/null +++ b/src/util/max_cliques.h @@ -0,0 +1,140 @@ +/*++ +Copyright (c) 2016 Microsoft Corporation + +Module Name: + + max_cliques.h + +Abstract: + + Utility for enumerating locally maximal sub cliques. + +Author: + + Nikolaj Bjorner (nbjorner) 2016-11-18 + +Notes: + + +--*/ + +#include "vector.h" +#include "uint_set.h" + +class max_cliques_plugin { +public: + virtual unsigned operator()(unsigned i) = 0; +}; + +template +class max_cliques : public T { + vector m_next, m_tc; + uint_set m_reachable[2]; + uint_set m_seen1, m_seen2; + unsigned_vector m_todo; + + void get_reachable(unsigned p, uint_set const& goal, uint_set& reachable) { + m_seen1.reset(); + m_todo.reset(); + m_todo.push_back(p); + for (unsigned i = 0; i < m_todo.size(); ++i) { + p = m_todo[i]; + if (m_seen1.contains(p)) { + continue; + } + m_seen1.insert(p); + if (m_seen2.contains(p)) { + unsigned_vector const& tc = m_tc[p]; + for (unsigned j = 0; j < tc.size(); ++j) { + unsigned np = tc[j]; + if (goal.contains(np)) { + reachable.insert(np); + } + } + } + else { + unsigned np = negate(p); + if (goal.contains(np)) { + reachable.insert(np); + } + m_todo.append(next(np)); + } + } + for (unsigned i = m_todo.size(); i > 0; ) { + --i; + p = m_todo[i]; + if (m_seen2.contains(p)) { + continue; + } + m_seen2.insert(p); + unsigned np = negate(p); + unsigned_vector& tc = m_tc[p]; + if (goal.contains(np)) { + tc.push_back(np); + } + else { + unsigned_vector const& succ = next(np); + for (unsigned j = 0; j < succ.size(); ++j) { + tc.append(m_tc[succ[j]]); + } + } + } + } + + + + + + unsigned_vector const& next(unsigned vertex) const { return m_next[vertex]; } + +public: + max_cliques() {} + + void add_edge(unsigned src, unsigned dst) { + m_next.reserve(std::max(src, dst) + 1); + m_next.reserve(std::max(negate(src), negate(dst)) + 1); + m_next[src].push_back(dst); + m_next[dst].push_back(src); + } + + void cliques(unsigned_vector const& ps, vector& cliques) { + unsigned max = 0; + unsigned num_ps = ps.size(); + for (unsigned i = 0; i < num_ps; ++i) { + unsigned p = ps[i]; + unsigned np = negate(p); + max = std::max(max, std::max(np, p) + 1); + } + m_next.reserve(max); + m_tc.reserve(max); + unsigned_vector clique; + uint_set vars; + for (unsigned i = 0; i < num_ps; ++i) { + vars.insert(ps[i]); + } + + while (!vars.empty()) { + clique.reset(); + bool turn = false; + m_reachable[turn] = vars; + while (!m_reachable[turn].empty()) { + unsigned p = *m_reachable[turn].begin(); + m_reachable[turn].remove(p); + vars.remove(p); + clique.push_back(p); + if (m_reachable[turn].empty()) { + break; + } + m_reachable[!turn].reset(); + get_reachable(p, m_reachable[turn], m_reachable[!turn]); + turn = !turn; + } + if (clique.size() > 1) { + std::cout << clique.size() << "\n"; + cliques.push_back(clique); + } + } + } + + +}; diff --git a/src/util/sorting_network.h b/src/util/sorting_network.h index 87d8bbf3f..2c819db04 100644 --- a/src/util/sorting_network.h +++ b/src/util/sorting_network.h @@ -744,6 +744,7 @@ Notes: return vc_cmp()*std::min(a-1,b); } + public: void sorting(unsigned n, literal const* xs, literal_vector& out) { TRACE("pb", tout << "sorting: " << n << "\n";); switch(n) { @@ -773,8 +774,9 @@ Notes: TRACE("pb", tout << "sorting: " << n << "\n"; pp(tout << "in:", n, xs) << "\n"; pp(tout << "out:", out) << "\n";); - } + + private: vc vc_sorting(unsigned n) { switch(n) { case 0: return vc(0,0); diff --git a/src/util/uint_set.h b/src/util/uint_set.h index 525638f4f..e78a4b0b6 100644 --- a/src/util/uint_set.h +++ b/src/util/uint_set.h @@ -163,10 +163,11 @@ public: class iterator { uint_set const* m_set; unsigned m_index; + unsigned m_last; - bool invariant() const { return m_index <= m_set->get_max_elem(); } + bool invariant() const { return m_index <= m_last; } - bool at_end() const { return m_index == m_set->get_max_elem(); } + bool at_end() const { return m_index == m_last; } void scan_idx() { SASSERT(invariant()); @@ -200,7 +201,7 @@ public: } public: iterator(uint_set const& s, bool at_end): - m_set(&s), m_index(at_end?s.get_max_elem():0) { + m_set(&s), m_index(at_end?s.get_max_elem():0), m_last(s.get_max_elem()) { scan(); SASSERT(invariant()); } @@ -212,6 +213,7 @@ public: iterator & operator=(iterator const& other) { m_set = other.m_set; m_index = other.m_index; + m_last = other.m_last; return *this; } }; From df0e3a100ca46cd5a2990b3cb94a47928c20130d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 19 Nov 2016 08:04:06 -0800 Subject: [PATCH 375/536] tune initialization for wmax and sortmax Signed-off-by: Nikolaj Bjorner --- src/opt/sortmax.cpp | 21 ++++++++++++++++++++- src/opt/wmax.cpp | 8 ++++++-- src/smt/theory_wmaxsat.cpp | 8 +++++--- src/smt/theory_wmaxsat.h | 2 +- src/util/max_cliques.h | 5 ----- 5 files changed, 32 insertions(+), 12 deletions(-) diff --git a/src/opt/sortmax.cpp b/src/opt/sortmax.cpp index 6df827896..e3cf59de4 100644 --- a/src/opt/sortmax.cpp +++ b/src/opt/sortmax.cpp @@ -58,15 +58,34 @@ namespace opt { ptr_vector out; obj_map::iterator it = soft.begin(), end = soft.end(); for (; it != end; ++it) { + if (!it->m_value.is_unsigned()) { + throw default_exception("sortmax can only handle unsigned weights. Use a different heuristic."); + } unsigned n = it->m_value.get_unsigned(); while (n > 0) { in.push_back(it->m_key); --n; } - m_upper += it->m_value; } m_sort.sorting(in.size(), in.c_ptr(), out); + + // initialize sorting network outputs using the initial assignment. unsigned first = 0; + it = soft.begin(); + for (; it != end; ++it) { + expr_ref tmp(m); + if (m_model->eval(it->m_key, tmp) && m.is_true(tmp)) { + unsigned n = it->m_value.get_unsigned(); + while (n > 0) { + s().assert_expr(out[first]); + ++first; + --n; + } + } + else { + m_upper += it->m_value; + } + } while (l_true == is_sat && first < out.size() && m_lower < m_upper) { trace_bounds("sortmax"); s().assert_expr(out[first]); diff --git a/src/opt/wmax.cpp b/src/opt/wmax.cpp index 7e0e796ca..d8ffe9f66 100644 --- a/src/opt/wmax.cpp +++ b/src/opt/wmax.cpp @@ -48,14 +48,18 @@ namespace opt { rational offset = m_lower; m_upper = offset; bool was_sat = false; + expr_ref_vector disj(m); obj_map::iterator it = soft.begin(), end = soft.end(); for (; it != end; ++it) { - wth().assert_weighted(it->m_key, it->m_value); expr_ref tmp(m); - if (!m_model->eval(it->m_key, tmp) || !m.is_true(tmp)) { + bool is_true = m_model->eval(it->m_key, tmp) && m.is_true(tmp); + expr* c = wth().assert_weighted(it->m_key, it->m_value, is_true); + if (!is_true) { m_upper += it->m_value; + disj.push_back(c); } } + s().assert_expr(mk_or(disj)); trace_bounds("wmax"); while (l_true == is_sat && m_lower < m_upper) { is_sat = s().check_sat(0, 0); diff --git a/src/smt/theory_wmaxsat.cpp b/src/smt/theory_wmaxsat.cpp index b572d8e69..fd07188e5 100644 --- a/src/smt/theory_wmaxsat.cpp +++ b/src/smt/theory_wmaxsat.cpp @@ -87,7 +87,7 @@ void theory_wmaxsat::init_search_eh() { m_propagate = true; } -bool_var theory_wmaxsat::assert_weighted(expr* fml, rational const& w) { +expr* theory_wmaxsat::assert_weighted(expr* fml, rational const& w, bool is_true) { context & ctx = get_context(); ast_manager& m = get_manager(); app_ref var(m), wfml(m); @@ -99,9 +99,11 @@ bool_var theory_wmaxsat::assert_weighted(expr* fml, rational const& w) { m_vars.push_back(var); m_fmls.push_back(fml); m_assigned.push_back(false); - m_rmin_cost += w; + if (!is_true) { + m_rmin_cost += w; + } m_normalize = true; - return register_var(var, true); + return ctx.bool_var2expr(register_var(var, true)); } bool_var theory_wmaxsat::register_var(app* var, bool attach) { diff --git a/src/smt/theory_wmaxsat.h b/src/smt/theory_wmaxsat.h index b0c556c0e..0804c4b68 100644 --- a/src/smt/theory_wmaxsat.h +++ b/src/smt/theory_wmaxsat.h @@ -57,7 +57,7 @@ namespace smt { virtual ~theory_wmaxsat(); void get_assignment(svector& result); virtual void init_search_eh(); - bool_var assert_weighted(expr* fml, rational const& w); + expr* assert_weighted(expr* fml, rational const& w, bool is_true); bool_var register_var(app* var, bool attach); rational const& get_min_cost(); class numeral_trail : public trail { diff --git a/src/util/max_cliques.h b/src/util/max_cliques.h index 8668b9931..e8493a9b9 100644 --- a/src/util/max_cliques.h +++ b/src/util/max_cliques.h @@ -21,10 +21,6 @@ Notes: #include "vector.h" #include "uint_set.h" -class max_cliques_plugin { -public: - virtual unsigned operator()(unsigned i) = 0; -}; template class max_cliques : public T { @@ -130,7 +126,6 @@ public: turn = !turn; } if (clique.size() > 1) { - std::cout << clique.size() << "\n"; cliques.push_back(clique); } } From 2ff5af7d42c90efdce367a0cb13ee6a6e5aae90c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 19 Nov 2016 10:06:16 -0800 Subject: [PATCH 376/536] fix bug incorrect clearing of goals during node creation. Issue #777 Signed-off-by: Nikolaj Bjorner --- src/muz/base/dl_context.cpp | 16 +++++++++++----- src/muz/pdr/pdr_context.cpp | 8 +++----- src/muz/pdr/pdr_dl_interface.cpp | 1 + 3 files changed, 15 insertions(+), 10 deletions(-) diff --git a/src/muz/base/dl_context.cpp b/src/muz/base/dl_context.cpp index 08fc0b9d7..2ca74a73b 100644 --- a/src/muz/base/dl_context.cpp +++ b/src/muz/base/dl_context.cpp @@ -1001,14 +1001,20 @@ namespace datalog { if (is_quantifier(body)) { quantifier* q = to_quantifier(body); expr* e = q->get_expr(); - VERIFY(m.is_implies(e, body, e2)); - fml = m.mk_quantifier(false, q->get_num_decls(), - q->get_decl_sorts(), q->get_decl_names(), - body); + if (m.is_implies(e, body, e2)) { + fml = m.mk_quantifier(false, q->get_num_decls(), + q->get_decl_sorts(), q->get_decl_names(), + body); + } + else { + fml = body; + } } else { - VERIFY(m.is_implies(body, body, e2)); fml = body; + if (m.is_implies(body, body, e2)) { + fml = body; + } } queries.push_back(fml); } diff --git a/src/muz/pdr/pdr_context.cpp b/src/muz/pdr/pdr_context.cpp index 01a9a4416..676f820b2 100644 --- a/src/muz/pdr/pdr_context.cpp +++ b/src/muz/pdr/pdr_context.cpp @@ -895,14 +895,12 @@ namespace pdr { void model_node::dequeue(model_node*& root) { - TRACE("pdr", tout << this << " " << state() << "\n";); - root = 0; + TRACE("pdr", tout << this << " root: " << root << " " << state() << "\n";); if (!m_next && !m_prev) return; SASSERT(m_next); SASSERT(m_prev); SASSERT(children().empty()); if (this == m_next) { - // SASSERT(root == this); root = 0; } else { @@ -975,7 +973,7 @@ namespace pdr { } void model_search::enqueue_leaf(model_node* n) { - TRACE("pdr_verbose", tout << n << " " << n->state() << " goal: " << m_goal << "\n";); + TRACE("pdr_verbose", tout << "node: " << n << " " << n->state() << " goal: " << m_goal << "\n";); SASSERT(n->is_open()); if (!m_goal) { m_goal = n; @@ -1005,7 +1003,7 @@ namespace pdr { return m_cache[l]; } - void model_search::erase_children(model_node& n, bool backtrack) { + void model_search::erase_children(model_node& n, bool backtrack) { ptr_vector todo, nodes; todo.append(n.children()); remove_goal(n); diff --git a/src/muz/pdr/pdr_dl_interface.cpp b/src/muz/pdr/pdr_dl_interface.cpp index dfc15636c..761b730ce 100644 --- a/src/muz/pdr/pdr_dl_interface.cpp +++ b/src/muz/pdr/pdr_dl_interface.cpp @@ -148,6 +148,7 @@ lbool dl_interface::query(expr * query) { TRACE("pdr", tout << "rules:\n"; m_ctx.display_rules(tout); + m_ctx.display_smt2(0, 0, tout); ); IF_VERBOSE(2, m_ctx.display_rules(verbose_stream());); From 6a9b5ea3af3693662eccd91a7183b1ad65a363ed Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 19 Nov 2016 15:29:43 -0800 Subject: [PATCH 377/536] fix unsoundness reported in issue #777, disable ematching on recursive function definition axioms exposed in #793 Signed-off-by: Nikolaj Bjorner --- src/muz/pdr/pdr_context.cpp | 5 ++- src/smt/smt_quantifier.cpp | 77 +++++++++++++++++++------------------ 2 files changed, 43 insertions(+), 39 deletions(-) diff --git a/src/muz/pdr/pdr_context.cpp b/src/muz/pdr/pdr_context.cpp index 676f820b2..32f8e1ef1 100644 --- a/src/muz/pdr/pdr_context.cpp +++ b/src/muz/pdr/pdr_context.cpp @@ -901,7 +901,10 @@ namespace pdr { SASSERT(m_prev); SASSERT(children().empty()); if (this == m_next) { - root = 0; + SASSERT(m_prev == this); + if (root == this) { + root = 0; + } } else { m_next->m_prev = m_prev; diff --git a/src/smt/smt_quantifier.cpp b/src/smt/smt_quantifier.cpp index 5787d6732..58aa01845 100644 --- a/src/smt/smt_quantifier.cpp +++ b/src/smt/smt_quantifier.cpp @@ -186,7 +186,7 @@ namespace smt { } bool check_quantifier(quantifier* q) { - return m_context.is_relevant(q) && m_context.get_assignment(q) == l_true; // TBD: && !m_context->get_manager().is_rec_fun_def(q); + return m_context.is_relevant(q) && m_context.get_assignment(q) == l_true; // && !m_context.get_manager().is_rec_fun_def(q); } bool quick_check_quantifiers() { @@ -357,15 +357,12 @@ namespace smt { } void quantifier_manager::reset() { - #pragma omp critical (quantifier_manager) - { - context & ctx = m_imp->m_context; - smt_params & p = m_imp->m_params; - quantifier_manager_plugin * plugin = m_imp->m_plugin->mk_fresh(); - m_imp->~imp(); - m_imp = new (m_imp) imp(*this, ctx, p, plugin); - plugin->set_manager(*this); - } + context & ctx = m_imp->m_context; + smt_params & p = m_imp->m_params; + quantifier_manager_plugin * plugin = m_imp->m_plugin->mk_fresh(); + m_imp->~imp(); + m_imp = new (m_imp) imp(*this, ctx, p, plugin); + plugin->set_manager(*this); } void quantifier_manager::display(std::ostream & out) const { @@ -481,36 +478,40 @@ namespace smt { virtual void assign_eh(quantifier * q) { m_active = true; - if (m_fparams->m_ematching) { - bool has_unary_pattern = false; - unsigned num_patterns = q->get_num_patterns(); - for (unsigned i = 0; i < num_patterns; i++) { - app * mp = to_app(q->get_pattern(i)); - if (mp->get_num_args() == 1) { - has_unary_pattern = true; - break; - } + if (!m_fparams->m_ematching) { + return; + } + if (m_context->get_manager().is_rec_fun_def(q) && mbqi_enabled(q)) { + return; + } + bool has_unary_pattern = false; + unsigned num_patterns = q->get_num_patterns(); + for (unsigned i = 0; i < num_patterns; i++) { + app * mp = to_app(q->get_pattern(i)); + if (mp->get_num_args() == 1) { + has_unary_pattern = true; + break; } - unsigned num_eager_multi_patterns = m_fparams->m_qi_max_eager_multipatterns; - if (!has_unary_pattern) - num_eager_multi_patterns++; - for (unsigned i = 0, j = 0; i < num_patterns; i++) { - app * mp = to_app(q->get_pattern(i)); - SASSERT(m_context->get_manager().is_pattern(mp)); - bool unary = (mp->get_num_args() == 1); - if (!unary && j >= num_eager_multi_patterns) { - TRACE("assign_quantifier", tout << "delaying (too many multipatterns):\n" << mk_ismt2_pp(mp, m_context->get_manager()) << "\n" - << "j: " << j << " unary: " << unary << " m_params.m_qi_max_eager_multipatterns: " << m_fparams->m_qi_max_eager_multipatterns - << " num_eager_multi_patterns: " << num_eager_multi_patterns << "\n";); - m_lazy_mam->add_pattern(q, mp); - } - else { - TRACE("assign_quantifier", tout << "adding:\n" << mk_ismt2_pp(mp, m_context->get_manager()) << "\n";); - m_mam->add_pattern(q, mp); - } - if (!unary) - j++; + } + unsigned num_eager_multi_patterns = m_fparams->m_qi_max_eager_multipatterns; + if (!has_unary_pattern) + num_eager_multi_patterns++; + for (unsigned i = 0, j = 0; i < num_patterns; i++) { + app * mp = to_app(q->get_pattern(i)); + SASSERT(m_context->get_manager().is_pattern(mp)); + bool unary = (mp->get_num_args() == 1); + if (!unary && j >= num_eager_multi_patterns) { + TRACE("assign_quantifier", tout << "delaying (too many multipatterns):\n" << mk_ismt2_pp(mp, m_context->get_manager()) << "\n" + << "j: " << j << " unary: " << unary << " m_params.m_qi_max_eager_multipatterns: " << m_fparams->m_qi_max_eager_multipatterns + << " num_eager_multi_patterns: " << num_eager_multi_patterns << "\n";); + m_lazy_mam->add_pattern(q, mp); } + else { + TRACE("assign_quantifier", tout << "adding:\n" << mk_ismt2_pp(mp, m_context->get_manager()) << "\n";); + m_mam->add_pattern(q, mp); + } + if (!unary) + j++; } } From 9939d07827e02ee62a00bbfe7f28742cb3c23767 Mon Sep 17 00:00:00 2001 From: Ricky Zhou Date: Sun, 20 Nov 2016 05:09:30 -0800 Subject: [PATCH 378/536] Fix GCC/Clang compilation. The calls to negate use a non-dependent name, so GCC and Clang do not examine dependent base classes when looking up the name. Adds a using declaration as suggested at https://isocpp.org/wiki/faq/templates#nondependent-name-lookup-members. --- src/util/max_cliques.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/util/max_cliques.h b/src/util/max_cliques.h index e8493a9b9..2410c1817 100644 --- a/src/util/max_cliques.h +++ b/src/util/max_cliques.h @@ -24,6 +24,8 @@ Notes: template class max_cliques : public T { + using T::negate; + vector m_next, m_tc; uint_set m_reachable[2]; uint_set m_seen1, m_seen2; From 650a719298b1757f26ce88dfb170d0e1c3c02b76 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 20 Nov 2016 06:20:22 -0800 Subject: [PATCH 379/536] fix crash in new clique code Signed-off-by: Nikolaj Bjorner --- src/util/max_cliques.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/util/max_cliques.h b/src/util/max_cliques.h index e8493a9b9..bb7b0b490 100644 --- a/src/util/max_cliques.h +++ b/src/util/max_cliques.h @@ -90,7 +90,7 @@ public: m_next.reserve(std::max(src, dst) + 1); m_next.reserve(std::max(negate(src), negate(dst)) + 1); m_next[src].push_back(dst); - m_next[dst].push_back(src); + m_next[dst].push_back(src); } void cliques(unsigned_vector const& ps, vector& cliques) { @@ -102,7 +102,7 @@ public: max = std::max(max, std::max(np, p) + 1); } m_next.reserve(max); - m_tc.reserve(max); + m_tc.reserve(m_next.size()); unsigned_vector clique; uint_set vars; for (unsigned i = 0; i < num_ps; ++i) { From 725e79e9eb5fdb6d321ad7763ed3f8f8c5f13f48 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 20 Nov 2016 06:24:47 -0800 Subject: [PATCH 380/536] re-enable ematching on recursive function definitions, disabling ematching breaks regressions Signed-off-by: Nikolaj Bjorner --- src/smt/smt_quantifier.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/smt/smt_quantifier.cpp b/src/smt/smt_quantifier.cpp index 58aa01845..2a56168f2 100644 --- a/src/smt/smt_quantifier.cpp +++ b/src/smt/smt_quantifier.cpp @@ -481,7 +481,7 @@ namespace smt { if (!m_fparams->m_ematching) { return; } - if (m_context->get_manager().is_rec_fun_def(q) && mbqi_enabled(q)) { + if (false && m_context->get_manager().is_rec_fun_def(q) && mbqi_enabled(q)) { return; } bool has_unary_pattern = false; From aaf449ae273ef1ed6a2724c7bbae834827cfd3ae Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Mon, 21 Nov 2016 14:49:32 +0000 Subject: [PATCH 381/536] Fix for the documentation scripts. Fixes #799. --- doc/mk_api_doc.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/mk_api_doc.py b/doc/mk_api_doc.py index beb6596d1..45bc9a99c 100644 --- a/doc/mk_api_doc.py +++ b/doc/mk_api_doc.py @@ -82,7 +82,7 @@ try: mk_dir('tmp') shutil.copyfile('website-adj.dox', 'tmp/website.dox') os.remove('website-adj.dox') - shutil.copyfile('../src/api/python/z3.py', 'tmp/z3py.py') + shutil.copyfile('../src/api/python/z3/z3.py', 'tmp/z3py.py') cleanup_API('../src/api/z3_api.h', 'tmp/z3_api.h') cleanup_API('../src/api/z3_ast_containers.h', 'tmp/z3_ast_containers.h') cleanup_API('../src/api/z3_algebraic.h', 'tmp/z3_algebraic.h') @@ -119,7 +119,7 @@ try: print("Removed temporary file z3py.py") os.removedirs('tmp') print("Removed temporary directory tmp.") - sys.path.append('../src/api/python') + sys.path.append('../src/api/python/z3') pydoc.writedoc('z3') shutil.move('z3.html', 'api/html/z3.html') print("Generated Python documentation.") From dee7c29b19ade620d66cb8f49f3ccb8b688530ea Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Tue, 22 Nov 2016 11:32:25 +0000 Subject: [PATCH 382/536] Added optional synchronization for multi-thread API logs. Relates to #798. --- scripts/mk_util.py | 16 +++++++--- src/api/api_log.cpp | 73 +++++++++++++++++++++++++++++++-------------- 2 files changed, 63 insertions(+), 26 deletions(-) diff --git a/scripts/mk_util.py b/scripts/mk_util.py index cf06a10a7..a28f330cc 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -105,6 +105,7 @@ GIT_HASH=False GIT_DESCRIBE=False SLOW_OPTIMIZE=False USE_OMP=True +LOG_SYNC=False FPMATH="Default" FPMATH_FLAGS="-mfpmath=sse -msse -msse2" @@ -652,6 +653,7 @@ def display_help(exit_code): print(" --gprof enable gprof") print(" -f --foci2= use foci2 library at path") print(" --noomp disable OpenMP and all features that require it.") + print(" --log-sync synchronize access to API log files to enable multi-thread API logging.") print("") print("Some influential environment variables:") if not IS_WINDOWS: @@ -678,13 +680,13 @@ def display_help(exit_code): def parse_options(): global VERBOSE, DEBUG_MODE, IS_WINDOWS, VS_X64, ONLY_MAKEFILES, SHOW_CPPS, VS_PROJ, TRACE, VS_PAR, VS_PAR_NUM global DOTNET_ENABLED, DOTNET_KEY_FILE, JAVA_ENABLED, ML_ENABLED, STATIC_LIB, STATIC_BIN, PREFIX, GMP, FOCI2, FOCI2LIB, PYTHON_PACKAGE_DIR, GPROF, GIT_HASH, GIT_DESCRIBE, PYTHON_INSTALL_ENABLED, PYTHON_ENABLED - global LINUX_X64, SLOW_OPTIMIZE, USE_OMP + global LINUX_X64, SLOW_OPTIMIZE, USE_OMP, LOG_SYNC try: options, remainder = getopt.gnu_getopt(sys.argv[1:], 'b:df:sxhmcvtnp:gj', ['build=', 'debug', 'silent', 'x64', 'help', 'makefiles', 'showcpp', 'vsproj', 'trace', 'dotnet', 'dotnet-key=', 'staticlib', 'prefix=', 'gmp', 'foci2=', 'java', 'parallel=', 'gprof', - 'githash=', 'git-describe', 'x86', 'ml', 'optimize', 'noomp', 'pypkgdir=', 'python', 'staticbin']) + 'githash=', 'git-describe', 'x86', 'ml', 'optimize', 'noomp', 'pypkgdir=', 'python', 'staticbin', 'log-sync']) except: print("ERROR: Invalid command line option") display_help(1) @@ -749,6 +751,8 @@ def parse_options(): ML_ENABLED = True elif opt in ('', '--noomp'): USE_OMP = False + elif opt in ('', '--log-sync'): + LOG_SYNC = True elif opt in ('--python'): PYTHON_ENABLED = True PYTHON_INSTALL_ENABLED = True @@ -2316,7 +2320,9 @@ def mk_config(): if HAS_OMP: extra_opt = ' /openmp' else: - extra_opt = ' -D_NO_OMP_' + extra_opt = ' /D_NO_OMP_' + if HAS_OMP and LOG_SYNC: + extra_opt = '%s /DZ3_LOG_SYNC' % extra_opt if GIT_HASH: extra_opt = ' %s /D Z3GITHASH=%s' % (extra_opt, GIT_HASH) if STATIC_BIN: @@ -2385,7 +2391,7 @@ def mk_config(): print('OCaml Native: %s' % OCAMLOPT) print('OCaml Library: %s' % OCAML_LIB) else: - global CXX, CC, GMP, FOCI2, CPPFLAGS, CXXFLAGS, LDFLAGS, EXAMP_DEBUG_FLAG, FPMATH_FLAGS + global CXX, CC, GMP, FOCI2, CPPFLAGS, CXXFLAGS, LDFLAGS, EXAMP_DEBUG_FLAG, FPMATH_FLAGS, HAS_OMP, LOG_SYNC OS_DEFINES = "" ARITH = "internal" check_ar() @@ -2423,6 +2429,8 @@ def mk_config(): SLIBEXTRAFLAGS = '%s -fopenmp' % SLIBEXTRAFLAGS else: CXXFLAGS = '%s -D_NO_OMP_' % CXXFLAGS + if HAS_OMP and LOG_SYNC: + CXXFLAGS = '%s -DZ3_LOG_SYNC' % CXXFLAGS if DEBUG_MODE: CXXFLAGS = '%s -g -Wall' % CXXFLAGS EXAMP_DEBUG_FLAG = '-g' diff --git a/src/api/api_log.cpp b/src/api/api_log.cpp index f153cd836..cd78103c3 100644 --- a/src/api/api_log.cpp +++ b/src/api/api_log.cpp @@ -26,32 +26,61 @@ std::ostream * g_z3_log = 0; bool g_z3_log_enabled = false; extern "C" { - Z3_bool Z3_API Z3_open_log(Z3_string filename) { - if (g_z3_log != 0) - Z3_close_log(); - g_z3_log = alloc(std::ofstream, filename); - g_z3_log_enabled = true; - if (g_z3_log->bad() || g_z3_log->fail()) { - dealloc(g_z3_log); - g_z3_log = 0; - return Z3_FALSE; - } - *g_z3_log << "V \"" << Z3_MAJOR_VERSION << "." << Z3_MINOR_VERSION << "." << Z3_BUILD_NUMBER << "." << Z3_REVISION_NUMBER << " " << __DATE__ << "\"\n"; - g_z3_log->flush(); - return Z3_TRUE; - } - - void Z3_API Z3_append_log(Z3_string str) { - if (g_z3_log == 0) - return; - _Z3_append_log(static_cast(str)); - } - - void Z3_API Z3_close_log(void) { + void Z3_close_log_unsafe(void) { if (g_z3_log != 0) { dealloc(g_z3_log); g_z3_log_enabled = false; g_z3_log = 0; } } + + Z3_bool Z3_API Z3_open_log(Z3_string filename) { +#ifdef Z3_LOG_SYNC + #pragma omp critical (z3_log) + { +#endif + if (g_z3_log != 0) + Z3_close_log_unsafe(); + g_z3_log = alloc(std::ofstream, filename); + if (g_z3_log->bad() || g_z3_log->fail()) { + dealloc(g_z3_log); + g_z3_log = 0; + return Z3_FALSE; + } + *g_z3_log << "V \"" << Z3_MAJOR_VERSION << "." << Z3_MINOR_VERSION << "." << Z3_BUILD_NUMBER << "." << Z3_REVISION_NUMBER << " " << __DATE__ << "\"\n"; + g_z3_log->flush(); + g_z3_log_enabled = true; +#ifdef Z3_LOG_SYNC + } +#endif + return Z3_TRUE; + } + + void Z3_API Z3_append_log(Z3_string str) { + if (g_z3_log == 0) + return; +#ifdef Z3_LOG_SYNC + #pragma omp critical (z3_log) + { +#endif + if (g_z3_log == 0) + return; + _Z3_append_log(static_cast(str)); +#ifdef Z3_LOG_SYNC + } +#endif + } + + void Z3_API Z3_close_log(void) { + if (g_z3_log != 0) { +#ifdef Z3_LOG_SYNC + #pragma omp critical (z3_log) + { +#endif + Z3_close_log_unsafe(); +#ifdef Z3_LOG_SYNC + } +#endif + } + } } From 71ca3552572fa320b520309f36c8c2847cbc179c Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Tue, 22 Nov 2016 13:26:29 +0000 Subject: [PATCH 383/536] Fixed OpenMP problems in log synchronization. Relates to #798. --- src/api/api_log.cpp | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/src/api/api_log.cpp b/src/api/api_log.cpp index cd78103c3..43cb607c8 100644 --- a/src/api/api_log.cpp +++ b/src/api/api_log.cpp @@ -35,6 +35,8 @@ extern "C" { } Z3_bool Z3_API Z3_open_log(Z3_string filename) { + Z3_bool res = Z3_TRUE; + #ifdef Z3_LOG_SYNC #pragma omp critical (z3_log) { @@ -45,15 +47,18 @@ extern "C" { if (g_z3_log->bad() || g_z3_log->fail()) { dealloc(g_z3_log); g_z3_log = 0; - return Z3_FALSE; + res = Z3_FALSE; + } + else { + *g_z3_log << "V \"" << Z3_MAJOR_VERSION << "." << Z3_MINOR_VERSION << "." << Z3_BUILD_NUMBER << "." << Z3_REVISION_NUMBER << " " << __DATE__ << "\"\n"; + g_z3_log->flush(); + g_z3_log_enabled = true; } - *g_z3_log << "V \"" << Z3_MAJOR_VERSION << "." << Z3_MINOR_VERSION << "." << Z3_BUILD_NUMBER << "." << Z3_REVISION_NUMBER << " " << __DATE__ << "\"\n"; - g_z3_log->flush(); - g_z3_log_enabled = true; #ifdef Z3_LOG_SYNC } #endif - return Z3_TRUE; + + return res; } void Z3_API Z3_append_log(Z3_string str) { @@ -63,9 +68,8 @@ extern "C" { #pragma omp critical (z3_log) { #endif - if (g_z3_log == 0) - return; - _Z3_append_log(static_cast(str)); + if (g_z3_log != 0) + _Z3_append_log(static_cast(str)); #ifdef Z3_LOG_SYNC } #endif From 7a4c20698ff9bb03e21ffa804d707c66e2ec19f6 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 22 Nov 2016 13:02:17 -0800 Subject: [PATCH 384/536] fix handling of AC operator ++ on regular expressions. Issue #804 Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/seq_rewriter.cpp | 3 +++ src/ast/seq_decl_plugin.cpp | 2 +- src/ast/well_sorted.cpp | 3 ++- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/ast/rewriter/seq_rewriter.cpp b/src/ast/rewriter/seq_rewriter.cpp index c343812fe..80fee36d4 100644 --- a/src/ast/rewriter/seq_rewriter.cpp +++ b/src/ast/rewriter/seq_rewriter.cpp @@ -335,6 +335,9 @@ br_status seq_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * con SASSERT(num_args == 1); return mk_re_opt(args[0], result); case OP_RE_CONCAT: + if (num_args == 1) { + result = args[0]; return BR_DONE; + } SASSERT(num_args == 2); return mk_re_concat(args[0], args[1], result); case OP_RE_UNION: diff --git a/src/ast/seq_decl_plugin.cpp b/src/ast/seq_decl_plugin.cpp index caf8bd5cb..e9d87b90b 100644 --- a/src/ast/seq_decl_plugin.cpp +++ b/src/ast/seq_decl_plugin.cpp @@ -555,7 +555,7 @@ func_decl* seq_decl_plugin::mk_assoc_fun(decl_kind k, unsigned arity, sort* cons } match_right_assoc(*m_sigs[k], arity, domain, range, rng); func_decl_info info(m_family_id, k_seq); - info.set_right_associative(); + info.set_right_associative(true); return m.mk_func_decl(m_sigs[(rng == m_string)?k_string:k_seq]->m_name, rng, rng, rng, info); } diff --git a/src/ast/well_sorted.cpp b/src/ast/well_sorted.cpp index cb9ee3f61..b0afe566b 100644 --- a/src/ast/well_sorted.cpp +++ b/src/ast/well_sorted.cpp @@ -44,7 +44,8 @@ struct well_sorted_proc { void operator()(app * n) { unsigned num_args = n->get_num_args(); func_decl * decl = n->get_decl(); - if (num_args != decl->get_arity() && !decl->is_associative()) { + if (num_args != decl->get_arity() && !decl->is_associative() && + !decl->is_right_associative() && !decl->is_left_associative()) { TRACE("ws", tout << "unexpected number of arguments.\n" << mk_ismt2_pp(n, m_manager);); warning_msg("unexpected number of arguments."); m_error = true; From 1d417f652737a6e275f6ab7d6f078851fe700efe Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Wed, 23 Nov 2016 09:32:20 +0000 Subject: [PATCH 385/536] fix warnings in configure script --- scripts/mk_util.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/mk_util.py b/scripts/mk_util.py index a28f330cc..cdd7bdeec 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -2299,6 +2299,7 @@ def mk_config(): if ONLY_MAKEFILES: return config = open(os.path.join(BUILD_DIR, 'config.mk'), 'w') + global CXX, CC, GMP, FOCI2, CPPFLAGS, CXXFLAGS, LDFLAGS, EXAMP_DEBUG_FLAG, FPMATH_FLAGS, HAS_OMP, LOG_SYNC if IS_WINDOWS: config.write( 'CC=cl\n' @@ -2391,7 +2392,6 @@ def mk_config(): print('OCaml Native: %s' % OCAMLOPT) print('OCaml Library: %s' % OCAML_LIB) else: - global CXX, CC, GMP, FOCI2, CPPFLAGS, CXXFLAGS, LDFLAGS, EXAMP_DEBUG_FLAG, FPMATH_FLAGS, HAS_OMP, LOG_SYNC OS_DEFINES = "" ARITH = "internal" check_ar() From 762e5fd09303b7755abe1eb29b3b7146dc9aa02a Mon Sep 17 00:00:00 2001 From: Martin Nowack Date: Wed, 23 Nov 2016 16:38:21 +0100 Subject: [PATCH 386/536] Do not request time stamp if not needed If no timeout is needed for solving queries, time stamps do not need to be acquired. --- src/util/timer.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/util/timer.h b/src/util/timer.h index cc082a9d8..b4a69f8bf 100644 --- a/src/util/timer.h +++ b/src/util/timer.h @@ -31,8 +31,8 @@ public: ~timer(); void start(); double get_seconds(); - bool timeout(unsigned secs) { return secs > 0 && get_seconds() > secs; } - bool ms_timeout(unsigned ms) { return ms > 0 && get_seconds() * 1000 > ms; } + bool timeout(unsigned secs) { return secs > 0 && secs != UINT_MAX && get_seconds() > secs; } + bool ms_timeout(unsigned ms) { return ms > 0 && ms != UINT_MAX && get_seconds() * 1000 > ms; } }; #endif /* TIMER_H_ */ From 441dbbb94bc7bd71f56d440b0029b473a3918e21 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 24 Nov 2016 13:08:50 -0800 Subject: [PATCH 387/536] streamline logging in arithmetic Signed-off-by: Nikolaj Bjorner --- src/smt/theory_arith_aux.h | 4 ++-- src/smt/theory_arith_core.h | 8 +++++--- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/smt/theory_arith_aux.h b/src/smt/theory_arith_aux.h index 50bfee20e..de357c8d3 100644 --- a/src/smt/theory_arith_aux.h +++ b/src/smt/theory_arith_aux.h @@ -417,8 +417,8 @@ namespace smt { template void theory_arith::atom::display(theory_arith const& th, std::ostream& out) const { literal l(get_bool_var(), !m_is_true); - out << "v" << bound::get_var() << " " << bound::get_bound_kind() << " " << get_k() << " "; - out << l << ":"; + // out << "v" << bound::get_var() << " " << bound::get_bound_kind() << " " << get_k() << " "; + // out << l << ":"; th.get_context().display_detailed_literal(out, l); } diff --git a/src/smt/theory_arith_core.h b/src/smt/theory_arith_core.h index 07d30222b..a08ee50ab 100644 --- a/src/smt/theory_arith_core.h +++ b/src/smt/theory_arith_core.h @@ -1069,7 +1069,7 @@ namespace smt { template void theory_arith::flush_bound_axioms() { - CTRACE("arith", !m_new_atoms.empty(), tout << "flush bound axioms\n";); + CTRACE("arith_verbose", !m_new_atoms.empty(), tout << "flush bound axioms\n";); while (!m_new_atoms.empty()) { ptr_vector atoms; @@ -1084,7 +1084,7 @@ namespace smt { --i; } } - CTRACE("arith", !atoms.empty(), + CTRACE("arith", atoms.size() > 1, for (unsigned i = 0; i < atoms.size(); ++i) { atoms[i]->display(*this, tout); tout << "\n"; }); @@ -1292,7 +1292,7 @@ namespace smt { template void theory_arith::assign_eh(bool_var v, bool is_true) { - TRACE("arith", tout << "p" << v << " := " << (is_true?"true":"false") << "\n";); + TRACE("arith_verbose", tout << "p" << v << " := " << (is_true?"true":"false") << "\n";); atom * a = get_bv2a(v); if (!a) return; SASSERT(get_context().get_assignment(a->get_bool_var()) != l_undef); @@ -3043,12 +3043,14 @@ namespace smt { m_stats.m_conflicts++; m_num_conflicts++; TRACE("arith_conflict", + tout << "scope: " << ctx.get_scope_level() << "\n"; for (unsigned i = 0; i < num_literals; i++) { ctx.display_detailed_literal(tout, lits[i]); tout << " "; if (coeffs_enabled()) { tout << "bound: " << bounds.lit_coeffs()[i] << "\n"; } + tout << "\n"; } for (unsigned i = 0; i < num_eqs; i++) { tout << "#" << eqs[i].first->get_owner_id() << "=#" << eqs[i].second->get_owner_id() << " "; From 17993101554675c309df40f94d29b2a4885f0b62 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Sat, 26 Nov 2016 14:07:05 +0000 Subject: [PATCH 388/536] Fixed iterator invalidation bug in SAT probing. Relates to #798. --- src/sat/sat_probing.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/sat/sat_probing.cpp b/src/sat/sat_probing.cpp index 0b5edb2c9..f54ee9f89 100644 --- a/src/sat/sat_probing.cpp +++ b/src/sat/sat_probing.cpp @@ -139,17 +139,17 @@ namespace sat { if (m_probing_binary) { watch_list & wlist = s.get_wlist(~l); - watch_list::iterator it = wlist.begin(); - watch_list::iterator end = wlist.end(); - for (; it != end ; ++it) { - if (!it->is_binary_clause()) + for (unsigned i = 0; i < wlist.size(); i++) { + watched & w = wlist[i]; + if (!w.is_binary_clause()) break; - literal l2 = it->get_literal(); + literal l2 = w.get_literal(); if (l.index() > l2.index()) continue; if (s.value(l2) != l_undef) continue; // verbose_stream() << "probing " << l << " " << l2 << " " << m_counter << "\n"; + // Note: that try_lit calls propagate, which may update the watch lists. if (!try_lit(l2, false)) return; if (s.inconsistent()) From 4452ac0d6d13001b95bba65ace9704b2857be5cc Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Mon, 28 Nov 2016 13:48:15 +0000 Subject: [PATCH 389/536] optimize pattern matching code generator for DAG patterns generated code now uses COMPARE instructions to compare subtrees instead of diving into both subtrees. Code is thus smaller and fails faster. --- src/smt/mam.cpp | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/src/smt/mam.cpp b/src/smt/mam.cpp index f5b3f34f7..62033c7b9 100644 --- a/src/smt/mam.cpp +++ b/src/smt/mam.cpp @@ -424,7 +424,7 @@ namespace smt { out << *curr; curr = curr->m_next; while (curr != 0 && curr->m_opcode != CHOOSE && curr->m_opcode != NOOP) { - out << " "; + out << "\n"; out << *curr; curr = curr->m_next; } @@ -796,6 +796,7 @@ namespace smt { unsigned m_num_choices; bool m_is_tmp_tree; svector m_mp_already_processed; + obj_map m_matched_exprs; struct pcheck_checked { func_decl * m_label; @@ -840,6 +841,7 @@ namespace smt { m_mp = mp; m_num_choices = 0; m_todo.reset(); + m_matched_exprs.reset(); m_registers.fill(0); app * p = to_app(mp->get_arg(first_idx)); @@ -951,7 +953,15 @@ namespace smt { set_check_mark(reg, NOT_CHECKED); // reset mark, register was fully processed. continue; } - + + unsigned matched_reg; + if (m_matched_exprs.find(p, matched_reg) && reg != matched_reg) { + m_seq.push_back(m_ct_manager.mk_compare(matched_reg, reg)); + set_check_mark(reg, NOT_CHECKED); // reset mark, register was fully processed. + continue; + } + m_matched_exprs.insert(p, reg); + if (m_use_filters && get_check_mark(reg) != CHECK_SINGLETON) { func_decl * lbl = to_app(p)->get_decl(); approx_set s(m_lbl_hasher(lbl)); @@ -1311,9 +1321,6 @@ namespace smt { unsigned reg2 = instr->m_reg2; return m_registers[reg1] != 0 && - m_registers[reg2] != 0 && - is_var(m_registers[reg1]) && - is_var(m_registers[reg2]) && m_registers[reg1] == m_registers[reg2]; } @@ -1571,12 +1578,13 @@ namespace smt { unsigned reg1 = static_cast(curr)->m_reg1; unsigned reg2 = static_cast(curr)->m_reg2; SASSERT(m_todo.contains(reg2)); - m_todo.erase(reg1); m_todo.erase(reg2); - SASSERT(is_var(m_registers[reg1])); - unsigned var_id = to_var(m_registers[reg1])->get_idx(); - if (m_vars[var_id] == -1) - m_vars[var_id] = reg1; + if (is_var(m_registers[reg1])) { + m_todo.erase(reg1); + unsigned var_id = to_var(m_registers[reg1])->get_idx(); + if (m_vars[var_id] == -1) + m_vars[var_id] = reg1; + } m_compatible.push_back(curr); } else { From 2babd192b8d1dd1645c28731cb331b2bdbf634b4 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Mon, 28 Nov 2016 14:43:47 +0000 Subject: [PATCH 390/536] small optimization in compilation of multi-patterns also make the path faster for single patterns --- src/smt/mam.cpp | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/smt/mam.cpp b/src/smt/mam.cpp index 62033c7b9..8c1eecb84 100644 --- a/src/smt/mam.cpp +++ b/src/smt/mam.cpp @@ -795,7 +795,7 @@ namespace smt { code_tree * m_tree; unsigned m_num_choices; bool m_is_tmp_tree; - svector m_mp_already_processed; + svector m_mp_already_processed; obj_map m_matched_exprs; struct pcheck_checked { @@ -1116,7 +1116,7 @@ namespace smt { unsigned best_j = 0; bool found_bounded_mp = false; for (unsigned j = 0; j < m_mp->get_num_args(); j++) { - if (std::find(m_mp_already_processed.begin(), m_mp_already_processed.end(), j) != m_mp_already_processed.end()) + if (m_mp_already_processed[j]) continue; app * p = to_app(m_mp->get_arg(j)); bool has_unbound_vars = false; @@ -1133,7 +1133,7 @@ namespace smt { best_j = j; } } - m_mp_already_processed.push_back(best_j); + m_mp_already_processed[best_j] = true; SASSERT(best != 0); app * p = best; func_decl * lbl = p->get_decl(); @@ -1226,13 +1226,15 @@ namespace smt { */ void linearise(instruction * head, unsigned first_idx) { m_seq.reset(); - m_mp_already_processed.reset(); - m_mp_already_processed.push_back(first_idx); while (!m_todo.empty()) linearise_core(); - if (m_mp->get_num_args() > 1) + if (m_mp->get_num_args() > 1) { + m_mp_already_processed.reset(); + m_mp_already_processed.resize(m_mp->get_num_args()); + m_mp_already_processed[first_idx] = true; linearise_multi_pattern(first_idx); + } #ifdef Z3DEBUG for (unsigned i = 0; i < m_qa->get_num_decls(); i++) { From 4b4365470d5000b14c7890f980d5b566571b52e1 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Mon, 28 Nov 2016 15:40:25 +0000 Subject: [PATCH 391/536] mam compiler: move reset of matched_exprs cache next to code reset --- src/smt/mam.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/smt/mam.cpp b/src/smt/mam.cpp index 8c1eecb84..60aed12e1 100644 --- a/src/smt/mam.cpp +++ b/src/smt/mam.cpp @@ -841,7 +841,6 @@ namespace smt { m_mp = mp; m_num_choices = 0; m_todo.reset(); - m_matched_exprs.reset(); m_registers.fill(0); app * p = to_app(mp->get_arg(first_idx)); @@ -1226,6 +1225,7 @@ namespace smt { */ void linearise(instruction * head, unsigned first_idx) { m_seq.reset(); + m_matched_exprs.reset(); while (!m_todo.empty()) linearise_core(); From d9227b95ea4e3894f63907c38c4b3a79e249c429 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 29 Nov 2016 15:45:23 -0800 Subject: [PATCH 392/536] blast distinct in incremental BV solver Signed-off-by: Nikolaj Bjorner --- src/sat/sat_solver/inc_sat_solver.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/sat/sat_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp index 682978287..e56abc50c 100644 --- a/src/sat/sat_solver/inc_sat_solver.cpp +++ b/src/sat/sat_solver/inc_sat_solver.cpp @@ -336,6 +336,7 @@ public: simp2_p.set_bool("flat", true); // required by som simp2_p.set_bool("hoist_mul", false); // required by som simp2_p.set_bool("elim_and", true); + simp2_p.set_bool("blast_distinct", true); m_preprocess = and_then(mk_card2bv_tactic(m, m_params), using_params(mk_simplify_tactic(m), simp2_p), From 024082a45f11505b5d6992472f8a50a409920606 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 30 Nov 2016 09:52:05 -0800 Subject: [PATCH 393/536] adding preferred sat, currently disabled, to wmax. Fixing issue #815 Signed-off-by: Nikolaj Bjorner --- src/opt/opt_solver.cpp | 4 + src/opt/opt_solver.h | 1 + src/opt/wmax.cpp | 256 ++++++++++++++-- src/smt/smt_consequences.cpp | 200 ++++++++++-- src/smt/smt_context.cpp | 162 +++++----- src/smt/smt_context.h | 27 +- src/smt/smt_context_inv.cpp | 3 + src/smt/smt_kernel.cpp | 9 + src/smt/smt_kernel.h | 7 +- src/smt/theory_wmaxsat.cpp | 577 +++++++++++++++++++---------------- src/smt/theory_wmaxsat.h | 30 +- src/solver/solver.cpp | 4 + src/solver/solver.h | 12 +- 13 files changed, 887 insertions(+), 405 deletions(-) diff --git a/src/opt/opt_solver.cpp b/src/opt/opt_solver.cpp index 0d0283232..868303660 100644 --- a/src/opt/opt_solver.cpp +++ b/src/opt/opt_solver.cpp @@ -198,6 +198,10 @@ namespace opt { return m_context.find_mutexes(vars, mutexes); } + lbool opt_solver::preferred_sat(expr_ref_vector const& asms, vector& cores) { + return m_context.preferred_sat(asms, cores); + } + /** diff --git a/src/opt/opt_solver.h b/src/opt/opt_solver.h index 16c2061c7..094023ba2 100644 --- a/src/opt/opt_solver.h +++ b/src/opt/opt_solver.h @@ -107,6 +107,7 @@ namespace opt { virtual std::ostream& display(std::ostream & out) const; virtual ast_manager& get_manager() const { return m; } virtual lbool find_mutexes(expr_ref_vector const& vars, vector& mutexes); + virtual lbool preferred_sat(expr_ref_vector const& asms, vector& cores); void set_logic(symbol const& logic); smt::theory_var add_objective(app* term); diff --git a/src/opt/wmax.cpp b/src/opt/wmax.cpp index d8ffe9f66..228e14cd6 100644 --- a/src/opt/wmax.cpp +++ b/src/opt/wmax.cpp @@ -32,64 +32,286 @@ namespace opt { class wmax : public maxsmt_solver_base { + obj_map m_weights; + obj_map m_keys; + expr_ref_vector m_trail, m_defs; + + void reset() { + m_weights.reset(); + m_keys.reset(); + m_trail.reset(); + m_defs.reset(); + } + public: wmax(maxsat_context& c, weights_t& ws, expr_ref_vector const& soft): - maxsmt_solver_base(c, ws, soft) {} + maxsmt_solver_base(c, ws, soft), + m_trail(m), + m_defs(m) {} + virtual ~wmax() {} lbool operator()() { TRACE("opt", tout << "weighted maxsat\n";); scoped_ensure_theory wth(*this); obj_map soft; + reset(); lbool is_sat = find_mutexes(soft); if (is_sat != l_true) { return is_sat; } - rational offset = m_lower; - m_upper = offset; + m_upper = m_lower; bool was_sat = false; - expr_ref_vector disj(m); + expr_ref_vector disj(m), asms(m); + vector cores; obj_map::iterator it = soft.begin(), end = soft.end(); for (; it != end; ++it) { - expr_ref tmp(m); - bool is_true = m_model->eval(it->m_key, tmp) && m.is_true(tmp); - expr* c = wth().assert_weighted(it->m_key, it->m_value, is_true); - if (!is_true) { + expr* c = assert_weighted(wth(), it->m_key, it->m_value); + if (!is_true(it->m_key)) { + disj.push_back(m.mk_not(c)); m_upper += it->m_value; - disj.push_back(c); } } + wth().init_min_cost(m_upper - m_lower); s().assert_expr(mk_or(disj)); trace_bounds("wmax"); - while (l_true == is_sat && m_lower < m_upper) { + + while (!m.canceled() && m_lower < m_upper) { + //mk_assumptions(asms); + //is_sat = s().preferred_sat(asms, cores); is_sat = s().check_sat(0, 0); if (m.canceled()) { is_sat = l_undef; } + if (is_sat == l_false) { + break; + } if (is_sat == l_true) { if (wth().is_optimal()) { - m_upper = offset + wth().get_min_cost(); + m_upper = m_lower + wth().get_cost(); s().get_model(m_model); } expr_ref fml = wth().mk_block(); + //DEBUG_CODE(verify_cores(cores);); s().assert_expr(fml); was_sat = true; } + else { + //DEBUG_CODE(verify_cores(cores);); + } + update_cores(wth(), cores); + wth().init_min_cost(m_upper - m_lower); trace_bounds("wmax"); + SASSERT(m_lower <= m_upper); } - if (was_sat) { - wth().get_assignment(m_assignment); - m_upper = offset + wth().get_min_cost(); - } - if (is_sat == l_false && was_sat) { + + update_assignment(); + + if (!m.canceled() && is_sat == l_undef && m_lower == m_upper) { is_sat = l_true; } - if (is_sat == l_true) { + if (is_sat == l_false) { + is_sat = l_true; m_lower = m_upper; } TRACE("opt", tout << "min cost: " << m_upper << "\n";); return is_sat; } + + bool is_true(expr* e) { + expr_ref tmp(m); + return m_model->eval(e, tmp) && m.is_true(tmp); + } + + void update_assignment() { + m_assignment.reset(); + for (unsigned i = 0; i < m_soft.size(); ++i) { + m_assignment.push_back(is_true(m_soft[i])); + } + } + + struct compare_asm { + wmax& max; + compare_asm(wmax& max):max(max) {} + bool operator()(expr* a, expr* b) const { + return max.m_weights[a] > max.m_weights[b]; + } + }; + + void mk_assumptions(expr_ref_vector& asms) { + ptr_vector _asms; + obj_map::iterator it = m_weights.begin(), end = m_weights.end(); + for (; it != end; ++it) { + _asms.push_back(it->m_key); + } + compare_asm comp(*this); + std::sort(_asms.begin(),_asms.end(), comp); + asms.reset(); + for (unsigned i = 0; i < _asms.size(); ++i) { + asms.push_back(m.mk_not(_asms[i])); + } + } + + void verify_cores(vector const& cores) { + for (unsigned i = 0; i < cores.size(); ++i) { + verify_core(cores[i]); + } + } + + void verify_core(expr_ref_vector const& core) { + s().push(); + s().assert_expr(core); + VERIFY(l_false == s().check_sat(0, 0)); + s().pop(1); + } + + void update_cores(smt::theory_wmaxsat& th, vector const& cores) { + obj_hashtable seen; + bool updated = false; + unsigned min_core_size = UINT_MAX; + for (unsigned i = 0; i < cores.size(); ++i) { + expr_ref_vector const& core = cores[i]; + if (core.size() <= 20) { + s().assert_expr(m.mk_not(mk_and(core))); + } + min_core_size = std::min(core.size(), min_core_size); + if (core.size() >= 11) { + continue; + } + bool found = false; + for (unsigned j = 0; !found && j < core.size(); ++j) { + found = seen.contains(core[j]); + } + if (found) { + continue; + } + for (unsigned j = 0; j < core.size(); ++j) { + seen.insert(core[j]); + } + update_core(th, core); + updated = true; + } + // if no core was selected, then take the smallest cores. + for (unsigned i = 0; !updated && i < cores.size(); ++i) { + expr_ref_vector const& core = cores[i]; + if (core.size() > min_core_size + 2) { + continue; + } + bool found = false; + for (unsigned j = 0; !found && j < core.size(); ++j) { + found = seen.contains(core[j]); + } + if (found) { + continue; + } + for (unsigned j = 0; j < core.size(); ++j) { + seen.insert(core[j]); + } + update_core(th, core); + } + } + + + rational remove_negations(smt::theory_wmaxsat& th, expr_ref_vector const& core, ptr_vector& keys, vector& weights) { + rational min_weight(-1); + for (unsigned i = 0; i < core.size(); ++i) { + expr* e; + VERIFY(m.is_not(core[i], e)); + keys.push_back(m_keys[e]); + rational weight = m_weights[e]; + if (i == 0 || weight < min_weight) { + min_weight = weight; + } + weights.push_back(weight); + m_weights.erase(e); + m_keys.erase(e); + th.disable_var(e); + } + for (unsigned i = 0; i < core.size(); ++i) { + rational weight = weights[i]; + if (weight > min_weight) { + weight -= min_weight; + assert_weighted(th, keys[i], weight); + } + } + return min_weight; + } + + // assert maxres clauses + // assert new core members with value of current model. + // update lower bound + // bounds get re-normalized when solver is invoked. + // each element of core is negated literal from theory_wmaxsat + // disable those literals from th + + void update_core(smt::theory_wmaxsat& th, expr_ref_vector const& core) { + ptr_vector keys; + vector weights; + rational min_weight = remove_negations(th, core, keys, weights); + max_resolve(th, keys, min_weight); + m_lower += min_weight; + // std::cout << core << " " << min_weight << "\n"; + } + + void max_resolve(smt::theory_wmaxsat& th, ptr_vector const& core, rational const& w) { + SASSERT(!core.empty()); + expr_ref fml(m), asum(m); + app_ref cls(m), d(m), dd(m); + // + // d_0 := true + // d_i := b_{i-1} and d_{i-1} for i = 1...sz-1 + // soft (b_i or !d_i) + // == (b_i or !(!b_{i-1} or d_{i-1})) + // == (b_i or b_0 & b_1 & ... & b_{i-1}) + // + // Soft constraint is satisfied if previous soft constraint + // holds or if it is the first soft constraint to fail. + // + // Soundness of this rule can be established using MaxRes + // + for (unsigned i = 1; i < core.size(); ++i) { + expr* b_i = core[i-1]; + expr* b_i1 = core[i]; + if (i == 1) { + d = to_app(b_i); + } + else if (i == 2) { + d = m.mk_and(b_i, d); + m_trail.push_back(d); + } + else { + dd = mk_fresh_bool("d"); + fml = m.mk_implies(dd, d); + s().assert_expr(fml); + m_defs.push_back(fml); + fml = m.mk_implies(dd, b_i); + s().assert_expr(fml); + m_defs.push_back(fml); + fml = m.mk_and(d, b_i); + update_model(dd, fml); + d = dd; + } + cls = m.mk_or(b_i1, d); + m_trail.push_back(cls); + assert_weighted(th, cls, w); + } + } + + expr* assert_weighted(smt::theory_wmaxsat& th, expr* key, rational const& w) { + expr* c = th.assert_weighted(key, w); + m_weights.insert(c, w); + m_keys.insert(c, key); + m_trail.push_back(c); + return c; + } + + void update_model(expr* def, expr* value) { + expr_ref val(m); + if (m_model && m_model->eval(value, val, true)) { + m_model->register_decl(to_app(def)->get_decl(), val); + } + } + }; maxsmt_solver_base* mk_wmax(maxsat_context& c, weights_t& ws, expr_ref_vector const& soft) { diff --git a/src/smt/smt_consequences.cpp b/src/smt/smt_consequences.cpp index e6edbf87e..ab1971a3e 100644 --- a/src/smt/smt_consequences.cpp +++ b/src/smt/smt_consequences.cpp @@ -56,36 +56,7 @@ namespace smt { s.insert(lit.var()); } else { - b_justification js = get_justification(lit.var()); - switch (js.get_kind()) { - case b_justification::CLAUSE: { - clause * cls = js.get_clause(); - if (!cls) break; - unsigned num_lits = cls->get_num_literals(); - for (unsigned j = 0; j < num_lits; ++j) { - literal lit2 = cls->get_literal(j); - if (lit2.var() != lit.var()) { - s |= m_antecedents.find(lit2.var()); - } - } - break; - } - case b_justification::BIN_CLAUSE: { - s |= m_antecedents.find(js.get_literal().var()); - break; - } - case b_justification::AXIOM: { - break; - } - case b_justification::JUSTIFICATION: { - literal_vector literals; - m_conflict_resolution->justification2literals(js.get_justification(), literals); - for (unsigned j = 0; j < literals.size(); ++j) { - s |= m_antecedents.find(literals[j].var()); - } - break; - } - } + justify(lit, s); } m_antecedents.insert(lit.var(), s); TRACE("context", display_literal_verbose(tout, lit); @@ -122,6 +93,39 @@ namespace smt { } } + void context::justify(literal lit, index_set& s) { + b_justification js = get_justification(lit.var()); + switch (js.get_kind()) { + case b_justification::CLAUSE: { + clause * cls = js.get_clause(); + if (!cls) break; + unsigned num_lits = cls->get_num_literals(); + for (unsigned j = 0; j < num_lits; ++j) { + literal lit2 = cls->get_literal(j); + if (lit2.var() != lit.var()) { + s |= m_antecedents.find(lit2.var()); + } + } + break; + } + case b_justification::BIN_CLAUSE: { + s |= m_antecedents.find(js.get_literal().var()); + break; + } + case b_justification::AXIOM: { + break; + } + case b_justification::JUSTIFICATION: { + literal_vector literals; + m_conflict_resolution->justification2literals(js.get_justification(), literals); + for (unsigned j = 0; j < literals.size(); ++j) { + s |= m_antecedents.find(literals[j].var()); + } + break; + } + } + } + void context::extract_fixed_consequences(unsigned& start, obj_map& vars, index_set const& assumptions, expr_ref_vector& conseq) { pop_to_search_lvl(); SASSERT(!inconsistent()); @@ -369,6 +373,142 @@ namespace smt { << ")\n"; } + void context::extract_cores(expr_ref_vector const& asms, vector& cores, unsigned& min_core_size) { + index_set _asms, _nasms; + u_map var2expr; + for (unsigned i = 0; i < asms.size(); ++i) { + literal lit = get_literal(asms[i]); + _asms.insert(lit.index()); + _nasms.insert((~lit).index()); + var2expr.insert(lit.var(), asms[i]); + } + + m_antecedents.reset(); + literal_vector const& lits = assigned_literals(); + for (unsigned i = 0; i < lits.size(); ++i) { + literal lit = lits[i]; + index_set s; + if (_asms.contains(lit.index())) { + s.insert(lit.var()); + } + else { + justify(lit, s); + } + m_antecedents.insert(lit.var(), s); + if (_nasms.contains(lit.index())) { + expr_ref_vector core(m_manager); + index_set::iterator it = s.begin(), end = s.end(); + for (; it != end; ++it) { + core.push_back(var2expr[*it]); + } + core.push_back(var2expr[lit.var()]); + cores.push_back(core); + min_core_size = std::min(min_core_size, core.size()); + } + } + } + + void context::preferred_sat(literal_vector& lits) { + bool retry = true; + while (retry) { + retry = false; + for (unsigned i = 0; i < lits.size(); ++i) { + literal lit = lits[i]; + if (lit == null_literal || get_assignment(lit) != l_undef) { + continue; + } + push_scope(); + assign(lit, b_justification::mk_axiom(), true); + while (!propagate()) { + lits[i] = null_literal; + retry = true; + if (!resolve_conflict() || inconsistent()) { + SASSERT(inconsistent()); + return; + } + } + } + } + } + + void context::display_partial_assignment(std::ostream& out, expr_ref_vector const& asms, unsigned min_core_size) { + unsigned num_true = 0, num_false = 0, num_undef = 0; + for (unsigned i = 0; i < asms.size(); ++i) { + literal lit = get_literal(asms[i]); + if (get_assignment(lit) == l_false) { + ++num_false; + } + if (get_assignment(lit) == l_true) { + ++num_true; + } + if (get_assignment(lit) == l_undef) { + ++num_undef; + } + } + out << "(smt.preferred-sat true: " << num_true << " false: " << num_false << " undef: " << num_undef << " min core: " << min_core_size << ")\n"; + } + + lbool context::preferred_sat(expr_ref_vector const& asms, vector& cores) { + pop_to_base_lvl(); + cores.reset(); + setup_context(false); + internalize_assertions(); + if (m_asserted_formulas.inconsistent() || inconsistent()) { + return l_false; + } + scoped_mk_model smk(*this); + init_search(); + flet l(m_searching, true); + unsigned level = m_scope_lvl; + unsigned min_core_size = UINT_MAX; + lbool is_sat = l_true; + unsigned num_restarts = 0; + + while (true) { + if (m_manager.canceled()) { + is_sat = l_undef; + break; + } + literal_vector lits; + for (unsigned i = 0; i < asms.size(); ++i) { + lits.push_back(get_literal(asms[i])); + } + preferred_sat(lits); + if (inconsistent()) { + SASSERT(m_scope_lvl == level); + is_sat = l_false; + break; + } + extract_cores(asms, cores, min_core_size); + IF_VERBOSE(1, display_partial_assignment(verbose_stream(), asms, min_core_size);); + + if (min_core_size <= 10) { + is_sat = l_undef; + break; + } + + is_sat = bounded_search(); + if (!restart(is_sat, level)) { + break; + } + ++num_restarts; + if (num_restarts >= min_core_size) { + is_sat = l_undef; + while (num_restarts <= 10*min_core_size) { + is_sat = bounded_search(); + if (!restart(is_sat, level)) { + break; + } + ++num_restarts; + } + break; + } + } + end_search(); + + return check_finalize(is_sat); + } + struct neg_literal { unsigned negate(unsigned i) { return (~to_literal(i)).index(); diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index 6b3d92602..e6d4d0c07 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -1111,6 +1111,8 @@ namespace smt { if (r1 == r2) { TRACE("add_diseq_inconsistent", tout << "add_diseq #" << n1->get_owner_id() << " #" << n2->get_owner_id() << " inconsistency, scope_lvl: " << m_scope_lvl << "\n";); + //return false; + theory_id t1 = r1->m_th_var_list.get_th_id(); if (t1 == null_theory_id) return false; return get_theory(t1)->use_diseqs(); @@ -3293,19 +3295,6 @@ namespace smt { m_num_conflicts_since_restart = 0; } - struct context::scoped_mk_model { - context & m_ctx; - scoped_mk_model(context & ctx):m_ctx(ctx) { - m_ctx.m_proto_model = 0; - m_ctx.m_model = 0; - } - ~scoped_mk_model() { - if (m_ctx.m_proto_model.get() != 0) { - m_ctx.m_model = m_ctx.m_proto_model->mk_model(); - m_ctx.m_proto_model = 0; // proto_model is not needed anymore. - } - } - }; lbool context::search() { #ifndef _EXTERNAL_RELEASE @@ -3333,79 +3322,10 @@ namespace smt { TRACE("search_bug", tout << "status: " << status << ", inconsistent: " << inconsistent() << "\n";); TRACE("assigned_literals_per_lvl", display_num_assigned_literals_per_lvl(tout); tout << ", num_assigned: " << m_assigned_literals.size() << "\n";); - - if (m_last_search_failure != OK) { - if (status != l_false) { - // build candidate model before returning - mk_proto_model(status); - // status = l_undef; - } + + if (!restart(status, curr_lvl)) { break; } - - bool force_restart = false; - - if (status == l_false) { - break; - } - else if (status == l_true) { - SASSERT(!inconsistent()); - mk_proto_model(l_true); - // possible outcomes DONE l_true, DONE l_undef, CONTINUE - quantifier_manager::check_model_result cmr = m_qmanager->check_model(m_proto_model.get(), m_model_generator->get_root2value()); - if (cmr == quantifier_manager::SAT) { - // done - break; - } - if (cmr == quantifier_manager::UNKNOWN) { - IF_VERBOSE(1, verbose_stream() << "(smt.giveup quantifiers)\n";); - // giving up - m_last_search_failure = QUANTIFIERS; - status = l_undef; - break; - } - status = l_undef; - force_restart = true; - } - - SASSERT(status == l_undef); - inc_limits(); - if (force_restart || !m_fparams.m_restart_adaptive || m_agility < m_fparams.m_restart_agility_threshold) { - SASSERT(!inconsistent()); - IF_VERBOSE(1, verbose_stream() << "(smt.restarting :propagations " << m_stats.m_num_propagations - << " :decisions " << m_stats.m_num_decisions - << " :conflicts " << m_stats.m_num_conflicts << " :restart " << m_restart_threshold; - if (m_fparams.m_restart_strategy == RS_IN_OUT_GEOMETRIC) { - verbose_stream() << " :restart-outer " << m_restart_outer_threshold; - } - if (m_fparams.m_restart_adaptive) { - verbose_stream() << " :agility " << m_agility; - } - verbose_stream() << ")" << std::endl; verbose_stream().flush();); - // execute the restart - m_stats.m_num_restarts++; - if (m_scope_lvl > curr_lvl) { - pop_scope(m_scope_lvl - curr_lvl); - SASSERT(at_search_level()); - } - ptr_vector::iterator it = m_theory_set.begin(); - ptr_vector::iterator end = m_theory_set.end(); - for (; it != end && !inconsistent(); ++it) - (*it)->restart_eh(); - TRACE("mbqi_bug_detail", tout << "before instantiating quantifiers...\n";); - if (!inconsistent()) { - m_qmanager->restart_eh(); - } - if (inconsistent()) { - VERIFY(!resolve_conflict()); - status = l_false; - break; - } - } - if (m_fparams.m_simplify_clauses) - simplify_clauses(); - if (m_fparams.m_lemma_gc_strategy == LGC_AT_RESTART) - del_inactive_lemmas(); } TRACE("search_lite", tout << "status: " << status << "\n";); @@ -3419,6 +3339,80 @@ namespace smt { end_search(); return status; } + + bool context::restart(lbool& status, unsigned curr_lvl) { + + if (m_last_search_failure != OK) { + if (status != l_false) { + // build candidate model before returning + mk_proto_model(status); + // status = l_undef; + } + return false; + } + + if (status == l_false) { + return false; + } + if (status == l_true) { + SASSERT(!inconsistent()); + mk_proto_model(l_true); + // possible outcomes DONE l_true, DONE l_undef, CONTINUE + quantifier_manager::check_model_result cmr = m_qmanager->check_model(m_proto_model.get(), m_model_generator->get_root2value()); + if (cmr == quantifier_manager::SAT) { + // done + status = l_true; + return false; + } + if (cmr == quantifier_manager::UNKNOWN) { + IF_VERBOSE(1, verbose_stream() << "(smt.giveup quantifiers)\n";); + // giving up + m_last_search_failure = QUANTIFIERS; + status = l_undef; + return false; + } + } + inc_limits(); + if (status == l_true || !m_fparams.m_restart_adaptive || m_agility < m_fparams.m_restart_agility_threshold) { + SASSERT(!inconsistent()); + IF_VERBOSE(1, verbose_stream() << "(smt.restarting :propagations " << m_stats.m_num_propagations + << " :decisions " << m_stats.m_num_decisions + << " :conflicts " << m_stats.m_num_conflicts << " :restart " << m_restart_threshold; + if (m_fparams.m_restart_strategy == RS_IN_OUT_GEOMETRIC) { + verbose_stream() << " :restart-outer " << m_restart_outer_threshold; + } + if (m_fparams.m_restart_adaptive) { + verbose_stream() << " :agility " << m_agility; + } + verbose_stream() << ")" << std::endl; verbose_stream().flush();); + // execute the restart + m_stats.m_num_restarts++; + if (m_scope_lvl > curr_lvl) { + pop_scope(m_scope_lvl - curr_lvl); + SASSERT(at_search_level()); + } + ptr_vector::iterator it = m_theory_set.begin(); + ptr_vector::iterator end = m_theory_set.end(); + for (; it != end && !inconsistent(); ++it) + (*it)->restart_eh(); + TRACE("mbqi_bug_detail", tout << "before instantiating quantifiers...\n";); + if (!inconsistent()) { + m_qmanager->restart_eh(); + } + if (inconsistent()) { + VERIFY(!resolve_conflict()); + status = l_false; + return false; + } + } + if (m_fparams.m_simplify_clauses) + simplify_clauses(); + if (m_fparams.m_lemma_gc_strategy == LGC_AT_RESTART) + del_inactive_lemmas(); + + status = l_undef; + return true; + } void context::tick(unsigned & counter) const { counter++; diff --git a/src/smt/smt_context.h b/src/smt/smt_context.h index 21d628e1a..c63d0614d 100644 --- a/src/smt/smt_context.h +++ b/src/smt/smt_context.h @@ -200,7 +200,20 @@ namespace smt { model_ref m_model; std::string m_unknown; void mk_proto_model(lbool r); - struct scoped_mk_model; + struct scoped_mk_model { + context & m_ctx; + scoped_mk_model(context & ctx):m_ctx(ctx) { + m_ctx.m_proto_model = 0; + m_ctx.m_model = 0; + } + ~scoped_mk_model() { + if (m_ctx.m_proto_model.get() != 0) { + m_ctx.m_model = m_ctx.m_proto_model->mk_model(); + m_ctx.m_proto_model = 0; // proto_model is not needed anymore. + } + } + }; + // ----------------------------------- // @@ -234,7 +247,6 @@ namespace smt { return m_params; } - bool get_cancel_flag() { return !m_manager.limit().inc(); } region & get_region() { @@ -1056,6 +1068,8 @@ namespace smt { void inc_limits(); + bool restart(lbool& status, unsigned curr_lvl); + void tick(unsigned & counter) const; lbool bounded_search(); @@ -1367,6 +1381,13 @@ namespace smt { void validate_consequences(expr_ref_vector const& assumptions, expr_ref_vector const& vars, expr_ref_vector const& conseq, expr_ref_vector const& unfixed); + void justify(literal lit, index_set& s); + + void extract_cores(expr_ref_vector const& asms, vector& cores, unsigned& min_core_size); + + void preferred_sat(literal_vector& literals); + + void display_partial_assignment(std::ostream& out, expr_ref_vector const& asms, unsigned min_core_size); public: context(ast_manager & m, smt_params & fp, params_ref const & p = params_ref()); @@ -1410,6 +1431,8 @@ namespace smt { lbool get_consequences(expr_ref_vector const& assumptions, expr_ref_vector const& vars, expr_ref_vector& conseq, expr_ref_vector& unfixed); lbool find_mutexes(expr_ref_vector const& vars, vector& mutexes); + + lbool preferred_sat(expr_ref_vector const& asms, vector& cores); lbool setup_and_check(bool reset_cancel = true); diff --git a/src/smt/smt_context_inv.cpp b/src/smt/smt_context_inv.cpp index 6b626c2de..5e3b091bc 100644 --- a/src/smt/smt_context_inv.cpp +++ b/src/smt/smt_context_inv.cpp @@ -322,6 +322,9 @@ namespace smt { bool context::check_th_diseq_propagation() const { TRACE("check_th_diseq_propagation", tout << "m_propagated_th_diseqs.size() " << m_propagated_th_diseqs.size() << "\n";); int num = get_num_bool_vars(); + if (inconsistent()) { + return true; + } for (bool_var v = 0; v < num; v++) { if (has_enode(v)) { enode * n = bool_var2enode(v); diff --git a/src/smt/smt_kernel.cpp b/src/smt/smt_kernel.cpp index df39b4186..9bdf962ec 100644 --- a/src/smt/smt_kernel.cpp +++ b/src/smt/smt_kernel.cpp @@ -115,6 +115,11 @@ namespace smt { return m_kernel.get_consequences(assumptions, vars, conseq, unfixed); } + lbool preferred_sat(expr_ref_vector const& asms, vector& cores) { + return m_kernel.preferred_sat(asms, cores); + } + + lbool find_mutexes(expr_ref_vector const& vars, vector& mutexes) { return m_kernel.find_mutexes(vars, mutexes); } @@ -282,6 +287,10 @@ namespace smt { return m_imp->get_consequences(assumptions, vars, conseq, unfixed); } + lbool kernel::preferred_sat(expr_ref_vector const& asms, vector& cores) { + return m_imp->preferred_sat(asms, cores); + } + lbool kernel::find_mutexes(expr_ref_vector const& vars, vector& mutexes) { return m_imp->find_mutexes(vars, mutexes); } diff --git a/src/smt/smt_kernel.h b/src/smt/smt_kernel.h index ea09081ec..264fae011 100644 --- a/src/smt/smt_kernel.h +++ b/src/smt/smt_kernel.h @@ -133,11 +133,16 @@ namespace smt { lbool get_consequences(expr_ref_vector const& assumptions, expr_ref_vector const& vars, expr_ref_vector& conseq, expr_ref_vector& unfixed); - /* + /** \brief find mutually exclusive variables. */ lbool find_mutexes(expr_ref_vector const& vars, vector& mutexes); + /** + \brief Preferential SAT. + */ + lbool preferred_sat(expr_ref_vector const& asms, vector& cores); + /** \brief Return the model associated with the last check command. */ diff --git a/src/smt/theory_wmaxsat.cpp b/src/smt/theory_wmaxsat.cpp index fd07188e5..b665c2a94 100644 --- a/src/smt/theory_wmaxsat.cpp +++ b/src/smt/theory_wmaxsat.cpp @@ -21,294 +21,351 @@ Notes: #include "smt_context.h" #include "ast_pp.h" #include "theory_wmaxsat.h" +#include "smt_justification.h" namespace smt { -theory_wmaxsat::theory_wmaxsat(ast_manager& m, filter_model_converter& mc): - theory(m.mk_family_id("weighted_maxsat")), - m_mc(mc), - m_vars(m), - m_fmls(m), - m_zweights(m_mpz), - m_old_values(m_mpz), - m_zcost(m_mpz), - m_zmin_cost(m_mpz), - m_found_optimal(false), - m_propagate(false), - m_normalize(false), - m_den(1) -{} - -theory_wmaxsat::~theory_wmaxsat() { - m_old_values.reset(); -} - -/** - \brief return the complement of variables that are currently assigned. -*/ -void theory_wmaxsat::get_assignment(svector& result) { - result.reset(); + theory_wmaxsat::theory_wmaxsat(ast_manager& m, filter_model_converter& mc): + theory(m.mk_family_id("weighted_maxsat")), + m_mc(mc), + m_vars(m), + m_fmls(m), + m_zweights(m_mpz), + m_old_values(m_mpz), + m_zcost(m_mpz), + m_zmin_cost(m_mpz), + m_found_optimal(false), + m_propagate(false), + m_normalize(false), + m_den(1) + {} - if (!m_found_optimal) { - for (unsigned i = 0; i < m_vars.size(); ++i) { - result.push_back(false); - } + theory_wmaxsat::~theory_wmaxsat() { + m_old_values.reset(); } - else { - std::sort(m_cost_save.begin(), m_cost_save.end()); - for (unsigned i = 0,j = 0; i < m_vars.size(); ++i) { - if (j < m_cost_save.size() && m_cost_save[j] == static_cast(i)) { + + /** + \brief return the complement of variables that are currently assigned. + */ + void theory_wmaxsat::get_assignment(svector& result) { + result.reset(); + + if (!m_found_optimal) { + for (unsigned i = 0; i < m_vars.size(); ++i) { result.push_back(false); - ++j; - } - else { - result.push_back(true); } } + else { + std::sort(m_cost_save.begin(), m_cost_save.end()); + for (unsigned i = 0,j = 0; i < m_vars.size(); ++i) { + if (j < m_cost_save.size() && m_cost_save[j] == static_cast(i)) { + result.push_back(false); + ++j; + } + else { + result.push_back(true); + } + } + } + TRACE("opt", + tout << "cost save: "; + for (unsigned i = 0; i < m_cost_save.size(); ++i) { + tout << m_cost_save[i] << " "; + } + tout << "\nvars: "; + for (unsigned i = 0; i < m_vars.size(); ++i) { + tout << mk_pp(m_vars[i].get(), get_manager()) << " "; + } + tout << "\nassignment: "; + for (unsigned i = 0; i < result.size(); ++i) { + tout << result[i] << " "; + } + tout << "\n";); } - TRACE("opt", - tout << "cost save: "; - for (unsigned i = 0; i < m_cost_save.size(); ++i) { - tout << m_cost_save[i] << " "; - } - tout << "\nvars: "; - for (unsigned i = 0; i < m_vars.size(); ++i) { - tout << mk_pp(m_vars[i].get(), get_manager()) << " "; - } - tout << "\nassignment: "; - for (unsigned i = 0; i < result.size(); ++i) { - tout << result[i] << " "; - } - tout << "\n";); -} - -void theory_wmaxsat::init_search_eh() { - m_propagate = true; -} - -expr* theory_wmaxsat::assert_weighted(expr* fml, rational const& w, bool is_true) { - context & ctx = get_context(); - ast_manager& m = get_manager(); - app_ref var(m), wfml(m); - var = m.mk_fresh_const("w", m.mk_bool_sort()); - m_mc.insert(var->get_decl()); - wfml = m.mk_or(var, fml); - ctx.assert_expr(wfml); - m_rweights.push_back(w); - m_vars.push_back(var); - m_fmls.push_back(fml); - m_assigned.push_back(false); - if (!is_true) { - m_rmin_cost += w; + void theory_wmaxsat::init_search_eh() { + m_propagate = true; } - m_normalize = true; - return ctx.bool_var2expr(register_var(var, true)); -} - -bool_var theory_wmaxsat::register_var(app* var, bool attach) { - context & ctx = get_context(); - bool_var bv; - SASSERT(!ctx.e_internalized(var)); - enode* x = ctx.mk_enode(var, false, true, true); - if (ctx.b_internalized(var)) { - bv = ctx.get_bool_var(var); + + expr* theory_wmaxsat::assert_weighted(expr* fml, rational const& w) { + context & ctx = get_context(); + ast_manager& m = get_manager(); + app_ref var(m), wfml(m); + var = m.mk_fresh_const("w", m.mk_bool_sort()); + m_mc.insert(var->get_decl()); + wfml = m.mk_or(var, fml); + ctx.assert_expr(wfml); + m_rweights.push_back(w); + m_vars.push_back(var); + m_fmls.push_back(fml); + m_assigned.push_back(false); + m_enabled.push_back(true); + m_normalize = true; + bool_var bv = register_var(var, true); + TRACE("opt", tout << "enable: v" << m_bool2var[bv] << " b" << bv << " " << mk_pp(var, get_manager()) << "\n"; + tout << wfml << "\n";); + return var; } - else { - bv = ctx.mk_bool_var(var); - } - ctx.set_enode_flag(bv, true); - if (attach) { - ctx.set_var_theory(bv, get_id()); - theory_var v = mk_var(x); - ctx.attach_th_var(x, this, v); - m_bool2var.insert(bv, v); - SASSERT(v == static_cast(m_var2bool.size())); - m_var2bool.push_back(bv); - SASSERT(ctx.bool_var2enode(bv)); - } - return bv; -} -rational const& theory_wmaxsat::get_min_cost() { - unsynch_mpq_manager mgr; - scoped_mpq q(mgr); - mgr.set(q, m_zmin_cost, m_den.to_mpq().numerator()); - m_rmin_cost = rational(q); - return m_rmin_cost; -} - -void theory_wmaxsat::assign_eh(bool_var v, bool is_true) { - TRACE("opt", tout << "Assign " << mk_pp(m_vars[m_bool2var[v]].get(), get_manager()) << " " << is_true << "\n";); - if (is_true) { - if (m_normalize) normalize(); + void theory_wmaxsat::disable_var(expr* var) { context& ctx = get_context(); - theory_var tv = m_bool2var[v]; - if (m_assigned[tv]) return; - scoped_mpz w(m_mpz); - w = m_zweights[tv]; - ctx.push_trail(numeral_trail(m_zcost, m_old_values)); - ctx.push_trail(push_back_vector >(m_costs)); - ctx.push_trail(value_trail(m_assigned[tv])); - m_zcost += w; - m_costs.push_back(tv); - m_assigned[tv] = true; - if (m_zcost > m_zmin_cost) { - block(); + SASSERT(ctx.b_internalized(var)); + bool_var bv = ctx.get_bool_var(var); + theory_var tv = m_bool2var[bv]; + m_enabled[tv] = false; + TRACE("opt", tout << "disable: v" << tv << " b" << bv << " " << mk_pp(var, get_manager()) << "\n";); + } + + bool_var theory_wmaxsat::register_var(app* var, bool attach) { + context & ctx = get_context(); + bool_var bv; + SASSERT(!ctx.e_internalized(var)); + enode* x = ctx.mk_enode(var, false, true, true); + if (ctx.b_internalized(var)) { + bv = ctx.get_bool_var(var); } - } -} - -final_check_status theory_wmaxsat::final_check_eh() { - if (m_normalize) normalize(); - return FC_DONE; -} - - -void theory_wmaxsat::reset_eh() { - theory::reset_eh(); - reset_local(); -} - -void theory_wmaxsat::reset_local() { - m_vars.reset(); - m_fmls.reset(); - m_rweights.reset(); - m_rmin_cost.reset(); - m_rcost.reset(); - m_zweights.reset(); - m_zcost.reset(); - m_zmin_cost.reset(); - m_cost_save.reset(); - m_bool2var.reset(); - m_var2bool.reset(); - m_propagate = false; - m_found_optimal = false; - m_assigned.reset(); -} - - -void theory_wmaxsat::propagate() { - context& ctx = get_context(); - for (unsigned i = 0; m_propagate && i < m_vars.size(); ++i) { - bool_var bv = m_var2bool[i]; - lbool asgn = ctx.get_assignment(bv); - if (asgn == l_true) { - assign_eh(bv, true); + else { + bv = ctx.mk_bool_var(var); } + ctx.set_enode_flag(bv, true); + if (attach) { + ctx.set_var_theory(bv, get_id()); + theory_var v = mk_var(x); + ctx.attach_th_var(x, this, v); + m_bool2var.insert(bv, v); + SASSERT(v == static_cast(m_var2bool.size())); + m_var2bool.push_back(bv); + SASSERT(ctx.bool_var2enode(bv)); + } + return bv; } - m_propagate = false; -} - -bool theory_wmaxsat::is_optimal() const { - return !m_found_optimal || m_zcost < m_zmin_cost; -} - -expr_ref theory_wmaxsat::mk_block() { - ++m_stats.m_num_blocks; - ast_manager& m = get_manager(); - expr_ref_vector disj(m); - compare_cost compare_cost(*this); - svector costs(m_costs); - std::sort(costs.begin(), costs.end(), compare_cost); - scoped_mpz weight(m_mpz); - m_mpz.reset(weight); - for (unsigned i = 0; i < costs.size() && m_mpz.lt(weight, m_zmin_cost); ++i) { - weight += m_zweights[costs[i]]; - disj.push_back(m.mk_not(m_vars[costs[i]].get())); - } - if (is_optimal()) { + + rational theory_wmaxsat::get_cost() { unsynch_mpq_manager mgr; scoped_mpq q(mgr); - mgr.set(q, m_zmin_cost, m_den.to_mpq().numerator()); - rational rw = rational(q); - m_zmin_cost = weight; - m_found_optimal = true; + mgr.set(q, m_zcost, m_den.to_mpq().numerator()); + return rational(q); + } + + void theory_wmaxsat::init_min_cost(rational const& r) { + m_rmin_cost = r; + m_zmin_cost = (m_rmin_cost * m_den).to_mpq().numerator(); + } + + + void theory_wmaxsat::assign_eh(bool_var v, bool is_true) { + if (is_true) { + if (m_normalize) normalize(); + context& ctx = get_context(); + theory_var tv = m_bool2var[v]; + if (m_assigned[tv] || !m_enabled[tv]) return; + scoped_mpz w(m_mpz); + w = m_zweights[tv]; + ctx.push_trail(numeral_trail(m_zcost, m_old_values)); + ctx.push_trail(push_back_vector >(m_costs)); + ctx.push_trail(value_trail(m_assigned[tv])); + m_zcost += w; + TRACE("opt", tout << "Assign v" << tv << " weight: " << w << " cost: " << m_zcost << " " << mk_pp(m_vars[m_bool2var[v]].get(), get_manager()) << "\n";); + m_costs.push_back(tv); + m_assigned[tv] = true; + if (m_zcost >= m_zmin_cost) { + block(); + } + else { + m_can_propagate = true; + } + } + } + + final_check_status theory_wmaxsat::final_check_eh() { + if (m_normalize) normalize(); + // std::cout << "cost: " << m_zcost << " min cost: " << m_zmin_cost << "\n"; + return FC_DONE; + } + + + void theory_wmaxsat::reset_eh() { + theory::reset_eh(); + reset_local(); + } + + void theory_wmaxsat::reset_local() { + m_vars.reset(); + m_fmls.reset(); + m_rweights.reset(); + m_rmin_cost.reset(); + m_zweights.reset(); + m_zcost.reset(); + m_zmin_cost.reset(); m_cost_save.reset(); - m_cost_save.append(m_costs); + m_bool2var.reset(); + m_var2bool.reset(); + m_propagate = false; + m_can_propagate = false; + m_found_optimal = false; + m_assigned.reset(); + m_enabled.reset(); + } + + + void theory_wmaxsat::propagate() { + context& ctx = get_context(); + for (unsigned i = 0; m_propagate && i < m_vars.size(); ++i) { + bool_var bv = m_var2bool[i]; + lbool asgn = ctx.get_assignment(bv); + if (asgn == l_true) { + assign_eh(bv, true); + } + } + m_propagate = false; + //while (m_found_optimal && max_unassigned_is_blocked() && !ctx.inconsistent()) { } + + m_can_propagate = false; + } + + bool theory_wmaxsat::is_optimal() const { + return !m_found_optimal || m_zcost < m_zmin_cost; + } + + expr_ref theory_wmaxsat::mk_block() { + ++m_stats.m_num_blocks; + ast_manager& m = get_manager(); + expr_ref_vector disj(m); + compare_cost compare_cost(*this); + svector costs(m_costs); + std::sort(costs.begin(), costs.end(), compare_cost); + scoped_mpz weight(m_mpz); + m_mpz.reset(weight); + for (unsigned i = 0; i < costs.size() && m_mpz.lt(weight, m_zmin_cost); ++i) { + theory_var tv = costs[i]; + if (m_enabled[tv]) { + weight += m_zweights[tv]; + disj.push_back(m.mk_not(m_vars[tv].get())); + } + } + if (is_optimal()) { + m_found_optimal = true; + m_cost_save.reset(); + m_cost_save.append(m_costs); + TRACE("opt", + tout << "costs: "; + for (unsigned i = 0; i < m_costs.size(); ++i) { + tout << mk_pp(get_enode(m_costs[i])->get_owner(), get_manager()) << " "; + } + tout << "\n"; + //get_context().display(tout); + ); + } + expr_ref result(m.mk_or(disj.size(), disj.c_ptr()), m); TRACE("opt", - tout << "costs: "; - for (unsigned i = 0; i < m_costs.size(); ++i) { - tout << mk_pp(get_enode(m_costs[i])->get_owner(), get_manager()) << " "; - } - tout << "\n"; - get_context().display(tout); - ); + tout << result << " weight: " << weight << "\n"; + tout << "cost: " << m_zcost << " min-cost: " << m_zmin_cost << "\n";); + return result; } - expr_ref result(m.mk_or(disj.size(), disj.c_ptr()), m); - TRACE("opt", - tout << result << " weight: " << weight << "\n"; - tout << "cost: " << m_zcost << " min-cost: " << m_zmin_cost << "\n";); - return result; -} -expr_ref theory_wmaxsat::mk_optimal_block(svector const& ws, rational const& weight) { - ast_manager& m = get_manager(); - expr_ref_vector disj(m); - rational new_w = weight*m_den; - m_zmin_cost = new_w.to_mpq().numerator(); - m_cost_save.reset(); - for (unsigned i = 0; i < ws.size(); ++i) { - bool_var bv = ws[i]; - theory_var v = m_bool2var[bv]; - m_cost_save.push_back(v); - disj.push_back(m.mk_not(m_vars[v].get())); - } - expr_ref result(m.mk_or(disj.size(), disj.c_ptr()), m); - return result; -} + void theory_wmaxsat::restart_eh() {} -void theory_wmaxsat::block() { - if (m_vars.empty()) { - return; + void theory_wmaxsat::block() { + if (m_vars.empty()) { + return; + } + ++m_stats.m_num_blocks; + context& ctx = get_context(); + literal_vector lits; + compare_cost compare_cost(*this); + svector costs(m_costs); + std::sort(costs.begin(), costs.end(), compare_cost); + + scoped_mpz weight(m_mpz); + m_mpz.reset(weight); + for (unsigned i = 0; i < costs.size() && weight < m_zmin_cost; ++i) { + weight += m_zweights[costs[i]]; + lits.push_back(literal(m_var2bool[costs[i]])); + } + TRACE("opt", ctx.display_literals_verbose(tout, lits); tout << "\n";); + + ctx.set_conflict( + ctx.mk_justification( + ext_theory_conflict_justification(get_id(), ctx.get_region(), lits.size(), lits.c_ptr(), 0, 0, 0, 0))); + } + + bool theory_wmaxsat::max_unassigned_is_blocked() { + context& ctx = get_context(); + unsigned max_unassigned = m_max_unassigned_index; + if (max_unassigned < m_sorted_vars.size() && + m_zcost + m_zweights[m_sorted_vars[max_unassigned]] < m_zmin_cost) { + return false; + } + // update value of max-unassigned + while (max_unassigned < m_sorted_vars.size() && + ctx.get_assignment(m_var2bool[m_sorted_vars[max_unassigned]]) != l_undef) { + ++max_unassigned; + } + // + if (max_unassigned > m_max_unassigned_index) { + ctx.push_trail(value_trail(m_max_unassigned_index)); + m_max_unassigned_index = max_unassigned; + } + if (max_unassigned < m_sorted_vars.size() && + m_zcost + m_zweights[m_sorted_vars[max_unassigned]] >= m_zmin_cost) { + theory_var tv = m_sorted_vars[max_unassigned]; + propagate(m_var2bool[tv]); + m_max_unassigned_index++; + return true; + } + + return false; } - ++m_stats.m_num_blocks; - context& ctx = get_context(); - literal_vector lits; - compare_cost compare_cost(*this); - svector costs(m_costs); - std::sort(costs.begin(), costs.end(), compare_cost); - scoped_mpz weight(m_mpz); - m_mpz.reset(weight); - for (unsigned i = 0; i < costs.size() && weight < m_zmin_cost; ++i) { - weight += m_zweights[costs[i]]; - 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); - ctx.literal2expr(lits[i], tmp); - tout << tmp << " "; - } - tout << "\n"; - ); - - ctx.mk_th_axiom(get_id(), lits.size(), lits.c_ptr()); -} + void theory_wmaxsat::propagate(bool_var v) { + ++m_stats.m_num_propagations; + context& ctx = get_context(); + literal_vector lits; + literal lit(v, true); + + SASSERT(ctx.get_assignment(lit) == l_undef); + + for (unsigned i = 0; i < m_costs.size(); ++i) { + bool_var w = m_var2bool[m_costs[i]]; + lits.push_back(literal(w)); + } + TRACE("opt", + ctx.display_literals_verbose(tout, lits.size(), lits.c_ptr()); + ctx.display_literal_verbose(tout << " --> ", lit);); + + region& r = ctx.get_region(); + ctx.assign(lit, ctx.mk_justification( + ext_theory_propagation_justification( + get_id(), r, lits.size(), lits.c_ptr(), 0, 0, lit, 0, 0))); + } -void theory_wmaxsat::normalize() { - m_den = rational::one(); - for (unsigned i = 0; i < m_rweights.size(); ++i) { - m_den = lcm(m_den, denominator(m_rweights[i])); + void theory_wmaxsat::normalize() { + m_den = rational::one(); + for (unsigned i = 0; i < m_rweights.size(); ++i) { + if (m_enabled[i]) { + m_den = lcm(m_den, denominator(m_rweights[i])); + } + } + m_den = lcm(m_den, denominator(m_rmin_cost)); + SASSERT(!m_den.is_zero()); + m_zweights.reset(); + m_sorted_vars.reset(); + for (unsigned i = 0; i < m_rweights.size(); ++i) { + rational r = m_rweights[i]*m_den; + SASSERT(r.is_int()); + mpq const& q = r.to_mpq(); + m_zweights.push_back(q.numerator()); + m_sorted_vars.push_back(i); + } + compare_cost compare_cost(*this); + std::sort(m_sorted_vars.begin(), m_sorted_vars.end(), compare_cost); + m_max_unassigned_index = 0; + + m_zcost.reset(); + rational r = m_rmin_cost * m_den; + m_zmin_cost = r.to_mpq().numerator(); + m_normalize = false; } - m_den = lcm(m_den, denominator(m_rmin_cost)); - SASSERT(!m_den.is_zero()); - m_zweights.reset(); - for (unsigned i = 0; i < m_rweights.size(); ++i) { - rational r = m_rweights[i]*m_den; - SASSERT(r.is_int()); - mpq const& q = r.to_mpq(); - m_zweights.push_back(q.numerator()); - } - rational r = m_rcost* m_den; - m_zcost = r.to_mpq().numerator(); - r = m_rmin_cost * m_den; - m_zmin_cost = r.to_mpq().numerator(); - m_normalize = false; -} }; diff --git a/src/smt/theory_wmaxsat.h b/src/smt/theory_wmaxsat.h index 0804c4b68..0f711b9f8 100644 --- a/src/smt/theory_wmaxsat.h +++ b/src/smt/theory_wmaxsat.h @@ -28,6 +28,7 @@ namespace smt { class theory_wmaxsat : public theory { struct stats { unsigned m_num_blocks; + unsigned m_num_propagations; void reset() { memset(this, 0, sizeof(*this)); } stats() { reset(); } }; @@ -39,27 +40,31 @@ namespace smt { scoped_mpz_vector m_zweights; scoped_mpz_vector m_old_values; svector m_costs; // set of asserted theory variables + unsigned m_max_unassigned_index; // index of literal that is not yet assigned and has maximal weight. + svector m_sorted_vars; // set of all theory variables, sorted by cost svector m_cost_save; // set of asserted theory variables - rational m_rcost; // current sum of asserted costs rational m_rmin_cost; // current maximal cost assignment. scoped_mpz m_zcost; // current sum of asserted costs scoped_mpz m_zmin_cost; // current maximal cost assignment. bool m_found_optimal; u_map m_bool2var; // bool_var -> theory_var svector m_var2bool; // theory_var -> bool_var - bool m_propagate; + bool m_propagate; + bool m_can_propagate; bool m_normalize; rational m_den; // lcm of denominators for rational weights. - svector m_assigned; + svector m_assigned, m_enabled; stats m_stats; public: theory_wmaxsat(ast_manager& m, filter_model_converter& mc); virtual ~theory_wmaxsat(); void get_assignment(svector& result); - virtual void init_search_eh(); - expr* assert_weighted(expr* fml, rational const& w, bool is_true); + expr* assert_weighted(expr* fml, rational const& w); + void disable_var(expr* var); bool_var register_var(app* var, bool attach); - rational const& get_min_cost(); + rational get_cost(); + void init_min_cost(rational const& r); + class numeral_trail : public trail { typedef scoped_mpz T; T & m_value; @@ -79,6 +84,8 @@ namespace smt { m_old_values.shrink(m_old_values.size() - 1); } }; + + virtual void init_search_eh(); virtual void assign_eh(bool_var v, bool is_true); virtual final_check_status final_check_eh(); virtual bool use_diseqs() const { @@ -95,23 +102,30 @@ namespace smt { virtual void new_eq_eh(theory_var v1, theory_var v2) { } virtual void new_diseq_eh(theory_var v1, theory_var v2) { } virtual void display(std::ostream& out) const {} + virtual void restart_eh(); virtual void collect_statistics(::statistics & st) const { st.update("wmaxsat num blocks", m_stats.m_num_blocks); + st.update("wmaxsat num props", m_stats.m_num_propagations); } virtual bool can_propagate() { - return m_propagate; + return m_propagate || m_can_propagate; } virtual void propagate(); + bool is_optimal() const; expr_ref mk_block(); - expr_ref mk_optimal_block(svector const& ws, rational const& weight); + + private: void block(); + void propagate(bool_var v); void normalize(); + + bool max_unassigned_is_blocked(); class compare_cost { theory_wmaxsat& m_th; diff --git a/src/solver/solver.cpp b/src/solver/solver.cpp index 441ece429..9163cfeda 100644 --- a/src/solver/solver.cpp +++ b/src/solver/solver.cpp @@ -154,6 +154,10 @@ lbool solver::find_mutexes(expr_ref_vector const& vars, vector& return l_true; } +lbool solver::preferred_sat(expr_ref_vector const& asms, vector& cores) { + return check_sat(0, 0); +} + bool solver::is_literal(ast_manager& m, expr* e) { return is_uninterp_const(e) || (m.is_not(e, e) && is_uninterp_const(e)); } diff --git a/src/solver/solver.h b/src/solver/solver.h index 15932fd5d..d5d9ccfd5 100644 --- a/src/solver/solver.h +++ b/src/solver/solver.h @@ -151,9 +151,9 @@ public: /** \brief under assumptions, asms, retrieve set of consequences that - fix values for expressions that can be built from vars. - The consequences are clauses whose first literal constrain one of the - functions from vars and the other literals are negations of literals from asms. + fix values for expressions that can be built from vars. + The consequences are clauses whose first literal constrain one of the + functions from vars and the other literals are negations of literals from asms. */ virtual lbool get_consequences(expr_ref_vector const& asms, expr_ref_vector const& vars, expr_ref_vector& consequences); @@ -166,6 +166,12 @@ public: virtual lbool find_mutexes(expr_ref_vector const& vars, vector& mutexes); + /** + \brief Preferential SAT. Prefer assumptions to be true, produce cores that witness cases when not all assumptions can be met. + by default, preferred sat ignores the assumptions. + */ + virtual lbool preferred_sat(expr_ref_vector const& asms, vector& cores); + /** \brief Display the content of this solver. */ From 42b26c63e52ae05338e2638d525f62c4badf826d Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Thu, 1 Dec 2016 14:01:20 +0000 Subject: [PATCH 394/536] make a few functions static --- src/smt/smt_context_stat.cpp | 12 ++++++------ src/smt/smt_internalizer.cpp | 4 ++-- src/smt/smt_model_checker.cpp | 3 --- src/smt/smt_setup.cpp | 8 ++++---- src/tactic/aig/aig.cpp | 24 ++++++++++++------------ 5 files changed, 24 insertions(+), 27 deletions(-) diff --git a/src/smt/smt_context_stat.cpp b/src/smt/smt_context_stat.cpp index 5e82923f0..3838a88b5 100644 --- a/src/smt/smt_context_stat.cpp +++ b/src/smt/smt_context_stat.cpp @@ -32,7 +32,7 @@ namespace smt { return static_cast(acc / m_lemmas.size()); } - void acc_num_occs(clause * cls, unsigned_vector & lit2num_occs) { + static void acc_num_occs(clause * cls, unsigned_vector & lit2num_occs) { unsigned num_lits = cls->get_num_literals(); for (unsigned i = 0; i < num_lits; i++) { literal l = cls->get_literal(i); @@ -40,7 +40,7 @@ namespace smt { } } - void acc_num_occs(clause_vector const & v, unsigned_vector & lit2num_occs) { + static void acc_num_occs(clause_vector const & v, unsigned_vector & lit2num_occs) { clause_vector::const_iterator it = v.begin(); clause_vector::const_iterator end = v.end(); for (; it != end; ++it) @@ -79,7 +79,7 @@ namespace smt { out << (m_assigned_literals.size() - n) << "]"; } - void acc_var_num_occs(clause * cls, unsigned_vector & var2num_occs) { + static void acc_var_num_occs(clause * cls, unsigned_vector & var2num_occs) { unsigned num_lits = cls->get_num_literals(); for (unsigned i = 0; i < num_lits; i++) { literal l = cls->get_literal(i); @@ -87,7 +87,7 @@ namespace smt { } } - void acc_var_num_occs(clause_vector const & v, unsigned_vector & var2num_occs) { + static void acc_var_num_occs(clause_vector const & v, unsigned_vector & var2num_occs) { clause_vector::const_iterator it = v.begin(); clause_vector::const_iterator end = v.end(); for (; it != end; ++it) @@ -114,7 +114,7 @@ namespace smt { out << "\n"; } - void acc_var_num_min_occs(clause * cls, unsigned_vector & var2num_min_occs) { + static void acc_var_num_min_occs(clause * cls, unsigned_vector & var2num_min_occs) { unsigned num_lits = cls->get_num_literals(); bool_var min_var = cls->get_literal(0).var(); for (unsigned i = 1; i < num_lits; i++) { @@ -125,7 +125,7 @@ namespace smt { var2num_min_occs[min_var]++; } - void acc_var_num_min_occs(clause_vector const & v, unsigned_vector & var2num_min_occs) { + static void acc_var_num_min_occs(clause_vector const & v, unsigned_vector & var2num_min_occs) { clause_vector::const_iterator it = v.begin(); clause_vector::const_iterator end = v.end(); for (; it != end; ++it) diff --git a/src/smt/smt_internalizer.cpp b/src/smt/smt_internalizer.cpp index 8028feae6..ad1e55ba6 100644 --- a/src/smt/smt_internalizer.cpp +++ b/src/smt/smt_internalizer.cpp @@ -335,7 +335,7 @@ namespace smt { } } - bool find_arg(app * n, expr * t, expr * & other) { + static bool find_arg(app * n, expr * t, expr * & other) { SASSERT(n->get_num_args() == 2); if (n->get_arg(0) == t) { other = n->get_arg(1); @@ -348,7 +348,7 @@ namespace smt { return false; } - bool check_args(app * n, expr * t1, expr * t2) { + static bool check_args(app * n, expr * t1, expr * t2) { SASSERT(n->get_num_args() == 2); return (n->get_arg(0) == t1 && n->get_arg(1) == t2) || (n->get_arg(1) == t1 && n->get_arg(0) == t2); } diff --git a/src/smt/smt_model_checker.cpp b/src/smt/smt_model_checker.cpp index a7f415aad..5329cd80f 100644 --- a/src/smt/smt_model_checker.cpp +++ b/src/smt/smt_model_checker.cpp @@ -363,9 +363,6 @@ namespace smt { } } - struct scoped_set_relevancy { - }; - bool model_checker::check(proto_model * md, obj_map const & root2value) { SASSERT(md != 0); m_root2value = &root2value; diff --git a/src/smt/smt_setup.cpp b/src/smt/smt_setup.cpp index 9f7656471..ee92c4f61 100644 --- a/src/smt/smt_setup.cpp +++ b/src/smt/smt_setup.cpp @@ -188,7 +188,7 @@ namespace smt { } } - void check_no_arithmetic(static_features const & st, char const * logic) { + static void check_no_arithmetic(static_features const & st, char const * logic) { if (st.m_num_arith_ineqs > 0 || st.m_num_arith_terms > 0 || st.m_num_arith_eqs > 0) throw default_exception("Benchmark constains arithmetic, but specified loging does not support it."); } @@ -231,21 +231,21 @@ namespace smt { (st.m_num_arith_eqs + st.m_num_arith_ineqs) > st.m_num_uninterpreted_constants * 9; } - bool is_in_diff_logic(static_features const & st) { + static bool is_in_diff_logic(static_features const & st) { return st.m_num_arith_eqs == st.m_num_diff_eqs && st.m_num_arith_terms == st.m_num_diff_terms && st.m_num_arith_ineqs == st.m_num_diff_ineqs; } - bool is_diff_logic(static_features const & st) { + static bool is_diff_logic(static_features const & st) { return is_in_diff_logic(st) && (st.m_num_diff_ineqs > 0 || st.m_num_diff_eqs > 0 || st.m_num_diff_terms > 0) ; } - void check_no_uninterpreted_functions(static_features const & st, char const * logic) { + static void check_no_uninterpreted_functions(static_features const & st, char const * logic) { if (st.m_num_uninterpreted_functions != 0) throw default_exception("Benchmark contains uninterpreted function symbols, but specified logic does not support them."); } diff --git a/src/tactic/aig/aig.cpp b/src/tactic/aig/aig.cpp index b84ae68f0..1312b0dea 100644 --- a/src/tactic/aig/aig.cpp +++ b/src/tactic/aig/aig.cpp @@ -53,26 +53,26 @@ struct aig { aig() {} }; -inline bool is_true(aig_lit const & r) { return !r.is_inverted() && r.ptr_non_inverted()->m_id == 0; } -inline bool is_false(aig_lit const & r) { return r.is_inverted() && r.ptr()->m_id == 0; } -inline bool is_var(aig * n) { return n->m_children[0].is_null(); } -inline bool is_var(aig_lit const & n) { return is_var(n.ptr()); } -inline unsigned id(aig_lit const & n) { return n.ptr()->m_id; } -inline unsigned ref_count(aig_lit const & n) { return n.ptr()->m_ref_count; } -inline aig_lit left(aig * n) { return n->m_children[0]; } -inline aig_lit right(aig * n) { return n->m_children[1]; } -inline aig_lit left(aig_lit const & n) { return left(n.ptr()); } -inline aig_lit right(aig_lit const & n) { return right(n.ptr()); } +static bool is_true(aig_lit const & r) { return !r.is_inverted() && r.ptr_non_inverted()->m_id == 0; } +static bool is_false(aig_lit const & r) { return r.is_inverted() && r.ptr()->m_id == 0; } +static bool is_var(aig * n) { return n->m_children[0].is_null(); } +static bool is_var(aig_lit const & n) { return is_var(n.ptr()); } +static unsigned id(aig_lit const & n) { return n.ptr()->m_id; } +static unsigned ref_count(aig_lit const & n) { return n.ptr()->m_ref_count; } +static aig_lit left(aig * n) { return n->m_children[0]; } +static aig_lit right(aig * n) { return n->m_children[1]; } +static aig_lit left(aig_lit const & n) { return left(n.ptr()); } +static aig_lit right(aig_lit const & n) { return right(n.ptr()); } inline unsigned to_idx(aig * p) { SASSERT(!is_var(p)); return p->m_id - FIRST_NODE_ID; } -void unmark(unsigned sz, aig_lit const * ns) { +static void unmark(unsigned sz, aig_lit const * ns) { for (unsigned i = 0; i < sz; i++) { ns[i].ptr()->m_mark = false; } } -void unmark(unsigned sz, aig * const * ns) { +static void unmark(unsigned sz, aig * const * ns) { for (unsigned i = 0; i < sz; i++) { ns[i]->m_mark = false; } From e697d3e8109e8c614412d137d9e1da83374beed7 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Thu, 1 Dec 2016 14:10:31 +0000 Subject: [PATCH 395/536] remove 2 outdated comments --- src/ast/rewriter/bit_blaster/bit_blaster_rewriter.cpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/ast/rewriter/bit_blaster/bit_blaster_rewriter.cpp b/src/ast/rewriter/bit_blaster/bit_blaster_rewriter.cpp index e8d8c4e4b..68f2a2b8e 100644 --- a/src/ast/rewriter/bit_blaster/bit_blaster_rewriter.cpp +++ b/src/ast/rewriter/bit_blaster/bit_blaster_rewriter.cpp @@ -66,9 +66,6 @@ struct blaster_cfg { void mk_nor(expr * a, expr * b, expr_ref & r) { m_rewriter.mk_nor(a, b, r); } }; -// CMW: GCC/LLVM do not like this definition because a symbol of the same name exists in assert_set_bit_blaster.o -// template class bit_blaster_tpl; - class blaster : public bit_blaster_tpl { bool_rewriter m_rewriter; bv_util m_util; @@ -625,9 +622,6 @@ MK_PARAMETRIC_UNARY_REDUCE(reduce_sign_extend, mk_sign_extend); } }; -// CMW: GCC/LLVM do not like this definition because a symbol of the same name exists in assert_set_bit_blaster.o -// template class rewriter_tpl; - struct bit_blaster_rewriter::imp : public rewriter_tpl { blaster m_blaster; blaster_rewriter_cfg m_cfg; From dedae29300ccd8a33f7c1c7d7dd6a17ca2569d09 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Thu, 1 Dec 2016 17:37:07 +0000 Subject: [PATCH 396/536] add a few more statics to avoid symbol clashes --- src/tactic/sls/sls_tactic.cpp | 4 ++-- src/tactic/smtlogics/qfbv_tactic.cpp | 4 ++-- src/tactic/smtlogics/qfnia_tactic.cpp | 6 +++--- src/tactic/ufbv/ufbv_tactic.cpp | 4 ++-- src/tactic/ufbv/ufbv_tactic.h | 2 -- 5 files changed, 9 insertions(+), 11 deletions(-) diff --git a/src/tactic/sls/sls_tactic.cpp b/src/tactic/sls/sls_tactic.cpp index 4e49e0d76..f4ef300e4 100644 --- a/src/tactic/sls/sls_tactic.cpp +++ b/src/tactic/sls/sls_tactic.cpp @@ -94,13 +94,13 @@ public: }; -tactic * mk_sls_tactic(ast_manager & m, params_ref const & p) { +static tactic * mk_sls_tactic(ast_manager & m, params_ref const & p) { return and_then(fail_if_not(mk_is_qfbv_probe()), // Currently only QF_BV is supported. clean(alloc(sls_tactic, m, p))); } -tactic * mk_preamble(ast_manager & m, params_ref const & p) { +static tactic * mk_preamble(ast_manager & m, params_ref const & p) { params_ref main_p; main_p.set_bool("elim_and", true); // main_p.set_bool("pull_cheap_ite", true); diff --git a/src/tactic/smtlogics/qfbv_tactic.cpp b/src/tactic/smtlogics/qfbv_tactic.cpp index 7cc875fba..918e0fc6d 100644 --- a/src/tactic/smtlogics/qfbv_tactic.cpp +++ b/src/tactic/smtlogics/qfbv_tactic.cpp @@ -32,7 +32,7 @@ Notes: #define MEMLIMIT 300 -tactic * mk_qfbv_preamble(ast_manager& m, params_ref const& p) { +static tactic * mk_qfbv_preamble(ast_manager& m, params_ref const& p) { params_ref solve_eq_p; // conservative guassian elimination. @@ -80,7 +80,7 @@ static tactic * main_p(tactic* t) { } -tactic * mk_qfbv_tactic(ast_manager& m, params_ref const & p, tactic* sat, tactic* smt) { +static tactic * mk_qfbv_tactic(ast_manager& m, params_ref const & p, tactic* sat, tactic* smt) { params_ref local_ctx_p = p; local_ctx_p.set_bool("local_ctx", true); diff --git a/src/tactic/smtlogics/qfnia_tactic.cpp b/src/tactic/smtlogics/qfnia_tactic.cpp index 950291221..5a71281fb 100644 --- a/src/tactic/smtlogics/qfnia_tactic.cpp +++ b/src/tactic/smtlogics/qfnia_tactic.cpp @@ -29,7 +29,7 @@ Notes: #include"ctx_simplify_tactic.h" #include"cofactor_term_ite_tactic.h" -tactic * mk_qfnia_bv_solver(ast_manager & m, params_ref const & p_ref) { +static tactic * mk_qfnia_bv_solver(ast_manager & m, params_ref const & p_ref) { params_ref p = p_ref; p.set_bool("flat", false); p.set_bool("hi_div0", true); @@ -51,7 +51,7 @@ tactic * mk_qfnia_bv_solver(ast_manager & m, params_ref const & p_ref) { return r; } -tactic * mk_qfnia_premable(ast_manager & m, params_ref const & p_ref) { +static tactic * mk_qfnia_premable(ast_manager & m, params_ref const & p_ref) { params_ref pull_ite_p = p_ref; pull_ite_p.set_bool("pull_cheap_ite", true); pull_ite_p.set_bool("local_ctx", true); @@ -77,7 +77,7 @@ tactic * mk_qfnia_premable(ast_manager & m, params_ref const & p_ref) { using_params(mk_simplify_tactic(m), simp_p)); } -tactic * mk_qfnia_sat_solver(ast_manager & m, params_ref const & p) { +static tactic * mk_qfnia_sat_solver(ast_manager & m, params_ref const & p) { params_ref nia2sat_p = p; nia2sat_p.set_uint("nla2bv_max_bv_size", 64); diff --git a/src/tactic/ufbv/ufbv_tactic.cpp b/src/tactic/ufbv/ufbv_tactic.cpp index 7a185c854..19d41be68 100644 --- a/src/tactic/ufbv/ufbv_tactic.cpp +++ b/src/tactic/ufbv/ufbv_tactic.cpp @@ -31,11 +31,11 @@ Notes: #include"ufbv_tactic.h" -tactic * mk_der_fp_tactic(ast_manager & m, params_ref const & p) { +static tactic * mk_der_fp_tactic(ast_manager & m, params_ref const & p) { return repeat(and_then(mk_der_tactic(m), mk_simplify_tactic(m, p))); } -tactic * mk_ufbv_preprocessor_tactic(ast_manager & m, params_ref const & p) { +static tactic * mk_ufbv_preprocessor_tactic(ast_manager & m, params_ref const & p) { params_ref no_elim_and(p); no_elim_and.set_bool("elim_and", false); diff --git a/src/tactic/ufbv/ufbv_tactic.h b/src/tactic/ufbv/ufbv_tactic.h index 2d5454de5..300fdd84a 100644 --- a/src/tactic/ufbv/ufbv_tactic.h +++ b/src/tactic/ufbv/ufbv_tactic.h @@ -23,8 +23,6 @@ Notes: class ast_manager; class tactic; -tactic * mk_ufbv_preprocessor_tactic(ast_manager & m, params_ref const & p = params_ref()); - tactic * mk_ufbv_tactic(ast_manager & m, params_ref const & p = params_ref()); /* From f1a704484b56555311b52dad2ab4146a5577f257 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Thu, 1 Dec 2016 23:16:15 +0000 Subject: [PATCH 397/536] Re-added context creation locks in the Java API. Relates to #819. --- src/api/java/Context.java | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/src/api/java/Context.java b/src/api/java/Context.java index b7656c5da..d50968a32 100644 --- a/src/api/java/Context.java +++ b/src/api/java/Context.java @@ -31,13 +31,17 @@ public class Context implements AutoCloseable { static final Object creation_lock = new Object(); public Context () { - m_ctx = Native.mkContextRc(0); - init(); + synchronized (creation_lock) { + m_ctx = Native.mkContextRc(0); + init(); + } } protected Context (long m_ctx) { - this.m_ctx = m_ctx; - init(); + synchronized (creation_lock) { + this.m_ctx = m_ctx; + init(); + } } @@ -59,13 +63,15 @@ public class Context implements AutoCloseable { * module parameters. For this purpose we should now use {@code Global.setParameter} **/ public Context(Map settings) { - long cfg = Native.mkConfig(); - for (Map.Entry kv : settings.entrySet()) { - Native.setParamValue(cfg, kv.getKey(), kv.getValue()); + synchronized (creation_lock) { + long cfg = Native.mkConfig(); + for (Map.Entry kv : settings.entrySet()) { + Native.setParamValue(cfg, kv.getKey(), kv.getValue()); + } + m_ctx = Native.mkContextRc(cfg); + Native.delConfig(cfg); + init(); } - m_ctx = Native.mkContextRc(cfg); - Native.delConfig(cfg); - init(); } private void init() { @@ -4037,7 +4043,9 @@ public class Context implements AutoCloseable { m_intSort = null; m_realSort = null; m_stringSort = null; - - Native.delContext(m_ctx); + + synchronized (creation_lock) { + Native.delContext(m_ctx); + } } } From 99d10d1224d92c7fd7091faa116fba7841752fee Mon Sep 17 00:00:00 2001 From: Wensheng Tang Date: Thu, 8 Dec 2016 15:09:59 +0800 Subject: [PATCH 398/536] Fixed utf-8 version string handling for python2. Resolved #787 --- scripts/mk_util.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/mk_util.py b/scripts/mk_util.py index cdd7bdeec..d5b045d96 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -881,8 +881,8 @@ def is_CXX_gpp(): return is_compiler(CXX, 'g++') def is_clang_in_gpp_form(cc): - version_string = check_output([cc, '--version']) - return str(version_string).find('clang') != -1 + version_string = check_output([cc, '--version']).encode('utf-8').decode('utf-8') + return version_string.find('clang') != -1 def is_CXX_clangpp(): if is_compiler(CXX, 'g++'): From dc0d29a00c51bcdd4f1d6158863f67a208a37011 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Thu, 8 Dec 2016 16:14:54 +0000 Subject: [PATCH 399/536] Bugfix for model construction. Fixes #828. --- src/model/model_core.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/model/model_core.cpp b/src/model/model_core.cpp index bef2e6494..6b8ff8d63 100644 --- a/src/model/model_core.cpp +++ b/src/model/model_core.cpp @@ -93,6 +93,7 @@ void model_core::unregister_decl(func_decl * d) { m_manager.dec_ref(ec->get_data().m_key); m_manager.dec_ref(ec->get_data().m_value); m_interp.remove(d); + m_const_decls.erase(d); return; } @@ -101,5 +102,6 @@ void model_core::unregister_decl(func_decl * d) { m_manager.dec_ref(ef->get_data().m_key); dealloc(ef->get_data().m_value); m_finterp.remove(d); + m_func_decls.erase(d); } } \ No newline at end of file From feb801564ba6a9a72259f60f854081333e3eda44 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 8 Dec 2016 18:28:27 +0100 Subject: [PATCH 400/536] adding range to C API. Issue #831 Signed-off-by: Nikolaj Bjorner --- src/api/api_seq.cpp | 2 +- src/api/c++/z3++.h | 4 ++++ src/api/z3_api.h | 8 ++++++++ 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/api/api_seq.cpp b/src/api/api_seq.cpp index 5704ffdb0..0fde6303a 100644 --- a/src/api/api_seq.cpp +++ b/src/api/api_seq.cpp @@ -145,7 +145,7 @@ extern "C" { MK_UNARY(Z3_mk_re_option, mk_c(c)->get_seq_fid(), OP_RE_OPTION, SKIP); MK_NARY(Z3_mk_re_union, mk_c(c)->get_seq_fid(), OP_RE_UNION, SKIP); MK_NARY(Z3_mk_re_concat, mk_c(c)->get_seq_fid(), OP_RE_CONCAT, SKIP); - + MK_BINARY(Z3_mk_re_range, mk_c(c)->get_seq_fid(), OP_RE_RANGE, SKIP); }; diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index 2a9c771a1..14702a4ea 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -934,6 +934,8 @@ namespace z3 { check_error(); return expr(ctx(), r); } + friend expr range(expr const& lo, expr const& hi); + @@ -1225,6 +1227,8 @@ namespace z3 { inline expr operator~(expr const & a) { Z3_ast r = Z3_mk_bvnot(a.ctx(), a); return expr(a.ctx(), r); } + inline expr range(expr const& lo, expr const& hi) { check_context(lo, hi); Z3_ast r = Z3_mk_re_range(lo.ctx(), lo, hi); lo.check_error(); return expr(lo.ctx(), r); } + diff --git a/src/api/z3_api.h b/src/api/z3_api.h index c7749ebef..d8570b852 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -3367,6 +3367,14 @@ extern "C" { */ Z3_ast Z3_API Z3_mk_re_concat(Z3_context c, unsigned n, Z3_ast const args[]); + + /** + \brief Create the range regular expression over two sequences of length 1. + + def_API('Z3_mk_re_range' ,AST ,(_in(CONTEXT), _in(AST), _in(AST))) + */ + Z3_ast Z3_API Z3_mk_re_range(Z3_context c, Z3_ast lo, Z3_ast hi); + /*@}*/ From 4e25bffab6318b3f5aa0643e9551bc8b740e8bbb Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 8 Dec 2016 18:33:02 +0100 Subject: [PATCH 401/536] add range constructor to .NET API Signed-off-by: Nikolaj Bjorner --- src/api/dotnet/Context.cs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/api/dotnet/Context.cs b/src/api/dotnet/Context.cs index c3c33a41e..421c81fae 100644 --- a/src/api/dotnet/Context.cs +++ b/src/api/dotnet/Context.cs @@ -2609,6 +2609,19 @@ namespace Microsoft.Z3 CheckContextMatch(t); return new ReExpr(this, Native.Z3_mk_re_union(nCtx, (uint)t.Length, AST.ArrayToNative(t))); } + + + /// + /// Create a range expression. + /// + public ReExpr MkRange(SeqExpr lo, SeqExpr hi) + { + Contract.Requires(lo != null); + Contract.Requires(hi != null); + Contract.Ensures(Contract.Result() != null); + CheckContextMatch(lo, hi); + return new ReExpr(this, Native.Z3_mk_re_range(nCtx, lo.NativeObject, hi.NativeObject)); + } #endregion From a82b5e21fe98817604f6bda5dfd016fde972c05a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 9 Dec 2016 06:11:36 +0100 Subject: [PATCH 402/536] add regular expression operations to C and C++ API Signed-off-by: Nikolaj Bjorner --- src/api/api_seq.cpp | 36 +++++++++++++++++++++++-------- src/api/c++/z3++.h | 48 +++++++++++++++++++++++++++++++++++------ src/api/z3_api.h | 52 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 121 insertions(+), 15 deletions(-) diff --git a/src/api/api_seq.cpp b/src/api/api_seq.cpp index 0fde6303a..e80d98553 100644 --- a/src/api/api_seq.cpp +++ b/src/api/api_seq.cpp @@ -116,15 +116,18 @@ extern "C" { Z3_CATCH_RETURN(""); } - Z3_ast Z3_API Z3_mk_seq_empty(Z3_context c, Z3_sort seq) { - Z3_TRY; - LOG_Z3_mk_seq_empty(c, seq); - RESET_ERROR_CODE(); - app* a = mk_c(c)->sutil().str.mk_empty(to_sort(seq)); - mk_c(c)->save_ast_trail(a); - RETURN_Z3(of_ast(a)); - Z3_CATCH_RETURN(0); - } +#define MK_SORTED(NAME, FN ) \ + Z3_ast Z3_API NAME(Z3_context c, Z3_sort s) { \ + Z3_TRY; \ + LOG_ ## NAME(c, s); \ + RESET_ERROR_CODE(); \ + app* a = FN(to_sort(s)); \ + mk_c(c)->save_ast_trail(a); \ + RETURN_Z3(of_ast(a)); \ + Z3_CATCH_RETURN(0); \ + } + + MK_SORTED(Z3_mk_seq_empty, mk_c(c)->sutil().str.mk_empty); MK_UNARY(Z3_mk_seq_unit, mk_c(c)->get_seq_fid(), OP_SEQ_UNIT, SKIP); MK_NARY(Z3_mk_seq_concat, mk_c(c)->get_seq_fid(), OP_SEQ_CONCAT, SKIP); @@ -139,13 +142,28 @@ extern "C" { MK_UNARY(Z3_mk_seq_to_re, mk_c(c)->get_seq_fid(), OP_SEQ_TO_RE, SKIP); MK_BINARY(Z3_mk_seq_in_re, mk_c(c)->get_seq_fid(), OP_SEQ_IN_RE, SKIP); + Z3_ast Z3_API Z3_mk_re_loop(Z3_context c, Z3_ast r, unsigned lo, unsigned hi) { + Z3_TRY; + LOG_Z3_mk_re_loop(c, r, lo, hi); + RESET_ERROR_CODE(); + app* a = hi == 0 ? mk_c(c)->sutil().re.mk_loop(to_expr(r), lo) : mk_c(c)->sutil().re.mk_loop(to_expr(r), lo, hi); + mk_c(c)->save_ast_trail(a); + RETURN_Z3(of_ast(a)); + Z3_CATCH_RETURN(0); + } MK_UNARY(Z3_mk_re_plus, mk_c(c)->get_seq_fid(), OP_RE_PLUS, SKIP); MK_UNARY(Z3_mk_re_star, mk_c(c)->get_seq_fid(), OP_RE_STAR, SKIP); MK_UNARY(Z3_mk_re_option, mk_c(c)->get_seq_fid(), OP_RE_OPTION, SKIP); + MK_UNARY(Z3_mk_re_complement, mk_c(c)->get_seq_fid(), OP_RE_OPTION, SKIP); MK_NARY(Z3_mk_re_union, mk_c(c)->get_seq_fid(), OP_RE_UNION, SKIP); + MK_NARY(Z3_mk_re_intersect, mk_c(c)->get_seq_fid(), OP_RE_UNION, SKIP); MK_NARY(Z3_mk_re_concat, mk_c(c)->get_seq_fid(), OP_RE_CONCAT, SKIP); MK_BINARY(Z3_mk_re_range, mk_c(c)->get_seq_fid(), OP_RE_RANGE, SKIP); + MK_SORTED(Z3_mk_re_empty, mk_c(c)->sutil().re.mk_empty); + MK_SORTED(Z3_mk_re_full, mk_c(c)->sutil().re.mk_full); + + }; diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index 14702a4ea..f8c1c57dc 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -934,9 +934,20 @@ namespace z3 { check_error(); return expr(ctx(), r); } - friend expr range(expr const& lo, expr const& hi); - - + friend expr range(expr const& lo, expr const& hi); + /** + \brief create a looping regular expression. + */ + expr loop(unsigned lo) { + Z3_ast r = Z3_mk_re_loop(ctx(), m_ast, lo, 0); + check_error(); + return expr(ctx(), r); + } + expr loop(unsigned lo, unsigned hi) { + Z3_ast r = Z3_mk_re_loop(ctx(), m_ast, lo, hi); + check_error(); + return expr(ctx(), r); + } /** @@ -1227,9 +1238,6 @@ namespace z3 { inline expr operator~(expr const & a) { Z3_ast r = Z3_mk_bvnot(a.ctx(), a); return expr(a.ctx(), r); } - inline expr range(expr const& lo, expr const& hi) { check_context(lo, hi); Z3_ast r = Z3_mk_re_range(lo.ctx(), lo, hi); lo.check_error(); return expr(lo.ctx(), r); } - - /** @@ -2465,6 +2473,34 @@ namespace z3 { re.check_error(); return expr(re.ctx(), r); } + inline expr re_empty(sort const& s) { + Z3_ast r = Z3_mk_re_empty(s.ctx(), s); + s.check_error(); + return expr(s.ctx(), r); + } + inline expr re_full(sort const& s) { + Z3_ast r = Z3_mk_re_full(s.ctx(), s); + s.check_error(); + return expr(s.ctx(), r); + } + inline expr re_intersect(expr_vector const& args) { + assert(args.size() > 0); + context& ctx = args[0].ctx(); + array _args(args); + Z3_ast r = Z3_mk_re_intersect(ctx, _args.size(), _args.ptr()); + ctx.check_error(); + return expr(ctx, r); + } + inline expr range(expr const& lo, expr const& hi) { + check_context(lo, hi); + Z3_ast r = Z3_mk_re_range(lo.ctx(), lo, hi); + lo.check_error(); + return expr(lo.ctx(), r); + } + + + + inline expr interpolant(expr const& a) { return expr(a.ctx(), Z3_mk_interpolant(a.ctx(), a)); diff --git a/src/api/z3_api.h b/src/api/z3_api.h index d8570b852..356f933d4 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -1154,6 +1154,12 @@ typedef enum { Z3_OP_RE_OPTION, Z3_OP_RE_CONCAT, Z3_OP_RE_UNION, + Z3_OP_RE_RANGE, + Z3_OP_RE_LOOP, + Z3_OP_RE_INTERSECT, + Z3_OP_RE_EMPTY_SET, + Z3_OP_RE_FULL_SET, + Z3_OP_RE_COMPLEMENT, // Auxiliary Z3_OP_LABEL = 0x700, @@ -3375,6 +3381,52 @@ extern "C" { */ Z3_ast Z3_API Z3_mk_re_range(Z3_context c, Z3_ast lo, Z3_ast hi); + /** + \brief Create a regular expression loop. The supplied regular expression \c r is repated + between \c lo and \c hi times. The \c lo should be below \c hi with one exection: when + supplying the value \c hi as 0, the meaning is to repeat the argument \c r at least + \c lo number of times, and with an unbounded upper bound. + + def_API('Z3_mk_re_loop', AST, (_in(CONTEXT), _in(AST), _in(UINT), _in(UINT))) + */ + Z3_ast Z3_API Z3_mk_re_loop(Z3_context c, Z3_ast r, unsigned lo, unsigned hi); + + /** + \brief Create the intersection of the regular languages. + + \pre n > 0 + + def_API('Z3_mk_re_intersect' ,AST ,(_in(CONTEXT), _in(UINT), _in_array(1, AST))) + */ + Z3_ast Z3_API Z3_mk_re_intersect(Z3_context c, unsigned n, Z3_ast const args[]); + + /** + \brief Create the complement of the regular language \c re. + + def_API('Z3_mk_re_complement' ,AST ,(_in(CONTEXT), _in(AST))) + */ + Z3_ast Z3_API Z3_mk_re_complement(Z3_context c, Z3_ast re); + + /** + \brief Create an empty regular expression of sort \c re. + + \pre re is a regular expression sort. + + def_API('Z3_mk_re_empty' ,AST ,(_in(CONTEXT), _in(SORT))) + */ + Z3_ast Z3_API Z3_mk_re_empty(Z3_context c, Z3_sort re); + + + /** + \brief Create an universal regular expression of sort \c re. + + \pre re is a regular expression sort. + + def_API('Z3_mk_re_full' ,AST ,(_in(CONTEXT), _in(SORT))) + */ + Z3_ast Z3_API Z3_mk_re_full(Z3_context c, Z3_sort re); + + /*@}*/ From 0473d2ef56c230f52d573df67027dcd7cf654c9d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 9 Dec 2016 06:17:13 +0100 Subject: [PATCH 403/536] add regular expression features to C# API Signed-off-by: Nikolaj Bjorner --- src/api/dotnet/Context.cs | 43 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/src/api/dotnet/Context.cs b/src/api/dotnet/Context.cs index 421c81fae..494b29a00 100644 --- a/src/api/dotnet/Context.cs +++ b/src/api/dotnet/Context.cs @@ -2564,6 +2564,16 @@ namespace Microsoft.Z3 return new ReExpr(this, Native.Z3_mk_re_star(nCtx, re.NativeObject)); } + /// + /// Take the bounded Kleene star of a regular expression. + /// + public ReExpr MkLoop(ReExpr re, uint lo, uint hi = 0) + { + Contract.Requires(re != null); + Contract.Ensures(Contract.Result() != null); + return new ReExpr(this, Native.Z3_mk_re_loop(nCtx, re.NativeObject, lo, hi)); + } + /// /// Take the Kleene plus of a regular expression. /// @@ -2610,6 +2620,39 @@ namespace Microsoft.Z3 return new ReExpr(this, Native.Z3_mk_re_union(nCtx, (uint)t.Length, AST.ArrayToNative(t))); } + /// + /// Create the intersection of regular languages. + /// + public ReExpr MkIntersect(params ReExpr[] t) + { + Contract.Requires(t != null); + Contract.Requires(Contract.ForAll(t, a => a != null)); + Contract.Ensures(Contract.Result() != null); + + CheckContextMatch(t); + return new ReExpr(this, Native.Z3_mk_re_intersect(nCtx, (uint)t.Length, AST.ArrayToNative(t))); + } + + /// + /// Create the empty regular expression. + /// + public ReExpr MkEmptyRe(Sort s) + { + Contract.Requires(s != null); + Contract.Ensures(Contract.Result() != null); + return new ReExpr(this, Native.Z3_mk_re_empty(nCtx, s.NativeObject)); + } + + /// + /// Create the full regular expression. + /// + public ReExpr MkFullRe(Sort s) + { + Contract.Requires(s != null); + Contract.Ensures(Contract.Result() != null); + return new ReExpr(this, Native.Z3_mk_re_full(nCtx, s.NativeObject)); + } + /// /// Create a range expression. From 976fadf7714f6a35528e8b0fbd0d4910e22324b0 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 9 Dec 2016 06:21:57 +0100 Subject: [PATCH 404/536] add missing complement Signed-off-by: Nikolaj Bjorner --- src/api/c++/z3++.h | 24 ++++++++---------------- src/api/dotnet/Context.cs | 14 ++++++++++++-- 2 files changed, 20 insertions(+), 18 deletions(-) diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index f8c1c57dc..86dc77ad5 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -2448,30 +2448,19 @@ namespace z3 { return expr(s.ctx(), r); } inline expr to_re(expr const& s) { - Z3_ast r = Z3_mk_seq_to_re(s.ctx(), s); - s.check_error(); - return expr(s.ctx(), r); + MK_EXPR1(Z3_mk_seq_to_re, s); } inline expr in_re(expr const& s, expr const& re) { - check_context(s, re); - Z3_ast r = Z3_mk_seq_in_re(s.ctx(), s, re); - s.check_error(); - return expr(s.ctx(), r); + MK_EXPR2(Z3_mk_seq_in_re, s, re); } inline expr plus(expr const& re) { - Z3_ast r = Z3_mk_re_plus(re.ctx(), re); - re.check_error(); - return expr(re.ctx(), r); + MK_EXPR1(Z3_mk_re_plus, re); } inline expr option(expr const& re) { - Z3_ast r = Z3_mk_re_option(re.ctx(), re); - re.check_error(); - return expr(re.ctx(), r); + MK_EXPR1(Z3_mk_re_option, re); } inline expr star(expr const& re) { - Z3_ast r = Z3_mk_re_star(re.ctx(), re); - re.check_error(); - return expr(re.ctx(), r); + MK_EXPR1(Z3_mk_re_star, re); } inline expr re_empty(sort const& s) { Z3_ast r = Z3_mk_re_empty(s.ctx(), s); @@ -2491,6 +2480,9 @@ namespace z3 { ctx.check_error(); return expr(ctx, r); } + inline expr re_complement(expr const& a) { + MK_EXPR1(Z3_mk_re_complement, a); + } inline expr range(expr const& lo, expr const& hi) { check_context(lo, hi); Z3_ast r = Z3_mk_re_range(lo.ctx(), lo, hi); diff --git a/src/api/dotnet/Context.cs b/src/api/dotnet/Context.cs index 494b29a00..f12ad58ea 100644 --- a/src/api/dotnet/Context.cs +++ b/src/api/dotnet/Context.cs @@ -2577,7 +2577,7 @@ namespace Microsoft.Z3 /// /// Take the Kleene plus of a regular expression. /// - public ReExpr MPlus(ReExpr re) + public ReExpr MkPlus(ReExpr re) { Contract.Requires(re != null); Contract.Ensures(Contract.Result() != null); @@ -2587,13 +2587,23 @@ namespace Microsoft.Z3 /// /// Create the optional regular expression. /// - public ReExpr MOption(ReExpr re) + public ReExpr MkOption(ReExpr re) { Contract.Requires(re != null); Contract.Ensures(Contract.Result() != null); return new ReExpr(this, Native.Z3_mk_re_option(nCtx, re.NativeObject)); } + /// + /// Create the complement regular expression. + /// + public ReExpr MkComplement(ReExpr re) + { + Contract.Requires(re != null); + Contract.Ensures(Contract.Result() != null); + return new ReExpr(this, Native.Z3_mk_re_complement(nCtx, re.NativeObject)); + } + /// /// Create the concatenation of regular languages. /// From 8e6600c6bedaffc6fd866dd6a473665c4bf6cc90 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 9 Dec 2016 09:09:03 +0100 Subject: [PATCH 405/536] add python API for newly exposed regex constructors Signed-off-by: Nikolaj Bjorner --- src/api/python/z3/z3.py | 44 ++++++++++++++++++++++++++++--- src/ast/rewriter/seq_rewriter.cpp | 6 ++--- src/ast/seq_decl_plugin.cpp | 6 ++--- 3 files changed, 47 insertions(+), 9 deletions(-) diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index 478ee0ce3..22b2f60e6 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -9384,6 +9384,7 @@ class SeqSortRef(SortRef): False """ return Z3_is_string_sort(self.ctx_ref(), self.ast) + def StringSort(ctx=None): """Create a string sort @@ -9507,8 +9508,29 @@ def Empty(s): >>> e3 = Empty(SeqSort(IntSort())) >>> print(e3) seq.empty + >>> e4 = Empty(ReSort(SeqSort(IntSort()))) + >>> print(e4) + re.empty """ - return SeqRef(Z3_mk_seq_empty(s.ctx_ref(), s.ast), s.ctx) + if isinstance(s, SeqSortRef): + return SeqRef(Z3_mk_seq_empty(s.ctx_ref(), s.ast), s.ctx) + if isinstance(s, ReSortRef): + return ReRef(Z3_mk_re_empty(s.ctx_ref(), s.ast), s.ctx) + raise Z3Exception("Non-sequence, non-regular expression sort passed to Empty") + +def Full(s): + """Create the regular expression that accepts the universal langauge + >>> e = Full(ReSort(SeqSort(IntSort()))) + >>> print(e) + re.all + >>> e1 = Full(ReSort(StringSort())) + >>> print(e1) + re.allchar + """ + if isinstance(s, ReSortRef): + return ReRef(Z3_mk_re_full(s.ctx_ref(), s.ast), s.ctx) + raise Z3Exception("Non-sequence, non-regular expression sort passed to Full") + def Unit(a): """Create a singleton sequence""" @@ -9624,10 +9646,10 @@ class ReSortRef(SortRef): def ReSort(s): if is_ast(s): - return ReSortRef(Z3_mk_re_sort(s.ctx.ref(), s.as_ast()), ctx) + return ReSortRef(Z3_mk_re_sort(s.ctx.ref(), s.ast), s.ctx) if s is None or isinstance(s, Context): ctx = _get_ctx(s) - return ReSortRef(Z3_mk_re_sort(ctx.ref(), Z3_mk_string_sort(ctx.ref())), ctx) + return ReSortRef(Z3_mk_re_sort(ctx.ref(), Z3_mk_string_sort(ctx.ref())), s.ctx) raise Z3Exception("Regular expression sort constructor expects either a string or a context or no argument") @@ -9698,6 +9720,10 @@ def Option(re): """ return ReRef(Z3_mk_re_option(re.ctx_ref(), re.as_ast()), re.ctx) +def Complement(re): + """Create the complement regular expression.""" + return ReRef(Z3_mk_re_complement(re.ctx_ref(), re.as_ast()), re.ctx) + def Star(re): """Create the regular expression accepting zero or more repetitions of argument. >>> re = Star(Re("a")) @@ -9709,3 +9735,15 @@ def Star(re): True """ return ReRef(Z3_mk_re_star(re.ctx_ref(), re.as_ast()), re.ctx) + +def Loop(re, lo, hi=0): + """Create the regular expression accepting between a lower and upper bound repetitions + >>> re = Loop(Re("a"), 1, 3) + >>> print(simplify(InRe("aa", re))) + True + >>> print(simplify(InRe("aaaa", re))) + False + >>> print(simplify(InRe("", re))) + False + """ + return ReRef(Z3_mk_re_loop(re.ctx_ref(), re.as_ast(), lo, hi), re.ctx) diff --git a/src/ast/rewriter/seq_rewriter.cpp b/src/ast/rewriter/seq_rewriter.cpp index 80fee36d4..cc948de9a 100644 --- a/src/ast/rewriter/seq_rewriter.cpp +++ b/src/ast/rewriter/seq_rewriter.cpp @@ -243,9 +243,9 @@ eautomaton* re2automaton::re2aut(expr* e) { TRACE("seq", tout << "Range expression is not handled: " << mk_pp(e, m) << "\n";); } } - else if (u.re.is_complement(e, e0) && (a = re2aut(e0)) && m_sa) { - return m_sa->mk_complement(*a); - } + else if (u.re.is_complement(e, e0) && (a = re2aut(e0)) && m_sa) { + return m_sa->mk_complement(*a); + } else if (u.re.is_loop(e, e1, lo, hi) && (a = re2aut(e1))) { scoped_ptr eps = eautomaton::mk_epsilon(sm); b = eautomaton::mk_epsilon(sm); diff --git a/src/ast/seq_decl_plugin.cpp b/src/ast/seq_decl_plugin.cpp index e9d87b90b..c645aa1a7 100644 --- a/src/ast/seq_decl_plugin.cpp +++ b/src/ast/seq_decl_plugin.cpp @@ -601,7 +601,7 @@ func_decl * seq_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, match(*m_sigs[k], arity, domain, range, rng); return m.mk_func_decl(symbol("re.allchar"), arity, domain, rng, func_decl_info(m_family_id, k)); } - return m.mk_func_decl(m_sigs[k]->m_name, arity, domain, rng, func_decl_info(m_family_id, k)); + return m.mk_func_decl(m_sigs[k]->m_name, arity, domain, range, func_decl_info(m_family_id, k)); case _OP_REGEXP_EMPTY: @@ -617,7 +617,7 @@ func_decl * seq_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, match(*m_sigs[k], arity, domain, range, rng); return m.mk_func_decl(symbol("re.nostr"), arity, domain, rng, func_decl_info(m_family_id, k)); } - return m.mk_func_decl(m_sigs[k]->m_name, arity, domain, rng, func_decl_info(m_family_id, k)); + return m.mk_func_decl(m_sigs[k]->m_name, arity, domain, range, func_decl_info(m_family_id, k)); case OP_RE_LOOP: switch (arity) { @@ -861,7 +861,7 @@ app* seq_util::re::mk_full(sort* s) { return m.mk_app(m_fid, OP_RE_FULL_SET, 0, 0, 0, 0, s); } -app* seq_util::re::mk_empty(sort* s) { +app* seq_util::re::mk_empty(sort* s) { return m.mk_app(m_fid, OP_RE_EMPTY_SET, 0, 0, 0, 0, s); } From 99b7c26e9f4b3e9dd6d9ccbb5cde385dce594c26 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 9 Dec 2016 13:05:02 +0100 Subject: [PATCH 406/536] exposing regular expression features to address issue #831 Signed-off-by: Nikolaj Bjorner --- src/api/api_ast.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/api/api_ast.cpp b/src/api/api_ast.cpp index eda6831b5..efa3ec098 100644 --- a/src/api/api_ast.cpp +++ b/src/api/api_ast.cpp @@ -1128,6 +1128,10 @@ extern "C" { case Z3_OP_RE_OPTION: return Z3_OP_RE_OPTION; case Z3_OP_RE_CONCAT: return Z3_OP_RE_CONCAT; case Z3_OP_RE_UNION: return Z3_OP_RE_UNION; + case Z3_OP_RE_INTERSECT: return Z3_OP_RE_INTERSECT; + case Z3_OP_RE_LOOP: return Z3_OP_RE_LOOP; + case Z3_OP_RE_FULL_SET: return Z3_OP_RE_FULL_SET; + case Z3_OP_RE_EMPTY_SET: return Z3_OP_RE_EMPTY_SET; default: return Z3_OP_INTERNAL; } From 0ab2067b69d876914a79ae7467db41a698f9a3ca Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 9 Dec 2016 13:15:40 +0100 Subject: [PATCH 407/536] produce error message for cores with optimization. Issue #825 Signed-off-by: Nikolaj Bjorner --- src/opt/opt_context.cpp | 5 +++++ src/opt/opt_context.h | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 624671e2b..b95bb62e8 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -169,6 +169,11 @@ namespace opt { r.append(m_labels); } + void context::get_unsat_core(ptr_vector & r) { + throw default_exception("Unsat cores are not supported with optimization"); + } + + void context::set_hard_constraints(ptr_vector& fmls) { if (m_scoped_state.set(fmls)) { clear_state(); diff --git a/src/opt/opt_context.h b/src/opt/opt_context.h index 18af756bf..ef02a4cbe 100644 --- a/src/opt/opt_context.h +++ b/src/opt/opt_context.h @@ -190,7 +190,7 @@ namespace opt { virtual void collect_statistics(statistics& stats) const; virtual proof* get_proof() { return 0; } virtual void get_labels(svector & r); - virtual void get_unsat_core(ptr_vector & r) {} + virtual void get_unsat_core(ptr_vector & r); virtual std::string reason_unknown() const; virtual void set_reason_unknown(char const* msg) { m_unknown = msg; } From 9df5c314852a69ed237553d00ecf317524daea29 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Fri, 9 Dec 2016 13:40:46 +0000 Subject: [PATCH 408/536] Whitespace --- src/util/mpf.cpp | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/util/mpf.cpp b/src/util/mpf.cpp index 03b720ae1..3199b13ef 100644 --- a/src/util/mpf.cpp +++ b/src/util/mpf.cpp @@ -1224,7 +1224,7 @@ void mpf_manager::renormalize(unsigned ebits, unsigned sbits, mpf_exp_t & exp, m 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); @@ -1235,7 +1235,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; - + SASSERT(-1 <= exp_diff && exp_diff < INT64_MAX); SASSERT(exp_diff < ebits+sbits || partial); @@ -1252,7 +1252,7 @@ void mpf_manager::partial_remainder(mpf & x, mpf const & y, mpf_exp_t const & ex 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 + // 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); @@ -1271,7 +1271,7 @@ void mpf_manager::partial_remainder(mpf & x, mpf const & y, mpf_exp_t const & ex mpf_exp_t Q_exp = x_div_y_exp; scoped_mpz Q_sig(m_mpz_manager), Q_rem(m_mpz_manager); unsigned Q_shft = (sbits-1) + (sbits+3) - (unsigned) (partial ? N :Q_exp); - if (partial) { + if (partial) { // Round according to MPF_ROUND_TOWARD_ZERO SASSERT(0 < N && N < Q_exp && Q_exp < INT_MAX); m_mpz_manager.machine_div2k(x_div_y_sig_lrg, Q_shft, Q_sig); @@ -1294,7 +1294,7 @@ void mpf_manager::partial_remainder(mpf & x, mpf const & y, mpf_exp_t const & ex TRACE("mpf_dbg_rem", tout << "Q_exp=" << Q_exp << std::endl; tout << "Q_sig=" << m_mpz_manager.to_string(Q_sig) << 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. @@ -1308,7 +1308,7 @@ void mpf_manager::partial_remainder(mpf & x, mpf const & y, mpf_exp_t const & ex bool YQ_sgn = x.sign; 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); + 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. (void)YQ_sgn; @@ -1317,11 +1317,11 @@ void mpf_manager::partial_remainder(mpf & x, mpf const & y, mpf_exp_t const & ex tout << "YQ_sig=" << m_mpz_manager.to_string(YQ_sig) << 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. + // `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 + // 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; @@ -1339,14 +1339,14 @@ void mpf_manager::partial_remainder(mpf & x, mpf const & y, mpf_exp_t const & ex 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); m_mpz_manager.set(sticky_rem, 0); if (exp_delta > sbits+5) - sticky_rem.swap(subtrahend); + sticky_rem.swap(subtrahend); else if (exp_delta > 0) - m_mpz_manager.machine_div_rem(subtrahend, m_powers2((unsigned)exp_delta), subtrahend, sticky_rem); + m_mpz_manager.machine_div_rem(subtrahend, m_powers2((unsigned)exp_delta), subtrahend, sticky_rem); else { SASSERT(exp_delta < 0); exp_delta = -exp_delta; @@ -1356,7 +1356,7 @@ void mpf_manager::partial_remainder(mpf & x, mpf const & y, mpf_exp_t const & ex 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;); @@ -1374,7 +1374,7 @@ void mpf_manager::partial_remainder(mpf & x, mpf const & y, mpf_exp_t const & ex 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_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 @@ -1384,7 +1384,7 @@ void mpf_manager::partial_remainder(mpf & x, mpf const & y, mpf_exp_t const & ex 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.eq(rnd_bits, mpz(32))) { // tie. if (m_mpz_manager.is_odd(X_YQ_sig)) { m_mpz_manager.inc(X_YQ_sig); } @@ -1430,7 +1430,7 @@ void mpf_manager::rem(mpf const & x, mpf const & y, mpf & o) { mpf_exp_t D; do { if (ST0.exponent() < ST1.exponent() - 1) { - D = 0; + D = 0; } else { D = ST0.exponent() - ST1.exponent(); @@ -1889,7 +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; + (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;); From 56b1a8b086de13dd065bded9b134c63012f72456 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Fri, 9 Dec 2016 13:43:05 +0000 Subject: [PATCH 409/536] Bugfix for special-case handling in fp.fma. Thanks to Florian Schanda for reporting this bug. --- src/ast/fpa/fpa2bv_converter.cpp | 12 ++++++--- src/smt/smt_model_checker.cpp | 43 ++++++++++++++++---------------- 2 files changed, 31 insertions(+), 24 deletions(-) diff --git a/src/ast/fpa/fpa2bv_converter.cpp b/src/ast/fpa/fpa2bv_converter.cpp index ba6d436cc..2c0ba1ce1 100644 --- a/src/ast/fpa/fpa2bv_converter.cpp +++ b/src/ast/fpa/fpa2bv_converter.cpp @@ -1463,11 +1463,17 @@ void fpa2bv_converter::mk_fma(func_decl * f, unsigned num, expr * const * args, v6 = z; // (x is 0) || (y is 0) -> z + expr_ref c71(m), xy_sgn(m), xyz_sgn(m); m_simp.mk_or(x_is_zero, y_is_zero, c7); - expr_ref ite_c(m), rm_is_not_to_neg(m); + m_simp.mk_xor(x_is_neg, y_is_neg, xy_sgn); + + m_simp.mk_xor(xy_sgn, z_is_neg, xyz_sgn); + m_simp.mk_and(z_is_zero, xyz_sgn, c71); + + expr_ref zero_cond(m), rm_is_not_to_neg(m); rm_is_not_to_neg = m.mk_not(rm_is_to_neg); - m_simp.mk_and(z_is_zero, rm_is_not_to_neg, ite_c); - mk_ite(ite_c, pzero, z, v7); + m_simp.mk_ite(rm_is_to_neg, nzero, pzero, zero_cond); + mk_ite(c71, zero_cond, z, v7); // else comes the fused multiplication. unsigned ebits = m_util.get_ebits(f->get_range()); diff --git a/src/smt/smt_model_checker.cpp b/src/smt/smt_model_checker.cpp index 5329cd80f..9ebdc5640 100644 --- a/src/smt/smt_model_checker.cpp +++ b/src/smt/smt_model_checker.cpp @@ -53,8 +53,8 @@ namespace smt { } void model_checker::set_qm(quantifier_manager & qm) { - SASSERT(m_qm == 0); - SASSERT(m_context == 0); + SASSERT(m_qm == 0); + SASSERT(m_context == 0); m_qm = &qm; m_context = &(m_qm->get_context()); } @@ -112,7 +112,7 @@ namespace smt { if (!m_curr_model->eval(q->get_expr(), tmp, true)) { return; } - TRACE("model_checker", tout << "q after applying interpretation:\n" << mk_ismt2_pp(tmp, m) << "\n";); + TRACE("model_checker", tout << "q after applying interpretation:\n" << mk_ismt2_pp(tmp, m) << "\n";); ptr_buffer subst_args; unsigned num_decls = q->get_num_decls(); subst_args.resize(num_decls, 0); @@ -139,7 +139,7 @@ namespace smt { bool model_checker::add_instance(quantifier * q, model * cex, expr_ref_vector & sks, bool use_inv) { if (cex == 0) { TRACE("model_checker", tout << "no model is available\n";); - return false; + return false; } unsigned num_decls = q->get_num_decls(); // Remark: sks were created for the flat version of q. @@ -187,20 +187,20 @@ namespace smt { } bindings.set(num_decls - i - 1, sk_value); } - + TRACE("model_checker", tout << q->get_qid() << " found (use_inv: " << use_inv << ") new instance: "; for (unsigned i = 0; i < num_decls; i++) { tout << mk_ismt2_pp(bindings[i].get(), m) << " "; } tout << "\n";); - + max_generation = std::max(m_qm->get_generation(q), max_generation); add_instance(q, bindings, max_generation); return true; } void model_checker::add_instance(quantifier* q, expr_ref_vector const& bindings, unsigned max_generation) { - for (unsigned i = 0; i < bindings.size(); i++) + for (unsigned i = 0; i < bindings.size(); i++) m_new_instances_bindings.push_back(bindings[i]); void * mem = m_new_instances_region.allocate(instance::get_obj_size(q->get_num_decls())); instance * new_inst = new (mem) instance(q, bindings.c_ptr(), max_generation); @@ -260,41 +260,42 @@ namespace smt { bool model_checker::check(quantifier * q) { SASSERT(!m_aux_context->relevancy()); m_aux_context->push(); - + quantifier * flat_q = get_flat_quantifier(q); - TRACE("model_checker", tout << "model checking:\n" << mk_ismt2_pp(q->get_expr(), m) << "\n" << + TRACE("model_checker", tout << "model checking:\n" << mk_ismt2_pp(q->get_expr(), m) << "\n" << mk_ismt2_pp(flat_q->get_expr(), m) << "\n";); expr_ref_vector sks(m); assert_neg_q_m(flat_q, sks); - TRACE("model_checker", tout << "skolems:\n"; + TRACE("model_checker", tout << "skolems:\n"; for (unsigned i = 0; i < sks.size(); i++) { expr * sk = sks.get(i); tout << mk_ismt2_pp(sk, m) << " " << mk_pp(m.get_sort(sk), m) << "\n"; }); - + lbool r = m_aux_context->check(); TRACE("model_checker", tout << "[complete] model-checker result: " << to_sat_str(r) << "\n";); if (r != l_true) { m_aux_context->pop(1); return r == l_false; // quantifier is satisfied by m_curr_model } - + model_ref complete_cex; - m_aux_context->get_model(complete_cex); - + m_aux_context->get_model(complete_cex); + // try to find new instances using instantiation sets. m_model_finder.restrict_sks_to_inst_set(m_aux_context.get(), q, sks); - + unsigned num_new_instances = 0; while (true) { lbool r = m_aux_context->check(); TRACE("model_checker", tout << "[restricted] model-checker (" << (num_new_instances+1) << ") result: " << to_sat_str(r) << "\n";); if (r != l_true) - break; + break; model_ref cex; m_aux_context->get_model(cex); + TRACE("model_checker", tout << "[restricted] model-checker model cex:\n"; model_pp(tout, *cex);); if (!add_instance(q, cex.get(), sks, true)) { break; } @@ -302,7 +303,7 @@ namespace smt { if (num_new_instances >= m_max_cexs || !add_blocking_clause(cex.get(), sks)) { TRACE("model_checker", tout << "Add blocking clause failed\n";); // add_blocking_clause failed... stop the search for new counter-examples... - break; + break; } } @@ -396,7 +397,7 @@ namespace smt { for (; it != end; ++it) { quantifier * q = *it; if(!m_qm->mbqi_enabled(q)) continue; - TRACE("model_checker", + TRACE("model_checker", tout << "Check: " << mk_pp(q, m) << "\n"; tout << m_context->get_assignment(q) << "\n";); @@ -418,12 +419,12 @@ namespace smt { } } } - + if (found_relevant) m_iteration_idx++; TRACE("model_checker", tout << "model after check:\n"; model_pp(tout, *md);); - TRACE("model_checker", tout << "model checker result: " << (num_failures == 0) << "\n";); + TRACE("model_checker", tout << "model checker result: " << (num_failures == 0) << "\n";); m_max_cexs += m_params.m_mbqi_max_cexs; if (num_failures == 0 && !m_context->validate_model()) { @@ -492,7 +493,7 @@ namespace smt { expr * b = inst->m_bindings[i]; tout << mk_pp(b, m) << "\n"; }); - TRACE("model_checker_instance", + TRACE("model_checker_instance", expr_ref inst_expr(m); instantiate(m, q, inst->m_bindings, inst_expr); tout << "(assert " << mk_ismt2_pp(inst_expr, m) << ")\n";); From acba529bce28d98204c95bb6493a9de45478ff12 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 9 Dec 2016 15:32:15 +0100 Subject: [PATCH 410/536] fix bug in encoding of axioms for indexof. Issue #806 Signed-off-by: Nikolaj Bjorner --- src/smt/theory_seq.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index 245ffe438..3be3fd5f8 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -2916,7 +2916,7 @@ void theory_seq::add_indexof_axiom(expr* i) { expr_ref len_t(m_util.str.mk_length(t), m); literal offset_ge_len = mk_literal(m_autil.mk_ge(mk_sub(offset, len_t), zero)); - add_axiom(offset_ge_len, mk_eq(i, minus_one, false)); + add_axiom(~offset_ge_len, mk_eq(i, minus_one, false)); expr_ref x = mk_skolem(m_indexof_left, t, s, offset); expr_ref y = mk_skolem(m_indexof_right, t, s, offset); From 16b32ecf124880d2896b1a1c2012f4706d09af76 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Fri, 9 Dec 2016 15:03:31 +0000 Subject: [PATCH 411/536] Bugfix for special-case handling in fp.fma. Thanks to Florian Schanda for reporting this bug. (+reversed accidental debug code commit). --- src/smt/smt_model_checker.cpp | 43 +++++++++++++++++------------------ src/util/mpf.cpp | 5 ++-- 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/src/smt/smt_model_checker.cpp b/src/smt/smt_model_checker.cpp index 9ebdc5640..5329cd80f 100644 --- a/src/smt/smt_model_checker.cpp +++ b/src/smt/smt_model_checker.cpp @@ -53,8 +53,8 @@ namespace smt { } void model_checker::set_qm(quantifier_manager & qm) { - SASSERT(m_qm == 0); - SASSERT(m_context == 0); + SASSERT(m_qm == 0); + SASSERT(m_context == 0); m_qm = &qm; m_context = &(m_qm->get_context()); } @@ -112,7 +112,7 @@ namespace smt { if (!m_curr_model->eval(q->get_expr(), tmp, true)) { return; } - TRACE("model_checker", tout << "q after applying interpretation:\n" << mk_ismt2_pp(tmp, m) << "\n";); + TRACE("model_checker", tout << "q after applying interpretation:\n" << mk_ismt2_pp(tmp, m) << "\n";); ptr_buffer subst_args; unsigned num_decls = q->get_num_decls(); subst_args.resize(num_decls, 0); @@ -139,7 +139,7 @@ namespace smt { bool model_checker::add_instance(quantifier * q, model * cex, expr_ref_vector & sks, bool use_inv) { if (cex == 0) { TRACE("model_checker", tout << "no model is available\n";); - return false; + return false; } unsigned num_decls = q->get_num_decls(); // Remark: sks were created for the flat version of q. @@ -187,20 +187,20 @@ namespace smt { } bindings.set(num_decls - i - 1, sk_value); } - + TRACE("model_checker", tout << q->get_qid() << " found (use_inv: " << use_inv << ") new instance: "; for (unsigned i = 0; i < num_decls; i++) { tout << mk_ismt2_pp(bindings[i].get(), m) << " "; } tout << "\n";); - + max_generation = std::max(m_qm->get_generation(q), max_generation); add_instance(q, bindings, max_generation); return true; } void model_checker::add_instance(quantifier* q, expr_ref_vector const& bindings, unsigned max_generation) { - for (unsigned i = 0; i < bindings.size(); i++) + for (unsigned i = 0; i < bindings.size(); i++) m_new_instances_bindings.push_back(bindings[i]); void * mem = m_new_instances_region.allocate(instance::get_obj_size(q->get_num_decls())); instance * new_inst = new (mem) instance(q, bindings.c_ptr(), max_generation); @@ -260,42 +260,41 @@ namespace smt { bool model_checker::check(quantifier * q) { SASSERT(!m_aux_context->relevancy()); m_aux_context->push(); - + quantifier * flat_q = get_flat_quantifier(q); - TRACE("model_checker", tout << "model checking:\n" << mk_ismt2_pp(q->get_expr(), m) << "\n" << + TRACE("model_checker", tout << "model checking:\n" << mk_ismt2_pp(q->get_expr(), m) << "\n" << mk_ismt2_pp(flat_q->get_expr(), m) << "\n";); expr_ref_vector sks(m); assert_neg_q_m(flat_q, sks); - TRACE("model_checker", tout << "skolems:\n"; + TRACE("model_checker", tout << "skolems:\n"; for (unsigned i = 0; i < sks.size(); i++) { expr * sk = sks.get(i); tout << mk_ismt2_pp(sk, m) << " " << mk_pp(m.get_sort(sk), m) << "\n"; }); - + lbool r = m_aux_context->check(); TRACE("model_checker", tout << "[complete] model-checker result: " << to_sat_str(r) << "\n";); if (r != l_true) { m_aux_context->pop(1); return r == l_false; // quantifier is satisfied by m_curr_model } - + model_ref complete_cex; - m_aux_context->get_model(complete_cex); - + m_aux_context->get_model(complete_cex); + // try to find new instances using instantiation sets. m_model_finder.restrict_sks_to_inst_set(m_aux_context.get(), q, sks); - + unsigned num_new_instances = 0; while (true) { lbool r = m_aux_context->check(); TRACE("model_checker", tout << "[restricted] model-checker (" << (num_new_instances+1) << ") result: " << to_sat_str(r) << "\n";); if (r != l_true) - break; + break; model_ref cex; m_aux_context->get_model(cex); - TRACE("model_checker", tout << "[restricted] model-checker model cex:\n"; model_pp(tout, *cex);); if (!add_instance(q, cex.get(), sks, true)) { break; } @@ -303,7 +302,7 @@ namespace smt { if (num_new_instances >= m_max_cexs || !add_blocking_clause(cex.get(), sks)) { TRACE("model_checker", tout << "Add blocking clause failed\n";); // add_blocking_clause failed... stop the search for new counter-examples... - break; + break; } } @@ -397,7 +396,7 @@ namespace smt { for (; it != end; ++it) { quantifier * q = *it; if(!m_qm->mbqi_enabled(q)) continue; - TRACE("model_checker", + TRACE("model_checker", tout << "Check: " << mk_pp(q, m) << "\n"; tout << m_context->get_assignment(q) << "\n";); @@ -419,12 +418,12 @@ namespace smt { } } } - + if (found_relevant) m_iteration_idx++; TRACE("model_checker", tout << "model after check:\n"; model_pp(tout, *md);); - TRACE("model_checker", tout << "model checker result: " << (num_failures == 0) << "\n";); + TRACE("model_checker", tout << "model checker result: " << (num_failures == 0) << "\n";); m_max_cexs += m_params.m_mbqi_max_cexs; if (num_failures == 0 && !m_context->validate_model()) { @@ -493,7 +492,7 @@ namespace smt { expr * b = inst->m_bindings[i]; tout << mk_pp(b, m) << "\n"; }); - TRACE("model_checker_instance", + TRACE("model_checker_instance", expr_ref inst_expr(m); instantiate(m, q, inst->m_bindings, inst_expr); tout << "(assert " << mk_ismt2_pp(inst_expr, m) << ")\n";); diff --git a/src/util/mpf.cpp b/src/util/mpf.cpp index 3199b13ef..e9d108cec 100644 --- a/src/util/mpf.cpp +++ b/src/util/mpf.cpp @@ -795,8 +795,9 @@ void mpf_manager::fma(mpf_rounding_mode rm, mpf const & x, mpf const & y, mpf co set(o, z); } else if (is_zero(x) || is_zero(y)) { - if (is_zero(z) && rm != MPF_ROUND_TOWARD_NEGATIVE) - mk_pzero(x.ebits, x.sbits, o); + bool xy_sgn = is_neg(x) ^ is_neg(y); + if (is_zero(z) && xy_sgn ^ is_neg(z)) + mk_zero(x.ebits, x.sbits, rm != MPF_ROUND_TOWARD_NEGATIVE, o); else set(o, z); } From 649d47468652160b21a0a103b0ae9b49685c261c Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Fri, 9 Dec 2016 19:09:47 +0000 Subject: [PATCH 412/536] Build fix for C++ example --- scripts/mk_util.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/mk_util.py b/scripts/mk_util.py index cdd7bdeec..890c60501 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -2086,12 +2086,12 @@ class CppExampleComponent(ExampleComponent): exefile = '%s$(EXE_EXT)' % self.name out.write('%s: %s %s\n' % (exefile, dll, objfiles)) - out.write('\t$(LINK) $(LINK_OUT_FLAG)%s $(LINK_FLAGS) %s ' % (exefile, objfiles)) + out.write('\t$(SLINK) $(SLINK_OUT_FLAG)%s $(SLINK_FLAGS) %s ' % (exefile, objfiles)) if IS_WINDOWS: out.write('%s.lib' % dll_name) else: out.write(dll) - out.write(' $(LINK_EXTRA_FLAGS)\n') + out.write(' $(SLINK_EXTRA_FLAGS)\n') out.write('_ex_%s: %s\n\n' % (self.name, exefile)) class CExampleComponent(CppExampleComponent): From e092232f6765c9c9b7b699d77ccf4c372c071764 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 9 Dec 2016 23:17:52 +0100 Subject: [PATCH 413/536] add virtual destructors, fix operator code for API methods complement and intersection per note by Loris d'Antoni Signed-off-by: Nikolaj Bjorner --- src/api/api_seq.cpp | 4 ++-- src/math/automata/boolean_algebra.h | 2 ++ src/math/subpaving/tactic/subpaving_tactic.cpp | 2 ++ src/tactic/arith/add_bounds_tactic.cpp | 11 ++++++----- src/tactic/arith/diff_neq_tactic.cpp | 10 +++++----- src/tactic/arith/fm_tactic.cpp | 10 +++++----- src/tactic/arith/lia2pb_tactic.cpp | 10 +++++----- src/tactic/arith/normalize_bounds_tactic.cpp | 10 +++++----- src/tactic/arith/pb2bv_tactic.cpp | 10 +++++----- src/tactic/core/elim_uncnstr_tactic.cpp | 2 +- 10 files changed, 38 insertions(+), 33 deletions(-) diff --git a/src/api/api_seq.cpp b/src/api/api_seq.cpp index e80d98553..138ea6fb0 100644 --- a/src/api/api_seq.cpp +++ b/src/api/api_seq.cpp @@ -155,9 +155,9 @@ extern "C" { MK_UNARY(Z3_mk_re_plus, mk_c(c)->get_seq_fid(), OP_RE_PLUS, SKIP); MK_UNARY(Z3_mk_re_star, mk_c(c)->get_seq_fid(), OP_RE_STAR, SKIP); MK_UNARY(Z3_mk_re_option, mk_c(c)->get_seq_fid(), OP_RE_OPTION, SKIP); - MK_UNARY(Z3_mk_re_complement, mk_c(c)->get_seq_fid(), OP_RE_OPTION, SKIP); + MK_UNARY(Z3_mk_re_complement, mk_c(c)->get_seq_fid(), OP_RE_COMPLEMENT, SKIP); MK_NARY(Z3_mk_re_union, mk_c(c)->get_seq_fid(), OP_RE_UNION, SKIP); - MK_NARY(Z3_mk_re_intersect, mk_c(c)->get_seq_fid(), OP_RE_UNION, SKIP); + MK_NARY(Z3_mk_re_intersect, mk_c(c)->get_seq_fid(), OP_RE_INTERSECT, SKIP); MK_NARY(Z3_mk_re_concat, mk_c(c)->get_seq_fid(), OP_RE_CONCAT, SKIP); MK_BINARY(Z3_mk_re_range, mk_c(c)->get_seq_fid(), OP_RE_RANGE, SKIP); diff --git a/src/math/automata/boolean_algebra.h b/src/math/automata/boolean_algebra.h index e3977b4cd..4f5527f5e 100644 --- a/src/math/automata/boolean_algebra.h +++ b/src/math/automata/boolean_algebra.h @@ -26,6 +26,7 @@ Revision History: template class positive_boolean_algebra { public: + virtual ~positive_boolean_algebra() {} virtual T mk_false() = 0; virtual T mk_true() = 0; virtual T mk_and(T x, T y) = 0; @@ -38,6 +39,7 @@ public: template class boolean_algebra : public positive_boolean_algebra { public: + virtual ~boolean_algebra() {} virtual T mk_not(T x) = 0; //virtual lbool are_equivalent(T x, T y) = 0; //virtual T simplify(T x) = 0; diff --git a/src/math/subpaving/tactic/subpaving_tactic.cpp b/src/math/subpaving/tactic/subpaving_tactic.cpp index 27e096777..2d0199223 100644 --- a/src/math/subpaving/tactic/subpaving_tactic.cpp +++ b/src/math/subpaving/tactic/subpaving_tactic.cpp @@ -35,6 +35,8 @@ class subpaving_tactic : public tactic { display_var_proc(expr2var & e2v):m_inv(e2v.m()) { e2v.mk_inv(m_inv); } + + virtual ~display_var_proc() {} ast_manager & m() const { return m_inv.get_manager(); } diff --git a/src/tactic/arith/add_bounds_tactic.cpp b/src/tactic/arith/add_bounds_tactic.cpp index 950248698..8ff82af17 100644 --- a/src/tactic/arith/add_bounds_tactic.cpp +++ b/src/tactic/arith/add_bounds_tactic.cpp @@ -51,6 +51,7 @@ public: virtual result operator()(goal const & g) { return is_unbounded(g); } + virtual ~is_unbounded_probe() {} }; probe * mk_is_unbounded_probe() { @@ -109,11 +110,11 @@ class add_bounds_tactic : public tactic { void operator()(quantifier*) {} }; - virtual void operator()(goal_ref const & g, - goal_ref_buffer & result, - model_converter_ref & mc, - proof_converter_ref & pc, - expr_dependency_ref & core) { + void operator()(goal_ref const & g, + goal_ref_buffer & result, + model_converter_ref & mc, + proof_converter_ref & pc, + expr_dependency_ref & core) { mc = 0; pc = 0; core = 0; tactic_report report("add-bounds", *g); bound_manager bm(m); diff --git a/src/tactic/arith/diff_neq_tactic.cpp b/src/tactic/arith/diff_neq_tactic.cpp index 410185cf8..d63c2fcf4 100644 --- a/src/tactic/arith/diff_neq_tactic.cpp +++ b/src/tactic/arith/diff_neq_tactic.cpp @@ -312,11 +312,11 @@ class diff_neq_tactic : public tactic { return md; } - virtual void operator()(goal_ref const & g, - goal_ref_buffer & result, - model_converter_ref & mc, - proof_converter_ref & pc, - expr_dependency_ref & core) { + void operator()(goal_ref const & g, + goal_ref_buffer & result, + model_converter_ref & mc, + proof_converter_ref & pc, + expr_dependency_ref & core) { SASSERT(g->is_well_sorted()); m_produce_models = g->models_enabled(); mc = 0; pc = 0; core = 0; result.reset(); diff --git a/src/tactic/arith/fm_tactic.cpp b/src/tactic/arith/fm_tactic.cpp index 5c82bbbc3..6db0f5ad3 100644 --- a/src/tactic/arith/fm_tactic.cpp +++ b/src/tactic/arith/fm_tactic.cpp @@ -1549,11 +1549,11 @@ class fm_tactic : public tactic { throw tactic_exception(TACTIC_MAX_MEMORY_MSG); } - virtual void operator()(goal_ref const & g, - goal_ref_buffer & result, - model_converter_ref & mc, - proof_converter_ref & pc, - expr_dependency_ref & core) { + void operator()(goal_ref const & g, + goal_ref_buffer & result, + model_converter_ref & mc, + proof_converter_ref & pc, + expr_dependency_ref & core) { SASSERT(g->is_well_sorted()); mc = 0; pc = 0; core = 0; tactic_report report("fm", *g); diff --git a/src/tactic/arith/lia2pb_tactic.cpp b/src/tactic/arith/lia2pb_tactic.cpp index 8d637bada..2b54dd463 100644 --- a/src/tactic/arith/lia2pb_tactic.cpp +++ b/src/tactic/arith/lia2pb_tactic.cpp @@ -188,11 +188,11 @@ class lia2pb_tactic : public tactic { return true; } - virtual void operator()(goal_ref const & g, - goal_ref_buffer & result, - model_converter_ref & mc, - proof_converter_ref & pc, - expr_dependency_ref & core) { + void operator()(goal_ref const & g, + goal_ref_buffer & result, + model_converter_ref & mc, + proof_converter_ref & pc, + expr_dependency_ref & core) { SASSERT(g->is_well_sorted()); fail_if_proof_generation("lia2pb", g); m_produce_models = g->models_enabled(); diff --git a/src/tactic/arith/normalize_bounds_tactic.cpp b/src/tactic/arith/normalize_bounds_tactic.cpp index b3ec505ea..06f1368a2 100644 --- a/src/tactic/arith/normalize_bounds_tactic.cpp +++ b/src/tactic/arith/normalize_bounds_tactic.cpp @@ -80,11 +80,11 @@ class normalize_bounds_tactic : public tactic { return false; } - virtual void operator()(goal_ref const & in, - goal_ref_buffer & result, - model_converter_ref & mc, - proof_converter_ref & pc, - expr_dependency_ref & core) { + void operator()(goal_ref const & in, + goal_ref_buffer & result, + model_converter_ref & mc, + proof_converter_ref & pc, + expr_dependency_ref & core) { mc = 0; pc = 0; core = 0; bool produce_models = in->models_enabled(); bool produce_proofs = in->proofs_enabled(); diff --git a/src/tactic/arith/pb2bv_tactic.cpp b/src/tactic/arith/pb2bv_tactic.cpp index 6348ddd74..3931a1ea4 100644 --- a/src/tactic/arith/pb2bv_tactic.cpp +++ b/src/tactic/arith/pb2bv_tactic.cpp @@ -885,11 +885,11 @@ private: r.erase("elim_and"); } - virtual void operator()(goal_ref const & g, - goal_ref_buffer & result, - model_converter_ref & mc, - proof_converter_ref & pc, - expr_dependency_ref & core) { + void operator()(goal_ref const & g, + goal_ref_buffer & result, + model_converter_ref & mc, + proof_converter_ref & pc, + expr_dependency_ref & core) { TRACE("pb2bv", g->display(tout);); SASSERT(g->is_well_sorted()); fail_if_proof_generation("pb2bv", g); diff --git a/src/tactic/core/elim_uncnstr_tactic.cpp b/src/tactic/core/elim_uncnstr_tactic.cpp index 156f69388..df3b9f0f5 100644 --- a/src/tactic/core/elim_uncnstr_tactic.cpp +++ b/src/tactic/core/elim_uncnstr_tactic.cpp @@ -819,7 +819,7 @@ class elim_uncnstr_tactic : public tactic { m_rw = alloc(rw, m(), produce_proofs, m_vars, m_mc.get(), m_max_memory, m_max_steps); } - virtual void operator()(goal_ref const & g, + void operator()(goal_ref const & g, goal_ref_buffer & result, model_converter_ref & mc, proof_converter_ref & pc, From fe10f2d244989b549b0e8e4c8f5291a4e82173e4 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 10 Dec 2016 07:51:16 +0100 Subject: [PATCH 414/536] address #835 Signed-off-by: Nikolaj Bjorner --- src/muz/rel/dl_relation_manager.cpp | 4 ++++ src/qe/qe_arrays.cpp | 2 +- src/qe/qe_datatypes.cpp | 2 +- src/smt/smt_model_finder.cpp | 2 +- src/tactic/fpa/fpa2bv_tactic.cpp | 10 +++++----- 5 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/muz/rel/dl_relation_manager.cpp b/src/muz/rel/dl_relation_manager.cpp index 7a73afd03..f8125f7a6 100644 --- a/src/muz/rel/dl_relation_manager.cpp +++ b/src/muz/rel/dl_relation_manager.cpp @@ -1622,6 +1622,8 @@ namespace datalog { m_union_fn = plugin.mk_union_fn(t, *m_aux_table, static_cast(0)); } + virtual ~default_table_map() {} + virtual void operator()(table_base & t) { SASSERT(t.get_signature()==m_aux_table->get_signature()); if(!m_aux_table->empty()) { @@ -1678,6 +1680,8 @@ namespace datalog { m_former_row.resize(get_result_signature().size()); } + virtual ~default_table_project_with_reduce_fn() {} + virtual void modify_fact(table_fact & f) const { unsigned ofs=1; unsigned r_i=1; diff --git a/src/qe/qe_arrays.cpp b/src/qe/qe_arrays.cpp index f8f44b6d9..a010c4ae4 100644 --- a/src/qe/qe_arrays.cpp +++ b/src/qe/qe_arrays.cpp @@ -110,7 +110,7 @@ namespace qe { imp(ast_manager& m): m(m), a(m) {} ~imp() {} - virtual bool solve(model& model, app_ref_vector& vars, expr_ref_vector& lits) { + bool solve(model& model, app_ref_vector& vars, expr_ref_vector& lits) { return false; } diff --git a/src/qe/qe_datatypes.cpp b/src/qe/qe_datatypes.cpp index aa67d28a3..8536e337f 100644 --- a/src/qe/qe_datatypes.cpp +++ b/src/qe/qe_datatypes.cpp @@ -37,7 +37,7 @@ namespace qe { imp(ast_manager& m): m(m), dt(m), m_val(m) {} - virtual bool solve(model& model, app_ref_vector& vars, expr_ref_vector& lits) { + bool solve(model& model, app_ref_vector& vars, expr_ref_vector& lits) { return lift_foreign(vars, lits); } diff --git a/src/smt/smt_model_finder.cpp b/src/smt/smt_model_finder.cpp index b8320f329..ff84992e1 100644 --- a/src/smt/smt_model_finder.cpp +++ b/src/smt/smt_model_finder.cpp @@ -498,7 +498,7 @@ namespace smt { m_bvsimp = static_cast(s.get_plugin(m.mk_family_id("bv"))); } - ~auf_solver() { + virtual ~auf_solver() { flush_nodes(); reset_eval_cache(); } diff --git a/src/tactic/fpa/fpa2bv_tactic.cpp b/src/tactic/fpa/fpa2bv_tactic.cpp index 28597c6ec..d55a2e25c 100644 --- a/src/tactic/fpa/fpa2bv_tactic.cpp +++ b/src/tactic/fpa/fpa2bv_tactic.cpp @@ -46,11 +46,11 @@ class fpa2bv_tactic : public tactic { m_rw.cfg().updt_params(p); } - virtual void operator()(goal_ref const & g, - goal_ref_buffer & result, - model_converter_ref & mc, - proof_converter_ref & pc, - expr_dependency_ref & core) { + void operator()(goal_ref const & g, + goal_ref_buffer & result, + model_converter_ref & mc, + proof_converter_ref & pc, + expr_dependency_ref & core) { SASSERT(g->is_well_sorted()); m_proofs_enabled = g->proofs_enabled(); m_produce_models = g->models_enabled(); From 8e078cf9e20990de2168922dd6172014afa7423b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 10 Dec 2016 07:52:00 +0100 Subject: [PATCH 415/536] address #835 Signed-off-by: Nikolaj Bjorner --- src/muz/rel/dl_relation_manager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/muz/rel/dl_relation_manager.cpp b/src/muz/rel/dl_relation_manager.cpp index f8125f7a6..74206a1f6 100644 --- a/src/muz/rel/dl_relation_manager.cpp +++ b/src/muz/rel/dl_relation_manager.cpp @@ -1622,7 +1622,7 @@ namespace datalog { m_union_fn = plugin.mk_union_fn(t, *m_aux_table, static_cast(0)); } - virtual ~default_table_map() {} + virtual ~default_table_map_fn() {} virtual void operator()(table_base & t) { SASSERT(t.get_signature()==m_aux_table->get_signature()); From dea3b8ddf7b64150d8cfa0dd41118419e3580c11 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 10 Dec 2016 13:14:36 +0100 Subject: [PATCH 416/536] address warnings from #836 Signed-off-by: Nikolaj Bjorner --- src/duality/duality_solver.cpp | 2 +- src/muz/base/dl_context.h | 1 - src/muz/base/dl_engine_base.h | 2 +- src/muz/rel/dl_table_relation.cpp | 2 +- src/muz/rel/dl_table_relation.h | 2 +- src/opt/opt_solver.cpp | 6 +++--- src/opt/opt_solver.h | 2 +- src/smt/proto_model/numeral_factory.cpp | 2 +- src/smt/proto_model/numeral_factory.h | 2 +- src/smt/theory_arith.h | 2 +- src/smt/theory_arith_core.h | 2 +- src/smt/theory_dense_diff_logic.h | 6 +++--- src/smt/theory_dense_diff_logic_def.h | 13 +++++++------ src/smt/theory_diff_logic.h | 7 ++++--- src/smt/theory_diff_logic_def.h | 13 +++++++------ src/smt/theory_opt.h | 1 - src/smt/theory_seq.cpp | 12 ++++++------ src/smt/theory_seq.h | 2 +- src/smt/theory_utvpi_def.h | 2 +- 19 files changed, 41 insertions(+), 40 deletions(-) diff --git a/src/duality/duality_solver.cpp b/src/duality/duality_solver.cpp index b3a96aea4..1869b74ce 100644 --- a/src/duality/duality_solver.cpp +++ b/src/duality/duality_solver.cpp @@ -3099,7 +3099,7 @@ namespace Duality { // Maps nodes of derivation tree into old subtree hash_map cex_map; - virtual void ChooseExpand(const std::set &choices, std::set &best){ + virtual void ChooseExpand(const std::set &choices, std::set &best, bool, bool){ if(old_node == 0){ Heuristic::ChooseExpand(choices,best); return; diff --git a/src/muz/base/dl_context.h b/src/muz/base/dl_context.h index 3c1a7bfaa..ba841c84f 100644 --- a/src/muz/base/dl_context.h +++ b/src/muz/base/dl_context.h @@ -119,7 +119,6 @@ namespace datalog { virtual expr_ref try_get_formula(func_decl * pred) const = 0; virtual void display_output_facts(rule_set const& rules, std::ostream & out) const = 0; virtual void display_facts(std::ostream & out) const = 0; - virtual void display_profile(std::ostream& out) = 0; virtual void restrict_predicates(func_decl_set const& predicates) = 0; virtual bool result_contains_fact(relation_fact const& f) = 0; virtual void add_fact(func_decl* pred, relation_fact const& fact) = 0; diff --git a/src/muz/base/dl_engine_base.h b/src/muz/base/dl_engine_base.h index f353fbf2e..9878f3a9e 100644 --- a/src/muz/base/dl_engine_base.h +++ b/src/muz/base/dl_engine_base.h @@ -66,7 +66,7 @@ namespace datalog { } virtual void reset_statistics() {} - virtual void display_profile(std::ostream& out) const {} + virtual void display_profile(std::ostream& out) {} virtual void collect_statistics(statistics& st) const {} virtual unsigned get_num_levels(func_decl* pred) { throw default_exception(std::string("get_num_levels is not supported for ") + m_name); diff --git a/src/muz/rel/dl_table_relation.cpp b/src/muz/rel/dl_table_relation.cpp index d42d071aa..00a25d169 100644 --- a/src/muz/rel/dl_table_relation.cpp +++ b/src/muz/rel/dl_table_relation.cpp @@ -54,7 +54,7 @@ namespace datalog { return alloc(table_relation, *this, s, t); } - relation_base * table_relation_plugin::mk_full(const relation_signature & s, func_decl* p, family_id kind) { + relation_base * table_relation_plugin::mk_full_relation(const relation_signature & s, func_decl* p, family_id kind) { table_signature tsig; if(!get_manager().relation_signature_to_table(s, tsig)) { return 0; diff --git a/src/muz/rel/dl_table_relation.h b/src/muz/rel/dl_table_relation.h index 8266995da..56ca509fa 100644 --- a/src/muz/rel/dl_table_relation.h +++ b/src/muz/rel/dl_table_relation.h @@ -49,7 +49,7 @@ namespace datalog { virtual bool can_handle_signature(const relation_signature & s); virtual relation_base * mk_empty(const relation_signature & s); - virtual relation_base * mk_full(const relation_signature & s, func_decl* p, family_id kind); + virtual relation_base * mk_full_relation(const relation_signature & s, func_decl* p, family_id kind); relation_base * mk_from_table(const relation_signature & s, table_base * t); protected: diff --git a/src/opt/opt_solver.cpp b/src/opt/opt_solver.cpp index 868303660..42129be70 100644 --- a/src/opt/opt_solver.cpp +++ b/src/opt/opt_solver.cpp @@ -57,7 +57,7 @@ namespace opt { opt_solver::~opt_solver() { } - void opt_solver::updt_params(params_ref & _p) { + void opt_solver::updt_params(params_ref const & _p) { opt_params p(_p); m_dump_benchmarks = p.dump_benchmarks(); m_params.updt_params(_p); @@ -383,13 +383,13 @@ namespace opt { if (typeid(smt::theory_idl) == typeid(opt)) { smt::theory_idl& th = dynamic_cast(opt); - return th.mk_ge(m_fm, v, val.get_rational()); + return th.mk_ge(m_fm, v, val); } if (typeid(smt::theory_rdl) == typeid(opt) && val.get_infinitesimal().is_zero()) { smt::theory_rdl& th = dynamic_cast(opt); - return th.mk_ge(m_fm, v, val.get_rational()); + return th.mk_ge(m_fm, v, val); } // difference logic? diff --git a/src/opt/opt_solver.h b/src/opt/opt_solver.h index 094023ba2..cdaad3cf2 100644 --- a/src/opt/opt_solver.h +++ b/src/opt/opt_solver.h @@ -88,7 +88,7 @@ namespace opt { virtual ~opt_solver(); virtual solver* translate(ast_manager& m, params_ref const& p); - virtual void updt_params(params_ref & p); + virtual void updt_params(params_ref const& p); virtual void collect_param_descrs(param_descrs & r); virtual void collect_statistics(statistics & st) const; virtual void assert_expr(expr * t); diff --git a/src/smt/proto_model/numeral_factory.cpp b/src/smt/proto_model/numeral_factory.cpp index a67b6c075..413cc1b9e 100644 --- a/src/smt/proto_model/numeral_factory.cpp +++ b/src/smt/proto_model/numeral_factory.cpp @@ -31,7 +31,7 @@ arith_factory::arith_factory(ast_manager & m): arith_factory::~arith_factory() { } -app * arith_factory::mk_value(rational const & val, bool is_int) { +app * arith_factory::mk_num_value(rational const & val, bool is_int) { return numeral_factory::mk_value(val, is_int ? m_util.mk_int() : m_util.mk_real()); } diff --git a/src/smt/proto_model/numeral_factory.h b/src/smt/proto_model/numeral_factory.h index 3c5d41040..e0d3cf6b5 100644 --- a/src/smt/proto_model/numeral_factory.h +++ b/src/smt/proto_model/numeral_factory.h @@ -38,7 +38,7 @@ public: arith_factory(ast_manager & m); virtual ~arith_factory(); - app * mk_value(rational const & val, bool is_int); + app * mk_num_value(rational const & val, bool is_int); }; class bv_factory : public numeral_factory { diff --git a/src/smt/theory_arith.h b/src/smt/theory_arith.h index 39f991c72..5a0f8db95 100644 --- a/src/smt/theory_arith.h +++ b/src/smt/theory_arith.h @@ -1080,7 +1080,7 @@ namespace smt { virtual inf_eps_rational maximize(theory_var v, expr_ref& blocker, bool& has_shared); virtual inf_eps_rational value(theory_var v); virtual theory_var add_objective(app* term); - virtual expr_ref mk_ge(filter_model_converter& fm, theory_var v, inf_numeral const& val); + expr_ref mk_ge(filter_model_converter& fm, theory_var v, inf_numeral const& val); void enable_record_conflict(expr* bound); void record_conflict(unsigned num_lits, literal const * lits, unsigned num_eqs, enode_pair const * eqs, diff --git a/src/smt/theory_arith_core.h b/src/smt/theory_arith_core.h index a08ee50ab..a8d771d1a 100644 --- a/src/smt/theory_arith_core.h +++ b/src/smt/theory_arith_core.h @@ -3231,7 +3231,7 @@ namespace smt { TRACE("arith", tout << "Truncating non-integer value. This is possible for non-linear constraints v" << v << " " << num << "\n";); num = floor(num); } - return alloc(expr_wrapper_proc, m_factory->mk_value(num, m_util.is_int(var2expr(v)))); + return alloc(expr_wrapper_proc, m_factory->mk_num_value(num, m_util.is_int(var2expr(v)))); } // ----------------------------------- diff --git a/src/smt/theory_dense_diff_logic.h b/src/smt/theory_dense_diff_logic.h index 1b1653eb7..c2be89bc3 100644 --- a/src/smt/theory_dense_diff_logic.h +++ b/src/smt/theory_dense_diff_logic.h @@ -198,7 +198,7 @@ namespace smt { void del_vars(unsigned old_num_vars); void init_model(); bool internalize_objective(expr * n, rational const& m, rational& r, objective_term & objective); - expr_ref mk_ineq(theory_var v, inf_rational const& val, bool is_strict); + expr_ref mk_ineq(theory_var v, inf_eps const& val, bool is_strict); #ifdef Z3DEBUG bool check_vector_sizes() const; bool check_matrix() const; @@ -270,8 +270,8 @@ namespace smt { virtual inf_eps_rational maximize(theory_var v, expr_ref& blocker, bool& has_shared); virtual inf_eps_rational value(theory_var v); virtual theory_var add_objective(app* term); - virtual expr_ref mk_gt(theory_var v, inf_rational const& val); - virtual expr_ref mk_ge(filter_model_converter& fm, theory_var v, inf_rational const& val); + virtual expr_ref mk_gt(theory_var v, inf_eps const& val); + expr_ref mk_ge(filter_model_converter& fm, theory_var v, inf_eps const& val); // ----------------------------------- // diff --git a/src/smt/theory_dense_diff_logic_def.h b/src/smt/theory_dense_diff_logic_def.h index fd388b5bd..877d4f659 100644 --- a/src/smt/theory_dense_diff_logic_def.h +++ b/src/smt/theory_dense_diff_logic_def.h @@ -828,7 +828,7 @@ namespace smt { SASSERT(v != null_theory_var); numeral const & val = m_assignment[v]; rational num = val.get_rational().to_rational() + m_epsilon * val.get_infinitesimal().to_rational(); - return alloc(expr_wrapper_proc, m_factory->mk_value(num, is_int(v))); + return alloc(expr_wrapper_proc, m_factory->mk_num_value(num, is_int(v))); } // TBD: code is common to both sparse and dense difference logic solvers. @@ -1002,9 +1002,10 @@ namespace smt { m_assignment[i] = a; // TBD: if epsilon is != 0, then adjust a by some small fraction. } - blocker = mk_gt(v, r); + inf_eps result(rational(0), r); + blocker = mk_gt(v, result); IF_VERBOSE(10, verbose_stream() << blocker << "\n";); - return inf_eps(rational(0), r); + return result; } default: TRACE("opt", tout << "unbounded\n"; ); @@ -1034,18 +1035,18 @@ namespace smt { } template - expr_ref theory_dense_diff_logic::mk_gt(theory_var v, inf_rational const& val) { + expr_ref theory_dense_diff_logic::mk_gt(theory_var v, inf_eps const& val) { return mk_ineq(v, val, true); } template expr_ref theory_dense_diff_logic::mk_ge( - filter_model_converter& fm, theory_var v, inf_rational const& val) { + filter_model_converter& fm, theory_var v, inf_eps const& val) { return mk_ineq(v, val, false); } template - expr_ref theory_dense_diff_logic::mk_ineq(theory_var v, inf_rational const& val, bool is_strict) { + expr_ref theory_dense_diff_logic::mk_ineq(theory_var v, inf_eps const& val, bool is_strict) { ast_manager& m = get_manager(); objective_term const& t = m_objectives[v]; expr_ref e(m), f(m), f2(m); diff --git a/src/smt/theory_diff_logic.h b/src/smt/theory_diff_logic.h index 6fb9e6454..f47e61548 100644 --- a/src/smt/theory_diff_logic.h +++ b/src/smt/theory_diff_logic.h @@ -324,14 +324,15 @@ namespace smt { virtual inf_eps maximize(theory_var v, expr_ref& blocker, bool& has_shared); virtual inf_eps value(theory_var v); virtual theory_var add_objective(app* term); - virtual expr_ref mk_gt(theory_var v, inf_rational const& val); - virtual expr_ref mk_ge(filter_model_converter& fm, theory_var v, inf_rational const& val); + expr_ref mk_ge(filter_model_converter& fm, theory_var v, inf_eps const& val); bool internalize_objective(expr * n, rational const& m, rational& r, objective_term & objective); private: - expr_ref mk_ineq(theory_var v, inf_rational const& val, bool is_strict); + expr_ref mk_gt(theory_var v, inf_eps const& val); + + expr_ref mk_ineq(theory_var v, inf_eps const& val, bool is_strict); virtual void new_eq_eh(theory_var v1, theory_var v2, justification& j); diff --git a/src/smt/theory_diff_logic_def.h b/src/smt/theory_diff_logic_def.h index 98f94c6d2..372786c01 100644 --- a/src/smt/theory_diff_logic_def.h +++ b/src/smt/theory_diff_logic_def.h @@ -905,7 +905,7 @@ model_value_proc * theory_diff_logic::mk_value(enode * n, model_generator & numeral val = m_graph.get_assignment(v); rational num = val.get_rational().to_rational() + m_delta * val.get_infinitesimal().to_rational(); TRACE("arith", tout << mk_pp(n->get_owner(), get_manager()) << " |-> " << num << "\n";); - return alloc(expr_wrapper_proc, m_factory->mk_value(num, m_util.is_int(n->get_owner()))); + return alloc(expr_wrapper_proc, m_factory->mk_num_value(num, m_util.is_int(n->get_owner()))); } template @@ -1242,7 +1242,8 @@ theory_diff_logic::maximize(theory_var v, expr_ref& blocker, bool& has_shar rational r = rational(val.first) + m_delta*rational(val.second); m_graph.set_assignment(i, numeral(r)); } - blocker = mk_gt(v, r); + inf_eps r1(rational(0), r); + blocker = mk_gt(v, r1); return inf_eps(rational(0), r + m_objective_consts[v]); } default: @@ -1273,7 +1274,7 @@ theory_var theory_diff_logic::add_objective(app* term) { } template -expr_ref theory_diff_logic::mk_ineq(theory_var v, inf_rational const& val, bool is_strict) { +expr_ref theory_diff_logic::mk_ineq(theory_var v, inf_eps const& val, bool is_strict) { ast_manager& m = get_manager(); objective_term const& t = m_objectives[v]; expr_ref e(m), f(m), f2(m); @@ -1304,7 +1305,7 @@ expr_ref theory_diff_logic::mk_ineq(theory_var v, inf_rational const& val, return f; } - inf_rational new_val = val; // - inf_rational(m_objective_consts[v]); + inf_eps new_val = val; // - inf_rational(m_objective_consts[v]); e = m_util.mk_numeral(new_val.get_rational(), m.get_sort(f)); if (new_val.get_infinitesimal().is_neg()) { @@ -1328,12 +1329,12 @@ expr_ref theory_diff_logic::mk_ineq(theory_var v, inf_rational const& val, } template -expr_ref theory_diff_logic::mk_gt(theory_var v, inf_rational const& val) { +expr_ref theory_diff_logic::mk_gt(theory_var v, inf_eps const& val) { return mk_ineq(v, val, true); } template -expr_ref theory_diff_logic::mk_ge(filter_model_converter& fm, theory_var v, inf_rational const& val) { +expr_ref theory_diff_logic::mk_ge(filter_model_converter& fm, theory_var v, inf_eps const& val) { return mk_ineq(v, val, false); } diff --git a/src/smt/theory_opt.h b/src/smt/theory_opt.h index 58e039140..421e6feca 100644 --- a/src/smt/theory_opt.h +++ b/src/smt/theory_opt.h @@ -33,7 +33,6 @@ namespace smt { virtual inf_eps value(theory_var) = 0; virtual inf_eps maximize(theory_var v, expr_ref& blocker, bool& has_shared) = 0; virtual theory_var add_objective(app* term) = 0; - virtual expr_ref mk_ge(filter_model_converter& fm, theory_var v, inf_eps const& val) { UNREACHABLE(); return expr_ref(*((ast_manager*)0)); } bool is_linear(ast_manager& m, expr* term); bool is_numeral(arith_util& a, expr* term); }; diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index 3be3fd5f8..4f2683ca9 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -2236,7 +2236,7 @@ bool theory_seq::add_stoi_axiom(expr* e) { expr* n; rational val; VERIFY(m_util.str.is_stoi(e, n)); - if (get_value(e, val) && !m_stoi_axioms.contains(val)) { + if (get_num_value(e, val) && !m_stoi_axioms.contains(val)) { m_stoi_axioms.insert(val); if (!val.is_minus_one()) { app_ref e1(m_util.str.mk_string(symbol(val.to_string().c_str())), m); @@ -2260,7 +2260,7 @@ bool theory_seq::add_itos_axiom(expr* e) { rational val; expr* n; VERIFY(m_util.str.is_itos(e, n)); - if (get_value(n, val)) { + if (get_num_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); @@ -2741,7 +2741,7 @@ expr_ref theory_seq::expand(expr* e0, dependency*& eqs) { } else if (m_util.str.is_itos(e, e1)) { rational val; - if (get_value(e1, val)) { + if (get_num_value(e1, val)) { TRACE("seq", tout << mk_pp(e, m) << " -> " << val << "\n";); expr_ref num(m), res(m); num = m_autil.mk_numeral(val, true); @@ -3024,7 +3024,7 @@ void theory_seq::add_itos_length_axiom(expr* len) { unsigned num_char1 = 1, num_char2 = 1; rational len1, len2; rational ten(10); - if (get_value(n, len1)) { + if (get_num_value(n, len1)) { bool neg = len1.is_neg(); if (neg) len1.neg(); num_char1 = neg?2:1; @@ -3038,7 +3038,7 @@ void theory_seq::add_itos_length_axiom(expr* len) { } SASSERT(len1 <= upper); } - if (get_value(len, len2) && len2.is_unsigned()) { + if (get_num_value(len, len2) && len2.is_unsigned()) { num_char2 = len2.get_unsigned(); } unsigned num_char = std::max(num_char1, num_char2); @@ -3172,7 +3172,7 @@ static theory_mi_arith* get_th_arith(context& ctx, theory_id afid, expr* e) { } } -bool theory_seq::get_value(expr* e, rational& val) const { +bool theory_seq::get_num_value(expr* e, rational& val) const { context& ctx = get_context(); theory_mi_arith* tha = get_th_arith(ctx, m_autil.get_family_id(), e); expr_ref _val(m); diff --git a/src/smt/theory_seq.h b/src/smt/theory_seq.h index 21955bf30..0e06997ad 100644 --- a/src/smt/theory_seq.h +++ b/src/smt/theory_seq.h @@ -512,7 +512,7 @@ namespace smt { // arithmetic integration - bool get_value(expr* s, rational& val) const; + bool get_num_value(expr* s, rational& val) const; bool lower_bound(expr* s, rational& lo) const; bool upper_bound(expr* s, rational& hi) const; bool get_length(expr* s, rational& val) const; diff --git a/src/smt/theory_utvpi_def.h b/src/smt/theory_utvpi_def.h index ff295d5a3..5f370c29c 100644 --- a/src/smt/theory_utvpi_def.h +++ b/src/smt/theory_utvpi_def.h @@ -901,7 +901,7 @@ namespace smt { bool is_int = a.is_int(n->get_owner()); rational num = mk_value(v, is_int); TRACE("utvpi", tout << mk_pp(n->get_owner(), get_manager()) << " |-> " << num << "\n";); - return alloc(expr_wrapper_proc, m_factory->mk_value(num, is_int)); + return alloc(expr_wrapper_proc, m_factory->mk_num_value(num, is_int)); } /** From 6594c3a0461a106a528e330b1d5427bbc8e4bebd Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 10 Dec 2016 13:58:39 +0100 Subject: [PATCH 417/536] add virtual destructor to intermediary class in case this helps for #835 Signed-off-by: Nikolaj Bjorner --- src/muz/rel/dl_base.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/muz/rel/dl_base.h b/src/muz/rel/dl_base.h index 1c7a81444..9b573f71f 100644 --- a/src/muz/rel/dl_base.h +++ b/src/muz/rel/dl_base.h @@ -220,6 +220,8 @@ namespace datalog { */ class mutator_fn : public base_fn { public: + virtual ~mutator_fn() {} + virtual void operator()(base_object & t) = 0; virtual bool supports_attachment(base_object& other) { return false; } From 32c63ce4cdae0e244c2b01ac0f0e0637035ec6d3 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 10 Dec 2016 17:23:59 +0100 Subject: [PATCH 418/536] address other warnings per input from delcypher Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/rewriter.h | 2 +- src/cmd_context/parametric_cmd.h | 1 + src/muz/rel/dl_base.h | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/ast/rewriter/rewriter.h b/src/ast/rewriter/rewriter.h index 401d00d89..fc596cabd 100644 --- a/src/ast/rewriter/rewriter.h +++ b/src/ast/rewriter/rewriter.h @@ -111,7 +111,7 @@ protected: void elim_reflex_prs(unsigned spos); public: rewriter_core(ast_manager & m, bool proof_gen); - ~rewriter_core(); + virtual ~rewriter_core(); ast_manager & m() const { return m_manager; } void reset(); void cleanup(); diff --git a/src/cmd_context/parametric_cmd.h b/src/cmd_context/parametric_cmd.h index 3e95832c4..cac5fe38e 100644 --- a/src/cmd_context/parametric_cmd.h +++ b/src/cmd_context/parametric_cmd.h @@ -72,6 +72,7 @@ public: // m_params.set_func_decl(m_last, f); // m_last = symbol::null; } + virtual void set_next_arg(cmd_context & ctx, sexpr * n) { UNREACHABLE(); } }; #endif diff --git a/src/muz/rel/dl_base.h b/src/muz/rel/dl_base.h index 9b573f71f..9a2db4dbb 100644 --- a/src/muz/rel/dl_base.h +++ b/src/muz/rel/dl_base.h @@ -871,6 +871,7 @@ namespace datalog { class table_row_mutator_fn { public: + virtual ~table_row_mutator_fn() {} /** \brief The function is called for a particular table row. The \c func_columns contains a pointer to an array of functional column values that can be modified. If the function From 20790c46ee1b461749657b59f71508eded6e2363 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 11 Dec 2016 04:23:07 +0100 Subject: [PATCH 419/536] bail out on failure to properly project Signed-off-by: Nikolaj Bjorner --- src/model/model_core.cpp | 30 +++++++++++++------------- src/model/model_core.h | 2 +- src/qe/qe_mbp.cpp | 2 ++ src/qe/qsat.cpp | 1 + src/tactic/smtlogics/quant_tactics.cpp | 9 -------- 5 files changed, 19 insertions(+), 25 deletions(-) diff --git a/src/model/model_core.cpp b/src/model/model_core.cpp index 6b8ff8d63..503abac2f 100644 --- a/src/model/model_core.cpp +++ b/src/model/model_core.cpp @@ -88,20 +88,20 @@ void model_core::register_decl(func_decl * d, func_interp * fi) { } void model_core::unregister_decl(func_decl * d) { - decl2expr::obj_map_entry * ec = m_interp.find_core(d); - if (ec && ec->get_data().m_value != 0) { - m_manager.dec_ref(ec->get_data().m_key); - m_manager.dec_ref(ec->get_data().m_value); - m_interp.remove(d); + decl2expr::obj_map_entry * ec = m_interp.find_core(d); + if (ec && ec->get_data().m_value != 0) { + m_manager.dec_ref(ec->get_data().m_key); + m_manager.dec_ref(ec->get_data().m_value); + m_interp.remove(d); m_const_decls.erase(d); - return; - } - - decl2finterp::obj_map_entry * ef = m_finterp.find_core(d); - if (ef && ef->get_data().m_value != 0) { - m_manager.dec_ref(ef->get_data().m_key); - dealloc(ef->get_data().m_value); - m_finterp.remove(d); + return; + } + + decl2finterp::obj_map_entry * ef = m_finterp.find_core(d); + if (ef && ef->get_data().m_value != 0) { + m_manager.dec_ref(ef->get_data().m_key); + dealloc(ef->get_data().m_value); + m_finterp.remove(d); m_func_decls.erase(d); - } -} \ No newline at end of file + } +} diff --git a/src/model/model_core.h b/src/model/model_core.h index 371106b05..c42451c5a 100644 --- a/src/model/model_core.h +++ b/src/model/model_core.h @@ -60,7 +60,7 @@ public: void register_decl(func_decl * d, expr * v); void register_decl(func_decl * f, func_interp * fi); - void unregister_decl(func_decl * d); + void unregister_decl(func_decl * d); virtual expr * get_some_value(sort * s) = 0; diff --git a/src/qe/qe_mbp.cpp b/src/qe/qe_mbp.cpp index eaedc470b..8aa6f509e 100644 --- a/src/qe/qe_mbp.cpp +++ b/src/qe/qe_mbp.cpp @@ -294,6 +294,7 @@ public: void extract_literals(model& model, expr_ref_vector& fmls) { expr_ref val(m); + TRACE("qe", tout << fmls << "\n";); for (unsigned i = 0; i < fmls.size(); ++i) { expr* fml = fmls[i].get(), *nfml, *f1, *f2, *f3; SASSERT(m.is_bool(fml)); @@ -404,6 +405,7 @@ public: // TBD other Boolean operations. } } + TRACE("qe", tout << fmls << "\n";); m_visited.reset(); } diff --git a/src/qe/qsat.cpp b/src/qe/qsat.cpp index 1bfd53597..e378c7fdf 100644 --- a/src/qe/qsat.cpp +++ b/src/qe/qsat.cpp @@ -909,6 +909,7 @@ namespace qe { num_scopes = 2; } else { + if (level.max() + 2 > m_level) return false; SASSERT(level.max() + 2 <= m_level); num_scopes = m_level - level.max(); SASSERT(num_scopes >= 2); diff --git a/src/tactic/smtlogics/quant_tactics.cpp b/src/tactic/smtlogics/quant_tactics.cpp index bc3585d09..044511c33 100644 --- a/src/tactic/smtlogics/quant_tactics.cpp +++ b/src/tactic/smtlogics/quant_tactics.cpp @@ -104,21 +104,12 @@ tactic * mk_aufnira_tactic(ast_manager & m, params_ref const & p) { } tactic * mk_lra_tactic(ast_manager & m, params_ref const & p) { -#if 0 - tactic * st = and_then(mk_quant_preprocessor(m), - or_else(try_for(mk_smt_tactic(), 100), - try_for(qe::mk_sat_tactic(m), 1000), - try_for(mk_smt_tactic(), 1000), - and_then(mk_qe_tactic(m), mk_smt_tactic()) - )); -#else tactic * st = and_then(mk_quant_preprocessor(m), mk_qe_lite_tactic(m, p), cond(mk_has_quantifier_probe(), or_else(mk_qsat_tactic(m, p), and_then(mk_qe_tactic(m), mk_smt_tactic())), mk_smt_tactic())); -#endif st->updt_params(p); return st; } From ff46a925a2f31cab964e5ee696a03bbbb99a9207 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 11 Dec 2016 04:25:05 +0100 Subject: [PATCH 420/536] bail out on failure to properly project. issue #837 Signed-off-by: Nikolaj Bjorner --- src/qe/qsat.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qe/qsat.cpp b/src/qe/qsat.cpp index e378c7fdf..841bdde9b 100644 --- a/src/qe/qsat.cpp +++ b/src/qe/qsat.cpp @@ -909,7 +909,7 @@ namespace qe { num_scopes = 2; } else { - if (level.max() + 2 > m_level) return false; + if (level.max() + 2 > m_level) return false; SASSERT(level.max() + 2 <= m_level); num_scopes = m_level - level.max(); SASSERT(num_scopes >= 2); From 70bb92d0163d4a9b1a033ab6c819207e231fdea4 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 11 Dec 2016 05:16:31 +0100 Subject: [PATCH 421/536] remove nested booleans during pre-processing. issue #837 Signed-off-by: Nikolaj Bjorner --- src/qe/qe_mbp.cpp | 57 ++++++++++++++++++++++++++++++----------------- 1 file changed, 37 insertions(+), 20 deletions(-) diff --git a/src/qe/qe_mbp.cpp b/src/qe/qe_mbp.cpp index 8aa6f509e..f4c0c9339 100644 --- a/src/qe/qe_mbp.cpp +++ b/src/qe/qe_mbp.cpp @@ -29,6 +29,7 @@ Revision History: #include "model_v2_pp.h" #include "expr_functors.h" #include "for_each_expr.h" +#include "model_evaluator.h" using namespace qe; @@ -125,6 +126,7 @@ class mbp::impl { th_rewriter m_rw; ptr_vector m_plugins; expr_mark m_visited; + expr_mark m_bool_visited; void add_plugin(project_plugin* p) { family_id fid = p->get_family_id(); @@ -212,10 +214,12 @@ class mbp::impl { } } - - void extract_bools(model& model, expr_ref_vector& fmls, expr* fml) { + bool extract_bools(model_evaluator& eval, expr_ref_vector& fmls, expr* fml) { TRACE("qe", tout << "extract bools: " << mk_pp(fml, m) << "\n";); ptr_vector todo; + expr_safe_replace sub(m); + m_visited.reset(); + bool found_bool = false; if (is_app(fml)) { todo.append(to_app(fml)->get_num_args(), to_app(fml)->get_args()); } @@ -226,16 +230,16 @@ class mbp::impl { continue; } m_visited.mark(e); - if (m.is_bool(e)) { - expr_ref val(m); - VERIFY(model.eval(e, val)); + if (m.is_bool(e) && !m.is_true(e) && !m.is_false(e)) { + expr_ref val = eval(e); TRACE("qe", tout << "found: " << mk_pp(e, m) << "\n";); - if (m.is_true(val)) { - fmls.push_back(e); - } - else { - fmls.push_back(mk_not(m, e)); + SASSERT(m.is_true(val) || m.is_false(val)); + if (!m_bool_visited.is_marked(e)) { + fmls.push_back(m.is_true(val) ? e : mk_not(m, e)); } + sub.insert(e, val); + m_bool_visited.mark(e); + found_bool = true; } else if (is_app(e)) { todo.append(to_app(e)->get_num_args(), to_app(e)->get_args()); @@ -244,6 +248,14 @@ class mbp::impl { TRACE("qe", tout << "expression not handled " << mk_pp(e, m) << "\n";); } } + if (found_bool) { + expr_ref tmp(m); + sub(fml, tmp); + expr_ref val = eval(tmp); + SASSERT(m.is_true(val) || m.is_false(val)); + fmls.push_back(m.is_true(val) ? tmp : mk_not(m, tmp)); + } + return found_bool; } void project_bools(model& model, app_ref_vector& vars, expr_ref_vector& fmls) { @@ -294,6 +306,7 @@ public: void extract_literals(model& model, expr_ref_vector& fmls) { expr_ref val(m); + model_evaluator eval(model); TRACE("qe", tout << fmls << "\n";); for (unsigned i = 0; i < fmls.size(); ++i) { expr* fml = fmls[i].get(), *nfml, *f1, *f2, *f3; @@ -304,7 +317,7 @@ public: } else if (m.is_or(fml)) { for (unsigned j = 0; j < to_app(fml)->get_num_args(); ++j) { - VERIFY (model.eval(to_app(fml)->get_arg(j), val)); + val = eval(to_app(fml)->get_arg(j)); if (m.is_true(val)) { fmls[i] = to_app(fml)->get_arg(j); --i; @@ -317,7 +330,7 @@ public: project_plugin::erase(fmls, i); } else if (m.is_iff(fml, f1, f2) || (m.is_not(fml, nfml) && m.is_xor(nfml, f1, f2))) { - VERIFY (model.eval(f1, val)); + val = eval(f1); if (m.is_false(val)) { f1 = mk_not(m, f1); f2 = mk_not(m, f2); @@ -327,7 +340,7 @@ public: --i; } else if (m.is_implies(fml, f1, f2)) { - VERIFY (model.eval(f2, val)); + val = eval(f2); if (m.is_true(val)) { fmls[i] = f2; } @@ -337,7 +350,7 @@ public: --i; } else if (m.is_ite(fml, f1, f2, f3)) { - VERIFY (model.eval(f1, val)); + val = eval(f1); if (m.is_true(val)) { project_plugin::push_back(fmls, f1); project_plugin::push_back(fmls, f2); @@ -354,7 +367,7 @@ public: } else if (m.is_not(fml, nfml) && m.is_and(nfml)) { for (unsigned j = 0; j < to_app(nfml)->get_num_args(); ++j) { - VERIFY (model.eval(to_app(nfml)->get_arg(j), val)); + val = eval(to_app(nfml)->get_arg(j)); if (m.is_false(val)) { fmls[i] = mk_not(m, to_app(nfml)->get_arg(j)); --i; @@ -369,7 +382,7 @@ public: project_plugin::erase(fmls, i); } else if ((m.is_not(fml, nfml) && m.is_iff(nfml, f1, f2)) || m.is_xor(fml, f1, f2)) { - VERIFY (model.eval(f1, val)); + val = eval(f1); if (m.is_true(val)) { f2 = mk_not(m, f2); } @@ -386,7 +399,7 @@ public: project_plugin::erase(fmls, i); } else if (m.is_not(fml, nfml) && m.is_ite(nfml, f1, f2, f3)) { - VERIFY (model.eval(f1, val)); + val = eval(f1); if (m.is_true(val)) { project_plugin::push_back(fmls, f1); project_plugin::push_back(fmls, mk_not(m, f2)); @@ -398,15 +411,19 @@ public: project_plugin::erase(fmls, i); } else if (m.is_not(fml, nfml)) { - extract_bools(model, fmls, nfml); + if (extract_bools(eval, fmls, nfml)) { + project_plugin::erase(fmls, i); + } } else { - extract_bools(model, fmls, fml); + if (extract_bools(eval, fmls, fml)) { + project_plugin::erase(fmls, i); + } // TBD other Boolean operations. } } TRACE("qe", tout << fmls << "\n";); - m_visited.reset(); + m_bool_visited.reset(); } impl(ast_manager& m):m(m), m_rw(m) { From 0765eea486f1bd55aba5ac30a6ce45f08f9ef67a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 11 Dec 2016 05:45:40 +0100 Subject: [PATCH 422/536] add suggestions from #835 Signed-off-by: Nikolaj Bjorner --- src/ast/macros/macro_util.cpp | 2 +- src/muz/rel/dl_base.h | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ast/macros/macro_util.cpp b/src/ast/macros/macro_util.cpp index 91bff5ab5..027cce09d 100644 --- a/src/ast/macros/macro_util.cpp +++ b/src/ast/macros/macro_util.cpp @@ -494,7 +494,7 @@ void macro_util::normalize_expr(app * head, expr * t, expr_ref & norm_t) const { tout << "applying substitution to:\n" << mk_ll_pp(t, m_manager) << "\nsubstitution:\n"; for (unsigned i = 0; i < var_mapping.size(); i++) { if (var_mapping[i] != 0) - tout << "#" << i << " -> " << mk_ll_pp(var_mapping[i], m_manager); + tout << "#" << i << " -> " << mk_ll_pp(var_mapping[i], m_manager); }); subst(t, var_mapping.size(), var_mapping.c_ptr(), norm_t); } diff --git a/src/muz/rel/dl_base.h b/src/muz/rel/dl_base.h index 9a2db4dbb..d3422f882 100644 --- a/src/muz/rel/dl_base.h +++ b/src/muz/rel/dl_base.h @@ -885,6 +885,7 @@ namespace datalog { class table_row_pair_reduce_fn { public: + virtual ~table_row_pair_reduce_fn() {} /** \brief The function is called for pair of table rows that became duplicit due to projection. The values that are in the first array after return from the function will be used for the From 2307a7ffa73fb06c80b206503b03d0c4af4fb12b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 11 Dec 2016 10:19:57 +0100 Subject: [PATCH 423/536] fix bug in handling of repeated soft constraints. #815 Signed-off-by: Nikolaj Bjorner --- src/opt/maxres.cpp | 3 ++- src/opt/maxsmt.cpp | 11 +++++++++-- src/opt/maxsmt.h | 2 +- src/opt/opt_context.cpp | 27 +++++++++++++++++++++++++++ src/opt/opt_context.h | 1 + 5 files changed, 40 insertions(+), 4 deletions(-) diff --git a/src/opt/maxres.cpp b/src/opt/maxres.cpp index 7f9183d9a..54e7f351c 100644 --- a/src/opt/maxres.cpp +++ b/src/opt/maxres.cpp @@ -805,8 +805,9 @@ public: lbool init_local() { m_lower.reset(); m_trail.reset(); + lbool is_sat = l_true; obj_map new_soft; - lbool is_sat = find_mutexes(new_soft); + is_sat = find_mutexes(new_soft); if (is_sat != l_true) { return is_sat; } diff --git a/src/opt/maxsmt.cpp b/src/opt/maxsmt.cpp index 85b19e427..21537a570 100644 --- a/src/opt/maxsmt.cpp +++ b/src/opt/maxsmt.cpp @@ -333,8 +333,15 @@ namespace opt { TRACE("opt", tout << mk_pp(f, m) << " weight: " << w << "\n";); SASSERT(m.is_bool(f)); SASSERT(w.is_pos()); - m_soft_constraints.push_back(f); - m_weights.push_back(w); + unsigned index = 0; + if (m_soft_constraint_index.find(f, index)) { + m_weights[index] += w; + } + else { + m_soft_constraint_index.insert(f, m_weights.size()); + m_soft_constraints.push_back(f); + m_weights.push_back(w); + } m_upper += w; } diff --git a/src/opt/maxsmt.h b/src/opt/maxsmt.h index 5ecb023f6..358ff4995 100644 --- a/src/opt/maxsmt.h +++ b/src/opt/maxsmt.h @@ -120,6 +120,7 @@ namespace opt { unsigned m_index; scoped_ptr m_msolver; expr_ref_vector m_soft_constraints; + obj_map m_soft_constraint_index; expr_ref_vector m_answer; vector m_weights; rational m_lower; @@ -138,7 +139,6 @@ namespace opt { expr* operator[](unsigned idx) const { return m_soft_constraints[idx]; } rational weight(unsigned idx) const { return m_weights[idx]; } void commit_assignment(); - rational get_value() const; rational get_lower() const; rational get_upper() const; void update_lower(rational const& r); diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index b95bb62e8..e63e29dc5 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -360,6 +360,7 @@ namespace opt { } if (scoped) get_solver().pop(1); if (result == l_true && committed) ms.commit_assignment(); + DEBUG_CODE(if (result == l_true) validate_maxsat(id);); return result; } @@ -1448,6 +1449,32 @@ namespace opt { return out.str(); } + void context::validate_maxsat(symbol const& id) { + maxsmt& ms = *m_maxsmts.find(id); + for (unsigned i = 0; i < m_objectives.size(); ++i) { + objective const& obj = m_objectives[i]; + if (obj.m_id == id) { + SASSERT(obj.m_type == O_MAXSMT); + rational value(0); + expr_ref val(m); + for (unsigned i = 0; i < obj.m_terms.size(); ++i) { + bool evaluated = m_model->eval(obj.m_terms[i], val); + SASSERT(evaluated); + CTRACE("opt", evaluated && !m.is_true(val) && !m.is_false(val), tout << mk_pp(obj.m_terms[i], m) << " " << val << "\n";); + CTRACE("opt", !evaluated, tout << mk_pp(obj.m_terms[i], m) << "\n";); + if (evaluated && !m.is_true(val)) { + value += obj.m_weights[i]; + } + // TBD: check that optimal was not changed. + } + value = obj.m_adjust_value(value); + rational value0 = ms.get_lower(); + TRACE("opt", tout << "value " << value << " " << value0 << "\n";); + SASSERT(value == value0); + } + } + } + void context::validate_lex() { rational r1; expr_ref val(m); diff --git a/src/opt/opt_context.h b/src/opt/opt_context.h index ef02a4cbe..461506258 100644 --- a/src/opt/opt_context.h +++ b/src/opt/opt_context.h @@ -291,6 +291,7 @@ namespace opt { void validate_lex(); + void validate_maxsat(symbol const& id); void display_benchmark(); From 7cc093eee0adeeb7682bb8dcd529f13e2491449d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 11 Dec 2016 11:05:12 +0100 Subject: [PATCH 424/536] Add rewrite rule for property encoded in #812 Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/seq_rewriter.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/ast/rewriter/seq_rewriter.cpp b/src/ast/rewriter/seq_rewriter.cpp index cc948de9a..b97d832b1 100644 --- a/src/ast/rewriter/seq_rewriter.cpp +++ b/src/ast/rewriter/seq_rewriter.cpp @@ -524,7 +524,7 @@ br_status seq_rewriter::mk_seq_contains(expr* a, expr* b, expr_ref& result) { result = m().mk_bool_val(c.contains(d)); return BR_DONE; } - // check if subsequence of b is in a. + // check if subsequence of a is in b. expr_ref_vector as(m()), bs(m()); m_util.str.get_concat(a, as); m_util.str.get_concat(b, bs); @@ -587,6 +587,12 @@ br_status seq_rewriter::mk_seq_contains(expr* a, expr* b, expr_ref& result) { SASSERT(sz > offs); result = m_util.str.mk_contains(m_util.str.mk_concat(sz-offs, as.c_ptr()+offs), b); return BR_REWRITE2; + } + + expr* x, *y, *z; + if (m_util.str.is_extract(b, x, y, z) && x == a) { + result = m().mk_true(); + return BR_DONE; } return BR_FAILED; From aca3d0545c4948a147a8efda7f2bd1e5efa4c131 Mon Sep 17 00:00:00 2001 From: Andrew Dutcher Date: Wed, 14 Sep 2016 15:21:29 -0700 Subject: [PATCH 425/536] Set soname version correctly in cmake build --- contrib/cmake/src/CMakeLists.txt | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/contrib/cmake/src/CMakeLists.txt b/contrib/cmake/src/CMakeLists.txt index f12c56f8e..6693b4f5b 100644 --- a/contrib/cmake/src/CMakeLists.txt +++ b/contrib/cmake/src/CMakeLists.txt @@ -117,14 +117,13 @@ else() set(lib_type "STATIC") endif() add_library(libz3 ${lib_type} ${object_files}) -# FIXME: Set "VERSION" and "SOVERSION" properly set_target_properties(libz3 PROPERTIES - # FIXME: Should we be using ${Z3_VERSION} here? - # VERSION: Sets up symlinks, does it do anything else? + # VERSION determines the version in the filename of the shared library. + # SOVERSION determines the value of the DT_SONAME field on ELF platforms. + # On ELF platforms the final compiled filename will be libz3.so.W.X.Y.Z + # but symlinks will be made to this file from libz3.so and also from libz3.so.W VERSION ${Z3_VERSION} - # SOVERSION: On platforms that use ELF this sets the API version - # and should be incremented everytime the API changes - SOVERSION ${Z3_VERSION}) + SOVERSION ${Z3_VERSION_MAJOR}) if (NOT MSVC) # On UNIX like platforms if we don't change the OUTPUT_NAME From 657b0de2fcb1c25009139e296532c6b8a5dc52d8 Mon Sep 17 00:00:00 2001 From: Andrew Dutcher Date: Sun, 11 Dec 2016 08:27:35 -0800 Subject: [PATCH 426/536] cmake build: set SOVERSION to include the minor version number --- contrib/cmake/src/CMakeLists.txt | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/contrib/cmake/src/CMakeLists.txt b/contrib/cmake/src/CMakeLists.txt index 6693b4f5b..65eef8094 100644 --- a/contrib/cmake/src/CMakeLists.txt +++ b/contrib/cmake/src/CMakeLists.txt @@ -121,9 +121,12 @@ set_target_properties(libz3 PROPERTIES # VERSION determines the version in the filename of the shared library. # SOVERSION determines the value of the DT_SONAME field on ELF platforms. # On ELF platforms the final compiled filename will be libz3.so.W.X.Y.Z - # but symlinks will be made to this file from libz3.so and also from libz3.so.W + # but symlinks will be made to this file from libz3.so and also from + # libz3.so.W.X. + # This indicates that no breaking API changes will be made within a single + # minor version. VERSION ${Z3_VERSION} - SOVERSION ${Z3_VERSION_MAJOR}) + SOVERSION ${Z3_VERSION_MAJOR}.${Z3_VERSION_MINOR}) if (NOT MSVC) # On UNIX like platforms if we don't change the OUTPUT_NAME From bd1f07f864a7f1790cec08a306ccc17507f7e5a8 Mon Sep 17 00:00:00 2001 From: Dan Liew Date: Sun, 11 Dec 2016 23:07:48 +0000 Subject: [PATCH 427/536] Fix implementation of `scoped_timer` under Linux where it was incorrectly assumed that `pthread_cond_timedwait()` would exit due to a condition variable being signaled or a timeout occuring. According to the documentation `pthread_cond_timedwait()` might spuriously wake so we introduce a new variable `m_signal_sent` (that is guarded by an existing mutex) that is used as the variable to check that the thread wake was not spurious. This is intended to partially fix #839 . --- src/util/scoped_timer.cpp | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/src/util/scoped_timer.cpp b/src/util/scoped_timer.cpp index 335b2c3bb..3b87f880f 100644 --- a/src/util/scoped_timer.cpp +++ b/src/util/scoped_timer.cpp @@ -73,6 +73,7 @@ struct scoped_timer::imp { pthread_cond_t m_cond; unsigned m_ms; bool m_initialized; + bool m_signal_sent; #else // Other #endif @@ -119,10 +120,18 @@ struct scoped_timer::imp { pthread_mutex_lock(&st->m_mutex); st->m_initialized = true; - int e = pthread_cond_timedwait(&st->m_cond, &st->m_mutex, &end_time); - ENSURE(e == 0 || e == ETIMEDOUT); - + int e = 0; + // `pthread_cond_timedwait()` may spuriously wake even if the signal + // was not sent so we loop until a timeout occurs or the signal was + // **really** sent. + while (!(e == 0 && st->m_signal_sent)) { + e = pthread_cond_timedwait(&st->m_cond, &st->m_mutex, &end_time); + ENSURE(e == 0 || e == ETIMEDOUT); + if (e == ETIMEDOUT) + break; + } pthread_mutex_unlock(&st->m_mutex); + if (e == ETIMEDOUT) st->m_eh->operator()(); return 0; @@ -170,6 +179,7 @@ struct scoped_timer::imp { // Linux & FreeBSD m_ms = ms; m_initialized = false; + m_signal_sent = false; ENSURE(pthread_mutex_init(&m_mutex, NULL) == 0); ENSURE(pthread_cond_init(&m_cond, NULL) == 0); ENSURE(pthread_create(&m_thread_id, NULL, &thread_func, this) == 0); @@ -218,7 +228,10 @@ struct scoped_timer::imp { if (!init) sched_yield(); } + pthread_mutex_lock(&m_mutex); + m_signal_sent = true; pthread_cond_signal(&m_cond); + pthread_mutex_unlock(&m_mutex); pthread_join(m_thread_id, NULL); pthread_cond_destroy(&m_cond); From c1480b43894cf191cb67dfcf4283a64e855f7508 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 12 Dec 2016 00:33:10 +0100 Subject: [PATCH 428/536] handle model generation from issue #748. Deal with warnings from #836 Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/seq_rewriter.cpp | 2 +- src/muz/rel/dl_product_relation.cpp | 6 +- src/muz/rel/dl_sieve_relation.cpp | 2 +- src/muz/rel/dl_sieve_relation.h | 3 +- src/smt/proto_model/numeral_factory.cpp | 2 +- src/smt/proto_model/numeral_factory.h | 2 +- src/smt/theory_bv.cpp | 2 +- src/smt/theory_seq.cpp | 121 +++++++++++++++++++++--- src/smt/theory_seq.h | 2 + 9 files changed, 118 insertions(+), 24 deletions(-) diff --git a/src/ast/rewriter/seq_rewriter.cpp b/src/ast/rewriter/seq_rewriter.cpp index b97d832b1..26c3e23e4 100644 --- a/src/ast/rewriter/seq_rewriter.cpp +++ b/src/ast/rewriter/seq_rewriter.cpp @@ -1721,7 +1721,7 @@ bool seq_rewriter::solve_itos(unsigned szl, expr* const* ls, unsigned szr, expr* } } - if (szr == 1 && m_util.str.is_itos(rs[0], r)) { + if (szr == 1 && m_util.str.is_itos(rs[0], r) && !m_util.str.is_itos(ls[0])) { return solve_itos(szr, rs, szl, ls, rhs, lhs, is_sat); } diff --git a/src/muz/rel/dl_product_relation.cpp b/src/muz/rel/dl_product_relation.cpp index 1bc5e3545..817ff194c 100644 --- a/src/muz/rel/dl_product_relation.cpp +++ b/src/muz/rel/dl_product_relation.cpp @@ -255,7 +255,7 @@ namespace datalog { table_plugin & tplugin = rmgr.get_appropriate_plugin(tsig); relation_plugin & inner_plugin = rmgr.get_table_relation_plugin(tplugin); - return sieve_relation_plugin::get_plugin(rmgr).mk_full(p, sig, inner_plugin); + return sieve_relation_plugin::get_plugin(rmgr).full(p, sig, inner_plugin); } void init(relation_signature const& r1_sig, unsigned num_rels1, relation_base const* const* r1, @@ -294,7 +294,7 @@ namespace datalog { rel2 = r1_plugin.mk_full(p, r2_sig, r1_kind); } else { - rel2 = sieve_relation_plugin::get_plugin(rmgr).mk_full(p, r2_sig, r1_plugin); + rel2 = sieve_relation_plugin::get_plugin(rmgr).full(p, r2_sig, r1_plugin); } m_offset1.push_back(i); m_kind1.push_back(T_INPUT); @@ -318,7 +318,7 @@ namespace datalog { rel1 = r2_plugin.mk_full(p, r1_sig, r2_kind); } else { - rel1 = sieve_relation_plugin::get_plugin(rmgr).mk_full(p, r1_sig, r2_plugin); + rel1 = sieve_relation_plugin::get_plugin(rmgr).full(p, r1_sig, r2_plugin); } m_offset1.push_back(m_full.size()); m_kind1.push_back(T_FULL); diff --git a/src/muz/rel/dl_sieve_relation.cpp b/src/muz/rel/dl_sieve_relation.cpp index 9f9419089..7729ec2eb 100644 --- a/src/muz/rel/dl_sieve_relation.cpp +++ b/src/muz/rel/dl_sieve_relation.cpp @@ -253,7 +253,7 @@ namespace datalog { return mk_from_inner(s, inner_cols, inner); } - sieve_relation * sieve_relation_plugin::mk_full(func_decl* p, const relation_signature & s, relation_plugin & inner_plugin) { + sieve_relation * sieve_relation_plugin::full(func_decl* p, const relation_signature & s, relation_plugin & inner_plugin) { SASSERT(!inner_plugin.is_sieve_relation()); //it does not make sense to make a sieve of a sieve svector inner_cols(s.size()); extract_inner_columns(s, inner_plugin, inner_cols); diff --git a/src/muz/rel/dl_sieve_relation.h b/src/muz/rel/dl_sieve_relation.h index da6c9bbff..4d89a66ae 100644 --- a/src/muz/rel/dl_sieve_relation.h +++ b/src/muz/rel/dl_sieve_relation.h @@ -104,8 +104,7 @@ namespace datalog { sieve_relation * mk_empty(const relation_signature & s, relation_plugin & inner_plugin); virtual relation_base * mk_full(func_decl* p, const relation_signature & s); - sieve_relation * mk_full(func_decl* p, const relation_signature & s, relation_plugin & inner_plugin); - + sieve_relation * full(func_decl* p, const relation_signature & s, relation_plugin & inner_plugin); sieve_relation * mk_from_inner(const relation_signature & s, const bool * inner_columns, relation_base * inner_rel); diff --git a/src/smt/proto_model/numeral_factory.cpp b/src/smt/proto_model/numeral_factory.cpp index 413cc1b9e..49ff15167 100644 --- a/src/smt/proto_model/numeral_factory.cpp +++ b/src/smt/proto_model/numeral_factory.cpp @@ -47,6 +47,6 @@ app * bv_factory::mk_value_core(rational const & val, sort * s) { return m_util.mk_numeral(val, s); } -app * bv_factory::mk_value(rational const & val, unsigned bv_size) { +app * bv_factory::mk_num_value(rational const & val, unsigned bv_size) { return numeral_factory::mk_value(val, m_util.mk_sort(bv_size)); } diff --git a/src/smt/proto_model/numeral_factory.h b/src/smt/proto_model/numeral_factory.h index e0d3cf6b5..9b1ff6a81 100644 --- a/src/smt/proto_model/numeral_factory.h +++ b/src/smt/proto_model/numeral_factory.h @@ -50,7 +50,7 @@ public: bv_factory(ast_manager & m); virtual ~bv_factory(); - app * mk_value(rational const & val, unsigned bv_size); + app * mk_num_value(rational const & val, unsigned bv_size); }; #endif /* NUMERAL_FACTORY_H_ */ diff --git a/src/smt/theory_bv.cpp b/src/smt/theory_bv.cpp index a53580b73..a886c8a1e 100644 --- a/src/smt/theory_bv.cpp +++ b/src/smt/theory_bv.cpp @@ -1583,7 +1583,7 @@ namespace smt { #endif get_fixed_value(v, val); SASSERT(r); - return alloc(expr_wrapper_proc, m_factory->mk_value(val, get_bv_size(v))); + return alloc(expr_wrapper_proc, m_factory->mk_num_value(val, get_bv_size(v))); } void theory_bv::display_var(std::ostream & out, theory_var v) const { diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index 4f2683ca9..ed95ef8d7 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -2235,6 +2235,7 @@ bool theory_seq::add_stoi_axiom(expr* e) { context& ctx = get_context(); expr* n; rational val; + TRACE("seq", tout << mk_pp(e, m) << "\n";); VERIFY(m_util.str.is_stoi(e, n)); if (get_num_value(e, val) && !m_stoi_axioms.contains(val)) { m_stoi_axioms.insert(val); @@ -2252,13 +2253,70 @@ bool theory_seq::add_stoi_axiom(expr* e) { return true; } } + if (upper_bound(n, val) && get_length(n, val) && val.is_pos() && !m_stoi_axioms.contains(val)) { + zstring s; + SASSERT(val.is_unsigned()); + unsigned sz = val.get_unsigned(); + expr_ref len1(m), len2(m), ith_char(m), num(m), coeff(m); + expr_ref_vector nums(m); + len1 = m_util.str.mk_length(n); + len2 = m_autil.mk_int(sz); + literal lit = mk_eq(len1, len2, false); + literal_vector lits; + lits.push_back(~lit); + for (unsigned i = 0; i < sz; ++i) { + ith_char = mk_nth(n, m_autil.mk_int(i)); + lits.push_back(~is_digit(ith_char)); + nums.push_back(digit2int(ith_char)); + } + for (unsigned i = sz-1, c = 1; i > 0; c *= 10) { + --i; + coeff = m_autil.mk_int(c); + nums[i] = m_autil.mk_mul(coeff, nums[i].get()); + } + num = m_autil.mk_add(nums.size(), nums.c_ptr()); + lits.push_back(mk_eq(e, num, false)); + ++m_stats.m_add_axiom; + m_new_propagation = true; + for (unsigned i = 0; i < lits.size(); ++i) { + ctx.mark_as_relevant(lits[i]); + } + ctx.mk_th_axiom(get_id(), lits.size(), lits.c_ptr()); + m_stoi_axioms.insert(val); + m_trail_stack.push(insert_map(m_stoi_axioms, val)); + m_trail_stack.push(push_replay(alloc(replay_axiom, m, e))); + return true; + } + return false; } +literal theory_seq::is_digit(expr* ch) { + bv_util bv(m); + literal isd = mk_literal(mk_skolem(symbol("seq.is_digit"), ch, 0, 0, m.mk_bool_sort())); + expr_ref d2i = digit2int(ch); + expr_ref _lo(bv.mk_ule(bv.mk_numeral(rational('0'), bv.mk_sort(8)), ch), m); + expr_ref _hi(bv.mk_ule(ch, bv.mk_numeral(rational('9'), bv.mk_sort(8))), m); + literal lo = mk_literal(_lo); + literal hi = mk_literal(_hi); + add_axiom(~lo, ~hi, isd); + add_axiom(~isd, lo); + add_axiom(~isd, hi); + for (unsigned i = 0; i < 10; ++i) { + add_axiom(~mk_eq(ch, bv.mk_numeral(rational('0'+i), bv.mk_sort(8)), false), mk_eq(d2i, m_autil.mk_int(i), false)); + } + return isd; +} + +expr_ref theory_seq::digit2int(expr* ch) { + return expr_ref(mk_skolem(symbol("seq.digit2int"), ch, 0, 0, m_autil.mk_int()), m); +} + bool theory_seq::add_itos_axiom(expr* e) { context& ctx = get_context(); rational val; expr* n; + TRACE("seq", tout << mk_pp(e, m) << "\n";); VERIFY(m_util.str.is_itos(e, n)); if (get_num_value(n, val)) { if (!m_itos_axioms.contains(val)) { @@ -2282,6 +2340,9 @@ bool theory_seq::add_itos_axiom(expr* e) { else { // stoi(itos(n)) = n app_ref e2(m_util.str.mk_stoi(e), m); + if (ctx.e_internalized(e2) && ctx.get_enode(e2)->get_root() == ctx.get_enode(n)->get_root()) { + return false; + } add_axiom(mk_eq(e2, n, false)); m_trail_stack.push(push_replay(alloc(replay_axiom, m, e))); return true; @@ -2464,22 +2525,27 @@ void theory_seq::init_model(model_generator & mg) { class theory_seq::seq_value_proc : public model_value_proc { + enum source_t { unit_source, int_source, string_source }; theory_seq& th; sort* m_sort; svector m_dependencies; ptr_vector m_strings; - svector m_source; + svector m_source; public: seq_value_proc(theory_seq& th, sort* s): th(th), m_sort(s) { } virtual ~seq_value_proc() {} - void add_dependency(enode* n) { + void add_unit(enode* n) { m_dependencies.push_back(model_value_dependency(n)); - m_source.push_back(true); + m_source.push_back(unit_source); + } + void add_int(enode* n) { + m_dependencies.push_back(model_value_dependency(n)); + m_source.push_back(int_source); } void add_string(expr* n) { m_strings.push_back(n); - m_source.push_back(false); + m_source.push_back(string_source); } virtual void get_dependencies(buffer & result) { result.append(m_dependencies.size(), m_dependencies.c_ptr()); @@ -2504,11 +2570,13 @@ public: unsigned sz; for (unsigned i = 0; i < m_source.size(); ++i) { - if (m_source[i]) { + switch (m_source[i]) { + case unit_source: { VERIFY(bv.is_numeral(values[j++], val, sz)); sbuffer.push_back(val.get_unsigned()); + break; } - else { + case string_source: { dependency* deps = 0; expr_ref tmp = th.canonize(m_strings[k], deps); zstring zs; @@ -2519,17 +2587,34 @@ public: TRACE("seq", tout << "Not a string: " << tmp << "\n";); } ++k; + break; + } + case int_source: { + std::ostringstream strm; + arith_util arith(th.m); + VERIFY(arith.is_numeral(values[j++], val)); + if (val.is_neg()) strm << "-"; + strm << abs(val); + zstring zs(strm.str().c_str()); + add_buffer(sbuffer, zs); + break; + } } } result = th.m_util.str.mk_string(zstring(sbuffer.size(), sbuffer.c_ptr())); } else { for (unsigned i = 0; i < m_source.size(); ++i) { - if (m_source[i]) { + switch (m_source[i]) { + case unit_source: args.push_back(th.m_util.str.mk_unit(values[j++])); - } - else { + break; + case string_source: args.push_back(m_strings[k++]); + break; + case int_source: + UNREACHABLE(); + break; } } result = th.mk_concat(args, m_sort); @@ -2567,7 +2652,12 @@ model_value_proc * theory_seq::mk_value(enode * n, model_generator & mg) { TRACE("seq", tout << mk_pp(c, m) << "\n";); if (m_util.str.is_unit(c, c1)) { if (ctx.e_internalized(c1)) { - sv->add_dependency(ctx.get_enode(c1)); + sv->add_unit(ctx.get_enode(c1)); + } + } + else if (m_util.str.is_itos(c, c1)) { + if (ctx.e_internalized(c1)) { + sv->add_int(ctx.get_enode(c1)); } } else if (m_util.str.is_string(c)) { @@ -2741,6 +2831,7 @@ expr_ref theory_seq::expand(expr* e0, dependency*& eqs) { } else if (m_util.str.is_itos(e, e1)) { rational val; + TRACE("seq", tout << mk_pp(e, m) << "\n";); if (get_num_value(e1, val)) { TRACE("seq", tout << mk_pp(e, m) << " -> " << val << "\n";); expr_ref num(m), res(m); @@ -3177,13 +3268,12 @@ bool theory_seq::get_num_value(expr* e, rational& val) const { theory_mi_arith* tha = get_th_arith(ctx, m_autil.get_family_id(), e); expr_ref _val(m); if (!tha) return false; - enode* next = ctx.get_enode(e), *n; + enode* next = ctx.get_enode(e), *n = next; do { - n = next; - if (tha->get_value(n, _val) && m_autil.is_numeral(_val, val) && val.is_int()) { + if (tha->get_value(next, _val) && m_autil.is_numeral(_val, val) && val.is_int()) { return true; } - next = n->get_next(); + next = next->get_next(); } while (next != n); return false; @@ -3692,7 +3782,10 @@ void theory_seq::assign_eh(bool_var v, bool is_true) { else if (is_skolem(symbol("seq.split"), e)) { // propagate equalities } + else if (is_skolem(symbol("seq.is_digit"), e)) { + } else { + TRACE("seq", tout << mk_pp(e, m) << "\n";); UNREACHABLE(); } } diff --git a/src/smt/theory_seq.h b/src/smt/theory_seq.h index 0e06997ad..aa7ddec1b 100644 --- a/src/smt/theory_seq.h +++ b/src/smt/theory_seq.h @@ -499,6 +499,8 @@ namespace smt { void add_in_re_axiom(expr* n); bool add_stoi_axiom(expr* n); bool add_itos_axiom(expr* n); + literal is_digit(expr* ch); + expr_ref digit2int(expr* ch); void add_itos_length_axiom(expr* n); literal mk_literal(expr* n); literal mk_eq_empty(expr* n, bool phase = true); From a1a662b23f4c9e2d072dc3a813d276537c488fb7 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Fri, 16 Dec 2016 04:51:07 -0800 Subject: [PATCH 429/536] Build fix for C/C++ example programs. --- scripts/mk_util.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/mk_util.py b/scripts/mk_util.py index 890c60501..cdd7bdeec 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -2086,12 +2086,12 @@ class CppExampleComponent(ExampleComponent): exefile = '%s$(EXE_EXT)' % self.name out.write('%s: %s %s\n' % (exefile, dll, objfiles)) - out.write('\t$(SLINK) $(SLINK_OUT_FLAG)%s $(SLINK_FLAGS) %s ' % (exefile, objfiles)) + out.write('\t$(LINK) $(LINK_OUT_FLAG)%s $(LINK_FLAGS) %s ' % (exefile, objfiles)) if IS_WINDOWS: out.write('%s.lib' % dll_name) else: out.write(dll) - out.write(' $(SLINK_EXTRA_FLAGS)\n') + out.write(' $(LINK_EXTRA_FLAGS)\n') out.write('_ex_%s: %s\n\n' % (self.name, exefile)) class CExampleComponent(CppExampleComponent): From 6ce903b1d698c9aa7976a1356b4bc62635a30582 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Fri, 16 Dec 2016 20:04:29 +0000 Subject: [PATCH 430/536] Style, whitespace. --- src/util/rlimit.cpp | 15 +++++++-------- src/util/rlimit.h | 6 +++--- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/src/util/rlimit.cpp b/src/util/rlimit.cpp index 9f6c692cc..bda06157d 100644 --- a/src/util/rlimit.cpp +++ b/src/util/rlimit.cpp @@ -20,7 +20,7 @@ Revision History: #include "common_msgs.h" reslimit::reslimit(): - m_cancel(false), + m_cancel(0), m_count(0), m_limit(0) { } @@ -29,7 +29,6 @@ uint64 reslimit::count() const { return m_count; } - bool reslimit::inc() { ++m_count; return m_cancel == 0 && (m_limit == 0 || m_count <= m_limit); @@ -46,7 +45,7 @@ void reslimit::push(unsigned delta_limit) { new_limit = 0; } m_limits.push_back(m_limit); - m_limit = m_limit==0?new_limit:std::min(new_limit, m_limit); + m_limit = m_limit==0 ? new_limit : std::min(new_limit, m_limit); m_cancel = 0; } @@ -71,14 +70,14 @@ char const* reslimit::get_cancel_msg() const { void reslimit::push_child(reslimit* r) { #pragma omp critical (reslimit_cancel) { - m_children.push_back(r); + m_children.push_back(r); } } void reslimit::pop_child() { #pragma omp critical (reslimit_cancel) { - m_children.pop_back(); + m_children.pop_back(); } } @@ -99,7 +98,7 @@ void reslimit::reset_cancel() { void reslimit::inc_cancel() { #pragma omp critical (reslimit_cancel) - { + { set_cancel(m_cancel+1); } } @@ -114,8 +113,8 @@ void reslimit::dec_cancel() { } } -void reslimit::set_cancel(unsigned f) { - m_cancel = f; +void reslimit::set_cancel(unsigned f) { + m_cancel = f; for (unsigned i = 0; i < m_children.size(); ++i) { m_children[i]->set_cancel(f); } diff --git a/src/util/rlimit.h b/src/util/rlimit.h index ac5db6136..913984768 100644 --- a/src/util/rlimit.h +++ b/src/util/rlimit.h @@ -29,8 +29,8 @@ class reslimit { ptr_vector m_children; void set_cancel(unsigned f); - -public: + +public: reslimit(); void push(unsigned delta_limit); void pop(); @@ -39,7 +39,7 @@ public: bool inc(); bool inc(unsigned offset); - uint64 count() const; + uint64 count() const; bool get_cancel_flag() const { return m_cancel > 0; } From 5cb21924ad844bda646a3f2c7b293d5790439e70 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 17 Dec 2016 16:02:54 -0800 Subject: [PATCH 431/536] ensure that FD logic understands pb from command context Signed-off-by: Nikolaj Bjorner --- src/ast/pb_decl_plugin.cpp | 2 +- src/cmd_context/check_logic.cpp | 7 ++++++- src/cmd_context/cmd_context.cpp | 7 ++++++- src/cmd_context/cmd_context.h | 1 + src/solver/smt_logics.cpp | 4 ++++ src/solver/smt_logics.h | 1 + 6 files changed, 19 insertions(+), 3 deletions(-) diff --git a/src/ast/pb_decl_plugin.cpp b/src/ast/pb_decl_plugin.cpp index 18a652859..09f020ca6 100644 --- a/src/ast/pb_decl_plugin.cpp +++ b/src/ast/pb_decl_plugin.cpp @@ -91,7 +91,7 @@ func_decl * pb_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, p } void pb_decl_plugin::get_op_names(svector & op_names, symbol const & logic) { - if (logic == symbol::null) { + if (logic == symbol::null || logic == "QF_FD") { op_names.push_back(builtin_name(m_at_most_sym.bare_str(), OP_AT_MOST_K)); op_names.push_back(builtin_name(m_at_least_sym.bare_str(), OP_AT_LEAST_K)); op_names.push_back(builtin_name(m_pble_sym.bare_str(), OP_PB_LE)); diff --git a/src/cmd_context/check_logic.cpp b/src/cmd_context/check_logic.cpp index d598dfa39..c75c12689 100644 --- a/src/cmd_context/check_logic.cpp +++ b/src/cmd_context/check_logic.cpp @@ -21,6 +21,7 @@ Revision History: #include"array_decl_plugin.h" #include"bv_decl_plugin.h" #include"seq_decl_plugin.h" +#include"pb_decl_plugin.h" #include"datatype_decl_plugin.h" #include"ast_pp.h" #include"for_each_expr.h" @@ -34,6 +35,7 @@ struct check_logic::imp { array_util m_ar_util; seq_util m_seq_util; datatype_util m_dt_util; + pb_util m_pb_util; bool m_uf; // true if the logic supports uninterpreted functions bool m_arrays; // true if the logic supports arbitrary arrays bool m_bv_arrays; // true if the logic supports only bv arrays @@ -45,7 +47,7 @@ struct check_logic::imp { bool m_quantifiers; // true if the logic supports quantifiers bool m_unknown_logic; - imp(ast_manager & _m):m(_m), m_a_util(m), m_bv_util(m), m_ar_util(m), m_seq_util(m), m_dt_util(m) { + imp(ast_manager & _m):m(_m), m_a_util(m), m_bv_util(m), m_ar_util(m), m_seq_util(m), m_dt_util(m), m_pb_util(m) { reset(); } @@ -443,6 +445,9 @@ struct check_logic::imp { else if (fid == m_dt_util.get_family_id() && m_logic == "QF_FD") { // nothing to check } + else if (fid == m_pb_util.get_family_id() && m_logic == "QF_FD") { + // nothing to check + } else { std::stringstream strm; strm << "logic does not support theory " << m.get_family_name(fid); diff --git a/src/cmd_context/cmd_context.cpp b/src/cmd_context/cmd_context.cpp index eb7b3ff44..67b1df50c 100644 --- a/src/cmd_context/cmd_context.cpp +++ b/src/cmd_context/cmd_context.cpp @@ -519,6 +519,10 @@ bool cmd_context::logic_has_seq() const { return !has_logic() || smt_logics::logic_has_seq(m_logic); } +bool cmd_context::logic_has_pb() const { + return !has_logic() || smt_logics::logic_has_pb(m_logic); +} + bool cmd_context::logic_has_fpa() const { return !has_logic() || smt_logics::logic_has_fpa(m_logic); } @@ -547,7 +551,7 @@ void cmd_context::init_manager_core(bool new_manager) { register_plugin(symbol("array"), alloc(array_decl_plugin), logic_has_array()); register_plugin(symbol("datatype"), alloc(datatype_decl_plugin), logic_has_datatype()); register_plugin(symbol("seq"), alloc(seq_decl_plugin), logic_has_seq()); - register_plugin(symbol("pb"), alloc(pb_decl_plugin), !has_logic()); + register_plugin(symbol("pb"), alloc(pb_decl_plugin), logic_has_pb()); register_plugin(symbol("fpa"), alloc(fpa_decl_plugin), logic_has_fpa()); register_plugin(symbol("datalog_relation"), alloc(datalog::dl_decl_plugin), !has_logic()); } @@ -563,6 +567,7 @@ void cmd_context::init_manager_core(bool new_manager) { load_plugin(symbol("datatype"), logic_has_datatype(), fids); load_plugin(symbol("seq"), logic_has_seq(), fids); load_plugin(symbol("fpa"), logic_has_fpa(), fids); + load_plugin(symbol("pb"), logic_has_pb(), fids); svector::iterator it = fids.begin(); svector::iterator end = fids.end(); diff --git a/src/cmd_context/cmd_context.h b/src/cmd_context/cmd_context.h index 34d93c97b..8eee632dc 100644 --- a/src/cmd_context/cmd_context.h +++ b/src/cmd_context/cmd_context.h @@ -251,6 +251,7 @@ protected: bool logic_has_arith() const; bool logic_has_bv() const; + bool logic_has_pb() const; bool logic_has_seq() const; bool logic_has_array() const; bool logic_has_datatype() const; diff --git a/src/solver/smt_logics.cpp b/src/solver/smt_logics.cpp index 9ee047839..210a09f96 100644 --- a/src/solver/smt_logics.cpp +++ b/src/solver/smt_logics.cpp @@ -144,6 +144,10 @@ bool smt_logics::logic_has_horn(symbol const& s) { return s == "HORN"; } +bool smt_logics::logic_has_pb(symbol const& s) { + return s == "QF_FD" || s == "ALL"; +} + bool smt_logics::logic_has_datatype(symbol const& s) { return s == "QF_FD"; } diff --git a/src/solver/smt_logics.h b/src/solver/smt_logics.h index f283040d9..72c3b8764 100644 --- a/src/solver/smt_logics.h +++ b/src/solver/smt_logics.h @@ -32,6 +32,7 @@ public: static bool logic_has_seq(symbol const & s); static bool logic_has_fpa(symbol const & s); static bool logic_has_horn(symbol const& s); + static bool logic_has_pb(symbol const& s); static bool logic_has_fd(symbol const& s) { return s == "QF_FD"; } static bool logic_has_datatype(symbol const& s); }; From e16577ff61a09123dd2609c3fdb17f6671995cf2 Mon Sep 17 00:00:00 2001 From: Kevin Chung Date: Sun, 18 Dec 2016 17:27:55 -0500 Subject: [PATCH 432/536] Making z3 python look in its installation directory for the z3 lib --- scripts/update_api.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/update_api.py b/scripts/update_api.py index 04378b371..3a3b2c40a 100755 --- a/scripts/update_api.py +++ b/scripts/update_api.py @@ -1611,7 +1611,7 @@ _lib = None def lib(): global _lib if _lib is None: - _dirs = ['.', pkg_resources.resource_filename('z3', 'lib'), os.path.join(sys.prefix, 'lib'), None] + _dirs = ['.', os.path.dirname(os.path.abspath(__file__)), pkg_resources.resource_filename('z3', 'lib'), os.path.join(sys.prefix, 'lib'), None] for _dir in _dirs: try: init(_dir) From 189d449cff42d5612e99386038e375e1dd534eb9 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 18 Dec 2016 14:49:45 -0800 Subject: [PATCH 433/536] fix generation of wcnf Signed-off-by: Nikolaj Bjorner --- src/sat/sat_solver.cpp | 6 ++-- src/sat/sat_solver/inc_sat_solver.cpp | 10 +++++- src/sat/tactic/goal2sat.cpp | 50 +++++++++++++++++++++++++-- 3 files changed, 60 insertions(+), 6 deletions(-) diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 9cf13afe4..e6fa15a4c 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -2917,6 +2917,7 @@ namespace sat { ++max_weight; out << "p wcnf " << num_vars() << " " << num_clauses() + sz << " " << max_weight << "\n"; + out << "c soft " << sz << "\n"; for (unsigned i = 0; i < m_trail.size(); i++) { out << max_weight << " " << dimacs_lit(m_trail[i]) << " 0\n"; @@ -2940,9 +2941,9 @@ namespace sat { clause_vector::const_iterator end = cs.end(); for (; it != end; ++it) { clause const & c = *(*it); - unsigned sz = c.size(); + unsigned clsz = c.size(); out << max_weight << " "; - for (unsigned j = 0; j < sz; j++) + for (unsigned j = 0; j < clsz; j++) out << dimacs_lit(c[j]) << " "; out << "0\n"; } @@ -2950,6 +2951,7 @@ namespace sat { for (unsigned i = 0; i < sz; ++i) { out << weights[i] << " " << lits[i] << " 0\n"; } + out.flush(); } diff --git a/src/sat/sat_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp index e56abc50c..e3a220cd2 100644 --- a/src/sat/sat_solver/inc_sat_solver.cpp +++ b/src/sat/sat_solver/inc_sat_solver.cpp @@ -115,10 +115,18 @@ public: if (weights != 0) { for (unsigned i = 0; i < sz; ++i) m_weights.push_back(weights[i]); } + init_preprocess(); m_solver.pop_to_base_level(); dep2asm_t dep2asm; + expr_ref_vector asms(m); + for (unsigned i = 0; i < sz; ++i) { + expr_ref a(m.mk_fresh_const("s", m.mk_bool_sort()), m); + expr_ref fml(m.mk_implies(a, assumptions[i]), m); + assert_expr(fml); + asms.push_back(a); + } VERIFY(l_true == internalize_formulas()); - VERIFY(l_true == internalize_assumptions(sz, assumptions, dep2asm)); + VERIFY(l_true == internalize_assumptions(sz, asms.c_ptr(), dep2asm)); svector nweights; for (unsigned i = 0; i < m_asms.size(); ++i) { nweights.push_back((unsigned) m_weights[i]); diff --git a/src/sat/tactic/goal2sat.cpp b/src/sat/tactic/goal2sat.cpp index 136921914..742a4fb1d 100644 --- a/src/sat/tactic/goal2sat.cpp +++ b/src/sat/tactic/goal2sat.cpp @@ -174,6 +174,7 @@ struct goal2sat::imp { switch (to_app(t)->get_decl_kind()) { case OP_NOT: case OP_OR: + case OP_AND: case OP_IFF: m_frame_stack.push_back(frame(to_app(t), root, sign, 0)); return false; @@ -185,7 +186,6 @@ struct goal2sat::imp { } convert_atom(t, root, sign); return true; - case OP_AND: case OP_XOR: case OP_IMPLIES: case OP_DISTINCT: { @@ -215,8 +215,8 @@ struct goal2sat::imp { } else { mk_clause(m_result_stack.size(), m_result_stack.c_ptr()); - m_result_stack.reset(); } + m_result_stack.reset(); } else { SASSERT(num <= m_result_stack.size()); @@ -240,6 +240,48 @@ struct goal2sat::imp { } } + void convert_and(app * t, bool root, bool sign) { + TRACE("goal2sat", tout << "convert_and:\n" << mk_ismt2_pp(t, m) << "\n";); + unsigned num = t->get_num_args(); + if (root) { + if (sign) { + for (unsigned i = 0; i < num; ++i) { + m_result_stack[i].neg(); + } + } + else { + for (unsigned i = 0; i < num; ++i) { + mk_clause(m_result_stack[i]); + } + } + m_result_stack.reset(); + } + else { + SASSERT(num <= m_result_stack.size()); + sat::bool_var k = m_solver.mk_var(); + sat::literal l(k, false); + m_cache.insert(t, l); + // l => /\ lits + sat::literal * lits = m_result_stack.end() - num; + for (unsigned i = 0; i < num; i++) { + mk_clause(~l, lits[i]); + } + // /\ lits => l + for (unsigned i = 0; i < num; ++i) { + m_result_stack[m_result_stack.size() - num + i].neg(); + } + m_result_stack.push_back(l); + lits = m_result_stack.end() - num - 1; + mk_clause(num+1, lits); + unsigned old_sz = m_result_stack.size() - num - 1; + m_result_stack.shrink(old_sz); + if (sign) + l.neg(); + m_result_stack.push_back(l); + } + } + + void convert_ite(app * n, bool root, bool sign) { unsigned sz = m_result_stack.size(); SASSERT(sz >= 3); @@ -316,6 +358,9 @@ struct goal2sat::imp { case OP_OR: convert_or(t, root, sign); break; + case OP_AND: + convert_and(t, root, sign); + break; case OP_ITE: convert_ite(t, root, sign); break; @@ -456,7 +501,6 @@ struct unsupported_bool_proc { void operator()(app * n) { if (n->get_family_id() == m.get_basic_family_id()) { switch (n->get_decl_kind()) { - case OP_AND: case OP_XOR: case OP_IMPLIES: case OP_DISTINCT: From 2c32e30fed1d6fe10bfa99fe8bc55d1882b67121 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Mon, 19 Dec 2016 16:47:28 +0000 Subject: [PATCH 434/536] Build fix for static binaries + shared examples --- scripts/mk_util.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/scripts/mk_util.py b/scripts/mk_util.py index cdd7bdeec..8973da65f 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -1168,7 +1168,8 @@ class ExeComponent(Component): c_dep = get_component(dep) out.write(' ' + c_dep.get_link_name()) out.write('\n') - out.write('\t$(LINK) $(LINK_OUT_FLAG)%s $(LINK_FLAGS)' % exefile) + extra_opt = '-static' if not IS_WINDOWS and STATIC_BIN else '' + out.write('\t$(LINK) %s $(LINK_OUT_FLAG)%s $(LINK_FLAGS)' % (extra_opt, exefile)) for obj in objs: out.write(' ') out.write(obj) @@ -2506,10 +2507,7 @@ def mk_config(): config.write('AR_OUTFLAG=\n') config.write('EXE_EXT=\n') config.write('LINK=%s\n' % CXX) - if STATIC_BIN: - config.write('LINK_FLAGS=-static\n') - else: - config.write('LINK_FLAGS=\n') + config.write('LINK_FLAGS=\n') config.write('LINK_OUT_FLAG=-o \n') config.write('LINK_EXTRA_FLAGS=-lpthread %s\n' % LDFLAGS) config.write('SO_EXT=%s\n' % SO_EXT) From 251d1ec031d02d4a56f6253a83e65746f4f3ea03 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Mon, 19 Dec 2016 16:58:25 +0000 Subject: [PATCH 435/536] Fix for parallel builds of the OCaml API. Relates to #797. --- scripts/mk_util.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/mk_util.py b/scripts/mk_util.py index 8973da65f..235453845 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -1973,7 +1973,7 @@ class MLComponent(Component): z3mls = os.path.join(self.sub_dir, 'z3ml') out.write('%s.cma: %s %s %s\n' % (z3mls, cmos, stubso, z3dllso)) out.write('\t%s -o %s -I %s %s %s %s\n' % (OCAMLMKLIB, z3mls, self.sub_dir, stubso, cmos, LIBZ3)) - out.write('%s.cmxa: %s %s %s\n' % (z3mls, cmxs, stubso, z3dllso)) + out.write('%s.cmxa: %s %s %s %s.cma\n' % (z3mls, cmxs, stubso, z3dllso, z3mls)) out.write('\t%s -o %s -I %s %s %s %s\n' % (OCAMLMKLIB, z3mls, self.sub_dir, stubso, cmxs, LIBZ3)) out.write('%s.cmxs: %s.cmxa\n' % (z3mls, z3mls)) out.write('\t%s -shared -o %s.cmxs -I %s %s.cmxa\n' % (OCAMLOPTF, z3mls, self.sub_dir, z3mls)) From 0e03fe9bf20859d4fc764e5e8ddc9c1bbec1ee4b Mon Sep 17 00:00:00 2001 From: Dan Liew Date: Mon, 21 Nov 2016 00:05:59 +0000 Subject: [PATCH 436/536] Fix inconsistent emission of OCaml enumeration files. The ordering of emitted enum values is not consistent between python 2 or 3. The root cause of the problem was a dictionary's keys being iterated over which has no defined order. This has been fixed by iterating over the dictionary's items and ordering by values. We could order by key rather than the values but seeing as these represent an enum, ordering by value makes more sense. --- scripts/mk_util.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/scripts/mk_util.py b/scripts/mk_util.py index 235453845..a5440946c 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -2986,21 +2986,22 @@ def mk_z3consts_ml(api_files): if m: name = words[1] if name not in DeprecatedEnums: + sorted_decls = sorted(decls.items(), key=lambda pair: pair[1]) efile.write('(** %s *)\n' % name[3:]) efile.write('type %s =\n' % name[3:]) # strip Z3_ - for k, i in decls.items(): + for k, i in sorted_decls: efile.write(' | %s \n' % k[3:]) # strip Z3_ efile.write('\n') efile.write('(** Convert %s to int*)\n' % name[3:]) efile.write('let int_of_%s x : int =\n' % (name[3:])) # strip Z3_ efile.write(' match x with\n') - for k, i in decls.items(): + for k, i in sorted_decls: efile.write(' | %s -> %d\n' % (k[3:], i)) efile.write('\n') efile.write('(** Convert int to %s*)\n' % name[3:]) efile.write('let %s_of_int x : %s =\n' % (name[3:],name[3:])) # strip Z3_ efile.write(' match x with\n') - for k, i in decls.items(): + for k, i in sorted_decls: efile.write(' | %d -> %s\n' % (i, k[3:])) # use Z3.Exception? efile.write(' | _ -> raise (Failure "undefined enum value")\n\n') @@ -3068,7 +3069,7 @@ def mk_z3consts_ml(api_files): # if name not in DeprecatedEnums: # efile.write('(** %s *)\n' % name[3:]) # efile.write('type %s =\n' % name[3:]) # strip Z3_ - # for k, i in decls.items(): + # for k, i in sorted(decls.items(), key=lambda pair: pair[1]): # efile.write(' | %s \n' % k[3:]) # strip Z3_ # efile.write('\n') # efile.write('(** Convert %s to int*)\n' % name[3:]) From 76bbecf4fe3232bbc67e7d1d06a6f9cdf5a8dc85 Mon Sep 17 00:00:00 2001 From: Dan Liew Date: Mon, 21 Nov 2016 00:45:43 +0000 Subject: [PATCH 437/536] Refactor `mk_z3consts_ml()` code into `mk_z3consts_ml_internal()` and move that into `mk_genfile_common.py`. Then adapt `mk_util.py` and `mk_consts_files.py` to call into the code at its new location. The purpose of this change is to have Python code common to the Python and CMake build systems separate from Python code that is only used for the Python build system. --- scripts/mk_consts_files.py | 10 ++ scripts/mk_genfile_common.py | 174 +++++++++++++++++++++++++++++++++++ scripts/mk_util.py | 168 ++------------------------------- 3 files changed, 190 insertions(+), 162 deletions(-) diff --git a/scripts/mk_consts_files.py b/scripts/mk_consts_files.py index e582d8468..d0502c19d 100755 --- a/scripts/mk_consts_files.py +++ b/scripts/mk_consts_files.py @@ -22,6 +22,7 @@ def main(args): dest="java_package_name", default=None, help="Name to give the Java package (e.g. ``com.microsoft.z3``).") + parser.add_argument("--ml-output-dir", dest="ml_output_dir", default=None) pargs = parser.parse_args(args) if not mk_genfile_common.check_files_exist(pargs.api_files): @@ -60,6 +61,15 @@ def main(args): logging.info('Generated "{}"'.format(generated_file)) count += 1 + if pargs.ml_output_dir: + if not mk_genfile_common.check_dir_exists(pargs.ml_output_dir): + return 1 + output = mk_genfile_common.mk_z3consts_ml_internal( + pargs.api_files, + pargs.ml_output_dir) + logging.info('Generated "{}"'.format(output)) + count += 1 + if count == 0: logging.info('No files generated. You need to specific an output directory' ' for the relevant langauge bindings') diff --git a/scripts/mk_genfile_common.py b/scripts/mk_genfile_common.py index 7e7cb5584..98346f99f 100644 --- a/scripts/mk_genfile_common.py +++ b/scripts/mk_genfile_common.py @@ -376,6 +376,180 @@ def mk_z3consts_java_internal(api_files, package_name, output_dir): api.close() return generated_enumeration_files +# Extract enumeration types from z3_api.h, and add ML definitions +def mk_z3consts_ml_internal(api_files, output_dir): + """ + Generate ``z3enums.ml`` from the list of API header files + in ``api_files`` and write the output file into + the ``output_dir`` directory + + Returns the path to the generated file. + """ + assert os.path.isdir(output_dir) + assert isinstance(api_files, list) + blank_pat = re.compile("^ *$") + comment_pat = re.compile("^ *//.*$") + typedef_pat = re.compile("typedef enum *") + typedef2_pat = re.compile("typedef enum { *") + openbrace_pat = re.compile("{ *") + closebrace_pat = re.compile("}.*;") + + + DeprecatedEnums = [ 'Z3_search_failure' ] + if not os.path.exists(output_dir): + os.mkdir(output_dir) + + efile = open('%s.ml' % os.path.join(output_dir, "z3enums"), 'w') + z3consts_output_path = efile.name + efile.write('(* Automatically generated file *)\n\n') + efile.write('(** The enumeration types of Z3. *)\n\n') + for api_file in api_files: + api = open(api_file, 'r') + + SEARCHING = 0 + FOUND_ENUM = 1 + IN_ENUM = 2 + + mode = SEARCHING + decls = {} + idx = 0 + + linenum = 1 + for line in api: + m1 = blank_pat.match(line) + m2 = comment_pat.match(line) + if m1 or m2: + # skip blank lines and comments + linenum = linenum + 1 + elif mode == SEARCHING: + m = typedef_pat.match(line) + if m: + mode = FOUND_ENUM + m = typedef2_pat.match(line) + if m: + mode = IN_ENUM + decls = {} + idx = 0 + elif mode == FOUND_ENUM: + m = openbrace_pat.match(line) + if m: + mode = IN_ENUM + decls = {} + idx = 0 + else: + assert False, "Invalid %s, line: %s" % (api_file, linenum) + else: + assert mode == IN_ENUM + words = re.split('[^\-a-zA-Z0-9_]+', line) + m = closebrace_pat.match(line) + if m: + name = words[1] + if name not in DeprecatedEnums: + sorted_decls = sorted(decls.items(), key=lambda pair: pair[1]) + efile.write('(** %s *)\n' % name[3:]) + efile.write('type %s =\n' % name[3:]) # strip Z3_ + for k, i in sorted_decls: + efile.write(' | %s \n' % k[3:]) # strip Z3_ + efile.write('\n') + efile.write('(** Convert %s to int*)\n' % name[3:]) + efile.write('let int_of_%s x : int =\n' % (name[3:])) # strip Z3_ + efile.write(' match x with\n') + for k, i in sorted_decls: + efile.write(' | %s -> %d\n' % (k[3:], i)) + efile.write('\n') + efile.write('(** Convert int to %s*)\n' % name[3:]) + efile.write('let %s_of_int x : %s =\n' % (name[3:],name[3:])) # strip Z3_ + efile.write(' match x with\n') + for k, i in sorted_decls: + efile.write(' | %d -> %s\n' % (i, k[3:])) + # use Z3.Exception? + efile.write(' | _ -> raise (Failure "undefined enum value")\n\n') + mode = SEARCHING + else: + if words[2] != '': + if len(words[2]) > 1 and words[2][1] == 'x': + idx = int(words[2], 16) + else: + idx = int(words[2]) + decls[words[1]] = idx + idx = idx + 1 + linenum = linenum + 1 + api.close() + efile.close() + return z3consts_output_path + # efile = open('%s.mli' % os.path.join(gendir, "z3enums"), 'w') + # efile.write('(* Automatically generated file *)\n\n') + # efile.write('(** The enumeration types of Z3. *)\n\n') + # for api_file in api_files: + # api_file_c = ml.find_file(api_file, ml.name) + # api_file = os.path.join(api_file_c.src_dir, api_file) + + # api = open(api_file, 'r') + + # SEARCHING = 0 + # FOUND_ENUM = 1 + # IN_ENUM = 2 + + # mode = SEARCHING + # decls = {} + # idx = 0 + + # linenum = 1 + # for line in api: + # m1 = blank_pat.match(line) + # m2 = comment_pat.match(line) + # if m1 or m2: + # # skip blank lines and comments + # linenum = linenum + 1 + # elif mode == SEARCHING: + # m = typedef_pat.match(line) + # if m: + # mode = FOUND_ENUM + # m = typedef2_pat.match(line) + # if m: + # mode = IN_ENUM + # decls = {} + # idx = 0 + # elif mode == FOUND_ENUM: + # m = openbrace_pat.match(line) + # if m: + # mode = IN_ENUM + # decls = {} + # idx = 0 + # else: + # assert False, "Invalid %s, line: %s" % (api_file, linenum) + # else: + # assert mode == IN_ENUM + # words = re.split('[^\-a-zA-Z0-9_]+', line) + # m = closebrace_pat.match(line) + # if m: + # name = words[1] + # if name not in DeprecatedEnums: + # efile.write('(** %s *)\n' % name[3:]) + # efile.write('type %s =\n' % name[3:]) # strip Z3_ + # for k, i in sorted(decls.items(), key=lambda pair: pair[1]): + # efile.write(' | %s \n' % k[3:]) # strip Z3_ + # efile.write('\n') + # efile.write('(** Convert %s to int*)\n' % name[3:]) + # efile.write('val int_of_%s : %s -> int\n' % (name[3:], name[3:])) # strip Z3_ + # efile.write('(** Convert int to %s*)\n' % name[3:]) + # efile.write('val %s_of_int : int -> %s\n' % (name[3:],name[3:])) # strip Z3_ + # efile.write('\n') + # mode = SEARCHING + # else: + # if words[2] != '': + # if len(words[2]) > 1 and words[2][1] == 'x': + # idx = int(words[2], 16) + # else: + # idx = int(words[2]) + # decls[words[1]] = idx + # idx = idx + 1 + # linenum = linenum + 1 + # api.close() + # efile.close() + # if VERBOSE: + # print ('Generated "%s/z3enums.mli"' % ('%s' % gendir)) + ############################################################################### # Functions for generating a "module definition file" for MSVC diff --git a/scripts/mk_util.py b/scripts/mk_util.py index a5440946c..d644b269c 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -2924,173 +2924,17 @@ def mk_z3consts_java(api_files): # Extract enumeration types from z3_api.h, and add ML definitions def mk_z3consts_ml(api_files): - blank_pat = re.compile("^ *$") - comment_pat = re.compile("^ *//.*$") - typedef_pat = re.compile("typedef enum *") - typedef2_pat = re.compile("typedef enum { *") - openbrace_pat = re.compile("{ *") - closebrace_pat = re.compile("}.*;") - ml = get_component(ML_COMPONENT) - - DeprecatedEnums = [ 'Z3_search_failure' ] - gendir = ml.src_dir - if not os.path.exists(gendir): - os.mkdir(gendir) - - efile = open('%s.ml' % os.path.join(gendir, "z3enums"), 'w') - efile.write('(* Automatically generated file *)\n\n') - efile.write('(** The enumeration types of Z3. *)\n\n') + full_path_api_files = [] for api_file in api_files: api_file_c = ml.find_file(api_file, ml.name) api_file = os.path.join(api_file_c.src_dir, api_file) - - api = open(api_file, 'r') - - SEARCHING = 0 - FOUND_ENUM = 1 - IN_ENUM = 2 - - mode = SEARCHING - decls = {} - idx = 0 - - linenum = 1 - for line in api: - m1 = blank_pat.match(line) - m2 = comment_pat.match(line) - if m1 or m2: - # skip blank lines and comments - linenum = linenum + 1 - elif mode == SEARCHING: - m = typedef_pat.match(line) - if m: - mode = FOUND_ENUM - m = typedef2_pat.match(line) - if m: - mode = IN_ENUM - decls = {} - idx = 0 - elif mode == FOUND_ENUM: - m = openbrace_pat.match(line) - if m: - mode = IN_ENUM - decls = {} - idx = 0 - else: - assert False, "Invalid %s, line: %s" % (api_file, linenum) - else: - assert mode == IN_ENUM - words = re.split('[^\-a-zA-Z0-9_]+', line) - m = closebrace_pat.match(line) - if m: - name = words[1] - if name not in DeprecatedEnums: - sorted_decls = sorted(decls.items(), key=lambda pair: pair[1]) - efile.write('(** %s *)\n' % name[3:]) - efile.write('type %s =\n' % name[3:]) # strip Z3_ - for k, i in sorted_decls: - efile.write(' | %s \n' % k[3:]) # strip Z3_ - efile.write('\n') - efile.write('(** Convert %s to int*)\n' % name[3:]) - efile.write('let int_of_%s x : int =\n' % (name[3:])) # strip Z3_ - efile.write(' match x with\n') - for k, i in sorted_decls: - efile.write(' | %s -> %d\n' % (k[3:], i)) - efile.write('\n') - efile.write('(** Convert int to %s*)\n' % name[3:]) - efile.write('let %s_of_int x : %s =\n' % (name[3:],name[3:])) # strip Z3_ - efile.write(' match x with\n') - for k, i in sorted_decls: - efile.write(' | %d -> %s\n' % (i, k[3:])) - # use Z3.Exception? - efile.write(' | _ -> raise (Failure "undefined enum value")\n\n') - mode = SEARCHING - else: - if words[2] != '': - if len(words[2]) > 1 and words[2][1] == 'x': - idx = int(words[2], 16) - else: - idx = int(words[2]) - decls[words[1]] = idx - idx = idx + 1 - linenum = linenum + 1 - api.close() - efile.close() + full_path_api_files.append(api_file) + generated_file = mk_genfile_common.mk_z3consts_ml_internal( + full_path_api_files, + ml.src_dir) if VERBOSE: - print ('Generated "%s/z3enums.ml"' % ('%s' % gendir)) - # efile = open('%s.mli' % os.path.join(gendir, "z3enums"), 'w') - # efile.write('(* Automatically generated file *)\n\n') - # efile.write('(** The enumeration types of Z3. *)\n\n') - # for api_file in api_files: - # api_file_c = ml.find_file(api_file, ml.name) - # api_file = os.path.join(api_file_c.src_dir, api_file) - - # api = open(api_file, 'r') - - # SEARCHING = 0 - # FOUND_ENUM = 1 - # IN_ENUM = 2 - - # mode = SEARCHING - # decls = {} - # idx = 0 - - # linenum = 1 - # for line in api: - # m1 = blank_pat.match(line) - # m2 = comment_pat.match(line) - # if m1 or m2: - # # skip blank lines and comments - # linenum = linenum + 1 - # elif mode == SEARCHING: - # m = typedef_pat.match(line) - # if m: - # mode = FOUND_ENUM - # m = typedef2_pat.match(line) - # if m: - # mode = IN_ENUM - # decls = {} - # idx = 0 - # elif mode == FOUND_ENUM: - # m = openbrace_pat.match(line) - # if m: - # mode = IN_ENUM - # decls = {} - # idx = 0 - # else: - # assert False, "Invalid %s, line: %s" % (api_file, linenum) - # else: - # assert mode == IN_ENUM - # words = re.split('[^\-a-zA-Z0-9_]+', line) - # m = closebrace_pat.match(line) - # if m: - # name = words[1] - # if name not in DeprecatedEnums: - # efile.write('(** %s *)\n' % name[3:]) - # efile.write('type %s =\n' % name[3:]) # strip Z3_ - # for k, i in sorted(decls.items(), key=lambda pair: pair[1]): - # efile.write(' | %s \n' % k[3:]) # strip Z3_ - # efile.write('\n') - # efile.write('(** Convert %s to int*)\n' % name[3:]) - # efile.write('val int_of_%s : %s -> int\n' % (name[3:], name[3:])) # strip Z3_ - # efile.write('(** Convert int to %s*)\n' % name[3:]) - # efile.write('val %s_of_int : int -> %s\n' % (name[3:],name[3:])) # strip Z3_ - # efile.write('\n') - # mode = SEARCHING - # else: - # if words[2] != '': - # if len(words[2]) > 1 and words[2][1] == 'x': - # idx = int(words[2], 16) - # else: - # idx = int(words[2]) - # decls[words[1]] = idx - # idx = idx + 1 - # linenum = linenum + 1 - # api.close() - # efile.close() - # if VERBOSE: - # print ('Generated "%s/z3enums.mli"' % ('%s' % gendir)) + print ('Generated "%s"' % generated_file) def mk_gui_str(id): return '4D2F40D8-E5F9-473B-B548-%012d' % id From 2e74a2c54e5935cdd1c8678d3a0641e7132da023 Mon Sep 17 00:00:00 2001 From: Dan Liew Date: Mon, 21 Nov 2016 01:04:55 +0000 Subject: [PATCH 438/536] Refactor `update_api.mk_ml()` so that the source and output directories can be different. This feature will be needed by the CMake build system to build the OCaml bindings. --- scripts/mk_util.py | 3 ++- scripts/update_api.py | 32 ++++++++++++++++++++++---------- 2 files changed, 24 insertions(+), 11 deletions(-) diff --git a/scripts/mk_util.py b/scripts/mk_util.py index d644b269c..fd8962bda 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -2870,7 +2870,8 @@ def mk_bindings(api_files): dotnet_output_dir=dotnet_output_dir, java_output_dir=java_output_dir, java_package_name=java_package_name, - ml_output_dir=ml_output_dir + ml_output_dir=ml_output_dir, + ml_src_dir=ml_output_dir ) cp_z3py_to_build() if is_ml_enabled(): diff --git a/scripts/update_api.py b/scripts/update_api.py index 3a3b2c40a..e531a103c 100755 --- a/scripts/update_api.py +++ b/scripts/update_api.py @@ -1195,13 +1195,13 @@ def ml_alloc_and_store(t, lhs, rhs): alloc_str = '%s = caml_alloc_custom(&%s, sizeof(%s), 0, 1); ' % (lhs, pops, pts) return alloc_str + ml_set_wrap(t, lhs, rhs) -def mk_ml(ml_dir): +def mk_ml(ml_src_dir, ml_output_dir): global Type2Str - ml_nativef = os.path.join(ml_dir, 'z3native.ml') + ml_nativef = os.path.join(ml_output_dir, 'z3native.ml') ml_native = open(ml_nativef, 'w') ml_native.write('(* Automatically generated file *)\n\n') - ml_pref = open(os.path.join(ml_dir, 'z3native.ml.pre'), 'r') + ml_pref = open(os.path.join(ml_src_dir, 'z3native.ml.pre'), 'r') for s in ml_pref: ml_native.write(s); ml_pref.close() @@ -1250,14 +1250,14 @@ def mk_ml(ml_dir): if mk_util.is_verbose(): print ('Generated "%s"' % ml_nativef) - mk_z3native_stubs_c(ml_dir) + mk_z3native_stubs_c(ml_src_dir, ml_output_dir) -def mk_z3native_stubs_c(ml_dir): # C interface - ml_wrapperf = os.path.join(ml_dir, 'z3native_stubs.c') +def mk_z3native_stubs_c(ml_src_dir, ml_output_dir): # C interface + ml_wrapperf = os.path.join(ml_output_dir, 'z3native_stubs.c') ml_wrapper = open(ml_wrapperf, 'w') ml_wrapper.write('// Automatically generated file\n\n') - ml_pref = open(os.path.join(ml_dir, 'z3native_stubs.c.pre'), 'r') + ml_pref = open(os.path.join(ml_src_dir, 'z3native_stubs.c.pre'), 'r') for s in ml_pref: ml_wrapper.write(s); ml_pref.close() @@ -1666,7 +1666,8 @@ def generate_files(api_files, dotnet_output_dir=None, java_output_dir=None, java_package_name=None, - ml_output_dir=None): + ml_output_dir=None, + ml_src_dir=None): """ Scan the api files in ``api_files`` and emit the relevant API files into the output directories specified. If an output directory is set to ``None`` @@ -1741,7 +1742,8 @@ def generate_files(api_files, mk_java(java_output_dir, java_package_name) if ml_output_dir: - mk_ml(ml_output_dir) + assert not ml_src_dir is None + mk_ml(ml_src_dir, ml_output_dir) def main(args): logging.basicConfig(level=logging.INFO) @@ -1768,6 +1770,10 @@ def main(args): dest="java_package_name", default=None, help="Name to give the Java package (e.g. ``com.microsoft.z3``).") + parser.add_argument("--ml-src-dir", + dest="ml_src_dir", + default=None, + help="Directory containing OCaml source files. If not specified no files are emitted") parser.add_argument("--ml-output-dir", dest="ml_output_dir", default=None, @@ -1779,6 +1785,11 @@ def main(args): logging.error('--java-package-name must be specified') return 1 + if pargs.ml_output_dir: + if pargs.ml_src_dir is None: + logging.error('--ml-src-dir must be specified') + return 1 + for api_file in pargs.api_files: if not os.path.exists(api_file): logging.error('"{}" does not exist'.format(api_file)) @@ -1790,7 +1801,8 @@ def main(args): dotnet_output_dir=pargs.dotnet_output_dir, java_output_dir=pargs.java_output_dir, java_package_name=pargs.java_package_name, - ml_output_dir=pargs.ml_output_dir) + ml_output_dir=pargs.ml_output_dir, + ml_src_dir=pargs.ml_src_dir) return 0 if __name__ == '__main__': From b5aa6d5eb5d9d71a55d51ee2eef5cde952cf3a51 Mon Sep 17 00:00:00 2001 From: Dan Liew Date: Mon, 19 Dec 2016 22:36:42 +0000 Subject: [PATCH 439/536] Fix issue with bd1f07f864a7f1790cec08a306ccc17507f7e5a8 pointed out by @nunolopes . If `pthread_cond_signal()` is called while `m_mutex` is held then the timing thread might be woken up twice due to waking up from `pthread_cond_timeout()` (due to being signaled) but then being forced to sleep again because the thread calling `~imp()` is still holding `m_mutex` (which the timing thread needs to acquire). --- src/util/scoped_timer.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/util/scoped_timer.cpp b/src/util/scoped_timer.cpp index 3b87f880f..f6b0429d9 100644 --- a/src/util/scoped_timer.cpp +++ b/src/util/scoped_timer.cpp @@ -230,8 +230,9 @@ struct scoped_timer::imp { } pthread_mutex_lock(&m_mutex); m_signal_sent = true; - pthread_cond_signal(&m_cond); pthread_mutex_unlock(&m_mutex); + // Perform signal outside of lock to avoid waking timing thread twice. + pthread_cond_signal(&m_cond); pthread_join(m_thread_id, NULL); pthread_cond_destroy(&m_cond); From 8d18fd075e7ca5edc3a7dde42c865f9b7e43e6c7 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 21 Dec 2016 09:54:45 -0800 Subject: [PATCH 440/536] remove sources for unused variable warnings Signed-off-by: Nikolaj Bjorner --- src/ast/fpa/bv2fpa_converter.cpp | 6 +++--- src/ast/rewriter/bv_bounds.cpp | 5 ++--- src/ast/simplifier/simplifier.cpp | 2 ++ src/muz/pdr/pdr_sym_mux.cpp | 1 + src/sat/sat_integrity_checker.cpp | 4 ++-- src/smt/smt_consequences.cpp | 3 +-- src/tactic/aig/aig.cpp | 10 +++------- src/tactic/bv/bv_bounds_tactic.cpp | 2 ++ src/tactic/extension_model_converter.cpp | 3 ++- src/tactic/tactic.cpp | 3 ++- src/test/fuzzing/expr_rand.cpp | 3 --- src/test/fuzzing/expr_rand.h | 3 --- 12 files changed, 20 insertions(+), 25 deletions(-) diff --git a/src/ast/fpa/bv2fpa_converter.cpp b/src/ast/fpa/bv2fpa_converter.cpp index 0dec98e5c..c113627f9 100644 --- a/src/ast/fpa/bv2fpa_converter.cpp +++ b/src/ast/fpa/bv2fpa_converter.cpp @@ -312,11 +312,11 @@ void bv2fpa_converter::convert_consts(model_core * mc, model_core * target_model unsigned sbits = m_fpa_util.get_sbits(var->get_range()); app * a0 = to_app(val->get_arg(0)); - app * a1 = to_app(val->get_arg(1)); - app * a2 = to_app(val->get_arg(2)); expr_ref v0(m), v1(m), v2(m); #ifdef Z3DEBUG + app * a1 = to_app(val->get_arg(1)); + app * a2 = to_app(val->get_arg(2)); v0 = mc->get_const_interp(a0->get_decl()); v1 = mc->get_const_interp(a1->get_decl()); v2 = mc->get_const_interp(a2->get_decl()); @@ -555,4 +555,4 @@ void bv2fpa_converter::convert(model_core * mc, model_core * float_mdl) { tout << "else " << mk_ismt2_pp(fi->get_else(), m) << std::endl; }); -} \ No newline at end of file +} diff --git a/src/ast/rewriter/bv_bounds.cpp b/src/ast/rewriter/bv_bounds.cpp index 22decbb7c..1e9ff926c 100644 --- a/src/ast/rewriter/bv_bounds.cpp +++ b/src/ast/rewriter/bv_bounds.cpp @@ -24,9 +24,8 @@ bv_bounds::~bv_bounds() { bv_bounds::conv_res bv_bounds::record(app * v, numeral lo, numeral hi, bool negated, vector& nis) { TRACE("bv_bounds", tout << "record0 " << mk_ismt2_pp(v, m_m) << ":" << (negated ? "~[" : "[") << lo << ";" << hi << "]" << std::endl;); const unsigned bv_sz = m_bv_util.get_bv_size(v); - const numeral& zero = numeral::zero(); const numeral& one = numeral::one(); - SASSERT(zero <= lo); + SASSERT(numerl::zero() <= lo); SASSERT(lo <= hi); SASSERT(hi < numeral::power_of_two(bv_sz)); numeral vmax, vmin; @@ -49,7 +48,7 @@ bv_bounds::conv_res bv_bounds::record(app * v, numeral lo, numeral hi, bool nega hi_max = hi >= vmax; lo_min = true; } - SASSERT(zero <= lo); + SASSERT(lo.is_nonneg()); SASSERT(lo <= hi); SASSERT(hi < numeral::power_of_two(bv_sz)); } diff --git a/src/ast/simplifier/simplifier.cpp b/src/ast/simplifier/simplifier.cpp index 63731c679..6f7e62fd4 100644 --- a/src/ast/simplifier/simplifier.cpp +++ b/src/ast/simplifier/simplifier.cpp @@ -650,10 +650,12 @@ void simplifier::mk_ac_congruent_term(app * n, app_ref & r, proof_ref & p) { #define Grey 1 #define Black 2 +#ifdef Z3DEBUG static int get_color(obj_map & colors, expr * n) { obj_map::obj_map_entry * entry = colors.insert_if_not_there2(n, White); return entry->get_data().m_value; } +#endif static bool visit_ac_children(func_decl * f, expr * n, obj_map & colors, ptr_buffer & todo, ptr_buffer & result) { if (is_app_of(n, f)) { diff --git a/src/muz/pdr/pdr_sym_mux.cpp b/src/muz/pdr/pdr_sym_mux.cpp index a68b57e9c..47edb35ac 100644 --- a/src/muz/pdr/pdr_sym_mux.cpp +++ b/src/muz/pdr/pdr_sym_mux.cpp @@ -366,6 +366,7 @@ public: app * a = to_app(s); func_decl * sym = a->get_decl(); if(!m_parent.has_index(sym, m_from_idx)) { + (void) m_homogenous; SASSERT(!m_homogenous || !m_parent.is_muxed(sym)); return false; } diff --git a/src/sat/sat_integrity_checker.cpp b/src/sat/sat_integrity_checker.cpp index 8db27c7ec..f7cd371f8 100644 --- a/src/sat/sat_integrity_checker.cpp +++ b/src/sat/sat_integrity_checker.cpp @@ -96,8 +96,8 @@ namespace sat { } // the first two literals must be watched. - SASSERT(contains_watched(s.get_wlist(~c[0]), c, s.get_offset(c))); - SASSERT(contains_watched(s.get_wlist(~c[1]), c, s.get_offset(c))); + VERIFY(contains_watched(s.get_wlist(~c[0]), c, s.get_offset(c))); + VERIFY(contains_watched(s.get_wlist(~c[1]), c, s.get_offset(c))); } return true; } diff --git a/src/smt/smt_consequences.cpp b/src/smt/smt_consequences.cpp index e6edbf87e..c872a7139 100644 --- a/src/smt/smt_consequences.cpp +++ b/src/smt/smt_consequences.cpp @@ -426,8 +426,7 @@ namespace smt { TRACE("context", tout << "checking: " << mk_pp(conseq[i], m) << "\n";); tmp = m.mk_not(conseq[i]); assert_expr(tmp); - lbool is_sat = check(); - SASSERT(is_sat != l_true); + VERIFY(check() != l_true); pop(1); } model_ref mdl; diff --git a/src/tactic/aig/aig.cpp b/src/tactic/aig/aig.cpp index b84ae68f0..dddb0c636 100644 --- a/src/tactic/aig/aig.cpp +++ b/src/tactic/aig/aig.cpp @@ -53,8 +53,10 @@ struct aig { aig() {} }; +#if Z3DEBUG inline bool is_true(aig_lit const & r) { return !r.is_inverted() && r.ptr_non_inverted()->m_id == 0; } -inline bool is_false(aig_lit const & r) { return r.is_inverted() && r.ptr()->m_id == 0; } +#endif +// inline bool is_false(aig_lit const & r) { return r.is_inverted() && r.ptr()->m_id == 0; } inline bool is_var(aig * n) { return n->m_children[0].is_null(); } inline bool is_var(aig_lit const & n) { return is_var(n.ptr()); } inline unsigned id(aig_lit const & n) { return n.ptr()->m_id; } @@ -66,12 +68,6 @@ inline aig_lit right(aig_lit const & n) { return right(n.ptr()); } inline unsigned to_idx(aig * p) { SASSERT(!is_var(p)); return p->m_id - FIRST_NODE_ID; } -void unmark(unsigned sz, aig_lit const * ns) { - for (unsigned i = 0; i < sz; i++) { - ns[i].ptr()->m_mark = false; - } -} - void unmark(unsigned sz, aig * const * ns) { for (unsigned i = 0; i < sz; i++) { ns[i]->m_mark = false; diff --git a/src/tactic/bv/bv_bounds_tactic.cpp b/src/tactic/bv/bv_bounds_tactic.cpp index e67c2470b..1b324b2eb 100644 --- a/src/tactic/bv/bv_bounds_tactic.cpp +++ b/src/tactic/bv/bv_bounds_tactic.cpp @@ -148,10 +148,12 @@ struct interval { } }; +#ifdef _TRACE std::ostream& operator<<(std::ostream& o, const interval& I) { o << "[" << I.l << ", " << I.h << "]"; return o; } +#endif struct undo_bound { diff --git a/src/tactic/extension_model_converter.cpp b/src/tactic/extension_model_converter.cpp index 345ea5cc9..ee6b8f691 100644 --- a/src/tactic/extension_model_converter.cpp +++ b/src/tactic/extension_model_converter.cpp @@ -25,7 +25,7 @@ Notes: extension_model_converter::~extension_model_converter() { } - +#ifdef _TRACE static void display_decls_info(std::ostream & out, model_ref & md) { ast_manager & m = md->get_manager(); unsigned sz = md->get_num_decls(); @@ -42,6 +42,7 @@ static void display_decls_info(std::ostream & out, model_ref & md) { out << " :id " << d->get_id() << "\n"; } } +#endif void extension_model_converter::operator()(model_ref & md, unsigned goal_idx) { SASSERT(goal_idx == 0); diff --git a/src/tactic/tactic.cpp b/src/tactic/tactic.cpp index 92e916d80..2ccb23305 100644 --- a/src/tactic/tactic.cpp +++ b/src/tactic/tactic.cpp @@ -126,7 +126,7 @@ tactic * mk_report_verbose_tactic(char const * msg, unsigned lvl) { class trace_tactic : public skip_tactic { char const * m_tag; public: - trace_tactic(char const * tag):m_tag(tag) {} + trace_tactic(char const * tag): m_tag(tag) {} virtual void operator()(goal_ref const & in, goal_ref_buffer & result, @@ -134,6 +134,7 @@ public: proof_converter_ref & pc, expr_dependency_ref & core) { TRACE(m_tag, in->display(tout);); + (void)m_tag; skip_tactic::operator()(in, result, mc, pc, core); } }; diff --git a/src/test/fuzzing/expr_rand.cpp b/src/test/fuzzing/expr_rand.cpp index f56704e45..ccc4a9e5c 100644 --- a/src/test/fuzzing/expr_rand.cpp +++ b/src/test/fuzzing/expr_rand.cpp @@ -13,9 +13,6 @@ Copyright (c) 2015 Microsoft Corporation expr_rand::expr_rand(ast_manager& m): m_manager(m), - m_num_vars(0), - m_num_apps(0), - m_num_nodes(0), m_max_steps(10), m_funcs(m) {} diff --git a/src/test/fuzzing/expr_rand.h b/src/test/fuzzing/expr_rand.h index 971a3ec60..bbadd587e 100644 --- a/src/test/fuzzing/expr_rand.h +++ b/src/test/fuzzing/expr_rand.h @@ -24,9 +24,6 @@ Revision History: class expr_rand { ast_manager& m_manager; - unsigned m_num_vars; - unsigned m_num_apps; - unsigned m_num_nodes; unsigned m_max_steps; random_gen m_random; From 4bcf1bf2f66759fe563e1f011b7ee88b5e4f307e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 21 Dec 2016 10:44:49 -0800 Subject: [PATCH 441/536] fix debug build, unused variable warnings Signed-off-by: Nikolaj Bjorner --- src/ast/pattern/pattern_inference.cpp | 4 +++- src/ast/rewriter/bv_bounds.cpp | 2 +- src/muz/transforms/dl_mk_rule_inliner.h | 2 +- src/smt/arith_eq_solver.cpp | 3 +++ src/smt/mam.cpp | 2 ++ src/smt/smt_internalizer.cpp | 17 ----------------- src/smt/theory_fpa.h | 3 +-- src/smt/theory_wmaxsat.cpp | 1 + 8 files changed, 12 insertions(+), 22 deletions(-) diff --git a/src/ast/pattern/pattern_inference.cpp b/src/ast/pattern/pattern_inference.cpp index b93dd7657..64ec064a8 100644 --- a/src/ast/pattern/pattern_inference.cpp +++ b/src/ast/pattern/pattern_inference.cpp @@ -474,13 +474,15 @@ void pattern_inference::reset_pre_patterns() { m_pre_patterns.reset(); } - +#ifdef _TRACE static void dump_app_vector(std::ostream & out, ptr_vector const & v, ast_manager & m) { ptr_vector::const_iterator it = v.begin(); ptr_vector::const_iterator end = v.end(); for (; it != end; ++it) out << mk_pp(*it, m) << "\n"; } +#endif + bool pattern_inference::is_forbidden(app * n) const { func_decl const * decl = n->get_decl(); if (is_ground(n)) diff --git a/src/ast/rewriter/bv_bounds.cpp b/src/ast/rewriter/bv_bounds.cpp index 1e9ff926c..76cdfbdbe 100644 --- a/src/ast/rewriter/bv_bounds.cpp +++ b/src/ast/rewriter/bv_bounds.cpp @@ -25,7 +25,7 @@ bv_bounds::conv_res bv_bounds::record(app * v, numeral lo, numeral hi, bool nega TRACE("bv_bounds", tout << "record0 " << mk_ismt2_pp(v, m_m) << ":" << (negated ? "~[" : "[") << lo << ";" << hi << "]" << std::endl;); const unsigned bv_sz = m_bv_util.get_bv_size(v); const numeral& one = numeral::one(); - SASSERT(numerl::zero() <= lo); + SASSERT(numeral::zero() <= lo); SASSERT(lo <= hi); SASSERT(hi < numeral::power_of_two(bv_sz)); numeral vmax, vmin; diff --git a/src/muz/transforms/dl_mk_rule_inliner.h b/src/muz/transforms/dl_mk_rule_inliner.h index 98f65a734..66d17fdc8 100644 --- a/src/muz/transforms/dl_mk_rule_inliner.h +++ b/src/muz/transforms/dl_mk_rule_inliner.h @@ -88,7 +88,7 @@ namespace datalog { svector m_can_remove, m_can_expand; obj_map m_positions; public: - visitor(context& c, substitution & s): st_visitor(s), m_context(c) {} + visitor(context& c, substitution & s): st_visitor(s), m_context(c) { (void) m_context; } virtual bool operator()(expr* e); void reset() { m_unifiers.reset(); } void reset(unsigned sz); diff --git a/src/smt/arith_eq_solver.cpp b/src/smt/arith_eq_solver.cpp index 9a6868ff1..de88d37bb 100644 --- a/src/smt/arith_eq_solver.cpp +++ b/src/smt/arith_eq_solver.cpp @@ -113,6 +113,8 @@ unsigned arith_eq_solver::find_abs_min(vector& values) { return index; } +#ifdef _TRACE + static void print_row(std::ostream& out, vector const& row) { for(unsigned i = 0; i < row.size(); ++i) { out << row[i] << " "; @@ -125,6 +127,7 @@ static void print_rows(std::ostream& out, vector > const& rows) print_row(out, rows[i]); } } +#endif // // The gcd of the coefficients to variables have to divide the diff --git a/src/smt/mam.cpp b/src/smt/mam.cpp index 60aed12e1..5d03a3563 100644 --- a/src/smt/mam.cpp +++ b/src/smt/mam.cpp @@ -490,6 +490,7 @@ namespace smt { #ifdef _PROFILE_MAM m_counter = 0; #endif + (void)m_lbl_hasher; } #ifdef _PROFILE_MAM @@ -2881,6 +2882,7 @@ namespace smt { - first_idx: index to be used as head of the multi-pattern mp */ void add_pattern(quantifier * qa, app * mp, unsigned first_idx) { + (void)m_ast_manager; SASSERT(m_ast_manager.is_pattern(mp)); SASSERT(first_idx < mp->get_num_args()); app * p = to_app(mp->get_arg(first_idx)); diff --git a/src/smt/smt_internalizer.cpp b/src/smt/smt_internalizer.cpp index ad1e55ba6..f7936eacd 100644 --- a/src/smt/smt_internalizer.cpp +++ b/src/smt/smt_internalizer.cpp @@ -335,23 +335,6 @@ namespace smt { } } - static bool find_arg(app * n, expr * t, expr * & other) { - SASSERT(n->get_num_args() == 2); - if (n->get_arg(0) == t) { - other = n->get_arg(1); - return true; - } - else if (n->get_arg(1) == t) { - other = n->get_arg(0); - return true; - } - return false; - } - - static bool check_args(app * n, expr * t1, expr * t2) { - SASSERT(n->get_num_args() == 2); - return (n->get_arg(0) == t1 && n->get_arg(1) == t2) || (n->get_arg(1) == t1 && n->get_arg(0) == t2); - } /** \brief Internalize the given formula into the logical context. diff --git a/src/smt/theory_fpa.h b/src/smt/theory_fpa.h index 2b327eb66..a70ddb98f 100644 --- a/src/smt/theory_fpa.h +++ b/src/smt/theory_fpa.h @@ -112,7 +112,6 @@ namespace smt { }; class fpa_rm_value_proc : public model_value_proc { - theory_fpa & m_th; ast_manager & m; fpa_util & m_fu; bv_util & m_bu; @@ -120,7 +119,7 @@ namespace smt { public: fpa_rm_value_proc(theory_fpa * th) : - m_th(*th), m(th->get_manager()), m_fu(th->m_fpa_util), m_bu(th->m_bv_util) {} + m(th->get_manager()), m_fu(th->m_fpa_util), m_bu(th->m_bv_util) {} void add_dependency(enode * e) { m_deps.push_back(model_value_dependency(e)); } diff --git a/src/smt/theory_wmaxsat.cpp b/src/smt/theory_wmaxsat.cpp index b665c2a94..e396b67cc 100644 --- a/src/smt/theory_wmaxsat.cpp +++ b/src/smt/theory_wmaxsat.cpp @@ -102,6 +102,7 @@ namespace smt { m_enabled.push_back(true); m_normalize = true; bool_var bv = register_var(var, true); + (void)bv; TRACE("opt", tout << "enable: v" << m_bool2var[bv] << " b" << bv << " " << mk_pp(var, get_manager()) << "\n"; tout << wfml << "\n";); return var; From f52baf1e17438650c10c316cae88549ea3366f66 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 21 Dec 2016 10:48:43 -0800 Subject: [PATCH 442/536] fix build again Signed-off-by: Nikolaj Bjorner --- src/smt/theory_fpa.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/smt/theory_fpa.h b/src/smt/theory_fpa.h index a70ddb98f..998f2be3c 100644 --- a/src/smt/theory_fpa.h +++ b/src/smt/theory_fpa.h @@ -112,6 +112,7 @@ namespace smt { }; class fpa_rm_value_proc : public model_value_proc { + theory_fpa & m_th; ast_manager & m; fpa_util & m_fu; bv_util & m_bu; @@ -119,7 +120,7 @@ namespace smt { public: fpa_rm_value_proc(theory_fpa * th) : - m(th->get_manager()), m_fu(th->m_fpa_util), m_bu(th->m_bv_util) {} + m_th(*th), m(th->get_manager()), m_fu(th->m_fpa_util), m_bu(th->m_bv_util) { (void) m_th; } void add_dependency(enode * e) { m_deps.push_back(model_value_dependency(e)); } From 1eec0799ca75825918f00407b454ee6507d415c3 Mon Sep 17 00:00:00 2001 From: Andrew Dutcher Date: Thu, 22 Dec 2016 14:26:41 -0800 Subject: [PATCH 443/536] Add -fpic to armv7/armv8 build --- scripts/mk_util.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/scripts/mk_util.py b/scripts/mk_util.py index cdd7bdeec..8b97909f6 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -2441,7 +2441,7 @@ def mk_config(): CXXFLAGS = '%s -O3 -D _EXTERNAL_RELEASE -fomit-frame-pointer' % CXXFLAGS if is_CXX_clangpp(): CXXFLAGS = '%s -Wno-unknown-pragmas -Wno-overloaded-virtual -Wno-unused-value' % CXXFLAGS - sysname = os.uname()[0] + sysname, _, _, _, machine = os.uname() if sysname == 'Darwin': SO_EXT = '.dylib' SLIBFLAGS = '-dynamiclib' @@ -2492,7 +2492,9 @@ def mk_config(): # and to make it create an import library. SLIBEXTRAFLAGS = '%s -static-libgcc -static-libstdc++ -Wl,--out-implib,libz3.dll.a' % SLIBEXTRAFLAGS LDFLAGS = '%s -static-libgcc -static-libstdc++' % LDFLAGS - + if sysname == 'Linux' and machine.startswith('armv7') or machine.startswith('armv8'): + CXXFLAGS = '%s -fpic' % CXXFLAGS + config.write('PREFIX=%s\n' % PREFIX) config.write('CC=%s\n' % CC) config.write('CXX=%s\n' % CXX) From a444a33c30db3206b56cdbcb9561b86298b69858 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 22 Dec 2016 17:45:21 -0800 Subject: [PATCH 444/536] updated encodings Signed-off-by: Nikolaj Bjorner --- src/parsers/smt2/smt2parser.cpp | 2 +- src/smt/theory_pb.cpp | 115 +++++++++++++++++--------------- src/smt/theory_pb.h | 30 ++++++++- 3 files changed, 89 insertions(+), 58 deletions(-) diff --git a/src/parsers/smt2/smt2parser.cpp b/src/parsers/smt2/smt2parser.cpp index 00f63afd5..bb0c5bfb9 100644 --- a/src/parsers/smt2/smt2parser.cpp +++ b/src/parsers/smt2/smt2parser.cpp @@ -2183,7 +2183,7 @@ namespace smt2 { SASSERT(curr_id() == m_check_sat_assuming); next(); unsigned spos = expr_stack().size(); - check_rparen_next("invalid check-sat-assuming command, '(', expected"); + check_lparen_next("invalid check-sat-assuming command, '(', expected"); parse_assumptions(); check_rparen_next("invalid check-sat-assuming command, ')', expected"); m_ctx.check_sat(expr_stack().size() - spos, expr_stack().c_ptr() + spos); diff --git a/src/smt/theory_pb.cpp b/src/smt/theory_pb.cpp index a2f8ceba9..68553453d 100644 --- a/src/smt/theory_pb.cpp +++ b/src/smt/theory_pb.cpp @@ -527,7 +527,8 @@ namespace smt { c->m_compilation_threshold = UINT_MAX; } init_watch_var(*c); - m_ineqs.insert(abv, c); + init_watch(abv); + m_var_infos[abv].m_ineq = c; m_ineqs_trail.push_back(abv); if (m_enable_simplex) { @@ -687,35 +688,43 @@ namespace smt { watch_literal(lit, &c); } + void theory_pb::init_watch(bool_var v) { + if (m_var_infos.size() <= static_cast(v)) { + m_var_infos.resize(static_cast(v)+100); + } + } + void theory_pb::watch_literal(literal lit, ineq* c) { - ptr_vector* ineqs; - if (!m_lwatch.find(lit.index(), ineqs)) { + init_watch(lit.var()); + ptr_vector* ineqs = m_var_infos[lit.var()].m_lit_watch[lit.sign()]; + if (ineqs == 0) { ineqs = alloc(ptr_vector); - m_lwatch.insert(lit.index(), ineqs); + m_var_infos[lit.var()].m_lit_watch[lit.sign()] = ineqs; } ineqs->push_back(c); } void theory_pb::watch_var(bool_var v, ineq* c) { - ptr_vector* ineqs; - if (!m_vwatch.find(v, ineqs)) { + init_watch(v); + ptr_vector* ineqs = m_var_infos[v].m_var_watch; + if (ineqs == 0) { ineqs = alloc(ptr_vector); - m_vwatch.insert(v, ineqs); + m_var_infos[v].m_var_watch = ineqs; } ineqs->push_back(c); } void theory_pb::unwatch_var(bool_var v, ineq* c) { - ptr_vector* ineqs = 0; - if (m_vwatch.find(v, ineqs)) { + ptr_vector* ineqs = m_var_infos[v].m_var_watch; + if (ineqs) { remove(*ineqs, c); } } - void theory_pb::unwatch_literal(literal w, ineq* c) { - ptr_vector* ineqs = 0; - if (m_lwatch.find(w.index(), ineqs)) { - remove(*ineqs, c); + void theory_pb::unwatch_literal(literal lit, ineq* c) { + ptr_vector* ineqs = m_var_infos[lit.var()].m_lit_watch[lit.sign()]; + if (ineqs) { + remove(*ineqs, c); } } @@ -741,22 +750,9 @@ namespace smt { void theory_pb::reset_eh() { - // m_watch; - u_map*>::iterator it = m_lwatch.begin(), end = m_lwatch.end(); - for (; it != end; ++it) { - dealloc(it->m_value); + for (unsigned i = 0; i < m_var_infos.size(); ++i) { + m_var_infos[i].reset(); } - it = m_vwatch.begin(), end = m_vwatch.end(); - for (; it != end; ++it) { - dealloc(it->m_value); - } - u_map::iterator itc = m_ineqs.begin(), endc = m_ineqs.end(); - for (; itc != endc; ++itc) { - dealloc(itc->m_value); - } - m_lwatch.reset(); - m_vwatch.reset(); - m_ineqs.reset(); m_ineqs_trail.reset(); m_ineqs_lim.reset(); m_stats.reset(); @@ -777,7 +773,8 @@ namespace smt { ptr_vector* ineqs = 0; literal nlit(v, is_true); TRACE("pb", tout << "assign: " << ~nlit << "\n";); - if (m_lwatch.find(nlit.index(), ineqs)) { + ineqs = m_var_infos[v].m_lit_watch[nlit.sign()]; + if (ineqs != 0) { if (m_enable_simplex) { mpq_inf num(mpq(is_true?1:0),mpq(0)); if (!update_bound(v, ~nlit, is_true, num)) { @@ -797,14 +794,15 @@ namespace smt { } } } - if (m_vwatch.find(v, ineqs)) { + ineqs = m_var_infos[v].m_var_watch; + if (ineqs != 0) { for (unsigned i = 0; i < ineqs->size(); ++i) { ineq* c = (*ineqs)[i]; assign_watch(v, is_true, *c); } } - ineq* c = 0; - if (m_ineqs.find(v, c)) { + ineq* c = m_var_infos[v].m_ineq; + if (c != 0) { if (m_enable_simplex) { row_info const& info = m_ineq_row_info.find(v); scoped_eps_numeral coeff(m_mpq_inf_mgr); @@ -1317,10 +1315,9 @@ namespace smt { unsigned sz = m_ineqs_lim[new_lim]; while (m_ineqs_trail.size() > sz) { bool_var v = m_ineqs_trail.back(); - ineq* c = 0; - VERIFY(m_ineqs.find(v, c)); + ineq* c = m_var_infos[v].m_ineq; clear_watch(*c); - m_ineqs.remove(v); + m_var_infos[v].m_ineq = 0; m_ineqs_trail.pop_back(); if (m_enable_simplex) { row_info r_info; @@ -1866,9 +1863,11 @@ namespace smt { } void theory_pb::validate_final_check() { - u_map::iterator itc = m_ineqs.begin(), endc = m_ineqs.end(); - for (; itc != endc; ++itc) { - validate_final_check(*itc->m_value); + for (unsigned i = 0; i < m_var_infos.size(); ++i) { + ineq* c = m_var_infos[i].m_ineq; + if (c) { + validate_final_check(*c); + } } } @@ -2076,29 +2075,37 @@ namespace smt { return p; } + void theory_pb::display_watch(std::ostream& out, bool_var v, bool sign) const { + watch_list const* w = m_var_infos[v].m_lit_watch[sign]; + if (!w) return; + watch_list const& wl = *w; + out << "watch: " << literal(v, sign) << " |-> "; + for (unsigned i = 0; i < wl.size(); ++i) { + out << wl[i]->lit() << " "; + } + out << "\n"; + } + void theory_pb::display(std::ostream& out) const { - u_map*>::iterator it = m_lwatch.begin(), end = m_lwatch.end(); - for (; it != end; ++it) { - out << "watch: " << to_literal(it->m_key) << " |-> "; - watch_list const& wl = *it->m_value; + for (unsigned vi = 0; vi < m_var_infos.size(); ++vi) { + display_watch(out, vi, false); + display_watch(out, vi, true); + } + for (unsigned vi = 0; vi < m_var_infos.size(); ++vi) { + watch_list const* w = m_var_infos[vi].m_var_watch; + if (!w) continue; + out << "watch (v): " << literal(vi) << " |-> "; + watch_list const& wl = *w; for (unsigned i = 0; i < wl.size(); ++i) { out << wl[i]->lit() << " "; } out << "\n"; } - it = m_vwatch.begin(), end = m_vwatch.end(); - for (; it != end; ++it) { - out << "watch (v): " << literal(it->m_key) << " |-> "; - watch_list const& wl = *it->m_value; - for (unsigned i = 0; i < wl.size(); ++i) { - out << wl[i]->lit() << " "; + for (unsigned vi = 0; vi < m_var_infos.size(); ++vi) { + ineq* c = m_var_infos[vi].m_ineq; + if (c) { + display(out, *c, true); } - out << "\n"; - } - u_map::iterator itc = m_ineqs.begin(), endc = m_ineqs.end(); - for (; itc != endc; ++itc) { - ineq& c = *itc->m_value; - display(out, c, true); } } diff --git a/src/smt/theory_pb.h b/src/smt/theory_pb.h index 1a08b7b61..7f621f9c5 100644 --- a/src/smt/theory_pb.h +++ b/src/smt/theory_pb.h @@ -193,10 +193,32 @@ namespace smt { typedef ptr_vector watch_list; typedef map arg_map; + struct var_info { + watch_list* m_lit_watch[2]; + watch_list* m_var_watch; + ineq* m_ineq; + + var_info(): m_var_watch(0), m_ineq(0) + { + m_lit_watch[0] = 0; + m_lit_watch[1] = 0; + } + + void reset() { + dealloc(m_lit_watch[0]); + dealloc(m_lit_watch[1]); + dealloc(m_var_watch); + dealloc(m_ineq); + } + }; + + theory_pb_params m_params; - u_map m_lwatch; // per literal. - u_map m_vwatch; // per variable. - u_map m_ineqs; // per inequality. + + svector m_var_infos; +// u_map m_lwatch; // per literal. +// u_map m_vwatch; // per variable. +// u_map m_ineqs; // per inequality. arg_map m_ineq_rep; // Simplex: representative inequality u_map m_ineq_row_info; // Simplex: row information per variable uint_set m_vars; // Simplex: 0-1 variables. @@ -221,6 +243,7 @@ namespace smt { literal compile_arg(expr* arg); void add_watch(ineq& c, unsigned index); void del_watch(watch_list& watch, unsigned index, ineq& c, unsigned ineq_index); + void init_watch(bool_var v); void init_watch_literal(ineq& c); void init_watch_var(ineq& c); void clear_watch(ineq& c); @@ -242,6 +265,7 @@ namespace smt { std::ostream& display(std::ostream& out, ineq const& c, bool values = false) const; std::ostream& display(std::ostream& out, arg_t const& c, bool values = false) const; virtual void display(std::ostream& out) const; + void display_watch(std::ostream& out, bool_var v, bool sign) const; void display_resolved_lemma(std::ostream& out) const; void add_clause(ineq& c, literal_vector const& lits); From 1787fa82965414ae9d5fd6cb0be5c0bc2571f095 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 22 Dec 2016 20:54:09 -0800 Subject: [PATCH 445/536] remove redundant disjunction in compilation of at-most-1 constraints, log mutexes Signed-off-by: Nikolaj Bjorner --- src/opt/maxsmt.cpp | 1 + src/smt/theory_pb.cpp | 2 +- src/util/sorting_network.h | 61 +++++++++++++++++--------------------- 3 files changed, 30 insertions(+), 34 deletions(-) diff --git a/src/opt/maxsmt.cpp b/src/opt/maxsmt.cpp index 21537a570..f31009bbf 100644 --- a/src/opt/maxsmt.cpp +++ b/src/opt/maxsmt.cpp @@ -206,6 +206,7 @@ namespace opt { rational w = weights[i]; weight = w - weight; m_lower += weight*rational(i); + IF_VERBOSE(1, verbose_stream() << "(opt.maxsat mutex size: " << i + 1 << " weight: " << weight << ")\n";); sum2 += weight*rational(i+1); new_soft.insert(soft, weight); for (; i > 0 && weights[i-1] == w; --i) {} diff --git a/src/smt/theory_pb.cpp b/src/smt/theory_pb.cpp index a2f8ceba9..5dd870b48 100644 --- a/src/smt/theory_pb.cpp +++ b/src/smt/theory_pb.cpp @@ -518,7 +518,7 @@ namespace smt { ++log; n *= 2; } - unsigned th = args.size()*log; + unsigned th = args.size()*log*log; c->m_compilation_threshold = th; IF_VERBOSE(2, verbose_stream() << "(smt.pb setting compilation threshold to " << th << ")\n";); TRACE("pb", tout << "compilation threshold: " << th << "\n";); diff --git a/src/util/sorting_network.h b/src/util/sorting_network.h index 2c819db04..b0efbd346 100644 --- a/src/util/sorting_network.h +++ b/src/util/sorting_network.h @@ -164,11 +164,27 @@ Notes: struct stats { unsigned m_num_compiled_vars; unsigned m_num_compiled_clauses; + unsigned m_num_clause_vars; void reset() { memset(this, 0, sizeof(*this)); } stats() { reset(); } }; stats m_stats; + struct scoped_stats { + stats& m_stats; + stats m_save; + unsigned m_k, m_n; + scoped_stats(stats& st, unsigned k, unsigned n): m_stats(st), m_save(st), m_k(k), m_n(n) {} + ~scoped_stats() { + IF_VERBOSE(1, + verbose_stream() << "k: " << m_k << " n: " << m_n; + verbose_stream() << " clauses: " << m_stats.m_num_compiled_clauses - m_save.m_num_compiled_clauses; + verbose_stream() << " vars: " << m_stats.m_num_clause_vars - m_save.m_num_clause_vars; + verbose_stream() << " clauses: " << m_stats.m_num_compiled_clauses; + verbose_stream() << " vars: " << m_stats.m_num_clause_vars << "\n";); + } + }; + psort_nw(psort_expr& c): ctx(c) {} literal ge(bool full, unsigned k, unsigned n, literal const* xs) { @@ -186,6 +202,7 @@ Notes: else { SASSERT(2*k <= n); m_t = full?GE_FULL:GE; + // scoped_stats _ss(m_stats, k, n); psort_nw::card(k, n, xs, out); return out[k-1]; } @@ -202,11 +219,13 @@ Notes: } else if (k == 1) { literal_vector ors; - return mk_at_most_1(full, n, xs, ors); + // scoped_stats _ss(m_stats, k, n); + return mk_at_most_1(full, n, xs, ors, false); } else { SASSERT(2*k <= n); m_t = full?LE_FULL:LE; + // scoped_stats _ss(m_stats, k, n); card(k + 1, n, xs, out); return ctx.mk_not(out[k]); } @@ -222,9 +241,11 @@ Notes: return eq(full, k, n, in.c_ptr()); } else if (k == 1) { + // scoped_stats _ss(m_stats, k, n); return mk_exactly_1(full, n, xs); } else { + // scoped_stats _ss(m_stats, k, n); SASSERT(2*k <= n); m_t = EQ; card(k+1, n, xs, out); @@ -304,7 +325,7 @@ Notes: literal mk_exactly_1(bool full, unsigned n, literal const* xs) { literal_vector ors; - literal r1 = mk_at_most_1(full, n, xs, ors); + literal r1 = mk_at_most_1(full, n, xs, ors, true); if (full) { r1 = mk_and(r1, mk_or(ors)); @@ -315,8 +336,7 @@ Notes: return r1; } -#if 1 - literal mk_at_most_1(bool full, unsigned n, literal const* xs, literal_vector& ors) { + literal mk_at_most_1(bool full, unsigned n, literal const* xs, literal_vector& ors, bool use_ors) { TRACE("pb", tout << (full?"full":"partial") << " "; for (unsigned i = 0; i < n; ++i) tout << xs[i] << " "; tout << "\n";); @@ -336,7 +356,9 @@ Notes: for (unsigned i = 0; i < n; i += inc_size) { unsigned inc = std::min(n - i, inc_size); mk_at_most_1_small(full, inc, in.c_ptr() + i, result, ands); - ors.push_back(mk_or(inc, in.c_ptr() + i)); + if (use_ors || n > inc_size) { + ors.push_back(mk_or(inc, in.c_ptr() + i)); + } } if (n <= inc_size) { break; @@ -349,35 +371,7 @@ Notes: } return result; } -#else - literal mk_at_most_1(bool full, unsigned n, literal const* xs, literal_vector& ors) { - TRACE("pb", tout << (full?"full":"partial") << " "; - for (unsigned i = 0; i < n; ++i) tout << xs[i] << " "; - tout << "\n";); - literal_vector in(n, xs); - unsigned inc_size = 4; - literal_vector ands; - while (!in.empty()) { - ors.reset(); - unsigned i = 0; - unsigned n = in.size(); - if (n + 1 == inc_size) ++inc_size; - for (; i < n; i += inc_size) { - unsigned inc = std::min(inc_size, n - i); - ands.push_back(mk_at_most_1_small(inc, in.c_ptr() + i)); - ors.push_back(mk_or(inc, in.c_ptr() + i)); - } - if (n <= inc_size) { - break; - } - in.reset(); - in.append(ors); - } - return mk_and(ands); - } - -#endif void mk_at_most_1_small(bool full, unsigned n, literal const* xs, literal result, literal_vector& ands) { SASSERT(n > 0); if (n == 1) { @@ -562,6 +556,7 @@ Notes: } void add_clause(unsigned n, literal const* ls) { m_stats.m_num_compiled_clauses++; + m_stats.m_num_clause_vars += n; literal_vector tmp(n, ls); TRACE("pb", for (unsigned i = 0; i < n; ++i) tout << ls[i] << " "; tout << "\n";); ctx.mk_clause(n, tmp.c_ptr()); From c44dd0129282b4c18308c8079b53d65af562bd68 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 22 Dec 2016 20:56:14 -0800 Subject: [PATCH 446/536] fix missing else reported in #855 Signed-off-by: Nikolaj Bjorner --- src/api/z3_replayer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/z3_replayer.cpp b/src/api/z3_replayer.cpp index e5fbf5720..68f279e3d 100644 --- a/src/api/z3_replayer.cpp +++ b/src/api/z3_replayer.cpp @@ -357,7 +357,7 @@ struct z3_replayer::imp { v.push_back(static_cast(m_args[i].m_uint)); } } - if (k == INT64) { + else if (k == INT64) { aidx = m_int_arrays.size(); nk = INT_ARRAY; m_int_arrays.push_back(svector()); From 2bd29548dae911796863c02c5093c7f9d2f5da48 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 25 Dec 2016 17:27:56 -0800 Subject: [PATCH 447/536] improve parser error message over API, streamline names of statistics for arithmetic solver Signed-off-by: Nikolaj Bjorner --- src/api/api_opt.cpp | 4 ++++ src/opt/maxsmt.cpp | 6 ++++-- src/opt/opt_context.cpp | 6 +++++- src/opt/opt_solver.cpp | 1 + src/smt/arith_eq_adapter.cpp | 2 +- src/smt/theory_arith_core.h | 4 +++- src/smt/theory_arith_eq.h | 24 ++++++++++++++++++++---- src/smt/theory_arith_pp.h | 32 ++++++++++++++++---------------- 8 files changed, 54 insertions(+), 25 deletions(-) diff --git a/src/api/api_opt.cpp b/src/api/api_opt.cpp index 308db4081..3d8580178 100644 --- a/src/api/api_opt.cpp +++ b/src/api/api_opt.cpp @@ -289,6 +289,10 @@ extern "C" { //LOG_Z3_optimize_from_file(c, d, s); std::ifstream is(s); if (!is) { + std::ostringstream strm; + strm << "Could not open file " << s; + throw default_exception(strm.str()); + SET_ERROR_CODE(Z3_PARSER_ERROR); return; } diff --git a/src/opt/maxsmt.cpp b/src/opt/maxsmt.cpp index f31009bbf..97b6a5293 100644 --- a/src/opt/maxsmt.cpp +++ b/src/opt/maxsmt.cpp @@ -350,8 +350,10 @@ namespace opt { for (unsigned i = 0; i < m_soft_constraints.size(); ++i) { expr* e = m_soft_constraints[i]; bool is_not = m.is_not(e, e); - out << mk_pp(e, m) - << ((is_not != get_assignment(i))?" |-> true\n":" |-> false\n"); + out << m_weights[i] << ": " << mk_pp(e, m) + << ((is_not != get_assignment(i))?" |-> true ":" |-> false ") + << "\n"; + } } diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index e63e29dc5..46122d619 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -792,10 +792,14 @@ namespace opt { arg = mk_not(m, arg); offset -= weight; } - if (m.is_true(arg) || weight.is_zero()) { + if (m.is_true(arg)) { + IF_VERBOSE(1, verbose_stream() << weight << ": " << mk_pp(m_objectives[index].m_terms[i].get(), m) << " |-> true\n";); + } + else if (weight.is_zero()) { // skip } else if (m.is_false(arg)) { + IF_VERBOSE(1, verbose_stream() << weight << ": " << mk_pp(m_objectives[index].m_terms[i].get(), m) << " |-> false\n";); offset += weight; } else { diff --git a/src/opt/opt_solver.cpp b/src/opt/opt_solver.cpp index 42129be70..0d0c6d35a 100644 --- a/src/opt/opt_solver.cpp +++ b/src/opt/opt_solver.cpp @@ -47,6 +47,7 @@ namespace opt { m_first(true), m_was_unknown(false) { m_params.updt_params(p); + std::cout << "Case split strategy " << m_params.m_case_split_strategy << "\n"; if (m_params.m_case_split_strategy == CS_ACTIVITY_DELAY_NEW) { m_params.m_relevancy_lvl = 0; } diff --git a/src/smt/arith_eq_adapter.cpp b/src/smt/arith_eq_adapter.cpp index 411588d79..ce831f9ae 100644 --- a/src/smt/arith_eq_adapter.cpp +++ b/src/smt/arith_eq_adapter.cpp @@ -264,7 +264,7 @@ namespace smt { } void arith_eq_adapter::collect_statistics(::statistics & st) const { - st.update("eq adapter", m_stats.m_num_eq_axioms); + st.update("arith eq adapter", m_stats.m_num_eq_axioms); } void arith_eq_adapter::display_already_processed(std::ostream & out) const { diff --git a/src/smt/theory_arith_core.h b/src/smt/theory_arith_core.h index a8d771d1a..9db5e8c72 100644 --- a/src/smt/theory_arith_core.h +++ b/src/smt/theory_arith_core.h @@ -465,7 +465,7 @@ namespace smt { tout << s_ante << "\n" << s_conseq << "\n";); literal lits[2] = {l_ante, l_conseq}; - ctx.mk_th_axiom(get_id(), 2, lits); + mk_clause(l_ante, l_conseq, 0, 0); if (ctx.relevancy()) { if (l_ante == false_literal) { ctx.mark_as_relevant(l_conseq); @@ -934,11 +934,13 @@ namespace smt { template void theory_arith::mk_clause(literal l1, literal l2, unsigned num_params, parameter * params) { + TRACE("arith", literal lits[2]; lits[0] = l1; lits[1] = l2; get_context().display_literals_verbose(tout, 2, lits); tout << "\n";); get_context().mk_th_axiom(get_id(), l1, l2, num_params, params); } template void theory_arith::mk_clause(literal l1, literal l2, literal l3, unsigned num_params, parameter * params) { + TRACE("arith", literal lits[3]; lits[0] = l1; lits[1] = l2; lits[2] = l3; get_context().display_literals_verbose(tout, 3, lits); tout << "\n";); get_context().mk_th_axiom(get_id(), l1, l2, l3, num_params, params); } diff --git a/src/smt/theory_arith_eq.h b/src/smt/theory_arith_eq.h index 8577f3553..ae0f17757 100644 --- a/src/smt/theory_arith_eq.h +++ b/src/smt/theory_arith_eq.h @@ -44,6 +44,7 @@ namespace smt { SASSERT(lower_bound(v).is_rational()); numeral const & val = lower_bound(v).get_rational(); value_sort_pair key(val, is_int_src(v)); + TRACE("arith_eq", tout << mk_pp(get_enode(v)->get_owner(), get_manager()) << " = " << val << "\n";); theory_var v2; if (m_fixed_var_table.find(key, v2)) { if (v2 < static_cast(get_num_vars()) && is_fixed(v2) && lower_bound(v2).get_rational() == val) { @@ -247,6 +248,7 @@ namespace smt { // // x1 <= k1 x1 >= k1, x2 <= x1 + k2 x2 >= x1 + k2 // + TRACE("arith_eq_propagation", tout << "fixed\n";); lower(x2)->push_justification(ante, numeral::zero(), proofs_enabled()); upper(x2)->push_justification(ante, numeral::zero(), proofs_enabled()); m_stats.m_fixed_eqs++; @@ -324,28 +326,42 @@ namespace smt { template void theory_arith::propagate_eq_to_core(theory_var x, theory_var y, antecedents& antecedents) { // Ignore equality if variables are already known to be equal. + ast_manager& m = get_manager(); if (is_equal(x, y)) return; // I doesn't make sense to propagate an equality (to the core) of variables of different sort. - if (get_manager().get_sort(var2expr(x)) != get_manager().get_sort(var2expr(y))) { - TRACE("arith", tout << mk_pp(var2expr(x), get_manager()) << " = " << mk_pp(var2expr(y), get_manager()) << "\n";); + if (m.get_sort(var2expr(x)) != m.get_sort(var2expr(y))) { + TRACE("arith", tout << mk_pp(var2expr(x), m) << " = " << mk_pp(var2expr(y), m) << "\n";); return; } context & ctx = get_context(); region & r = ctx.get_region(); enode * _x = get_enode(x); enode * _y = get_enode(y); + eq_vector const& eqs = antecedents.eqs(); + literal_vector const& lits = antecedents.lits(); justification * js = ctx.mk_justification( ext_theory_eq_propagation_justification( get_id(), r, - antecedents.lits().size(), antecedents.lits().c_ptr(), - antecedents.eqs().size(), antecedents.eqs().c_ptr(), + lits.size(), lits.c_ptr(), + eqs.size(), eqs.c_ptr(), _x, _y, antecedents.num_params(), antecedents.params("eq-propagate"))); TRACE("arith_eq", tout << "detected equality: #" << _x->get_owner_id() << " = #" << _y->get_owner_id() << "\n"; display_var(tout, x); display_var(tout, y);); + TRACE("arith_eq_propagation", + for (unsigned i = 0; i < lits.size(); ++i) { + ctx.display_detailed_literal(tout, lits[i]); + tout << "\n"; + } + for (unsigned i = 0; i < eqs.size(); ++i) { + tout << mk_pp(eqs[i].first->get_owner(), m) << " = " << mk_pp(eqs[i].second->get_owner(), m) << "\n"; + } + tout << " ==> "; + tout << mk_pp(_x->get_owner(), m) << " = " << mk_pp(_y->get_owner(), m) << "\n"; + ); ctx.assign_eq(_x, _y, eq_justification(js)); } }; diff --git a/src/smt/theory_arith_pp.h b/src/smt/theory_arith_pp.h index ec14d8374..7b657d9c2 100644 --- a/src/smt/theory_arith_pp.h +++ b/src/smt/theory_arith_pp.h @@ -27,22 +27,22 @@ namespace smt { template void theory_arith::collect_statistics(::statistics & st) const { st.update("arith conflicts", m_stats.m_conflicts); - st.update("add rows", m_stats.m_add_rows); - st.update("pivots", m_stats.m_pivots); - st.update("assert lower", m_stats.m_assert_lower); - st.update("assert upper", m_stats.m_assert_upper); - st.update("assert diseq", m_stats.m_assert_diseq); - st.update("bound prop", m_stats.m_bound_props); - st.update("fixed eqs", m_stats.m_fixed_eqs); - st.update("offset eqs", m_stats.m_offset_eqs); - st.update("gcd tests", m_stats.m_gcd_tests); - st.update("ineq splits", m_stats.m_branches); - st.update("gomory cuts", m_stats.m_gomory_cuts); - st.update("max-min", m_stats.m_max_min); - st.update("grobner", m_stats.m_gb_compute_basis); - st.update("pseudo nonlinear", m_stats.m_nl_linear); - st.update("nonlinear bounds", m_stats.m_nl_bounds); - st.update("nonlinear horner", m_stats.m_nl_cross_nested); + st.update("arith add rows", m_stats.m_add_rows); + st.update("arith pivots", m_stats.m_pivots); + st.update("arith assert lower", m_stats.m_assert_lower); + st.update("arith assert upper", m_stats.m_assert_upper); + st.update("arith assert diseq", m_stats.m_assert_diseq); + st.update("arith bound prop", m_stats.m_bound_props); + st.update("arith fixed eqs", m_stats.m_fixed_eqs); + st.update("arith offset eqs", m_stats.m_offset_eqs); + st.update("arith gcd tests", m_stats.m_gcd_tests); + st.update("arith ineq splits", m_stats.m_branches); + st.update("arith gomory cuts", m_stats.m_gomory_cuts); + st.update("arith max-min", m_stats.m_max_min); + st.update("arith grobner", m_stats.m_gb_compute_basis); + st.update("arith pseudo nonlinear", m_stats.m_nl_linear); + st.update("arith nonlinear bounds", m_stats.m_nl_bounds); + st.update("arith nonlinear horner", m_stats.m_nl_cross_nested); m_arith_eq_adapter.collect_statistics(st); } From aaf6e67ec8aa10f07d700873a559b2cdf388cb0e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 25 Dec 2016 17:43:47 -0800 Subject: [PATCH 448/536] add restart.max parameter to control cancellation based on restart count Signed-off-by: Nikolaj Bjorner --- src/opt/opt_solver.cpp | 1 - src/sat/sat_config.cpp | 4 +++- src/sat/sat_config.h | 1 + src/sat/sat_params.pyg | 1 + src/sat/sat_solver.cpp | 9 ++++++++- src/sat/sat_solver.h | 1 + 6 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/opt/opt_solver.cpp b/src/opt/opt_solver.cpp index 0d0c6d35a..42129be70 100644 --- a/src/opt/opt_solver.cpp +++ b/src/opt/opt_solver.cpp @@ -47,7 +47,6 @@ namespace opt { m_first(true), m_was_unknown(false) { m_params.updt_params(p); - std::cout << "Case split strategy " << m_params.m_case_split_strategy << "\n"; if (m_params.m_case_split_strategy == CS_ACTIVITY_DELAY_NEW) { m_params.m_relevancy_lvl = 0; } diff --git a/src/sat/sat_config.cpp b/src/sat/sat_config.cpp index f976e1d71..58505f8ac 100644 --- a/src/sat/sat_config.cpp +++ b/src/sat/sat_config.cpp @@ -26,6 +26,7 @@ namespace sat { m_always_true("always_true"), m_always_false("always_false"), m_caching("caching"), + m_restart_max(0), m_random("random"), m_geometric("geometric"), m_luby("luby"), @@ -66,7 +67,8 @@ namespace sat { m_restart_initial = p.restart_initial(); m_restart_factor = p.restart_factor(); - + m_restart_max = p.restart_max(); + m_random_freq = p.random_freq(); m_random_seed = p.random_seed(); if (m_random_seed == 0) diff --git a/src/sat/sat_config.h b/src/sat/sat_config.h index 0234b5710..1cdabddef 100644 --- a/src/sat/sat_config.h +++ b/src/sat/sat_config.h @@ -52,6 +52,7 @@ namespace sat { restart_strategy m_restart; unsigned m_restart_initial; double m_restart_factor; // for geometric case + unsigned m_restart_max; double m_random_freq; unsigned m_random_seed; unsigned m_burst_search; diff --git a/src/sat/sat_params.pyg b/src/sat/sat_params.pyg index 90e715a9d..80e6f403f 100644 --- a/src/sat/sat_params.pyg +++ b/src/sat/sat_params.pyg @@ -7,6 +7,7 @@ def_module_params('sat', ('phase.caching.off', UINT, 100, 'phase caching off period (in number of conflicts)'), ('restart', SYMBOL, 'luby', 'restart strategy: luby or geometric'), ('restart.initial', UINT, 100, 'initial restart (number of conflicts)'), + ('restart.max', UINT, 0, 'maximal number of restarts. Ignored if set to 0'), ('restart.factor', DOUBLE, 1.5, 'restart increment factor for geometric strategy'), ('random_freq', DOUBLE, 0.01, 'frequency of random case splits'), ('random_seed', UINT, 0, 'random seed'), diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index e6fa15a4c..a5c9005df 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -744,7 +744,6 @@ namespace sat { simplify_problem(); if (check_inconsistent()) return l_false; - if (m_config.m_max_conflicts == 0) { IF_VERBOSE(SAT_VB_LVL, verbose_stream() << "(sat \"abort: max-conflicts = 0\")\n";); return l_undef; @@ -766,6 +765,12 @@ namespace sat { simplify_problem(); if (check_inconsistent()) return l_false; gc(); + + if (m_config.m_restart_max != 0 && m_config.m_restart_max <= m_restarts) { + IF_VERBOSE(SAT_VB_LVL, verbose_stream() << "(sat \"abort: max-restarts\")\n";); + return l_undef; + } + } } catch (abort_solver) { @@ -1126,6 +1131,7 @@ namespace sat { m_restart_threshold = m_config.m_restart_initial; m_luby_idx = 1; m_gc_threshold = m_config.m_gc_initial; + m_restarts = 0; m_min_d_tk = 1.0; m_stopwatch.reset(); m_stopwatch.start(); @@ -1308,6 +1314,7 @@ namespace sat { void solver::restart() { m_stats.m_restart++; + m_restarts++; IF_VERBOSE(1, verbose_stream() << "(sat-restart :conflicts " << m_stats.m_conflict << " :decisions " << m_stats.m_decision << " :restarts " << m_stats.m_restart << mk_stat(*this) diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index bcd9a66d2..aa45a1043 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -293,6 +293,7 @@ namespace sat { protected: unsigned m_conflicts; + unsigned m_restarts; unsigned m_conflicts_since_restart; unsigned m_restart_threshold; unsigned m_luby_idx; From 8dde60f6345bd12f3222546dd41ca9a22a6beee7 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 26 Dec 2016 10:18:55 -0800 Subject: [PATCH 449/536] initialize watch in assign_eh Signed-off-by: Nikolaj Bjorner --- src/smt/theory_pb.cpp | 1 + src/smt/theory_pb.h | 3 --- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/smt/theory_pb.cpp b/src/smt/theory_pb.cpp index 1f11b9bf5..1885fc9c4 100644 --- a/src/smt/theory_pb.cpp +++ b/src/smt/theory_pb.cpp @@ -772,6 +772,7 @@ namespace smt { void theory_pb::assign_eh(bool_var v, bool is_true) { ptr_vector* ineqs = 0; literal nlit(v, is_true); + init_watch(v); TRACE("pb", tout << "assign: " << ~nlit << "\n";); ineqs = m_var_infos[v].m_lit_watch[nlit.sign()]; if (ineqs != 0) { diff --git a/src/smt/theory_pb.h b/src/smt/theory_pb.h index 7f621f9c5..ee68bd26e 100644 --- a/src/smt/theory_pb.h +++ b/src/smt/theory_pb.h @@ -216,9 +216,6 @@ namespace smt { theory_pb_params m_params; svector m_var_infos; -// u_map m_lwatch; // per literal. -// u_map m_vwatch; // per variable. -// u_map m_ineqs; // per inequality. arg_map m_ineq_rep; // Simplex: representative inequality u_map m_ineq_row_info; // Simplex: row information per variable uint_set m_vars; // Simplex: 0-1 variables. From a4d5c4a00a06045ac2d960d19aa9aea156d78ca4 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 30 Dec 2016 18:05:19 -0800 Subject: [PATCH 450/536] make get_consequence call skip check-sat if a model is already there Signed-off-by: Nikolaj Bjorner --- src/sat/sat_solver.cpp | 14 +++++++++++++- src/sat/sat_solver/inc_sat_solver.cpp | 2 +- src/smt/theory_pb.cpp | 2 +- 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index a5c9005df..8a75e8dfc 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -123,6 +123,7 @@ namespace sat { // ----------------------- bool_var solver::mk_var(bool ext, bool dvar) { + m_model_is_current = false; m_stats.m_mk_var++; bool_var v = m_level.size(); m_watches.push_back(watch_list()); @@ -148,6 +149,7 @@ namespace sat { } void solver::mk_clause(unsigned num_lits, literal * lits) { + m_model_is_current = false; DEBUG_CODE({ for (unsigned i = 0; i < num_lits; i++) SASSERT(m_eliminated[lits[i].var()] == false); @@ -3118,7 +3120,11 @@ namespace sat { lbool solver::get_consequences(literal_vector const& asms, bool_var_vector const& vars, vector& conseq) { literal_vector lits; - lbool is_sat = check(asms.size(), asms.c_ptr()); + lbool is_sat = l_true; + + if (!m_model_is_current) { + is_sat = check(asms.size(), asms.c_ptr()); + } if (is_sat != l_true) { return is_sat; } @@ -3212,6 +3218,12 @@ namespace sat { << " unfixed: " << lits.size() - conseq.size() - vars.size() << ")\n";); + if (!vars.empty() && + m_config.m_restart_max != 0 && + m_config.m_restart_max <= num_iterations) { + return l_undef; + } + } return l_true; } diff --git a/src/sat/sat_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp index e3a220cd2..6d3a5b552 100644 --- a/src/sat/sat_solver/inc_sat_solver.cpp +++ b/src/sat/sat_solver/inc_sat_solver.cpp @@ -257,7 +257,7 @@ public: r = internalize_vars(vars, bvars); r = m_solver.get_consequences(m_asms, bvars, lconseq); - if (r != l_true) return r; + if (r == l_false) return r; // build map from bound variables to // the consequences that cover them. diff --git a/src/smt/theory_pb.cpp b/src/smt/theory_pb.cpp index 1885fc9c4..507cb6d43 100644 --- a/src/smt/theory_pb.cpp +++ b/src/smt/theory_pb.cpp @@ -1752,7 +1752,7 @@ namespace smt { // verbose_stream() << "(pb.conflict min size: " << l_size << ")\n"; // s_min_l_size = l_size; //} - //IF_VERBOSE(1, verbose_stream() << "(pb.conflict " << m_ineq_literals.size() << " " << m_lemma.size() << "\n";); + IF_VERBOSE(1, verbose_stream() << "(pb.conflict " << m_ineq_literals.size() << " " << m_lemma.size() << ")\n";); switch(is_true) { case l_true: UNREACHABLE(); From 74d3de01b3ef16d59d316c84b49f30a3e4a683b2 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 2 Jan 2017 10:07:02 -0800 Subject: [PATCH 451/536] enable incremental consequence finding with restart timeout Signed-off-by: Nikolaj Bjorner --- src/sat/sat_params.pyg | 2 +- src/sat/sat_solver.cpp | 146 ++++++++++++++++++++++---- src/sat/sat_solver.h | 12 ++- src/sat/sat_solver/inc_sat_solver.cpp | 11 +- 4 files changed, 141 insertions(+), 30 deletions(-) diff --git a/src/sat/sat_params.pyg b/src/sat/sat_params.pyg index 80e6f403f..de1759486 100644 --- a/src/sat/sat_params.pyg +++ b/src/sat/sat_params.pyg @@ -7,7 +7,7 @@ def_module_params('sat', ('phase.caching.off', UINT, 100, 'phase caching off period (in number of conflicts)'), ('restart', SYMBOL, 'luby', 'restart strategy: luby or geometric'), ('restart.initial', UINT, 100, 'initial restart (number of conflicts)'), - ('restart.max', UINT, 0, 'maximal number of restarts. Ignored if set to 0'), + ('restart.max', UINT, UINT_MAX, 'maximal number of restarts.'), ('restart.factor', DOUBLE, 1.5, 'restart increment factor for geometric strategy'), ('random_freq', DOUBLE, 0.01, 'frequency of random case splits'), ('random_seed', UINT, 0, 'random seed'), diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 8a75e8dfc..5c004b1a2 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -768,7 +768,7 @@ namespace sat { if (check_inconsistent()) return l_false; gc(); - if (m_config.m_restart_max != 0 && m_config.m_restart_max <= m_restarts) { + if (m_config.m_restart_max <= m_restarts) { IF_VERBOSE(SAT_VB_LVL, verbose_stream() << "(sat \"abort: max-restarts\")\n";); return l_undef; } @@ -3122,6 +3122,9 @@ namespace sat { literal_vector lits; lbool is_sat = l_true; + if (m_config.m_restart_max != UINT_MAX && !m_model_is_current) { + return get_bounded_consequences(asms, vars, conseq); + } if (!m_model_is_current) { is_sat = check(asms.size(), asms.c_ptr()); } @@ -3142,9 +3145,89 @@ namespace sat { return is_sat; } + void solver::fixup_consequence_core() { + index_set s; + for (unsigned i = 0; i < m_core.size(); ++i) { + s |= m_antecedents.find(m_core[i].var()); + } + m_core.reset(); + index_set::iterator it = s.begin(), end = s.end(); + for (; it != end; ++it) { + m_core.push_back(to_literal(*it)); + } + } + + + lbool solver::get_bounded_consequences(literal_vector const& asms, bool_var_vector const& vars, vector& conseq) { + bool_var_set unfixed_vars; + unsigned num_units = 0, num_iterations = 0; + for (unsigned i = 0; i < vars.size(); ++i) { + unfixed_vars.insert(vars[i]); + } + m_antecedents.reset(); + pop_to_base_level(); + if (inconsistent()) return l_false; + init_search(); + propagate(false); + if (inconsistent()) return l_false; + if (asms.empty()) { + bool_var v = mk_var(true, false); + literal lit(v, false); + init_assumptions(1, &lit, 0, 0); + } + else { + init_assumptions(asms.size(), asms.c_ptr(), 0, 0); + } + propagate(false); + if (check_inconsistent()) return l_false; + + extract_fixed_consequences(num_units, asms, unfixed_vars, conseq); + + simplify_problem(); + if (check_inconsistent()) { + fixup_consequence_core(); + return l_false; + } + + while (true) { + ++num_iterations; + SASSERT(!inconsistent()); + + lbool r = bounded_search(); + if (r != l_undef) { + fixup_consequence_core(); + return r; + } + + extract_fixed_consequences(num_units, asms, unfixed_vars, conseq); + + if (m_conflicts > m_config.m_max_conflicts) { + IF_VERBOSE(SAT_VB_LVL, verbose_stream() << "(sat \"abort: max-conflicts = " << m_conflicts << "\")\n";); + return l_undef; + } + + restart(); + simplify_problem(); + if (check_inconsistent()) { + fixup_consequence_core(); + return l_false; + } + gc(); + + if (m_config.m_restart_max <= num_iterations) { + IF_VERBOSE(SAT_VB_LVL, verbose_stream() << "(sat \"abort: max-restarts\")\n";); + return l_undef; + } + } + } + lbool solver::get_consequences(literal_vector const& asms, literal_vector const& lits, vector& conseq) { m_antecedents.reset(); - literal_set vars(lits), assumptions(asms); + literal_set unfixed_lits(lits), assumptions(asms); + bool_var_set unfixed_vars; + for (unsigned i = 0; i < lits.size(); ++i) { + unfixed_vars.insert(lits[i].var()); + } pop_to_base_level(); if (inconsistent()) return l_false; @@ -3163,11 +3246,15 @@ namespace sat { if (check_inconsistent()) return l_false; unsigned num_units = 0, num_iterations = 0; - extract_fixed_consequences(num_units, assumptions, vars, conseq); - while (!vars.empty()) { + extract_fixed_consequences(num_units, assumptions, unfixed_vars, conseq); + update_unfixed_literals(unfixed_lits, unfixed_vars); + while (!unfixed_lits.empty()) { + if (scope_lvl() > 1) { + pop(scope_lvl() - 1); + } ++num_iterations; checkpoint(); - literal_set::iterator it = vars.begin(), end = vars.end(); + literal_set::iterator it = unfixed_lits.begin(), end = unfixed_lits.end(); unsigned num_resolves = 0; lbool is_sat = l_true; for (; it != end; ++it) { @@ -3208,45 +3295,58 @@ namespace sat { m_inconsistent = false; } if (is_sat == l_true) { - delete_unfixed(vars); + delete_unfixed(unfixed_lits, unfixed_vars); } - extract_fixed_consequences(num_units, assumptions, vars, conseq); + extract_fixed_consequences(num_units, assumptions, unfixed_vars, conseq); + update_unfixed_literals(unfixed_lits, unfixed_vars); IF_VERBOSE(1, verbose_stream() << "(sat.get-consequences" << " iterations: " << num_iterations - << " variables: " << vars.size() + << " variables: " << unfixed_lits.size() << " fixed: " << conseq.size() - << " unfixed: " << lits.size() - conseq.size() - vars.size() + << " unfixed: " << lits.size() - conseq.size() - unfixed_lits.size() << ")\n";); - if (!vars.empty() && - m_config.m_restart_max != 0 && - m_config.m_restart_max <= num_iterations) { + if (!unfixed_lits.empty() && m_config.m_restart_max <= num_iterations) { return l_undef; } - } return l_true; } - void solver::delete_unfixed(literal_set& unfixed) { + void solver::delete_unfixed(literal_set& unfixed_lits, bool_var_set& unfixed_vars) { literal_set to_keep; - literal_set::iterator it = unfixed.begin(), end = unfixed.end(); + literal_set::iterator it = unfixed_lits.begin(), end = unfixed_lits.end(); for (; it != end; ++it) { literal lit = *it; if (value(lit) == l_true) { to_keep.insert(lit); } + else { + unfixed_vars.remove(lit.var()); + } } - unfixed = to_keep; + unfixed_lits = to_keep; } - void solver::extract_fixed_consequences(unsigned& start, literal_set const& assumptions, literal_set& unfixed, vector& conseq) { - if (scope_lvl() > 1) { - pop(scope_lvl() - 1); + void solver::update_unfixed_literals(literal_set& unfixed_lits, bool_var_set& unfixed_vars) { + literal_vector to_delete; + literal_set::iterator it = unfixed_lits.begin(), end = unfixed_lits.end(); + for (; it != end; ++it) { + literal lit = *it; + if (!unfixed_vars.contains(lit.var())) { + to_delete.push_back(lit); + } } + for (unsigned i = 0; i < to_delete.size(); ++i) { + unfixed_lits.remove(to_delete[i]); + } + } + + + void solver::extract_fixed_consequences(unsigned& start, literal_set const& assumptions, bool_var_set& unfixed, vector& conseq) { SASSERT(!inconsistent()); unsigned sz = m_trail.size(); - for (unsigned i = start; i < sz; ++i) { + for (unsigned i = start; i < sz && lvl(m_trail[i]) <= 1; ++i) { extract_fixed_consequences(m_trail[i], assumptions, unfixed, conseq); } start = sz; @@ -3288,7 +3388,7 @@ namespace sat { } } - void solver::extract_fixed_consequences(literal lit, literal_set const& assumptions, literal_set& unfixed, vector& conseq) { + void solver::extract_fixed_consequences(literal lit, literal_set const& assumptions, bool_var_set& unfixed, vector& conseq) { index_set s; if (assumptions.contains(lit)) { s.insert(lit.index()); @@ -3298,14 +3398,14 @@ namespace sat { extract_assumptions(lit, s); } m_antecedents.insert(lit.var(), s); - if (unfixed.contains(lit)) { + if (unfixed.contains(lit.var())) { literal_vector cons; cons.push_back(lit); index_set::iterator it = s.begin(), end = s.end(); for (; it != end; ++it) { cons.push_back(to_literal(*it)); } - unfixed.remove(lit); + unfixed.remove(lit.var()); conseq.push_back(cons); } } diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index aa45a1043..a9037c65a 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -457,11 +457,17 @@ namespace sat { lbool get_consequences(literal_vector const& assms, literal_vector const& lits, vector& conseq); - void delete_unfixed(literal_set& unfixed); + lbool get_bounded_consequences(literal_vector const& assms, bool_var_vector const& vars, vector& conseq); - void extract_fixed_consequences(unsigned& start, literal_set const& assumptions, literal_set& unfixed, vector& conseq); + void delete_unfixed(literal_set& unfixed_lits, bool_var_set& unfixed_vars); - void extract_fixed_consequences(literal lit, literal_set const& assumptions, literal_set& unfixed, vector& conseq); + void extract_fixed_consequences(unsigned& start, literal_set const& assumptions, bool_var_set& unfixed, vector& conseq); + + void extract_fixed_consequences(literal lit, literal_set const& assumptions, bool_var_set& unfixed, vector& conseq); + + void update_unfixed_literals(literal_set& unfixed_lits, bool_var_set& unfixed_vars); + + void fixup_consequence_core(); // ----------------------- // diff --git a/src/sat/sat_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp index 6d3a5b552..b7ce92108 100644 --- a/src/sat/sat_solver/inc_sat_solver.cpp +++ b/src/sat/sat_solver/inc_sat_solver.cpp @@ -252,12 +252,17 @@ public: m_solver.pop_to_base_level(); lbool r = internalize_formulas(); if (r != l_true) return r; + r = internalize_vars(vars, bvars); + if (r != l_true) return r; r = internalize_assumptions(assumptions.size(), assumptions.c_ptr(), dep2asm); if (r != l_true) return r; - r = internalize_vars(vars, bvars); - r = m_solver.get_consequences(m_asms, bvars, lconseq); - if (r == l_false) return r; + if (r == l_false) { + if (!m_asms.empty()) { + extract_core(dep2asm); + } + return r; + } // build map from bound variables to // the consequences that cover them. From cb75a55095bc33cce8da48d9f80910e36f90c3d8 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Tue, 3 Jan 2017 13:41:08 +0000 Subject: [PATCH 452/536] Fixed initialization order warning. --- src/sat/sat_config.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sat/sat_config.cpp b/src/sat/sat_config.cpp index 58505f8ac..7e0a7c50c 100644 --- a/src/sat/sat_config.cpp +++ b/src/sat/sat_config.cpp @@ -23,10 +23,10 @@ Revision History: namespace sat { config::config(params_ref const & p): + m_restart_max(0), m_always_true("always_true"), m_always_false("always_false"), m_caching("caching"), - m_restart_max(0), m_random("random"), m_geometric("geometric"), m_luby("luby"), From ae9a3bfc241ce9490d74aa8af4916195deadfe81 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 4 Jan 2017 09:14:09 -0800 Subject: [PATCH 453/536] add operator for issue #860 Signed-off-by: Nikolaj Bjorner --- src/api/api_ast.cpp | 3 ++- src/api/dotnet/Solver.cs | 9 +++++++++ src/api/z3_api.h | 1 + 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/api/api_ast.cpp b/src/api/api_ast.cpp index efa3ec098..08a931fdc 100644 --- a/src/api/api_ast.cpp +++ b/src/api/api_ast.cpp @@ -1063,9 +1063,10 @@ 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_BIT2BOOL: return Z3_OP_BIT2BOOL; 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_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; diff --git a/src/api/dotnet/Solver.cs b/src/api/dotnet/Solver.cs index 8cb7670d7..dff2677df 100644 --- a/src/api/dotnet/Solver.cs +++ b/src/api/dotnet/Solver.cs @@ -18,6 +18,7 @@ Notes: --*/ using System; +using System.Linq; using System.Collections.Generic; using System.Diagnostics.Contracts; @@ -126,6 +127,14 @@ namespace Microsoft.Z3 Assert(constraints); } + /// + /// Alias for Assert. + /// + public void Add(IEnumerable constraints) + { + Assert(constraints.ToArray()); + } + /// /// Assert multiple constraints into the solver, and track them (in the unsat) core /// using the Boolean constants in ps. diff --git a/src/api/z3_api.h b/src/api/z3_api.h index 356f933d4..b80ce3177 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -1060,6 +1060,7 @@ typedef enum { Z3_OP_EXT_ROTATE_LEFT, Z3_OP_EXT_ROTATE_RIGHT, + Z3_OP_BIT2BOOL, Z3_OP_INT2BV, Z3_OP_BV2INT, Z3_OP_CARRY, From ddf4bc548f9ae50c849ff2a50ba9466525193f1e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 4 Jan 2017 19:04:43 -0800 Subject: [PATCH 454/536] allow disabling exceptions from C++. Issue #861 Signed-off-by: Nikolaj Bjorner --- src/api/c++/z3++.h | 37 ++++++++++++++++++++++++++----------- 1 file changed, 26 insertions(+), 11 deletions(-) diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index 86dc77ad5..3f1ed614f 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -132,16 +132,19 @@ namespace z3 { \brief A Context manages all other Z3 objects, global configuration options, etc. */ class context { + bool m_enable_exceptions; Z3_context m_ctx; static void error_handler(Z3_context /*c*/, Z3_error_code /*e*/) { /* do nothing */ } void init(config & c) { m_ctx = Z3_mk_context_rc(c); + m_enable_exceptions = true; Z3_set_error_handler(m_ctx, error_handler); Z3_set_ast_print_mode(m_ctx, Z3_PRINT_SMTLIB2_COMPLIANT); } void init_interp(config & c) { m_ctx = Z3_mk_interpolation_context(c); + m_enable_exceptions = true; Z3_set_error_handler(m_ctx, error_handler); Z3_set_ast_print_mode(m_ctx, Z3_PRINT_SMTLIB2_COMPLIANT); } @@ -159,12 +162,24 @@ namespace z3 { /** \brief Auxiliary method used to check for API usage errors. */ - void check_error() const { + Z3_error_code check_error() const { Z3_error_code e = Z3_get_error_code(m_ctx); - if (e != Z3_OK) + if (e != Z3_OK && enable_exceptions()) throw exception(Z3_get_error_msg(m_ctx, e)); + return e; } + /** + \brief The C++ API uses by defaults exceptions on errors. + For applications that don't work well with exceptions (there should be only few) + you have the ability to turn off exceptions. The tradeoffs are that applications + have to very careful about using check_error() after calls that may result in an errornous + state. + */ + void set_enable_exceptions(bool f) { m_enable_exceptions = f; } + + bool enable_exceptions() const { return m_enable_exceptions; } + /** \brief Update global parameter \c param with string \c value. */ @@ -676,8 +691,8 @@ namespace z3 { \pre is_numeral() */ int get_numeral_int() const { - int result; - if (!is_numeral_i(result)) { + int result = 0; + if (!is_numeral_i(result) && ctx().enable_exceptions()) { throw exception("numeral does not fit in machine int"); } return result; @@ -691,8 +706,8 @@ namespace z3 { */ unsigned get_numeral_uint() const { assert(is_numeral()); - unsigned result; - if (!is_numeral_u(result)) { + unsigned result = 0; + if (!is_numeral_u(result) && ctx().enable_exceptions()) { throw exception("numeral does not fit in machine uint"); } return result; @@ -706,8 +721,8 @@ namespace z3 { */ __int64 get_numeral_int64() const { assert(is_numeral()); - __int64 result; - if (!is_numeral_i64(result)) { + __int64 result = 0; + if (!is_numeral_i64(result) && ctx().enable_exceptions()) { throw exception("numeral does not fit in machine __int64"); } return result; @@ -721,8 +736,8 @@ namespace z3 { */ __uint64 get_numeral_uint64() const { assert(is_numeral()); - __uint64 result; - if (!is_numeral_u64(result)) { + __uint64 result = 0; + if (!is_numeral_u64(result) && ctx().enable_exceptions()) { throw exception("numeral does not fit in machine __uint64"); } return result; @@ -1615,7 +1630,7 @@ namespace z3 { Z3_ast r = 0; Z3_bool status = Z3_model_eval(ctx(), m_model, n, model_completion, &r); check_error(); - if (status == Z3_FALSE) + if (status == Z3_FALSE && ctx().enable_exceptions()) throw exception("failed to evaluate expression"); return expr(ctx(), r); } From e9edcdc6e6b2fb08a2b1959d8e583fabba5cbd26 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 5 Jan 2017 16:09:16 -0500 Subject: [PATCH 455/536] moderate exception behavior for issue #861 Signed-off-by: Nikolaj Bjorner --- src/api/c++/z3++.h | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index 3f1ed614f..1556064d6 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -345,7 +345,7 @@ namespace z3 { object(context & c):m_ctx(&c) {} object(object const & s):m_ctx(s.m_ctx) {} context & ctx() const { return *m_ctx; } - void check_error() const { m_ctx->check_error(); } + Z3_error_code check_error() const { return m_ctx->check_error(); } friend void check_context(object const & a, object const & b); }; inline void check_context(object const & a, object const & b) { assert(a.m_ctx == b.m_ctx); } @@ -687,12 +687,18 @@ namespace z3 { /** \brief Return int value of numeral, throw if result cannot fit in machine int + + It only makes sense to use this function if the caller can ensure that + the result is an integer or if exceptions are enabled. + If exceptions are disabled, then use the the is_numeral_i function. \pre is_numeral() */ int get_numeral_int() const { int result = 0; - if (!is_numeral_i(result) && ctx().enable_exceptions()) { + if (!is_numeral_i(result)) { + assert(ctx().enable_exceptions()); + if (!ctx().enable_exceptions()) return 0; throw exception("numeral does not fit in machine int"); } return result; @@ -701,13 +707,18 @@ namespace z3 { /** \brief Return uint value of numeral, throw if result cannot fit in machine uint - + + It only makes sense to use this function if the caller can ensure that + the result is an integer or if exceptions are enabled. + If exceptions are disabled, then use the the is_numeral_u function. \pre is_numeral() */ unsigned get_numeral_uint() const { assert(is_numeral()); unsigned result = 0; - if (!is_numeral_u(result) && ctx().enable_exceptions()) { + if (!is_numeral_u(result)) { + assert(ctx().enable_exceptions()); + if (!ctx().enable_exceptions()) return 0; throw exception("numeral does not fit in machine uint"); } return result; @@ -722,7 +733,9 @@ namespace z3 { __int64 get_numeral_int64() const { assert(is_numeral()); __int64 result = 0; - if (!is_numeral_i64(result) && ctx().enable_exceptions()) { + if (!is_numeral_i64(result)) { + assert(ctx().enable_exceptions()); + if (!ctx().enable_exceptions()) return 0; throw exception("numeral does not fit in machine __int64"); } return result; @@ -737,7 +750,9 @@ namespace z3 { __uint64 get_numeral_uint64() const { assert(is_numeral()); __uint64 result = 0; - if (!is_numeral_u64(result) && ctx().enable_exceptions()) { + if (!is_numeral_u64(result)) { + assert(ctx().enable_exceptions()); + if (!ctx().enable_exceptions()) return 0; throw exception("numeral does not fit in machine __uint64"); } return result; From c69a86e647c65ac5c01daa63fc4ed666f0411fc7 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 6 Jan 2017 19:34:50 -0500 Subject: [PATCH 456/536] fix bug in antecedent collection for consequence finding: once an antecedent is set, it should not be cleared Signed-off-by: Nikolaj Bjorner --- src/sat/sat_solver.cpp | 26 ++++++++++++++++++++++++++ src/sat/sat_solver.h | 2 ++ 2 files changed, 28 insertions(+) diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 5c004b1a2..10c97b296 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -1114,6 +1114,13 @@ namespace sat { for (unsigned i = 0; !inconsistent() && i < m_assumptions.size(); ++i) { assign(m_assumptions[i], justification()); } + TRACE("sat", + for (unsigned i = 0; i < m_assumptions.size(); ++i) { + index_set s; + if (m_antecedents.find(m_assumptions[i].var(), s)) { + tout << m_assumptions[i] << ": "; display_index_set(tout, s) << "\n"; + } + }); } } @@ -3147,7 +3154,9 @@ namespace sat { void solver::fixup_consequence_core() { index_set s; + TRACE("sat", tout << m_core << "\n";); for (unsigned i = 0; i < m_core.size(); ++i) { + TRACE("sat", tout << m_core[i] << ": "; display_index_set(tout, m_antecedents.find(m_core[i].var())) << "\n";); s |= m_antecedents.find(m_core[i].var()); } m_core.reset(); @@ -3155,6 +3164,7 @@ namespace sat { for (; it != end; ++it) { m_core.push_back(to_literal(*it)); } + TRACE("sat", tout << m_core << "\n";); } @@ -3164,6 +3174,7 @@ namespace sat { for (unsigned i = 0; i < vars.size(); ++i) { unfixed_vars.insert(vars[i]); } + TRACE("sat", tout << asms << "\n";); m_antecedents.reset(); pop_to_base_level(); if (inconsistent()) return l_false; @@ -3222,6 +3233,7 @@ namespace sat { } lbool solver::get_consequences(literal_vector const& asms, literal_vector const& lits, vector& conseq) { + TRACE("sat", tout << asms << "\n";); m_antecedents.reset(); literal_set unfixed_lits(lits), assumptions(asms); bool_var_set unfixed_vars; @@ -3386,10 +3398,24 @@ namespace sat { UNREACHABLE(); break; } + TRACE("sat", display_index_set(tout << lit << ": " , s) << "\n";); } + std::ostream& solver::display_index_set(std::ostream& out, index_set const& s) const { + index_set::iterator it = s.begin(); + index_set::iterator end = s.end(); + for (; it != end; ++it) { + out << to_literal(*it) << " "; + } + return out; + } + + void solver::extract_fixed_consequences(literal lit, literal_set const& assumptions, bool_var_set& unfixed, vector& conseq) { index_set s; + if (m_antecedents.contains(lit.var())) { + return; + } if (assumptions.contains(lit)) { s.insert(lit.index()); } diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index a9037c65a..1700dfb7e 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -455,6 +455,8 @@ namespace sat { void extract_assumptions(literal lit, index_set& s); + std::ostream& display_index_set(std::ostream& out, index_set const& s) const; + lbool get_consequences(literal_vector const& assms, literal_vector const& lits, vector& conseq); lbool get_bounded_consequences(literal_vector const& assms, bool_var_vector const& vars, vector& conseq); From 8d09b6e4a8f241d77105f62d77a6a2c47daaab10 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 9 Jan 2017 21:23:00 -0800 Subject: [PATCH 457/536] add at-least and pbge to API, fix for issue #864 Signed-off-by: Nikolaj Bjorner --- src/api/api_ast.cpp | 2 + src/api/api_pb.cpp | 32 +++++++++++++++ src/api/dotnet/Context.cs | 26 ++++++++++++ src/api/python/z3/z3.py | 61 ++++++++++++++--------------- src/api/z3_api.h | 28 +++++++++++++ src/smt/smt_bool_var_data.h | 10 +++++ src/smt/smt_conflict_resolution.cpp | 27 +++++++++---- src/smt/smt_context.cpp | 22 +++++++---- src/smt/smt_context.h | 6 ++- src/smt/smt_context_inv.cpp | 14 +++++++ src/smt/smt_literal.cpp | 2 + 11 files changed, 182 insertions(+), 48 deletions(-) diff --git a/src/api/api_ast.cpp b/src/api/api_ast.cpp index 08a931fdc..fd2776079 100644 --- a/src/api/api_ast.cpp +++ b/src/api/api_ast.cpp @@ -1211,7 +1211,9 @@ extern "C" { switch(_d->get_decl_kind()) { case OP_PB_LE: return Z3_OP_PB_LE; case OP_PB_GE: return Z3_OP_PB_GE; + case OP_PB_EQ: return Z3_OP_PB_EQ; case OP_AT_MOST_K: return Z3_OP_PB_AT_MOST; + case OP_AT_LEAST_K: return Z3_OP_PB_AT_LEAST; default: return Z3_OP_INTERNAL; } } diff --git a/src/api/api_pb.cpp b/src/api/api_pb.cpp index b7c28c34f..ee504146f 100644 --- a/src/api/api_pb.cpp +++ b/src/api/api_pb.cpp @@ -39,6 +39,20 @@ extern "C" { } + Z3_ast Z3_API Z3_mk_atleast(Z3_context c, unsigned num_args, + Z3_ast const args[], unsigned k) { + Z3_TRY; + LOG_Z3_mk_atmost(c, num_args, args, k); + RESET_ERROR_CODE(); + parameter param(k); + pb_util util(mk_c(c)->m()); + ast* a = util.mk_at_least_k(num_args, to_exprs(args), k); + mk_c(c)->save_ast_trail(a); + check_sorts(c, a); + RETURN_Z3(of_ast(a)); + Z3_CATCH_RETURN(0); + } + Z3_ast Z3_API Z3_mk_pble(Z3_context c, unsigned num_args, Z3_ast const args[], int _coeffs[], int k) { @@ -57,6 +71,24 @@ extern "C" { Z3_CATCH_RETURN(0); } + Z3_ast Z3_API Z3_mk_pbge(Z3_context c, unsigned num_args, + Z3_ast const args[], int _coeffs[], + int k) { + Z3_TRY; + LOG_Z3_mk_pble(c, num_args, args, _coeffs, k); + RESET_ERROR_CODE(); + pb_util util(mk_c(c)->m()); + vector coeffs; + for (unsigned i = 0; i < num_args; ++i) { + coeffs.push_back(rational(_coeffs[i])); + } + ast* a = util.mk_ge(num_args, coeffs.c_ptr(), to_exprs(args), rational(k)); + mk_c(c)->save_ast_trail(a); + check_sorts(c, a); + RETURN_Z3(of_ast(a)); + Z3_CATCH_RETURN(0); + } + Z3_ast Z3_API Z3_mk_pbeq(Z3_context c, unsigned num_args, Z3_ast const args[], int _coeffs[], int k) { diff --git a/src/api/dotnet/Context.cs b/src/api/dotnet/Context.cs index f12ad58ea..f5c4dc99d 100644 --- a/src/api/dotnet/Context.cs +++ b/src/api/dotnet/Context.cs @@ -2692,6 +2692,18 @@ namespace Microsoft.Z3 AST.ArrayToNative(args), k)); } + /// + /// Create an at-least-k constraint. + /// + public BoolExpr MkAtLeast(BoolExpr[] args, uint k) + { + Contract.Requires(args != null); + Contract.Requires(Contract.Result() != null); + CheckContextMatch(args); + return new BoolExpr(this, Native.Z3_mk_atleast(nCtx, (uint) args.Length, + AST.ArrayToNative(args), k)); + } + /// /// Create a pseudo-Boolean less-or-equal constraint. /// @@ -2707,6 +2719,20 @@ namespace Microsoft.Z3 coeffs, k)); } + /// + /// Create a pseudo-Boolean greater-or-equal constraint. + /// + public BoolExpr MkPBGe(int[] coeffs, BoolExpr[] args, int k) + { + Contract.Requires(args != null); + Contract.Requires(coeffs != null); + Contract.Requires(args.Length == coeffs.Length); + Contract.Requires(Contract.Result() != null); + CheckContextMatch(args); + return new BoolExpr(this, Native.Z3_mk_pbge(nCtx, (uint) args.Length, + AST.ArrayToNative(args), + coeffs, k)); + } /// /// Create a pseudo-Boolean equal constraint. /// diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index 22b2f60e6..01dacace7 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -7617,11 +7617,6 @@ def AtLeast(*args): >>> a, b, c = Bools('a b c') >>> f = AtLeast(a, b, c, 2) """ - def mk_not(a): - if is_not(a): - return a.arg(0) - else: - return Not(a) args = _get_args(args) if __debug__: _z3_assert(len(args) > 1, "Non empty list of arguments expected") @@ -7629,10 +7624,25 @@ def AtLeast(*args): if __debug__: _z3_assert(ctx is not None, "At least one of the arguments must be a Z3 expression") args1 = _coerce_expr_list(args[:-1], ctx) - args1 = [ mk_not(a) for a in args1 ] - k = len(args1) - args[-1] + k = args[-1] _args, sz = _to_ast_array(args1) - return BoolRef(Z3_mk_atmost(ctx.ref(), sz, _args, k), ctx) + return BoolRef(Z3_mk_atleast(ctx.ref(), sz, _args, k), ctx) + + +def _pb_args_coeffs(args): + args = _get_args(args) + args, coeffs = zip(*args) + if __debug__: + _z3_assert(len(args) > 0, "Non empty list of arguments expected") + ctx = _ctx_from_ast_arg_list(args) + if __debug__: + _z3_assert(ctx is not None, "At least one of the arguments must be a Z3 expression") + args = _coerce_expr_list(args, ctx) + _args, sz = _to_ast_array(args) + _coeffs = (ctypes.c_int * len(coeffs))() + for i in range(len(coeffs)): + _coeffs[i] = coeffs[i] + return ctx, sz, _args, _coeffs def PbLe(args, k): """Create a Pseudo-Boolean inequality k constraint. @@ -7640,38 +7650,25 @@ def PbLe(args, k): >>> a, b, c = Bools('a b c') >>> f = PbLe(((a,1),(b,3),(c,2)), 3) """ - args = _get_args(args) - args, coeffs = zip(*args) - if __debug__: - _z3_assert(len(args) > 0, "Non empty list of arguments expected") - ctx = _ctx_from_ast_arg_list(args) - if __debug__: - _z3_assert(ctx is not None, "At least one of the arguments must be a Z3 expression") - args = _coerce_expr_list(args, ctx) - _args, sz = _to_ast_array(args) - _coeffs = (ctypes.c_int * len(coeffs))() - for i in range(len(coeffs)): - _coeffs[i] = coeffs[i] + ctx, sz, _args, _coeffs = _pb_args_coeffs(args) return BoolRef(Z3_mk_pble(ctx.ref(), sz, _args, _coeffs, k), ctx) +def PbGe(args, k): + """Create a Pseudo-Boolean inequality k constraint. + + >>> a, b, c = Bools('a b c') + >>> f = PbGe(((a,1),(b,3),(c,2)), 3) + """ + ctx, sz, _args, _coeffs = _pb_args_coeffs(args) + return BoolRef(Z3_mk_pbge(ctx.ref(), sz, _args, _coeffs, k), ctx) + def PbEq(args, k): """Create a Pseudo-Boolean inequality k constraint. >>> a, b, c = Bools('a b c') >>> f = PbEq(((a,1),(b,3),(c,2)), 3) """ - args = _get_args(args) - args, coeffs = zip(*args) - if __debug__: - _z3_assert(len(args) > 0, "Non empty list of arguments expected") - ctx = _ctx_from_ast_arg_list(args) - if __debug__: - _z3_assert(ctx is not None, "At least one of the arguments must be a Z3 expression") - args = _coerce_expr_list(args, ctx) - _args, sz = _to_ast_array(args) - _coeffs = (ctypes.c_int * len(coeffs))() - for i in range(len(coeffs)): - _coeffs[i] = coeffs[i] + ctx, sz, _args, _coeffs = _pb_args_coeffs(args) return BoolRef(Z3_mk_pbeq(ctx.ref(), sz, _args, _coeffs, k), ctx) diff --git a/src/api/z3_api.h b/src/api/z3_api.h index b80ce3177..fcf22961c 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -855,6 +855,9 @@ typedef enum - Z3_OP_PB_AT_MOST: Cardinality constraint. E.g., x + y + z <= 2 + - Z3_OP_PB_AT_LEAST: Cardinality constraint. + E.g., x + y + z >= 2 + - Z3_OP_PB_LE: Generalized Pseudo-Boolean cardinality constraint. Example 2*x + 3*y <= 4 @@ -1174,6 +1177,7 @@ typedef enum { // Pseudo Booleans Z3_OP_PB_AT_MOST=0x900, + Z3_OP_PB_AT_LEAST, Z3_OP_PB_LE, Z3_OP_PB_GE, Z3_OP_PB_EQ, @@ -3966,6 +3970,17 @@ extern "C" { Z3_ast Z3_API Z3_mk_atmost(Z3_context c, unsigned num_args, Z3_ast const args[], unsigned k); + + /** + \brief Pseudo-Boolean relations. + + Encode p1 + p2 + ... + pn >= k + + def_API('Z3_mk_atleast', AST, (_in(CONTEXT), _in(UINT), _in_array(1,AST), _in(UINT))) + */ + + Z3_ast Z3_mk_atleast(Z3_context c, unsigned num_args, + Z3_ast const args[], unsigned k); /** \brief Pseudo-Boolean relations. @@ -3978,6 +3993,19 @@ extern "C" { Z3_ast const args[], int coeffs[], int k); + + /** + \brief Pseudo-Boolean relations. + + Encode k1*p1 + k2*p2 + ... + kn*pn >= k + + def_API('Z3_mk_pbge', AST, (_in(CONTEXT), _in(UINT), _in_array(1,AST), _in_array(1,INT), _in(INT))) + */ + + Z3_ast Z3_mk_pbge(Z3_context c, unsigned num_args, + Z3_ast const args[], int coeffs[], + int k); + /** \brief Pseudo-Boolean relations. diff --git a/src/smt/smt_bool_var_data.h b/src/smt/smt_bool_var_data.h index e65036d9c..af0b7f9d2 100644 --- a/src/smt/smt_bool_var_data.h +++ b/src/smt/smt_bool_var_data.h @@ -24,7 +24,9 @@ Revision History: namespace smt { struct bool_var_data { + private: b_justification m_justification; + public: unsigned m_scope_lvl:24; //!< scope level of when the variable was assigned. unsigned m_mark:1; unsigned m_assumption:1; @@ -45,6 +47,14 @@ namespace smt { public: unsigned get_intern_level() const { return m_iscope_lvl; } + + b_justification justification() const { return m_justification; } + + void set_axiom() { m_justification = b_justification::mk_axiom(); } + + void set_null_justification() { m_justification = null_b_justification; } + + void set_justification(b_justification const& j) { m_justification = j; } bool is_atom() const { return m_atom; } diff --git a/src/smt/smt_conflict_resolution.cpp b/src/smt/smt_conflict_resolution.cpp index 4568abb55..7dd9144fe 100644 --- a/src/smt/smt_conflict_resolution.cpp +++ b/src/smt/smt_conflict_resolution.cpp @@ -496,13 +496,15 @@ namespace smt { unsigned idx = skip_literals_above_conflict_level(); + TRACE("conflict", m_ctx.display_literal_verbose(tout, not_l); m_ctx.display(tout << " ", conflict);); + // save space for first uip m_lemma.push_back(null_literal); m_lemma_atoms.push_back(0); unsigned num_marks = 0; if (not_l != null_literal) { - TRACE("conflict", tout << "not_l: "; m_ctx.display_literal(tout, not_l); tout << "\n";); + TRACE("conflict", tout << "not_l: "; m_ctx.display_literal_verbose(tout, not_l); tout << "\n";); process_antecedent(not_l, num_marks); } @@ -514,7 +516,7 @@ namespace smt { get_manager().trace_stream() << "\n"; } - TRACE("conflict", tout << "processing consequent: "; m_ctx.display_literal(tout, consequent); tout << "\n"; + TRACE("conflict", tout << "processing consequent: "; m_ctx.display_literal_verbose(tout, consequent); tout << "\n"; tout << "num_marks: " << num_marks << ", js kind: " << js.get_kind() << "\n";); SASSERT(js != null_b_justification); switch (js.get_kind()) { @@ -1076,6 +1078,7 @@ namespace smt { return true; SASSERT(js.get_kind() != b_justification::BIN_CLAUSE); CTRACE("visit_b_justification_bug", js.get_kind() == b_justification::AXIOM, tout << "l: " << l << "\n"; m_ctx.display(tout);); + if (js.get_kind() == b_justification::AXIOM) return true; SASSERT(js.get_kind() != b_justification::AXIOM); @@ -1089,14 +1092,17 @@ namespace smt { i = 1; } else { + SASSERT(cls->get_literal(1) == l); if (get_proof(~cls->get_literal(0)) == 0) visited = false; i = 2; } } - for (; i < num_lits; i++) + for (; i < num_lits; i++) { + SASSERT(cls->get_literal(i) != l); if (get_proof(~cls->get_literal(i)) == 0) visited = false; + } return visited; } else @@ -1251,14 +1257,19 @@ namespace smt { } tout << "\n";); init_mk_proof(); - literal consequent = false_literal; - if (not_l != null_literal) - consequent = ~not_l; - visit_b_justification(consequent, conflict); - if (not_l != null_literal) + literal consequent; + if (not_l == null_literal) { + consequent = false_literal; + } + else { + consequent = ~not_l; m_todo_pr.push_back(tp_elem(not_l)); + } + visit_b_justification(consequent, conflict); + while (!m_todo_pr.empty()) { tp_elem & elem = m_todo_pr.back(); + switch (elem.m_kind) { case tp_elem::EQUALITY: { enode * lhs = elem.m_lhs; diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index e6d4d0c07..476a419eb 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -261,10 +261,11 @@ namespace smt { m_assignment[false_literal.index()] = l_false; if (m_manager.proofs_enabled()) { proof * pr = m_manager.mk_true_proof(); - m_bdata[true_bool_var].m_justification = b_justification(mk_justification(justification_proof_wrapper(*this, pr))); + + set_justification(true_bool_var, m_bdata[true_bool_var], b_justification(mk_justification(justification_proof_wrapper(*this, pr)))); } else { - m_bdata[true_bool_var].m_justification = b_justification::mk_axiom(); + m_bdata[true_bool_var].set_axiom(); } m_true_enode = mk_enode(t, true, true, false); // internalizer is marking enodes as interpreted whenever the associated ast is a value and a constant. @@ -292,6 +293,12 @@ namespace smt { std::swap(lhs, rhs); return m_manager.mk_eq(lhs, rhs); } + + void context::set_justification(bool_var v, bool_var_data& d, b_justification const& j) { + SASSERT(validate_justification(v, d, j)); + d.set_justification(j); + } + void context::assign_core(literal l, b_justification j, bool decision) { TRACE("assign_core", tout << (decision?"decision: ":"propagating: ") << l << " "; @@ -302,7 +309,7 @@ namespace smt { m_assignment[l.index()] = l_true; m_assignment[(~l).index()] = l_false; bool_var_data & d = get_bdata(l.var()); - d.m_justification = j; + set_justification(l.var(), d, j); d.m_scope_lvl = m_scope_lvl; if (m_fparams.m_restart_adaptive && d.m_phase_available) { m_agility *= m_fparams.m_agility_factor; @@ -1406,7 +1413,8 @@ namespace smt { else { TRACE("add_diseq", display_eq_detail(tout, bool_var2enode(v));); if (!add_diseq(get_enode(lhs), get_enode(rhs)) && !inconsistent()) { - set_conflict(b_justification(mk_justification(eq_propagation_justification(get_enode(lhs), get_enode(rhs)))), ~l); + literal not_eq = literal(l.var(), true); + set_conflict(b_justification(mk_justification(eq_propagation_justification(get_enode(lhs), get_enode(rhs)))), not_eq); } } } @@ -2042,7 +2050,7 @@ namespace smt { m_assignment[(~l).index()] = l_undef; bool_var v = l.var(); bool_var_data & d = get_bdata(v); - d.m_justification = null_b_justification; + d.set_null_justification(); m_case_split_queue->unassign_var_eh(v); } @@ -2593,10 +2601,10 @@ namespace smt { cls->set_justification(0); m_justifications.push_back(js); } - m_bdata[v0].m_justification = b_justification(js); + set_justification(v0, m_bdata[v0], b_justification(js)); } else - m_bdata[v0].m_justification = b_justification::mk_axiom(); + m_bdata[v0].set_axiom(); } } del_clause(cls); diff --git a/src/smt/smt_context.h b/src/smt/smt_context.h index c63d0614d..0d758196e 100644 --- a/src/smt/smt_context.h +++ b/src/smt/smt_context.h @@ -363,9 +363,11 @@ namespace smt { void get_assignments(expr_ref_vector& assignments); b_justification get_justification(bool_var v) const { - return get_bdata(v).m_justification; + return get_bdata(v).justification(); } + void set_justification(bool_var v, bool_var_data& d, b_justification const& j); + bool has_th_justification(bool_var v, theory_id th_id) const { b_justification js = get_justification(v); return js.get_kind() == b_justification::JUSTIFICATION && js.get_justification()->get_from_theory() == th_id; @@ -1381,6 +1383,8 @@ namespace smt { void validate_consequences(expr_ref_vector const& assumptions, expr_ref_vector const& vars, expr_ref_vector const& conseq, expr_ref_vector const& unfixed); + bool validate_justification(bool_var v, bool_var_data const& d, b_justification const& j); + void justify(literal lit, index_set& s); void extract_cores(expr_ref_vector const& asms, vector& cores, unsigned& min_core_size); diff --git a/src/smt/smt_context_inv.cpp b/src/smt/smt_context_inv.cpp index 5e3b091bc..7d009a037 100644 --- a/src/smt/smt_context_inv.cpp +++ b/src/smt/smt_context_inv.cpp @@ -402,6 +402,20 @@ namespace smt { #endif + bool context::validate_justification(bool_var v, bool_var_data const& d, b_justification const& j) { + if (j.get_kind() == b_justification::CLAUSE && v != true_bool_var) { + clause* cls = j.get_clause(); + unsigned num_lits = cls->get_num_literals(); + literal l = cls->get_literal(0); + if (l.var() != v) { + l = cls->get_literal(1); + } + SASSERT(l.var() == v); + SASSERT(m_assignment[l.index()] == l_true); + } + return true; + } + bool context::validate_model() { if (!m_proto_model) { return true; diff --git a/src/smt/smt_literal.cpp b/src/smt/smt_literal.cpp index d510027f0..e6e795ed4 100644 --- a/src/smt/smt_literal.cpp +++ b/src/smt/smt_literal.cpp @@ -27,6 +27,8 @@ namespace smt { out << "true"; else if (*this == false_literal) out << "false"; + else if (*this == null_literal) + out << "null"; else if (sign()) out << "(not " << mk_pp(bool_var2expr_map[var()], m) << ")"; else From 331658f20809a7ea32c3899f3cae37ffa63a7d4f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 9 Jan 2017 21:30:54 -0800 Subject: [PATCH 458/536] remove polynomial factorization as suggested by issue #852 Signed-off-by: Nikolaj Bjorner --- .../cmake/src/math/polynomial/CMakeLists.txt | 1 - src/math/polynomial/polynomial.cpp | 1 - .../polynomial/polynomial_factorization.cpp | 1143 ----------------- .../polynomial/polynomial_factorization.h | 65 - 4 files changed, 1210 deletions(-) delete mode 100644 src/math/polynomial/polynomial_factorization.cpp delete mode 100644 src/math/polynomial/polynomial_factorization.h diff --git a/contrib/cmake/src/math/polynomial/CMakeLists.txt b/contrib/cmake/src/math/polynomial/CMakeLists.txt index 1792f50aa..1d320d751 100644 --- a/contrib/cmake/src/math/polynomial/CMakeLists.txt +++ b/contrib/cmake/src/math/polynomial/CMakeLists.txt @@ -3,7 +3,6 @@ z3_add_component(polynomial algebraic_numbers.cpp polynomial_cache.cpp polynomial.cpp - polynomial_factorization.cpp rpolynomial.cpp sexpr2upolynomial.cpp upolynomial.cpp diff --git a/src/math/polynomial/polynomial.cpp b/src/math/polynomial/polynomial.cpp index 93858b6be..1a4aa8304 100644 --- a/src/math/polynomial/polynomial.cpp +++ b/src/math/polynomial/polynomial.cpp @@ -25,7 +25,6 @@ Notes: #include"scoped_ptr_vector.h" #include"cooperate.h" #include"upolynomial_factorization.h" -#include"polynomial_factorization.h" #include"polynomial_primes.h" #include"permutation.h" #include"algebraic_numbers.h" diff --git a/src/math/polynomial/polynomial_factorization.cpp b/src/math/polynomial/polynomial_factorization.cpp deleted file mode 100644 index 4bf227d44..000000000 --- a/src/math/polynomial/polynomial_factorization.cpp +++ /dev/null @@ -1,1143 +0,0 @@ -/*++ -Copyright (c) 2011 Microsoft Corporation - -Module Name: - - polynomial_factorization.cpp - -Abstract: - - Implementation of polynomial factorization. - -Author: - - Dejan (t-dejanj) 2011-11-15 - -Notes: - - [1] Elwyn Ralph Berlekamp. Factoring Polynomials over Finite Fields. Bell System Technical Journal, - 46(8-10):1853-1859, 1967. - [2] Donald Ervin Knuth. The Art of Computer Programming, volume 2: Seminumerical Algorithms. Addison Wesley, third - edition, 1997. - [3] Henri Cohen. A Course in Computational Algebraic Number Theory. Springer Verlag, 1993. - ---*/ -#if 0 -// disabled for reorg - -#include"trace.h" -#include"util.h" -#include"polynomial_factorization.h" -#include"upolynomial_factorization_int.h" -#include"prime_generator.h" - -using namespace std; - -namespace polynomial { - -typedef upolynomial::manager::scoped_numeral scoped_numeral; - -/** - Generates a substitution of values for f -> f_univariate in order to reduce the factorization to the - univariate case. - - @param f multivariate polynomial (square-free, primitive, vars(f) > 1) - @param x the variable we want to keep as the univarate one - @param f_lc the leading coefficient of f in x - @param vars the vector of all variables from f witouth x - @param size the bound to use for selecting the values, i.e. |a_i| <= size - @param a the output values corresponding to vairables in (place place for x should be ignored) - @param f_univariate the output substitution -*/ -void generate_substitution_values( - polynomial_ref const & f, var x, polynomial_ref const & f_lc, var_vector const & vars, unsigned & size, - upolynomial::numeral_vector & a, upolynomial::manager upm, upolynomial::numeral_vector & f_u) { - - SASSERT(a.size() == vars.size()); - - TRACE("polynomial::factorization", tout << "polynomial::generate_substitution_values(f = " << f << ", f_lc = " << f_lc << ")";); - - // f = f_n x^n + ... + f_0, square-free and primitive - // this means - // f_lc = f_n - // since f is primitive, - // we are looking for numbers a_i such that - // (1) f_lc doesn't vanish - // (2) f_u = f(a_0, ..., a_n, x) is square-free - - manager & pm = f.m(); - numeral_manager & nm = pm.m(); - - // polynomial to use for subtituting into the lc(f) - polynomial_ref f_lc_subst(pm); - - // random generator - random_gen generator; - - // increase the size every once in a while (RETHINK THIS) - unsigned inc_size_c = 0; - unsigned inc_size_c_max = size; - - while (true) { - - // see if we should increase the size of the substitution - if ((++ inc_size_c) % inc_size_c_max == 0) { - size ++; - inc_size_c = 0; - inc_size_c_max *= 2; - } - - // the head coefficient we'll substitute in - f_lc_subst = f_lc; - - bool vanished = false; - for (unsigned i = 0; i < vars.size() && !vanished; ++ i) { - SASSERT(vars[i] != x); - - // the value for x_i - nm.set(a[i], (int)generator(2*size+1) - (int)size); - - // substitute - f_lc_subst = pm.substitute(f_lc_subst, x, a[i]); - - // did it vanish - vanished = pm.is_zero(f_lc_subst); - } - - if (vanished) { - // leading coefficient vanished, try again - continue; - } - - // substitute into f and get the univariate one - polynomial_ref f_subst(pm); - f_subst = pm.substitute(f, vars.size(), vars.c_ptr(), a.c_ptr()); - upm.to_numeral_vector(f_subst, f_u); - - // if the result is not square-free we try again - if (!upm.is_square_free(f_u)) - continue; - - // found it, break - break; - } -} - -/** - \brief Bound for the coefficients of the factorst of the multivariate polynomial f. R - Returns power of p -> p^e that covers the bound - - We use the gelfond bound here: - d_i: degree of x_i in f(x1, ..., x_n) - bound = |f| * 2^(\sum d_i - (n-1)/2)) -*/ -void multivariate_factor_coefficient_bound(polynomial_ref const & f, var x, numeral const & p, unsigned & e, numeral & p_e, var2degree & d) { - manager & pm = f.m(); - numeral_manager & nm = pm.m(); - - // compute g = lc(f)*f - polynomial_ref f_lc(pm), g(pm); - f_lc = pm.coeff(f, x, pm.degree(f, x)); - g = pm.mul(f, f_lc); - - // get the norm - scoped_numeral g_norm(nm); - pm.abs_norm(g, g_norm); - - // get the variable degrees - var_vector vars; - pm.vars(f, vars); - unsigned power = 0; - for (unsigned i = 0; i < vars.size(); ++ i) { - unsigned c_d = pm.degree(g, vars[i]); - d.set_degree(vars[i], c_d + 1); - power += c_d; - } - power = power - (vars.size()-1)/2; - - // compute the bound - scoped_numeral bound(nm); - nm.set(bound, 2); - nm.power(bound, power, bound); - nm.mul(g_norm, bound, bound); - - // return the first power of two that is bigger than the norm - e = 1; - nm.set(p_e, p); - while (nm.lt(p_e, bound)) { - nm.mul(p_e, p_e, p_e); - e *= 2; - } -} - -// check that A*S+B*T=C in zp mod ideal -bool check_solve(zp_manager & zp_pm, var2degree const & ideal, - zp_polynomial_ref const & A, zp_polynomial_ref const & B, zp_polynomial_ref const & C, - zp_polynomial_ref const & S, zp_polynomial_ref const & T) { - zp_polynomial_ref AS(zp_pm), BT(zp_pm), sum(zp_pm); - AS = zp_pm.mul(A, S); AS = zp_pm.mod_d(AS, ideal); - BT = zp_pm.mul(B, T); BT = zp_pm.mod_d(BT, ideal); - sum = zp_pm.add(AS, BT); - - TRACE("polynomial::factorization::multivariate", - tout << "zp_pm = Z_" << zp_pm.m().m().to_string(zp_pm.m().p()) << endl; - tout << "ideal = " << ideal << endl; - tout << "A = " << A << endl; - tout << "B = " << B << endl; - tout << "S = " << S << endl; - tout << "T = " << T << endl; - tout << "C = " << C << endl; - tout << "sum = " << sum << endl; - ); - - bool result = zp_pm.eq(sum, C); - return result; -} - -/** - Solve the equation A*S + B*T = C, given, AU + BV = 1, with deg(T) < deg(A) - S = U*C + tB - T = V*C - tA - we divide VC with A to get (T, t) -*/ -template -void solve(zp_manager & zp_pm, var x, var2degree const & ideal, - zp_polynomial_ref const & A, zp_polynomial_ref const & U, - zp_polynomial_ref const & B, zp_polynomial_ref const & V, - zp_polynomial_ref const & C, - output_manager & out_pm, - typename output_manager::polynomial_ref & S_out, - typename output_manager::polynomial_ref & T_out) { - TRACE("polynomial::factorization::multivariate", - tout << "polynomial::solve(" << endl; - tout << "zp_pm = Z_" << zp_pm.m().m().to_string(zp_pm.m().p()) << endl; - tout << "ideal = " << ideal << endl; - tout << "A = " << A << endl; - tout << "B = " << B << endl; - tout << "U = " << U << endl; - tout << "V = " << V << endl; - tout << "C = " << C << endl; - ); - - // solution is S = C*U + tB, T = C*V - tA - zp_polynomial_ref CV(zp_pm); - CV = zp_pm.mul(C, V); CV = zp_pm.mod_d(CV, ideal); - zp_polynomial_ref CU(zp_pm); - CU = zp_pm.mul(C, U); CU = zp_pm.mod_d(CU, ideal); - zp_polynomial_ref t(zp_pm), T(zp_pm); - zp_pm.exact_pseudo_division_mod_d(CV, A, x, ideal, t, T); - - zp_polynomial_ref tB(zp_pm); - tB = zp_pm.mul(t, B); tB = zp_pm.mod_d(tB, ideal); - zp_polynomial_ref S(zp_pm); - S = zp_pm.add(CU, tB); - - SASSERT(check_solve(zp_pm, ideal, A, B, C, S, T)); - - // convert to the other manager - S_out = convert(zp_pm, S, out_pm); - T_out = convert(zp_pm, T, out_pm); - - TRACE("polynomial::factorization::multivariate", - tout << "CU = " << CU << endl; - tout << "CV = " << CV << endl; - tout << "t = " << t << endl; - tout << "--- solution ---" << endl; - tout << "S = " << S_out << endl; - tout << "T = " << T_out << endl; - ); -} - -/** - A, B, U, V: multivariate polynomials in Z_p[x, ...], mod ..., also the output polynomials, y is not there - C: C = A*B in Z_p[x, ...] mod p, ... - - ideal: all the vars we care about in the ideal - - y, the variable we are lifting is not in ideal_vars, we will add it - - A monic, A*U+B*V = 1 - - p is not necessary prime, it's a power of a prime - - we're doing quadratic lifting here - - output: added y, i.e. - * all polynomials in Z_p[x, ..., y] mod (..., y^d) -*/ -void multivariate_hansel_lift_ideal( - zp_manager & zp_pm, var x, - zp_polynomial_ref const & C, - zp_polynomial_ref & A, zp_polynomial_ref & U, zp_polynomial_ref & B, zp_polynomial_ref & V, - var2degree & ideal, var y, unsigned d) { - numeral_manager & nm = zp_pm.m().m(); - - TRACE("polynomial::factorization::multivariate", - tout << "polynomial::multiratiate_hensel_lift_ideal" << endl; - tout << "zp_pm is Z_" << zp_pm.m().m().to_string(zp_pm.m().p()) << endl; - tout << "x = x" << x << endl; - tout << "y = x" << y << endl; - tout << "C = " << C << endl; - tout << "A = " << A << endl; - tout << "B = " << B << endl; - tout << "U = " << U << endl; - tout << "V = " << V << endl; - tout << "ideal = " << ideal << endl; - ); - - // constant 1 - scoped_numeral one(nm); - nm.set(one, 1); - zp_polynomial_ref one_p(zp_pm); - one_p = zp_pm.mk_const(one); - - SASSERT(zp_pm.degree(A, y) == 0 && zp_pm.degree(B, y) == 0 && zp_pm.degree(U, y) == 0 && zp_pm.degree(V, y) == 0); - - // update the ideal, and start with y - ideal.set_degree(y, 1); - unsigned current_d = 1; - zp_polynomial_ref current_power(zp_pm); - current_power = zp_pm.mk_polynomial(y); - - // lift quadratic until we are over the asked for - while (current_d < d) { - - TRACE("polynomial::factorization::multivariate", - tout << "zp_pm = Z_" << nm.to_string(zp_pm.m().p()) << endl; - tout << "ideal = " << ideal << endl; - tout << "C = " << C << endl; - tout << "A = " << A << endl; - tout << "B = " << B << endl; - ); - - // again, classic hensel: - // since C = A*B mod (p, ideal, y^k) we know that (C - A*B) = 0 mod (p, ideal, y^k) - // f = (C - A*B) mod (p, ideal, y^k) and thus divisible by y^current_d = current_power - zp_polynomial_ref f(zp_pm); - f = zp_pm.mul(A, B); - - TRACE("polynomial::factorization::multivariate", - tout << "zp_pm = Z_" << nm.to_string(zp_pm.m().p()) << endl; - tout << "ideal = " << ideal << endl; - tout << "C = " << C << endl; - tout << "A = " << A << endl; - tout << "B = " << B << endl; - tout << "f = " << f << endl; - ); - - f = zp_pm.sub(C, f); - f = zp_pm.exact_div(f, current_power); - f = zp_pm.mod_d(f, ideal); - - TRACE("polynomial::factorization::multivariate", - tout << "A = " << A << endl; - tout << "B = " << B << endl; - ); - - // get the S, T, solution to A*S+B*T = f, with d(T, x) < d(A, x) - // but we know that S = U*f + Bt, T = V*f - At, so we do division - zp_polynomial_ref S(zp_pm), T(zp_pm); - solve(zp_pm, x, ideal, A, U, B, V, f, zp_pm, S, T); - // now, lets lift A and B - // we want A1 = A + T*y^d, B1 = B + S*y^d with A1*B1 = C mod (ideal, y^(2*k)) - // hence A*B + y^d*(A*S+B*T) = C - S = zp_pm.mul(S, current_power); - T = zp_pm.mul(T, current_power); - A = zp_pm.add(A, T); - B = zp_pm.add(B, S); - - TRACE("polynomial::factorization::multivariate", - tout << "A = " << A << endl; - tout << "B = " << B << endl; - ); - - // again, classic quadratic hensel - // we need A*U1 + B*V1 = 1 mod (p, ideal, y^2), from above - // U1 = U + S*y^d, V1 = V + T*y^d, hence A*U + B*V + y^d(S + T) = 1 mod new ideal^2 - // we know that y^d divides (1-UA-BV) so we compute f = (1-UA-BV)/y^d - // UA + VB + y^d(SA + TB) = 1 (mod ideal^2) - // SA + TB = f (mod ideal) - // we solve for S, T again, and do as above - zp_polynomial_ref UA(zp_pm), BV(zp_pm); - f = zp_pm.mk_const(one); - UA = zp_pm.mul(U, A); - BV = zp_pm.mul(V, B); - f = zp_pm.sub(f, UA); f = zp_pm.sub(f, BV); - - TRACE("polynomial::factorization::multivariate", - tout << "ideal = " << ideal << endl; - tout << "current_power = " << current_power << endl; - tout << "UA = " << UA << endl; - tout << "BV = " << BV << endl; - tout << "f = " << f << endl; - tout << "x = x" << x << endl; - tout << "y = x" << y << endl; - ); - - f = zp_pm.exact_div(f, current_power); - f = zp_pm.mod_d(f, ideal); - - // get the S, T, solution to A*S+B*T = f, with d(T, x) < d(A, x) - solve(zp_pm, x, ideal, A, U, B, V, f, zp_pm, S, T); - // now, lets lift U and V - S = zp_pm.mul(S, current_power); - U = zp_pm.add(U, S); - T = zp_pm.mul(T, current_power); - V = zp_pm.add(V, T); - - // lift the ideal - current_d *= 2; - current_power = zp_pm.mul(current_power, current_power); - ideal.set_degree(y, current_d); - - // move, A, B, C, D into the ideal - A = zp_pm.mod_d(A, ideal); - B = zp_pm.mod_d(B, ideal); - S = zp_pm.mod_d(S, ideal); - T = zp_pm.mod_d(T, ideal); - - TRACE("polynomial::factorization::multivariate", - tout << "current_d = " << d << endl; - tout << "zp_pm is Z_" << zp_pm.m().m().to_string(zp_pm.m().p()) << endl; - tout << "x = x" << x << endl; - tout << "y = x" << y << endl; - tout << "C = " << C << endl; - tout << "A = " << A << endl; - tout << "B = " << B << endl; - tout << "U = " << U << endl; - tout << "V = " << V << endl; - tout << "ideal = " << ideal << endl; - ); - - SASSERT(check_solve(zp_pm, ideal, A, B, one_p, U, V)); - } -} - -template -bool are_equal_in( - manager_to_check pm, - typename manager_1::polynomial_ref const & A, - typename manager_2::polynomial_ref const & B) { - typename manager_to_check::polynomial_ref A_pm(pm), B_pm(pm); - - A_pm = convert(A.m(), A, pm); - B_pm = convert(B.m(), B, pm); - - bool equal = pm.eq(A_pm, B_pm); - return equal; -} - -/** - C: target multivariate polynomial mod ideal, p^e, the manager is in p^e - x: main variable - A, B, U, V: univariate polynomials in Z_p[x] such that U*A+B*V=1 mod ideal, these guys managers are in Z_p - - output: A_lifted, B_lifted, A = A_lifted mod ideal - A_lifted*B_lifted = f mod x_i^d_i, p^e -*/ -void multivariate_hansel_lift_zp( - manager & pm, zp_manager & zp_pm, zp_manager & zpe_pm, - zp_polynomial_ref const & C_pe, var x, unsigned e, - zp_polynomial_ref const & A_p, zp_polynomial_ref const & U_p, - zp_polynomial_ref const & B_p, zp_polynomial_ref const & V_p, - var2degree const & ideal, - zp_polynomial_ref & A_lifted, zp_polynomial_ref & B_lifted) { - TRACE("polynomial::factorization::multivariate", - tout << "polynomial::multiratiate_hensel_lift_zp:" << endl; - tout << "zp_pm = Z_" << zp_pm.m().m().to_string(zp_pm.m().p()) << endl; - tout << "zpe_pm = Z_" << zpe_pm.m().m().to_string(zpe_pm.m().p()) << endl; - tout << "x = x" << x << endl; - tout << "ideal = " << ideal << endl; - tout << "C_pe = " << C_pe << "," << endl; - tout << "A_p = " << A_p << "," << endl; - tout << "B_p = " << B_p << "," << endl; - ); - - // fixed zpe_pm - // upolynomial::zp_numeral_manager & zpe_nm = zpe_pm.m(); - // numeral const & pe = zpe_nm.p(); - // fixed zp_pm - upolynomial::zp_numeral_manager & zp_nm = zp_pm.m(); - numeral const & p = zp_nm.p(); - // regular numeral manager and mangager - numeral_manager & nm = zp_nm.m(); - - // sliding zpk_pm mod p^k - upolynomial::zp_numeral_manager zpk_nm(nm, p); - zp_manager zpk_pm(zpk_nm, &zp_pm.mm()); // in the end we copy the result over to zpe - unsigned k = 1; - upolynomial::scoped_numeral pk(nm); - nm.set(pk, zpk_nm.p()); - - // constant 1 - scoped_numeral one(nm); - nm.set(one, 1); - zp_polynomial_ref one_p(zpk_pm); - one_p = zpk_pm.mk_const(one); - - // lift until you get over the requested power of e - zp_polynomial_ref A_pk(zpk_pm), B_pk(zpk_pm), U_pk(zpk_pm), V_pk(zpk_pm); - - A_pk = convert(zp_pm, A_p, zpk_pm); - B_pk = convert(zp_pm, B_p, zpk_pm); - U_pk = convert(zp_pm, U_p, zpk_pm); - V_pk = convert(zp_pm, V_p, zpk_pm); - - TRACE("polynomial::factorization::multivariate", - tout << "zpk_pm = Z_" << zpk_pm.m().m().to_string(zpk_pm.m().p()) << endl; - tout << "A_pk = " << A_pk << endl; - tout << "B_pk = " << B_pk << endl; - tout << "U_pk = " << U_pk << endl; - tout << "V_pk = " << V_pk << endl; - ); - - SASSERT(check_solve(zpk_pm, ideal, A_pk, B_pk, one_p, U_pk, V_pk)); - - while (k < e) { - - // standard hensel: - // (C - AB) and is divisible by p^k, so we compute f = (C - AB)/p^k mod ideal in Z[...] - zp_polynomial_ref f_pk(zpk_pm); - polynomial_ref A_pk_in_Z(pm), B_pk_in_Z(pm), AB_in_Z(pm), f_in_Z(pm); - f_in_Z = convert(zpe_pm, C_pe, pm); - A_pk_in_Z = convert(zpk_pm, A_pk, pm); - B_pk_in_Z = convert(zpk_pm, B_pk, pm); - AB_in_Z = pm.mul(A_pk_in_Z, B_pk_in_Z); - AB_in_Z = pm.mod_d(AB_in_Z, ideal); - f_in_Z = pm.sub(f_in_Z, AB_in_Z); - f_in_Z = pm.exact_div(f_in_Z, pk); - f_in_Z = pm.mod_d(f_in_Z, ideal); - f_pk = convert(pm, f_in_Z, zpk_pm); - - TRACE("polynomial::factorization::multivariate", - tout << "zpk_pm = Z_" << zpk_pm.m().m().to_string(zpk_pm.m().p()) << endl; - tout << "f_pk = " << f_pk << endl; - ); - - // standard hensel we need to lift to p^(2k) - // we have U*A+V*B = 1, C = A*B, so p^k divides C - AB - // we want A1 = A + p^k*S, B1 = B + p^k*T, and also - // C - (A + p^k*S)*(B + p^k*T) = 0 mod (p^2k) - // C - A*B = p^k (T*A + S*B), i.e. - // f = (C - A*B)/p^k = (T*A + S*B), so we solve this equation in Z_p^k - polynomial_ref S_in_Z(pm), T_in_Z(pm); - solve(zpk_pm, x, ideal, A_pk, U_pk, B_pk, V_pk, f_pk, pm, T_in_Z, S_in_Z); - - TRACE("polynomial::factorization::multivariate", - tout << "zpk_pm = Z_" << zpk_pm.m().m().to_string(zpk_pm.m().p()) << endl; - tout << "S_in_Z = " << S_in_Z << endl; - tout << "T_in_Z = " << T_in_Z << endl; - ); - - // lift A and B to, A = A + p^k*S, B = B + p^k*T - polynomial_ref A_next_in_Z(pm), B_next_in_Z(pm); - S_in_Z = pm.mul(pk, S_in_Z); - S_in_Z = pm.mod_d(S_in_Z, ideal); - A_next_in_Z = convert(zpk_pm, A_pk, pm); - A_next_in_Z = pm.add(A_next_in_Z, S_in_Z); - T_in_Z = pm.mul(pk, T_in_Z); - T_in_Z = pm.mod_d(T_in_Z, ideal); - B_next_in_Z = convert(zpk_pm, B_pk, pm); - B_next_in_Z = pm.add(B_next_in_Z, T_in_Z); - - TRACE("polynomial::factorization::multivariate", - tout << "pk = " << nm.to_string(pk) << endl; - tout << "zpk_pm = Z_" << zpk_pm.m().m().to_string(zpk_pm.m().p()) << endl; - tout << "S_in_Z = " << S_in_Z << endl; - tout << "T_in_Z = " << T_in_Z << endl; - tout << "A_pk = " << A_pk << endl; - tout << "B_pk = " << B_pk << endl; - tout << "A_next_in_Z = " << A_next_in_Z << endl; - tout << "B_next_in_Z = " << B_next_in_Z << endl; - ); - - bool eq1 = are_equal_in(zpk_pm, A_next_in_Z, A_pk); - SASSERT(eq1); - bool eq2 = are_equal_in(zpk_pm, B_next_in_Z, B_pk); - SASSERT(eq2); - - // again, classic quadratic hensel - // we need A*U1 + B*V1 = 1 mod p^2k, from above - // U1 = U + p^k*S, V1 = V + p^k*T, hence A*U + B*V + p^k*(S + T) = 1 mod (p^2k) - // we know that p^k divides (1-UA-BV) so we compute f = (1-UA-BV)/p^k - // UA + VB + p^k(SA + TB) = 1 (mod p^k) - // SA + TB = f (mod ideal) - // we solve for S, T again, and do as above - polynomial_ref U_pk_in_Z(pm), V_pk_in_Z(pm), UA_in_Z(pm), BV_in_Z(pm); - U_pk_in_Z = convert(zpk_pm, U_pk, pm); - V_pk_in_Z = convert(zpk_pm, V_pk, pm); - f_in_Z = pm.mk_const(one); - UA_in_Z = pm.mul(U_pk_in_Z, A_next_in_Z); - UA_in_Z = pm.mod_d(UA_in_Z, ideal); - BV_in_Z = pm.mul(V_pk_in_Z, B_next_in_Z); - BV_in_Z = pm.mod_d(BV_in_Z, ideal); - f_in_Z = pm.sub(f_in_Z, UA_in_Z); - f_in_Z = pm.sub(f_in_Z, BV_in_Z); - - TRACE("polynomial::factorization::multivariate", - tout << "pk = " << nm.to_string(pk) << endl; - tout << "zpk_pm = Z_" << zpk_pm.m().m().to_string(zpk_pm.m().p()) << endl; - tout << "U_pk_in_Z = " << U_pk_in_Z << endl; - tout << "V_pk_in_Z = " << V_pk_in_Z << endl; - tout << "UA_in_Z = " << UA_in_Z << endl; - tout << "BV_in_Z = " << BV_in_Z << endl; - tout << "f_in_Z = " << f_in_Z << endl; - ); - - f_in_Z = pm.exact_div(f_in_Z, pk); - f_pk = convert(pm, f_in_Z, zpk_pm); - - // get the S, T, solution to A*S+B*T = f, with d(T, x) < d(A, x) - solve(zpk_pm, x, ideal, A_pk, U_pk, B_pk, V_pk, f_pk, pm, S_in_Z, T_in_Z); - - TRACE("polynomial::factorization::multivariate", - tout << "pk = " << nm.to_string(pk) << endl; - tout << "zpk_pm = Z_" << zpk_pm.m().m().to_string(zpk_pm.m().p()) << endl; - tout << "S_in_Z = " << S_in_Z << endl; - tout << "T_in_Z = " << T_in_Z << endl; - ); - - // go to the next zpk - scoped_numeral next_pk(nm); - nm.mul(pk, pk, next_pk); - zpk_nm.set_p(next_pk); - - TRACE("polynomial::factorization::multivariate", - tout << "zp_pk = Z_" << zpk_pm.m().m().to_string(zpk_pm.m().p()) << endl; - ); - - // lift U - zp_polynomial_ref S_pk(zpk_pm); - S_in_Z = pm.mul(pk, S_in_Z); - S_pk = convert(pm, S_in_Z, zpk_pm); - - TRACE("polynomial::factorization::multivariate", - tout << "S_pk = " << S_pk << endl; - ); - - U_pk = zpk_pm.add(U_pk, S_pk); - // lift V - zp_polynomial_ref T_pk(zpk_pm); - T_in_Z = pm.mul(pk, T_in_Z); - T_pk = convert(pm, T_in_Z, zpk_pm); - - TRACE("polynomial::factorization::multivariate", - tout << "T_pk = " << T_pk << endl; - ); - - V_pk = zpk_pm.add(V_pk, T_pk); - - // lift A and B - TRACE("polynomial::factorization::multivariate", - tout << "A_pk_in_Z = " << A_pk_in_Z << endl; - tout << "B_pk_in_Z = " << B_pk_in_Z << endl; - ); - A_pk = convert(pm, A_pk_in_Z, zpk_pm); - B_pk = convert(pm, B_pk_in_Z, zpk_pm); - - // move to the next pk - k *= 2; - nm.set(pk, next_pk); - - TRACE("polynomial::factorization::multivariate", - tout << "zp_pk = Z_" << zpk_pm.m().m().to_string(zpk_pm.m().p()) << endl; - tout << "A_pk = " << A_pk << endl; - tout << "B_pk = " << B_pk << endl; - tout << "U_pk = " << U_pk << endl; - tout << "V_pk = " << V_pk << endl; - tout << "C_pe = " << C_pe << endl; - ); - - SASSERT(check_solve(zpk_pm, ideal, A_pk, B_pk, one_p, U_pk, V_pk)); - } - - // now convert to the non-sliding zpe_manager - SASSERT(k == e); - A_lifted = convert(zpk_pm, A_pk, zpe_pm); - B_lifted = convert(zpk_pm, B_pk, zpe_pm); -} - -/** - f: target multivariate polynomial mod x_i^d_i, p^e - x: main variable - all_vars: all variables (including x) - A, B, U, V: univariate polynomials in Z_p[x] such that U*A+B*V=1 from ext gcd - - output: A_lifted, B_lifted d(A) = d(A_lifted), A = A_lifted mod x_i^d_i, p - A_lifted*B_lifted = f mod x_i^d_i, p^e -*/ -void multivariate_hensel_lift( - manager & pm, zp_manager & zp_pm, zp_manager & zpe_pm, - zp_polynomial_ref const & f, var x, unsigned e, var_vector const & all_vars, - upolynomial::zp_manager & zp_upm, - upolynomial::numeral_vector const & U, upolynomial::numeral_vector const & A, - upolynomial::numeral_vector const & V, upolynomial::numeral_vector const & B, - var2degree & target_ideal, zp_polynomial_ref & A_lifted, zp_polynomial_ref & B_lifted) { - upolynomial::zp_numeral_manager & zp_nm = zp_upm.m(); - upolynomial::numeral_manager & nm = zp_nm.m(); - - TRACE("polynomial::factorization::multivariate", - tout << "polynomial::multiratiate_hensel_lift(" << endl; - tout << "f = " << f << "," << endl; - tout << "x = x" << x << "," << endl; - tout << "e = " << e << "," << endl; - tout << "U = "; zp_upm.display(tout, U); tout << "," << endl; - tout << "A = "; zp_upm.display(tout, A); tout << "," << endl; - tout << "V = "; zp_upm.display(tout, V); tout << "," << endl; - tout << "B = "; zp_upm.display(tout, B); tout << "," << endl; - tout << "target_ideal = " << target_ideal << "," << endl; - tout << "p = " << nm.to_string(zp_pm.m().p()) << endl; - tout << "pe = " << nm.to_string(zpe_pm.m().p()) << endl; - ); - - // multivariate versions of A, B, U, V that we keep lifting over ideal x_i^d_i - zp_polynomial_ref A_m_p(zp_pm), B_m_p(zp_pm), U_m_p(zp_pm), V_m_p(zp_pm); - A_m_p = zp_pm.to_polynomial(A, x); - B_m_p = zp_pm.to_polynomial(B, x); - U_m_p = zp_pm.to_polynomial(U, x); - V_m_p = zp_pm.to_polynomial(V, x); - - TRACE("polynomial::factorization::multivariate", - tout << "A_m_p = " << A_m_p << endl; - tout << "B_m_p = " << B_m_p << endl; - tout << "U_m_p = " << U_m_p << endl; - tout << "V_m_p = " << V_m_p << endl; - ); - - // the the target in Z_p[...] - zp_polynomial_ref C_m_p(zp_pm); - C_m_p = convert(zpe_pm, f, zp_pm); - - // lift each variable individually - var2degree lifted_ideal; - unsigned_vector lifted_degs; - for (unsigned i = 0; i < all_vars.size(); ++ i) { - if (all_vars[i] == x) { - // skip the main variable - continue; - } - // current variable and degree we are lifting to, y^(d_y), at least - var y = all_vars[i]; - // lift to y^(d_y) - multivariate_hansel_lift_ideal(zp_pm, x, C_m_p, A_m_p, U_m_p, B_m_p, V_m_p, lifted_ideal, y, target_ideal.degree(y)); - } - - TRACE("polynomial::factorization::multivariate", - tout << "A_m_p = " << A_m_p << endl; - tout << "B_m_p = " << B_m_p << endl; - tout << "U_m_p = " << U_m_p << endl; - tout << "V_m_p = " << V_m_p << endl; - tout << "lifted_ideal = " << lifted_ideal << endl; - ); - - // now lift it all to p^e - multivariate_hansel_lift_zp(pm, zp_pm, zpe_pm, f, x, e, A_m_p, U_m_p, B_m_p, V_m_p, lifted_ideal, A_lifted, B_lifted); -} - - -/** - f: multivariate polynomial - x: main variable - all_vars: all variables (including x) - f_u: f mod x_1, ..., x_n (excluding mod x), i.e. this is f(0, x), f_u is square_free - f_u_zp_factors: monic factors of f_u (mod p), pairvise gcd = 1 - - we're lifting the factors to mod x_1^d_1, ..., x_n&d_n (excliding x), mod p^e - i.e. such that f congruent to the new factors. output goes to f_zpe factors. -*/ -void multivariate_hensel_lift( - manager & pm, zp_manager & zp_pm, zp_manager & zpe_pm, - polynomial_ref const & f, var x, unsigned e, var_vector const & all_vars, - upolynomial::manager & upm, upolynomial::numeral_vector const & f_u, - upolynomial::zp_factors const & f_u_zp_factors, - var2degree & target_ideal, - zp_factors & f_zpe_factors) { - SASSERT(f_u_zp_factors.distinct_factors() > 1); - - TRACE("polynomial::factorization::multivariate", - tout << "polynomial::multivariate_hensel_lift(" << endl; - tout << "f = " << f << "," << endl; - tout << "x = x" << x << "," << endl; - tout << "e = " << e << "," << endl; - tout << "f_u = "; upm.display(tout, f_u); tout << "," << endl; - tout << "f_u_zp_factors" << f_u_zp_factors << "," << endl; - tout << "target_ideal = " << target_ideal << "," << endl; - tout << "f_zpe_factors = " << f_zpe_factors << ")" << endl; - ); - - // managers and all - numeral_manager & nm = pm.m(); - upolynomial::zp_manager & zp_upm = f_u_zp_factors.upm(); - // upolynomial::zp_numeral_manager & zp_nm = zp_upm.m(); - upolynomial::zp_numeral_manager & zpe_nm = zpe_pm.m(); - upolynomial::zp_manager zpe_upm(zpe_nm); - - // the targed product we want (mod x_i^d_i, mod p^e) - zp_polynomial_ref f_target_zpe(zpe_pm); - f_target_zpe = convert(pm, f, zpe_pm); - f_target_zpe = zpe_pm.mod_d(f_target_zpe, target_ideal); - - TRACE("polynomial::factorization::multivariate", - tout << "target_ideal = " << target_ideal << endl; - tout << "f_target_zpe = " << f_target_zpe << endl; - ); - - // we do the product by doing individual lifting like in the univarate case - zp_polynomial_ref B(zp_pm), C_p(zp_pm); - zp_polynomial_ref A_lifted(zpe_pm), B_lifted(zpe_pm); - upolynomial::scoped_numeral_vector B_u(nm), C_u(nm), tmp_u(nm); - upolynomial::scoped_numeral_vector U(nm), V(nm); - for (int i = 0, i_end = f_u_zp_factors.distinct_factors() - 1; i < i_end; ++ i) - { - // get the univarate ones to lift now - upolynomial::numeral_vector const & A_u = f_u_zp_factors[i]; - // current starting product is f_target_zpe(0, x) in *Z_p* - zp_upm.to_numeral_vector(f_target_zpe, x, C_u); - // we get the rest into B (mod p) - zp_upm.exact_div(C_u, A_u, B_u); - - TRACE("polynomial::factorization::multivariate", - tout << "p = " << nm.to_string(zp_upm.m().p()) << endl; - tout << "f_target_zpe = " << f_target_zpe << endl; - tout << "A_u = "; upm.display(tout, A_u); tout << endl; - tout << "B_u = "; upm.display(tout, B_u); tout << endl; - tout << "C_u = "; upm.display(tout, C_u); tout << endl; - ); - - // and get the U, V, such that A*U+B*V = 1 - zp_upm.ext_gcd(A_u, B_u, U, V, tmp_u); - - TRACE("polynomial::factorization::multivariate", - tout << "U = "; upm.display(tout, U); tout << endl; - tout << "V = "; upm.display(tout, V); tout << endl; - tout << "gcd = "; upm.display(tout, tmp_u); tout << endl; - ); - - // do the lifting for this pair - multivariate_hensel_lift(pm, zp_pm, zpe_pm, f_target_zpe, x, e, all_vars, zp_upm, U, A_u, V, B_u, target_ideal, A_lifted, B_lifted); - - // add the lifted A to the output - f_zpe_factors.push_back(A_lifted, 1); - // move to the new target by dividing with the lifted A - f_target_zpe = zpe_pm.exact_div(f_target_zpe, A_lifted); - } - - // add the last f_target - f_zpe_factors.push_back(f_target_zpe, 1); -} - -class mfactorization_combination_iterator : public upolynomial::factorization_combination_iterator_base { - - /** main variable */ - var m_x; - -public: - - mfactorization_combination_iterator(zp_factors const & factors, var x) - : upolynomial::factorization_combination_iterator_base(factors) - {} - - /** - \brief Filter the ones not in the degree set. - */ - bool filter_current() const { - return false; - } - - /** - \brief Returns the degree of the current selection. - */ - unsigned current_degree() const { - unsigned degree = 0; - zp_manager & pm = m_factors.pm(); - for (unsigned i = 0; i < left_size(); ++ i) { - degree += pm.degree(m_factors[m_current[i]], m_x); - } - return degree; - } - - void left(zp_polynomial_ref & out) const { - SASSERT(m_current_size > 0); - zp_manager & zp_pm = m_factors.pm(); - out = m_factors[m_current[0]]; - for (int i = 1; i < m_current_size; ++ i) { - out = zp_pm.mul(out, m_factors[m_current[i]]); - } - } - - void get_left_tail_coeff(numeral const & m, numeral & out) { - zp_manager & zp_pm = m_factors.pm(); - upolynomial::zp_numeral_manager & zp_nm = zp_pm.m(); - zp_nm.set(out, m); - for (int i = 0; i < m_current_size; ++ i) { - zp_nm.mul(out, zp_pm.numeral_tc(m_factors[m_current[i]]), out); - } - } - - void get_right_tail_coeff(numeral const & m, numeral & out) { - zp_manager & zp_pm = m_factors.pm(); - upolynomial::zp_numeral_manager & zp_nm = zp_pm.m(); - zp_nm.set(out, m); - - unsigned current = 0; - unsigned selection_i = 0; - - // selection is ordered, so we just take the ones in between that are not disable - while (current < m_factors.distinct_factors()) { - if (!m_enabled[current]) { - // by skipping the disabled we never skip a selected one - current ++; - } else { - if (selection_i >= m_current.size() || (int) current < m_current[selection_i]) { - SASSERT(m_factors.get_degree(current) == 1); - zp_nm.mul(out, zp_pm.numeral_tc(m_factors[current]), out); - current ++; - } else { - current ++; - selection_i ++; - } - } - } - } - - void right(zp_polynomial_ref & out) const { - SASSERT(m_current_size > 0); - zp_manager & zp_pm = m_factors.pm(); - upolynomial::zp_numeral_manager & zp_nm = zp_pm.m(); - - unsigned current = 0; - unsigned selection_i = 0; - - numeral one; - zp_nm.set(one, 1); - out = zp_pm.mk_const(one); - - // selection is ordered, so we just take the ones in between that are not disable - while (current < m_factors.distinct_factors()) { - if (!m_enabled[current]) { - // by skipping the disabled we never skip a selected one - current ++; - } else { - if (selection_i >= m_current.size() || (int) current < m_current[selection_i]) { - SASSERT(m_factors.get_degree(current) == 1); - out = zp_pm.mul(out, m_factors[current]); - current ++; - } else { - current ++; - selection_i ++; - } - } - } - } -}; - - -// the multivariate factorization -bool factor_square_free_primitive(polynomial_ref const & f, factors & f_factors) { - - TRACE("polynomial::factorization", tout << "polynomial::factor_square_free_primitive(f = " << f << ", factors = " << f_factors << ")" << endl;); - - manager & pm = f.m(); - numeral_manager & nm = pm.m(); - - // to start with, maybe this should be part of input - var x = pm.max_var(f); - // get all the variables - var_vector vars, vars_no_x; - pm.vars(f, vars); - for(unsigned i = 0; i < vars.size(); ++ i) { - if (vars[i] != x) { - vars_no_x.push_back(vars[i]); - } - } - SASSERT(vars.size() > 1); - - // degree of the main variable - unsigned x_degree = pm.degree(f, x); - // the leading coefficient - polynomial_ref f_lc(pm); - f_lc = pm.coeff(f, x, x_degree); - - // the vector of values we substitute - upolynomial::scoped_numeral_vector a(nm); - - // the univariate polynomial - upolynomial::manager upm(nm); - upolynomial::scoped_numeral_vector f_u(upm); - - // generate the values to substitute and substitute them to get f_u(x) = f(a, x), the univariate version of f - unsigned size = 1; - a.resize(vars_no_x.size()); - for (unsigned i = 0; i < a.size(); ++ i) { nm.reset(a[i]); } - generate_substitution_values(f, x, f_lc, vars_no_x, size, a, upm, f_u); - - TRACE("polynomial::factorization::multivariate", - tout << "f_u = "; upm.display(tout, f_u); tout << endl; - tout << "substitution:" << endl; - for (unsigned i = 0; i < vars_no_x.size(); ++ i) { - tout << "x" << vars[i] << " -> " << nm.to_string(a[i]) << endl; - }); - - // the primitive part of f_u - scoped_numeral f_u_lc(nm); - upolynomial::scoped_numeral_vector f_u_pp(nm); - upm.get_primitive_and_content(f_u, f_u_pp, f_u_lc); - - TRACE("polynomial::factorization::multivariate", - tout << "f_u_lc" << nm.to_string(f_u_lc) << endl; - tout << "f_u_pp = "; upm.display(tout, f_u_pp); tout << endl; - ); - - // factor the univariate one - upolynomial::factors factors_u(upm); - upolynomial::factor_square_free(upm, f_u, factors_u); - - TRACE("polynomial::factorization::multivariate", - tout << "factors_u = " << factors_u << endl; - ); - - // if there is no univariate factors, it's irreducible - if (factors_u.distinct_factors() == 1) { - f_factors.push_back(f, 1); - return false; - } - - // translate f with a, so that we work modulo x_i^k and not (x_i - a_i)^k - polynomial_ref f_t(pm); - // Do the translation, we must have that a[x] = 0 - pm.translate(f, vars_no_x, a, f_t); - - TRACE("polynomial::factorization::multivariate", - tout << "f_t = " << f_t << endl; - ); - - // the zp manager stuff, we'll be changing the base - upolynomial::zp_numeral_manager zp_nm(nm, 2); - upolynomial::zp_manager zp_upm(zp_nm); - - // get the first prime number p that keeps f square-free - scoped_numeral p(nm); - prime_iterator prime_it; - upolynomial::scoped_numeral_vector f_u_pp_zp(nm); - do { - // create Z_p with the next prime - nm.set(p, prime_it.next()); - // translate to Zp[x] - zp_nm.set_p(p); - upolynomial::to_zp_manager(zp_upm, f_u_pp, f_u_pp_zp); - } while (!zp_upm.is_square_free(f_u_pp_zp)); - - TRACE("polynomial::factorization::multivariate", - tout << "p = " << p << endl; - tout << "f_t = " << f_t << endl; - ); - - // convert factors of f to factors modulo p (monic ones) - upolynomial::zp_factors factors_u_zp(zp_upm); - upolynomial::scoped_numeral_vector current_factor(nm); - for (unsigned i = 0; i < factors_u.distinct_factors(); ++ i) { - upolynomial::to_zp_manager(zp_upm, factors_u[i], current_factor); - zp_upm.mk_monic(current_factor); - factors_u_zp.push_back_swap(current_factor, 1); - } - - TRACE("polynomial::factorization::multivariate", - tout << "factors_u_zp = " << factors_u_zp << endl; - ); - - // compute factor coefficient bound (pover p^e) of the translated f with the leading coefficient added, i.e. - // f_t*lc(f_t, x) = f_t*lc(f, x) - unsigned e; - scoped_numeral p_e(nm); - var2degree target_ideal; - upolynomial::scoped_numeral f_t_lc(nm); - nm.set(f_t_lc, pm.numeral_lc(f_t, x)); - polynomial_ref f_t_with_lc(pm); - f_t_with_lc = pm.mul(f_t_lc, f_t); - multivariate_factor_coefficient_bound(f_t_with_lc, x, p, e, p_e, target_ideal); - - TRACE("polynomial::factorization::multivariate", - tout << "target_ideal = " << target_ideal << endl; - ); - - // do the multivariate lifting of the translated one f_t - upolynomial::zp_numeral_manager zpe_nm(nm, p_e); - zp_manager zpe_pm(zpe_nm, &pm.mm()); - zp_manager zp_pm(zp_nm, &pm.mm()); - zp_factors factors_zpe(zpe_pm); - multivariate_hensel_lift(pm, zp_pm, zpe_pm, f_t, x, e, vars, upm, f_u_pp_zp, factors_u_zp, target_ideal, factors_zpe); - - TRACE("polynomial::factorization::multivariate", - tout << "factors_zpe = " << factors_zpe << endl; - ); - - // try the factors from the lifted combinations - factors f_t_factors(pm); - bool remove = false; - mfactorization_combination_iterator it(factors_zpe, x); - unsigned max_degre = pm.degree(f_t, x) / 2; - zp_polynomial_ref zpe_trial_factor(zpe_pm); - while (it.next(remove)) { - // - // our bound ensures we can extract the right factors of degree at most 1/2 of the original - // so, if out trial factor has degree bigger than 1/2, we need to take the rest of the factors - // but, if we take the rest and it works, it doesn't meen that the rest is factorized, so we still take out - // the original factor - // - bool using_left = it.current_degree() <= max_degre; - if (using_left) { - // do a quick check first - it.left(zpe_trial_factor); - } else { - // do a quick check first - it.right(zpe_trial_factor); - } - // add the lc(f_pp) to the trial divisor - zpe_trial_factor = zpe_pm.mul(f_t_lc, zpe_trial_factor); - polynomial_ref trial_factor(pm), trial_factor_quo(pm); - trial_factor = convert(zpe_pm, zpe_trial_factor, pm); - bool true_factor = true; - trial_factor_quo = pm.exact_div(f_t_with_lc, trial_factor); - // if division is precise we have a factor - if (true_factor) { - if (!using_left) { - // as noted above, we still use the original factor - trial_factor.swap(trial_factor_quo); - } - // We need to get the content out of the factor - upolynomial::scoped_numeral trial_factor_cont(nm); - pm.int_content(f_t, trial_factor_cont); - trial_factor = pm.exact_div(trial_factor, trial_factor_cont); - // add the factor - f_t_factors.push_back(trial_factor, 1); - // we continue with the int-primitive quotient (with the lc added back) - // but we also have to keep lc(f_t)*f_t - pm.int_content(trial_factor_quo, f_t_lc); // content - trial_factor_quo = pm.exact_div(trial_factor_quo, f_t_lc); - nm.set(f_t_lc, pm.numeral_lc(trial_factor_quo, x)); - f_t = pm.mul(f_t_lc, trial_factor_quo); - // but we also remove it from the iterator - remove = true; - } else { - // don't remove this combination - remove = false; - } - } - - // translate the factor back - for (unsigned i = 0; i < a.size(); ++ i) { - nm.neg(a[i]); - } - for (unsigned i = 0; i < f_t_factors.distinct_factors(); ++ i) { - polynomial_ref factor(pm); - pm.translate(f_t_factors[i], vars_no_x, a, factor); - f_factors.push_back(factor, 1); - } - - TRACE("polynomial::factorization", tout << "polynomial::factor_square_free_primitive(f = " << f << ") => " << f_factors << endl;); - return true; -} - -}; // end polynomial namespace - -#endif diff --git a/src/math/polynomial/polynomial_factorization.h b/src/math/polynomial/polynomial_factorization.h deleted file mode 100644 index f069121ba..000000000 --- a/src/math/polynomial/polynomial_factorization.h +++ /dev/null @@ -1,65 +0,0 @@ -/*++ -Copyright (c) 2011 Microsoft Corporation - -Module Name: - - polynomial_factorization.h - -Abstract: - - Methods for factoring polynomials. - -Author: - - Dejan (t-dejanj) 2011-11-29 - -Notes: - - [1] Elwyn Ralph Berlekamp. Factoring Polynomials over Finite Fields. Bell System Technical Journal, - 46(8-10):1853-1859, 1967. - [2] Donald Ervin Knuth. The Art of Computer Programming, volume 2: Seminumerical Algorithms. Addison Wesley, third - edition, 1997. - [3] Henri Cohen. A Course in Computational Algebraic Number Theory. Springer Verlag, 1993. - ---*/ - -#pragma once - -#if 0 -// Disabled for reorg -#include "polynomial.h" -#include "upolynomial.h" -#include "bit_vector.h" -#include "z3_exception.h" - -namespace polynomial { - - /** - \brief Something to throw when we are in trouble. - */ - class factorization_exception : public default_exception { - public: - factorization_exception(char const * msg) : default_exception(msg) {} - }; - - /** - \brief Factor the polynomial f from Z[x1, ..., x_n]. Returns the index of the last factor that is completely - factored. I.e., if the method returns m, then f_1, ..., f_m are true irreducible factors, and the rest might - be further reducible. - */ - unsigned factor(polynomial_ref & f, factors & factors); - - /** - \brief Factor the square-free primitive polynomial f from Z[x1, ..., x_n]. Returns true if the factorization - was sucesseful, i.e. it was completed and the result is complete. Otherwise the quarantee is that the all but - the last factor are irreducible. - */ - bool factor_square_free_primitive(polynomial_ref const & f, factors & factors); -} - -inline std::ostream & operator<<(std::ostream & out, polynomial::factors & factors) { - factors.display(out); - return out; -} - -#endif From 8f95ee01e199b874f6542dbedaa3f0cb9ba804d4 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Tue, 10 Jan 2017 14:02:59 +0000 Subject: [PATCH 459/536] Removed polynomial factorization test cases. Relates to #852 and fixes #865. --- src/test/main.cpp | 1 - src/test/polynomial.cpp | 1 - src/test/polynomial_factorization.cpp | 746 -------------------------- 3 files changed, 748 deletions(-) delete mode 100644 src/test/polynomial_factorization.cpp diff --git a/src/test/main.cpp b/src/test/main.cpp index 320eddd7b..9239d0119 100644 --- a/src/test/main.cpp +++ b/src/test/main.cpp @@ -193,7 +193,6 @@ int main(int argc, char ** argv) { TST(polynomial); TST(upolynomial); TST(algebraic); - TST(polynomial_factorization); TST(prime_generator); TST(permutation); TST(nlsat); diff --git a/src/test/polynomial.cpp b/src/test/polynomial.cpp index 56eb61a11..03eb321cd 100644 --- a/src/test/polynomial.cpp +++ b/src/test/polynomial.cpp @@ -18,7 +18,6 @@ Notes: --*/ #if !defined(__clang__) #include"polynomial.h" -#include"polynomial_factorization.h" #include"polynomial_var2value.h" #include"polynomial_cache.h" #include"linear_eq_solver.h" diff --git a/src/test/polynomial_factorization.cpp b/src/test/polynomial_factorization.cpp deleted file mode 100644 index 361ca4630..000000000 --- a/src/test/polynomial_factorization.cpp +++ /dev/null @@ -1,746 +0,0 @@ -/*++ -Copyright (c) 2011 Microsoft Corporation - -Module Name: - - polynomial_factorization.cpp - -Abstract: - - Testing of factorization. - -Author: - - Dejan (t-dejanj) 2011-11-29 - -Notes: - ---*/ -#include"upolynomial_factorization_int.h" -#include"timeit.h" -#include"polynomial.h" -#include"rlimit.h" -#if 0 -#include"polynomial_factorization.h" -#endif - -using std::cout; -using std::endl; - -// some prime numbers -unsigned primes[] = { - 2, 3, 5, 7, 11, 13, 17, 19, 23, 29 -}; - -// [i,l]: how many factors the Knuth example has over p_i, when i = 0 it's Z, p_1 = 2, for l=0 distinct, for l = 1 total -unsigned knuth_factors[2][11] = { - // x^8 + x^6 + 10*x^4 + 10*x^3 + 8*x^2 + 2*x + 8 - {2, 2, 3, 3, 2, 3, 1, 4, 3, 1, 1}, - {8, 2, 3, 3, 2, 3, 1, 4, 3, 1, 1}, -}; - -// [k,l,i]: how many factors the S_k has over p_i, when i = 0 it's Z, p_1 = 2, for l=0 distinct, for l = 1 total -unsigned swinnerton_dyer_factors[5][2][11] = { - // S1 = (x^2) - 2 - { - // 2, 3, 5, 7,11,13,17,19,23,29, Z - {1, 1, 1, 2, 1, 1, 2, 1, 2, 1, 1}, - {2, 1, 1, 2, 1, 1, 2, 1, 2, 1, 1} - }, - // S2 = (x^4) - 10*(x^2) + 1 - { - {1, 1, 2, 2, 2, 2, 2, 2, 4, 2, 1}, - {4, 2, 2, 2, 2, 2, 2, 2, 4, 2, 1} - }, - // S3 = (x^8) - 40*(x^6) + 352*(x^4) - 960*(x^2) + 576 - { - {1, 2, 2, 4, 4, 4, 4, 4, 4, 4, 1}, - {8, 6, 4, 4, 4, 4, 4, 4, 4, 4, 1} - }, - // S4 = (x^16) - 136*(x^14) + 6476*(x^12) - 141912*(x^10) + 1513334*(x^8) - 7453176*(x^6) + 13950764*(x^4) - 5596840*(x^2) + 46225 - { - {1, 4, 3, 4, 8, 8, 8, 8, 8, 8, 1}, - {16, 12, 10, 8, 8, 8, 8, 8, 8, 8, 1} - }, - // SA = S1*S2*S3*S4 - { - //p = 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, Z - { 2, 6, 3, 6, 15, 11, 16, 15, 18, 15, 1}, - {30, 21, 17, 16, 15, 15, 16, 15, 18, 15, 1} - } -}; - -int random_polynomial[20][2][11] = { - { - // 3*x^10 + 2*x^9 + 4*x^8 + 4*x^7 + 4*x^6 + x^5 + 3*x^2 + 3*x - { 4, 3, 4, 4, 3, 4, 4, 4, 3, 4, 2 }, - { 7, 7, 4, 4, 3, 4, 4, 4, 3, 4, 2 }, - }, - { - // 4*x^9 + 4*x^8 + x^7 + x^6 + 2*x^5 + 3*x^4 + 4*x^2 + 4*x - { 2, 2, 3, 3, 4, 2, 5, 3, 4, 2, 2 }, - { 5, 2, 3, 3, 4, 2, 5, 3, 5, 2, 2 }, - }, - { - // 3*x^10 + 4*x^9 + 3*x^8 + x^6 + 4*x^5 + 4*x^4 + x^2 - { 3, 2, 4, 4, 5, 3, 4, 2, 4, 5, 2 }, - { 6, 3, 5, 5, 6, 4, 5, 3, 5, 7, 3 }, - }, - { - // x^10 + 4*x^9 + x^8 + 3*x^7 + 3*x^4 + 3*x^3 + x^2 + 4*x - { 3, 4, 4, 3, 3, 3, 4, 4, 5, 3, 2 }, - { 8, 4, 4, 3, 3, 3, 4, 4, 5, 3, 2 }, - }, - { - // x^9 + 2*x^8 + 3*x^7 + x^6 + 2*x^5 + 4*x^4 + 3*x^2 - { 3, 3, 3, 3, 4, 4, 4, 3, 3, 4, 2 }, - { 5, 6, 4, 5, 5, 6, 5, 4, 4, 5, 3 }, - }, - { - // x^10 + x^9 + 4*x^7 + x^6 + 3*x^5 + x^4 + x^3 + x - { 3, 2, 3, 3, 3, 5, 3, 2, 4, 4, 2 }, - { 3, 2, 3, 3, 3, 5, 3, 2, 4, 4, 2 }, - }, - { - // 4*x^10 + 4*x^9 + x^8 + 2*x^7 + 3*x^6 + 4*x^5 + 3*x^4 + x^3 + 2*x^2 + 4*x - { 3, 3, 2, 5, 3, 4, 2, 4, 5, 5, 2 }, - { 5, 3, 2, 5, 3, 4, 2, 4, 5, 5, 2 }, - }, - { - // 3*x^10 + 4*x^9 + 3*x^8 + x^7 + x^6 + 2*x^5 + x^4 + 2*x^3 + 2*x^2 + x - { 3, 4, 6, 4, 4, 4, 4, 6, 6, 4, 3 }, - { 4, 4, 7, 4, 4, 4, 4, 6, 6, 4, 3 }, - }, - { - // 4*x^10 + x^9 + x^7 + 2*x^5 + 3*x^3 + x^2 + 4*x - { 3, 3, 3, 4, 4, 5, 4, 5, 2, 4, 2 }, - { 4, 4, 3, 4, 4, 5, 4, 5, 2, 4, 2 }, - }, - { - // x^10 + 3*x^9 + 3*x^8 + x^7 + 3*x^6 + 3*x^5 + 3*x^4 + x^2 + 3*x - { 2, 3, 4, 4, 3, 3, 4, 3, 3, 4, 2 }, - { 2, 4, 5, 4, 3, 3, 4, 3, 3, 4, 2 }, - }, - { - // x^10 + x^9 + 2*x^8 + x^7 + 4*x^6 + 2*x^5 + 3*x^4 + 4*x^3 + x^2 + 2*x - { 3, 4, 4, 3, 3, 3, 3, 4, 5, 3, 2 }, - { 4, 4, 4, 3, 3, 3, 3, 4, 5, 3, 2 }, - }, - { - // 3*x^9 + x^8 + 3*x^7 + 3*x^6 + x^5 + 2*x^4 + 4*x^3 + 4*x^2 + 3*x - { 4, 3, 3, 3, 5, 3, 6, 4, 2, 2, 2 }, - { 6, 4, 3, 3, 5, 3, 6, 4, 2, 2, 2 }, - }, - { - // 2*x^10 + 3*x^9 + 2*x^8 + 4*x^7 + x^6 + 3*x^5 + 2*x^3 + 3*x^2 + 2*x + 2 - { 3, 3, 3, 5, 4, 5, 6, 7, 4, 6, 3 }, - { 8, 4, 3, 7, 4, 5, 6, 7, 4, 7, 3 }, - }, - { - // 3*x^10 + x^9 + 4*x^8 + 2*x^7 + x^6 + 4*x^5 + x^4 + 3*x^3 + x + 2 - { 3, 3, 3, 2, 6, 4, 4, 4, 3, 3, 2 }, - { 3, 3, 3, 2, 6, 5, 4, 5, 3, 3, 2 }, - }, - { - // 4*x^10 + 2*x^9 + x^8 + x^6 + x^5 + 3*x^4 + 4*x^3 + x^2 + x - { 3, 4, 2, 4, 4, 4, 4, 2, 3, 3, 2 }, - { 6, 4, 2, 4, 4, 4, 4, 2, 3, 3, 2 }, - }, - { - // 4*x^10 + 2*x^7 + 4*x^6 + 2*x^3 + x - { 1, 3, 3, 3, 4, 4, 4, 3, 3, 2, 2 }, - { 1, 3, 3, 3, 4, 4, 4, 3, 3, 2, 2 }, - }, - { - // 4*x^10 + x^9 + x^8 + 4*x^7 + 4*x^4 + 2*x^2 + x + 4 - { 3, 4, 2, 5, 3, 6, 3, 6, 3, 3, 2 }, - { 3, 6, 2, 5, 3, 6, 3, 6, 3, 3, 2 }, - }, - { - // 3*x^10 + 2*x^8 + x^7 + x^6 + 3*x^4 + 3*x^3 + 4*x^2 + 3*x - { 4, 3, 4, 3, 3, 3, 2, 4, 4, 3, 2 }, - { 5, 4, 4, 3, 3, 3, 2, 4, 4, 3, 2 }, - }, - { - // x^10 + 2*x^9 + 2*x^6 + 4*x^3 + 4*x^2 - { 1, 2, 2, 3, 3, 4, 3, 3, 3, 3, 2 }, - { 10, 3, 3, 4, 4, 6, 4, 4, 4, 4, 3 }, - }, - { - // x^10 + 2*x^9 + 2*x^8 + 4*x^7 + 4*x^6 + x^5 + x^3 + x^2 + 3*x - { 2, 4, 2, 3, 3, 3, 5, 5, 6, 2, 2 }, - { 2, 5, 2, 3, 3, 3, 5, 5, 6, 2, 2 }, - } -}; - -#if 0 -static void tst_square_free_finite_1() { - polynomial::numeral_manager nm; - reslimit rl; polynomial::manager pm(rl, nm); - - // example from Knuth, p. 442 - polynomial_ref x(pm); - x = pm.mk_polynomial(pm.mk_var()); - - // polynomials \prod_{i < p} (x - i)^i - for (unsigned prime_i = 0; prime_i < 5; ++ prime_i) - { - int p = primes[prime_i]; - - // make the polynomial - polynomial_ref f(pm); - f = x - 1; - for (int i = 2; i < p; ++ i) { - f = f*((x + (-i))^i); - } - cout << "Factoring " << f << " into square-free over Z_" << p << endl; - - // convert to univariate over Z_p - upolynomial::zp_manager upm(nm); - upm.set_zp(p); - upolynomial::numeral_vector f_u; - upm.to_numeral_vector(f, f_u); - - cout << "Input: "; upm.display(cout, f_u); cout << endl; - - // factor it - upolynomial::zp_factors f_factors(upm); - cout << "Start: " << f_factors << endl; - - upolynomial::zp_square_free_factor(upm, f_u, f_factors); - - upolynomial::numeral_vector mult; - f_factors.multiply(mult); - cout << "Multiplied: "; upm.display(cout, mult); cout << endl; - - SASSERT(upm.eq(mult, f_u)); - - // remove the temps - upm.reset(f_u); - upm.reset(mult); - } -} - -static void tst_factor_finite_1() { - - polynomial::numeral_manager nm; - reslimit rl; polynomial::manager pm(rl, nm); - - // example from Knuth, p. 442 - polynomial_ref x(pm); - x = pm.mk_polynomial(pm.mk_var()); - polynomial_ref K(pm); - K = (x^8) + (x^6) + 10*(x^4) + 10*(x^3) + 8*(x^2) + 2*x + 8; - - // factor them for all the prime numbers - for (unsigned prime_i = 0; prime_i < sizeof(primes)/sizeof(unsigned); ++ prime_i) - { - // make the Z_p - unsigned prime = primes[prime_i]; - upolynomial::zp_manager upm(nm); - upm.set_zp(prime); - - // make the polynomial in Z_p - upolynomial::numeral_vector K_u; - upm.to_numeral_vector(K, K_u); - - cout << "Factoring " << K << "("; upm.display(cout, K_u); cout << ") in Z_" << prime << endl; - cout << "Expecting " << knuth_factors[0][prime_i] << " distinct factors, " << knuth_factors[1][prime_i] << " total" << endl; - - // factor it - upolynomial::zp_factors factors(upm); - /* bool factorized = */ upolynomial::zp_factor(upm, K_u, factors); - - // check the result - unsigned distinct = factors.distinct_factors(); - unsigned total = factors.total_factors(); - - cout << "Got " << factors << endl; - cout << "Thats " << distinct << " distinct factors, " << total << " total" << endl; - - SASSERT(knuth_factors[0][prime_i] == distinct); - SASSERT(knuth_factors[1][prime_i] == total); - - upolynomial::numeral_vector multiplied; - factors.multiply(multiplied); - SASSERT(upm.eq(K_u, multiplied)); - upm.reset(multiplied); - - // remove the temp - upm.reset(K_u); - } -} - -static void tst_factor_finite_2() { - - polynomial::numeral_manager nm; - reslimit rl; polynomial::manager pm(rl, nm); - - polynomial_ref x(pm); - x = pm.mk_polynomial(pm.mk_var()); - - // Swinnerton-Dyer polynomials (irreducible, modular factors of degree at most 2) - polynomial_ref S1 = (x^2) - 2; - polynomial_ref S2 = (x^4) - 10*(x^2) + 1; - polynomial_ref S3 = (x^8) - 40*(x^6) + 352*(x^4) - 960*(x^2) + 576; - polynomial_ref S4 = (x^16) - 136*(x^14) + 6476*(x^12) - 141912*(x^10) + 1513334*(x^8) - 7453176*(x^6) + 13950764*(x^4) - 5596840*(x^2) + 46225; - - vector S; - S.push_back(S1); - S.push_back(S2); - S.push_back(S3); - S.push_back(S4); - S.push_back(S1*S2*S3*S4); - - // factor all the S_i them for all the prime numbers - for (unsigned S_i = 0; S_i < S.size(); ++ S_i) { - for (unsigned prime_i = 0; prime_i < sizeof(primes)/sizeof(unsigned); ++ prime_i) { - unsigned prime = primes[prime_i]; - - upolynomial::zp_manager upm(nm); - upm.set_zp(prime); - - upolynomial::numeral_vector S_i_u; - upm.to_numeral_vector(S[S_i], S_i_u); - - cout << "Factoring "; upm.display(cout, S_i_u); cout << " over Z_" << prime << endl; - cout << "Expecting " << swinnerton_dyer_factors[S_i][0][prime_i] << " distinct factors, " << swinnerton_dyer_factors[S_i][1][prime_i] << " total" << endl; - - upolynomial::zp_factors factors(upm); - upolynomial::zp_factor(upm, S_i_u, factors); - - // check the result - unsigned distinct = factors.distinct_factors(); - unsigned total = factors.total_factors(); - - cout << "Got " << factors << endl; - cout << "Thats " << distinct << " distinct factors, " << total << " total" << endl; - - SASSERT(swinnerton_dyer_factors[S_i][0][prime_i] == distinct); - SASSERT(swinnerton_dyer_factors[S_i][1][prime_i] == total); - - upolynomial::numeral_vector multiplied; - factors.multiply(multiplied); - SASSERT(upm.eq(S_i_u, multiplied)); - upm.reset(multiplied); - - // remove the temp - upm.reset(S_i_u); - } - } -} - -static void tst_factor_finite_3() { - - polynomial::numeral_manager nm; - reslimit rl; polynomial::manager pm(rl, nm); - - polynomial_ref x(pm); - x = pm.mk_polynomial(pm.mk_var()); - - // random polynomials - vector random_p; - random_p.push_back( 3*(x^10) + 2*(x^9) + 4*(x^8) + 4*(x^7) + 4*(x^6) + 1*(x^5) + 3*(x^2) + 3*x + 0 ); - random_p.push_back( 4*(x^9) + 4*(x^8) + 1*(x^7) + 1*(x^6) + 2*(x^5) + 3*(x^4) + 4*(x^2) + 4*x + 0 ); - random_p.push_back( 3*(x^10) + 4*(x^9) + 3*(x^8) + 1*(x^6) + 4*(x^5) + 4*(x^4) + 1*(x^2) + 0 ); - random_p.push_back( 1*(x^10) + 4*(x^9) + 1*(x^8) + 3*(x^7) + 3*(x^4) + 3*(x^3) + 1*(x^2) + 4*x + 0 ); - random_p.push_back( 1*(x^9) + 2*(x^8) + 3*(x^7) + 1*(x^6) + 2*(x^5) + 4*(x^4) + 3*(x^2) + 0 ); - random_p.push_back( 1*(x^10) + 1*(x^9) + 4*(x^7) + 1*(x^6) + 3*(x^5) + 1*(x^4) + 1*(x^3) + 1*x + 0 ); - random_p.push_back( 4*(x^10) + 4*(x^9) + 1*(x^8) + 2*(x^7) + 3*(x^6) + 4*(x^5) + 3*(x^4) + 1*(x^3) + 2*(x^2) + 4*x + 0 ); - random_p.push_back( 3*(x^10) + 4*(x^9) + 3*(x^8) + 1*(x^7) + 1*(x^6) + 2*(x^5) + 1*(x^4) + 2*(x^3) + 2*(x^2) + 1*x + 0 ); - random_p.push_back( 4*(x^10) + 1*(x^9) + 1*(x^7) + 2*(x^5) + 3*(x^3) + 1*(x^2) + 4*x + 0 ); - random_p.push_back( 1*(x^10) + 3*(x^9) + 3*(x^8) + 1*(x^7) + 3*(x^6) + 3*(x^5) + 3*(x^4) + 1*(x^2) + 3*x + 0 ); - random_p.push_back( 1*(x^10) + 1*(x^9) + 2*(x^8) + 1*(x^7) + 4*(x^6) + 2*(x^5) + 3*(x^4) + 4*(x^3) + 1*(x^2) + 2*x + 0 ); - random_p.push_back( 3*(x^9) + 1*(x^8) + 3*(x^7) + 3*(x^6) + 1*(x^5) + 2*(x^4) + 4*(x^3) + 4*(x^2) + 3*x + 0 ); - random_p.push_back( 2*(x^10) + 3*(x^9) + 2*(x^8) + 4*(x^7) + 1*(x^6) + 3*(x^5) + 2*(x^3) + 3*(x^2) + 2*x + 2 ); - random_p.push_back( 3*(x^10) + 1*(x^9) + 4*(x^8) + 2*(x^7) + 1*(x^6) + 4*(x^5) + 1*(x^4) + 3*(x^3) + 1*x + 2 ); - random_p.push_back( 4*(x^10) + 2*(x^9) + 1*(x^8) + 1*(x^6) + 1*(x^5) + 3*(x^4) + 4*(x^3) + 1*(x^2) + 1*x + 0 ); - random_p.push_back( 4*(x^10) + 2*(x^7) + 4*(x^6) + 2*(x^3) + 1*x + 0 ); - random_p.push_back( 4*(x^10) + 1*(x^9) + 1*(x^8) + 4*(x^7) + 4*(x^4) + 2*(x^2) + 1*x + 4 ); - random_p.push_back( 3*(x^10) + 2*(x^8) + 1*(x^7) + 1*(x^6) + 3*(x^4) + 3*(x^3) + 4*(x^2) + 3*x + 0 ); - random_p.push_back( 1*(x^10) + 2*(x^9) + 2*(x^6) + 4*(x^3) + 4*(x^2) + 0 ); - random_p.push_back( 1*(x^10) + 2*(x^9) + 2*(x^8) + 4*(x^7) + 4*(x^6) + 1*(x^5) + 1*(x^3) + 1*(x^2) + 3*x + 0 ); - - // factor all the randoms them for all the prime numbers - for (unsigned random_i = 0; random_i < random_p.size(); ++ random_i) { - for (unsigned prime_i = 0; prime_i < sizeof(primes)/sizeof(unsigned); ++ prime_i) { - unsigned prime = primes[prime_i]; - - upolynomial::zp_manager upm(nm); - upm.set_zp(prime); - - upolynomial::numeral_vector poly; - upm.to_numeral_vector(random_p[random_i], poly); - - cout << "Factoring "; upm.display(cout, poly); cout << " over Z_" << prime << endl; - cout << "Expecting " << swinnerton_dyer_factors[random_i][0][prime_i] << " distinct factors, " << random_polynomial[random_i][1][prime_i] << " total" << endl; - - upolynomial::zp_factors factors(upm); - upolynomial::zp_factor(upm, poly, factors); - - // check the result - unsigned distinct = factors.distinct_factors(); - unsigned total = factors.total_factors(); - - cout << "Got " << factors << endl; - cout << "Thats " << distinct << " distinct factors, " << total << " total" << endl; - - // SASSERT(random_polynomial[random_i][0][prime_i] == distinct); - // SASSERT(random_polynomial[random_i][1][prime_i] == total); - - upolynomial::numeral_vector multiplied; - factors.multiply(multiplied); - bool equal = upm.eq(poly, multiplied); - cout << (equal ? "equal" : "not equal") << endl; - SASSERT(equal); - upm.reset(multiplied); - - // remove the temp - upm.reset(poly); - } - } -} - -static void tst_factor_enumeration() { - polynomial::numeral_manager nm; - reslimit rl; polynomial::manager pm(rl, nm); - - polynomial_ref x(pm); - x = pm.mk_polynomial(pm.mk_var()); - - vector factors; - for (int i = 0; i < 5; ++ i) { - polynomial_ref factor(pm); - factor = x + i; - factors.push_back(factor); - } - - upolynomial::manager upm(nm); - - upolynomial::zp_manager upm_13(nm); - upm_13.set_zp(13); - upolynomial::zp_factors factors_13(upm_13); - - upolynomial::numeral constant; - nm.set(constant, 10); - factors_13.set_constant(constant); - - for (unsigned i = 0; i < 5; ++ i) { - upolynomial::numeral_vector ufactor; - upm_13.to_numeral_vector(factors[i], ufactor); - factors_13.push_back(ufactor, 1); - upm.reset(ufactor); - } - - cout << "All: " << factors_13 << endl; - - upolynomial::factorization_degree_set degrees(factors_13); - degrees.display(cout); cout << endl; - - scoped_mpz_vector left(nm), right(nm); - upolynomial::ufactorization_combination_iterator it(factors_13, degrees); - unsigned i = 0; - it.display(cout); - bool remove = false; - while (it.next(remove)) { - it.left(left); - it.right(right); - cout << "Left " << i << ": "; upm.display(cout, left); cout << endl; - cout << "Right " << i << ": "; upm.display(cout, right); cout << endl; - i ++; - if (i % 3 == 0) { - remove = true; - } else { - remove = false; - } - it.display(cout); - } - // SASSERT(i == 15); - - return; - - for (unsigned i = 0; i < 5; ++ i) { - factors_13.set_degree(i, factors_13.get_degree(i) + i); - } - cout << "Different: " << factors_13 << " of degree " << factors_13.get_degree() << endl; - upolynomial::factorization_degree_set degrees1(factors_13); - degrees1.display(cout); cout << endl; // [0, ..., 15] - - polynomial_ref tmp1 = (x^3) + 1; - polynomial_ref tmp2 = (x^5) + 2; - polynomial_ref tmp3 = (x^7) + 3; - upolynomial::numeral_vector up1, up2, up3; - upm_13.to_numeral_vector(tmp1, up1); - upm_13.to_numeral_vector(tmp2, up2); - upm_13.to_numeral_vector(tmp3, up3); - upolynomial::zp_factors tmp(upm_13); - tmp.push_back(up1, 1); - tmp.push_back(up2, 1); - tmp.push_back(up3, 1); - upm_13.reset(up1); - upm_13.reset(up2); - upm_13.reset(up3); - - cout << "Different: " << tmp << " of degree " << tmp.get_degree() << endl; - upolynomial::factorization_degree_set degrees2(tmp); - degrees2.display(cout); cout << endl; - - tmp1 = (x^2) + 1; - tmp2 = (x^10) + 2; - tmp3 = x + 3; - upm_13.to_numeral_vector(tmp1, up1); - upm_13.to_numeral_vector(tmp2, up2); - upm_13.to_numeral_vector(tmp3, up3); - tmp.clear(); - tmp.push_back(up1, 2); - tmp.push_back(up2, 1); - tmp.push_back(up3, 1); - cout << "Different: " << tmp << " of degree " << tmp.get_degree() << endl; - upm_13.reset(up1); - upm_13.reset(up2); - upm_13.reset(up3); - upolynomial::factorization_degree_set degrees3(tmp); - degrees3.display(cout); cout << endl; - degrees1.intersect(degrees3); - degrees1.display(cout); cout << endl; -} - -static void tst_factor_square_free_univariate_1(unsigned max_length) { - - polynomial::numeral_manager nm; - upolynomial::numeral test; - upolynomial::numeral p; - nm.set(test, -9); - nm.set(p, 5); - nm.mod(test, p, test); - - reslimit rl; polynomial::manager pm(rl, nm); - - polynomial_ref x(pm); - x = pm.mk_polynomial(pm.mk_var()); - - cout << "R. = QQ['x']" << endl; - - // let's start with \prod (p_i x^{p_{i+1} - p_{i+1}) - unsigned n_primes = sizeof(primes)/sizeof(unsigned); - max_length = std::min(max_length, n_primes); - for(unsigned length = 1; length < max_length; ++ length) { - - // starting from prime_i going for length - for(unsigned start_i = 0; start_i < n_primes; ++ start_i) { - - polynomial_ref f(pm); - - bool first = true; - for (unsigned prime_i = 0; prime_i < length; ++ prime_i) { - int p1 = primes[(start_i + prime_i) % n_primes]; - int p2 = primes[(start_i + prime_i + 1) % n_primes]; - if (first) { - f = (p1*(x^p2) - p2); - first = false; - } else { - f = f*(p1*(x^p2) - p2); - } - } - - upolynomial::manager upm(nm); - scoped_mpz_vector f_u(nm); - upm.to_numeral_vector(f, f_u); - - cout << "factoring "; upm.display(cout, f_u); cout << endl; - cout << "expecting " << length << " factors "; - upolynomial::factors factors(upm); - /* bool ok = */ upolynomial::factor_square_free(upm, f_u, factors); - cout << "got " << factors << endl; - - SASSERT(factors.distinct_factors() == length); - } - } -} - -static void tst_factor_square_free_univariate_2() { - polynomial::numeral_manager nm; - reslimit rl; polynomial::manager pm(rl, nm); - - polynomial_ref x(pm); - x = pm.mk_polynomial(pm.mk_var()); - - // Swinnerton-Dyer polynomials (irreducible, modular factors of degree at most 2) - polynomial_ref S1 = (x^2) - 2; - polynomial_ref S2 = (x^4) - 10*(x^2) + 1; - polynomial_ref S3 = (x^8) - 40*(x^6) + 352*(x^4) - 960*(x^2) + 576; - polynomial_ref S4 = (x^16) - 136*(x^14) + 6476*(x^12) - 141912*(x^10) + 1513334*(x^8) - 7453176*(x^6) + 13950764*(x^4) - 5596840*(x^2) + 46225; - - vector S; - S.push_back(S1); - S.push_back(S2); - S.push_back(S3); - S.push_back(S4); - - upolynomial::manager upm(nm); - - // factor all the S_i them for all the prime numbers - for (unsigned S_i = 0; S_i < S.size(); ++ S_i) { - upolynomial::numeral_vector S_i_u; - upm.to_numeral_vector(S[S_i], S_i_u); - - cout << "Factoring "; upm.display(cout, S_i_u); cout << " over Z " << endl; - upolynomial::factors factors(upm); - upolynomial::factor_square_free(upm, S_i_u, factors); - - // check the result - cout << "Got " << factors << endl; - - // remove the temp - upm.reset(S_i_u); - } -} - -static void tst_factor_square_free_univariate_3() { - polynomial::numeral_manager nm; - reslimit rl; polynomial::manager pm(rl, nm); - - polynomial_ref x(pm); - x = pm.mk_polynomial(pm.mk_var()); - - polynomial_ref deg70 = (x^70) - 6*(x^65) - (x^60) + 60*(x^55) - 54*(x^50) - 230*(x^45) + 274*(x^40) + 542*(x^35) - 615*(x^30) - 1120*(x^25) + 1500*(x^20) - 160*(x^15) - 395*(x^10) + 76*(x^5) + 34; - - upolynomial::manager upm(nm); - upolynomial::numeral_vector deg70_u; - - upm.to_numeral_vector(deg70, deg70_u); - - cout << "Factoring "; upm.display(cout, deg70_u); cout << " over Z " << endl; - upolynomial::factors factors(upm); - upolynomial::factor_square_free(upm, deg70_u, factors); - - cout << "Got " << factors << endl; - - upm.reset(deg70_u); -} -#endif - -void tst_factor_swinnerton_dyer_big(unsigned max) { - polynomial::numeral_manager nm; - reslimit rl; polynomial::manager pm(rl, nm); - - polynomial_ref x(pm); - x = pm.mk_polynomial(pm.mk_var()); - - vector roots; - vector vars; - - unsigned n = std::min(max, static_cast(sizeof(primes)/sizeof(unsigned))); - for(unsigned prime_i = 0; prime_i < n; ++ prime_i) { - - int prime = primes[prime_i]; - - cout << "Computing Swinnerton-Dyer[" << prime_i + 1 << "]" << endl; - - polynomial_ref y(pm); - vars.push_back(pm.mk_var()); - y = pm.mk_polynomial(vars.back()); - - polynomial_ref p(pm); - p = (y^2) - prime; - roots.push_back(p); - - polynomial_ref computation = x; - for (unsigned i = 0; i < roots.size(); ++ i) { - polynomial_ref var(pm); - var = pm.mk_polynomial(vars[i]); - computation = computation - var; - } - - { - timeit timer(true, "computing swinnerton-dyer"); - - for (unsigned i = 0; i < roots.size(); ++ i) { - polynomial_ref tmp(pm); - pm.resultant(computation, roots[i], vars[i], tmp); - computation = tmp; - } - } - - cout << "Computed Swinnerton-Dyer[" << prime_i + 1 << "], degree = " << pm.total_degree(computation) << ", size = " << pm.size(computation) << endl; - - cout << "Starting factoring " << endl; - - { - timeit timer(true, "factoring swinnerton-dyer"); - - reslimit rl; - upolynomial::manager upm(rl, nm); - scoped_mpz_vector sd_u(nm); - upm.to_numeral_vector(computation, sd_u); - upolynomial::factors factors(upm); - upolynomial::factor_square_free(upm, sd_u, factors); - cout << "Got " << factors.distinct_factors() << " factors" << endl; - } - - } -} - -static void tst_factor_square_free_multivariate_1(unsigned max_n) { -#if 0 - polynomial::numeral_manager nm; - upolynomial::numeral test; - upolynomial::numeral p; - nm.set(test, -9); - nm.set(p, 5); - nm.mod(test, p, test); - - reslimit rl; polynomial::manager pm(rl, nm); - - polynomial_ref x(pm); - x = pm.mk_polynomial(pm.mk_var()); - - polynomial_ref y(pm); - y = pm.mk_polynomial(pm.mk_var()); - - // lets start simple x^n - y^n - for (unsigned prime_i = 0; prime_i < sizeof(primes)/sizeof(unsigned); ++ prime_i) { - unsigned prime = primes[prime_i]; - - if (prime > max_n) { - break; - } - - polynomial_ref f = (x^prime) - (y^prime); - cout << "factoring: " << f << endl; - - // factor - polynomial::factors factors(pm); - polynomial::factor_square_free_primitive(f, factors); - - cout << "got: " << factors << endl; - } -#endif -} - - -void tst_polynomial_factorization() { - - enable_trace("polynomial::factorization"); - // enable_trace("polynomial::factorization::bughunt"); - enable_trace("polynomial::factorization::multivariate"); - // enable_trace("upolynomial"); - - // Z_p square-free factorization tests - // tst_square_free_finite_1(); - - // Z_p factorization tests - // tst_factor_finite_1(); - // tst_factor_finite_2(); - // tst_factor_finite_3(); - - // Z factorization - // tst_factor_enumeration(); - // tst_factor_square_free_univariate_1(3); - // tst_factor_square_free_univariate_2(); - // tst_factor_square_free_univariate_3(); - // tst_factor_swinnerton_dyer_big(3); - - // Multivariate factorization - tst_factor_square_free_multivariate_1(3); -} From 8047f0d91ae249d1e86c36bebc7c3b6e91c1ebfe Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Tue, 10 Jan 2017 14:06:30 +0000 Subject: [PATCH 460/536] GCC compilation/keyword fix. Relates to #864 --- src/smt/smt_context.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index 476a419eb..ea97d1a64 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -1413,8 +1413,8 @@ namespace smt { else { TRACE("add_diseq", display_eq_detail(tout, bool_var2enode(v));); if (!add_diseq(get_enode(lhs), get_enode(rhs)) && !inconsistent()) { - literal not_eq = literal(l.var(), true); - set_conflict(b_justification(mk_justification(eq_propagation_justification(get_enode(lhs), get_enode(rhs)))), not_eq); + literal n_eq = literal(l.var(), true); + set_conflict(b_justification(mk_justification(eq_propagation_justification(get_enode(lhs), get_enode(rhs)))), n_eq); } } } From dda1774fa184e60744901ed42940d33d7122079a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 10 Jan 2017 08:21:49 -0800 Subject: [PATCH 461/536] update CMakeList to remove polynomial-factorization Signed-off-by: Nikolaj Bjorner --- contrib/cmake/src/test/CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/contrib/cmake/src/test/CMakeLists.txt b/contrib/cmake/src/test/CMakeLists.txt index 6f6615e0c..6ea07e84c 100644 --- a/contrib/cmake/src/test/CMakeLists.txt +++ b/contrib/cmake/src/test/CMakeLists.txt @@ -82,7 +82,6 @@ add_executable(test-z3 pdr.cpp permutation.cpp polynomial.cpp - polynomial_factorization.cpp polynorm.cpp prime_generator.cpp proof_checker.cpp From ba9d36605ba4b1b393edb267baa7f91b0c3b7d5d Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Tue, 10 Jan 2017 20:12:08 +0000 Subject: [PATCH 462/536] Formatting, whitespace --- src/smt/smt_context.h | 156 +++++++++++++++++++++--------------------- 1 file changed, 78 insertions(+), 78 deletions(-) diff --git a/src/smt/smt_context.h b/src/smt/smt_context.h index 0d758196e..b9b068442 100644 --- a/src/smt/smt_context.h +++ b/src/smt/smt_context.h @@ -50,9 +50,9 @@ Revision History: #include"statistics.h" #include"progress_callback.h" -// there is a significant space overhead with allocating 1000+ contexts in +// there is a significant space overhead with allocating 1000+ contexts in // the case that each context only references a few expressions. -// Using a map instead of a vector for the literals can compress space +// Using a map instead of a vector for the literals can compress space // consumption. #ifdef SPARSE_MAP #define USE_BOOL_VAR_VECTOR 0 @@ -98,7 +98,7 @@ namespace smt { // Remark: boolean expressions can also be internalized as // enodes. Examples: boolean expression nested in an // uninterpreted function. - expr_ref_vector m_e_internalized_stack; // stack of the expressions already internalized as enodes. + expr_ref_vector m_e_internalized_stack; // stack of the expressions already internalized as enodes. ptr_vector m_justifications; @@ -116,7 +116,7 @@ namespace smt { plugin_manager m_theories; // mapping from theory_id -> theory ptr_vector m_theory_set; // set of theories for fast traversal vector m_decl2enodes; // decl -> enode (for decls with arity > 0) - cg_table m_cg_table; + cg_table m_cg_table; dyn_ack_manager m_dyn_ack_manager; struct new_eq { enode * m_lhs; @@ -140,7 +140,7 @@ namespace smt { svector m_propagated_th_eqs; svector m_propagated_th_diseqs; svector m_diseq_vector; -#endif +#endif enode * m_is_diseq_tmp; // auxiliary enode used to find congruent equality atoms. tmp_enode m_tmp_enode; @@ -161,8 +161,8 @@ namespace smt { vector m_watches; //!< per literal vector m_lit_occs; //!< index for backward subsumption svector m_bdata; //!< mapping bool_var -> data - svector m_activity; - clause_vector m_aux_clauses; + svector m_activity; + clause_vector m_aux_clauses; clause_vector m_lemmas; vector m_clauses_to_reinit; expr_ref_vector m_units_to_reassert; @@ -176,7 +176,7 @@ namespace smt { bool m_phase_cache_on; unsigned m_phase_counter; //!< auxiliary variable used to decide when to turn on/off phase caching bool m_phase_default; //!< default phase when using phase caching - + // A conflict is usually a single justification. That is, a justification // for false. If m_not_l is not null_literal, then m_conflict is a // justification for l, and the conflict is union of m_no_l and m_conflict; @@ -220,10 +220,10 @@ namespace smt { // Unsat core extraction // // ----------------------------------- - typedef u_map literal2assumption; + typedef u_map literal2assumption; literal_vector m_assumptions; literal2assumption m_literal2assumption; // maps an expression associated with a literal to the original assumption - expr_ref_vector m_unsat_core; + expr_ref_vector m_unsat_core; // ----------------------------------- // @@ -261,7 +261,7 @@ namespace smt { SASSERT(e_internalized(n)); return m_app2enode[n->get_id()]; } - + /** \brief Similar to get_enode, but returns 0 if n is to e_internalized. */ @@ -323,7 +323,7 @@ namespace smt { literal enode2literal(enode const * n) const { SASSERT(n->is_bool()); return n == m_false_enode ? false_literal : literal(enode2bool_var(n)); - } + } unsigned get_num_bool_vars() const { return m_b_internalized_stack.size(); @@ -336,7 +336,7 @@ namespace smt { bool_var_data const & get_bdata(bool_var v) const { return m_bdata[v]; } - + lbool get_lit_assignment(unsigned lit_idx) const { return static_cast(m_assignment[lit_idx]); } @@ -349,8 +349,8 @@ namespace smt { return get_assignment(literal(v)); } - literal_vector const & assigned_literals() const { - return m_assigned_literals; + literal_vector const & assigned_literals() const { + return m_assigned_literals; } lbool get_assignment(expr * n) const; @@ -425,7 +425,7 @@ namespace smt { unsigned get_assign_level(literal l) const { return get_assign_level(l.var()); } - + /** \brief Return the scope level when v was internalized. */ @@ -436,7 +436,7 @@ namespace smt { theory * get_theory(theory_id th_id) const { return m_theories.get_plugin(th_id); } - + ptr_vector::const_iterator begin_theories() const { return m_theories.begin(); } @@ -450,7 +450,7 @@ namespace smt { } unsigned get_base_level() const { - return m_base_lvl; + return m_base_lvl; } bool at_base_level() const { @@ -470,11 +470,11 @@ namespace smt { } expr * bool_var2expr(bool_var v) const { - return m_bool_var2expr[v]; + return m_bool_var2expr[v]; } - + void literal2expr(literal l, expr_ref & result) const { - if (l == true_literal) + if (l == true_literal) result = m_manager.mk_true(); else if (l == false_literal) result = m_manager.mk_false(); @@ -501,7 +501,7 @@ namespace smt { unsigned id = decl->get_decl_id(); return id < m_decl2enodes.size() ? m_decl2enodes[id].begin() : 0; } - + enode_vector::const_iterator end_enodes_of(func_decl const * decl) const { unsigned id = decl->get_decl_id(); return id < m_decl2enodes.size() ? m_decl2enodes[id].end() : 0; @@ -591,7 +591,7 @@ namespace smt { void push_scope(); unsigned pop_scope_core(unsigned num_scopes); - + void pop_scope(unsigned num_scopes); void undo_trail_stack(unsigned old_size); @@ -617,13 +617,13 @@ namespace smt { bool is_empty_clause(clause const * c) const; void cache_generation(unsigned new_scope_lvl); - + void cache_generation(clause const * cls, unsigned new_scope_lvl); void cache_generation(unsigned num_lits, literal const * lits, unsigned new_scope_lvl); void cache_generation(expr * n, unsigned new_scope_lvl); - + void reset_cache_generation(); void reinit_clauses(unsigned num_scopes, unsigned num_bool_vars); @@ -632,14 +632,14 @@ namespace smt { // ----------------------------------- // - // Internalization + // Internalization // // ----------------------------------- public: bool b_internalized(expr const * n) const { return get_bool_var_of_id_option(n->get_id()) != null_bool_var; } - + bool lit_internalized(expr const * n) const { return m_manager.is_false(n) || (m_manager.is_not(n) ? b_internalized(to_app(n)->get_arg(0)) : b_internalized(n)); } @@ -648,7 +648,7 @@ namespace smt { return m_app2enode.get(n->get_id(), 0) != 0; } - unsigned get_num_b_internalized() const { + unsigned get_num_b_internalized() const { return m_b_internalized_stack.size(); } @@ -656,7 +656,7 @@ namespace smt { return m_b_internalized_stack.get(idx); } - unsigned get_num_e_internalized() const { + unsigned get_num_e_internalized() const { return m_e_internalized_stack.size(); } @@ -693,9 +693,9 @@ namespace smt { void ts_visit_child(expr * n, bool gate_ctx, svector & tcolors, svector & fcolors, svector & todo, bool & visited); bool ts_visit_children(expr * n, bool gate_ctx, svector & tcolors, svector & fcolors, svector & todo); - + void top_sort_expr(expr * n, svector & sorted_exprs); - + void assert_default(expr * n, proof * pr); void assert_distinct(app * n, proof * pr); @@ -723,7 +723,7 @@ namespace smt { void internalize_term(app * n); void internalize_ite_term(app * n); - + bool internalize_theory_term(app * n); void internalize_uninterpreted(app * n); @@ -754,7 +754,7 @@ namespace smt { bool simplify_aux_lemma_literals(unsigned & num_lits, literal * lits); void mark_for_reinit(clause * cls, unsigned scope_lvl, bool reinternalize_atoms); - + unsigned get_max_iscope_lvl(unsigned num_lits, literal const * lits) const; bool use_binary_clause_opt(literal l1, literal l2, bool lemma) const; @@ -786,7 +786,7 @@ namespace smt { void add_and_rel_watches(app * n); void add_or_rel_watches(app * n); - + void add_ite_rel_watches(app * n); void mk_not_cnstr(app * n); @@ -798,7 +798,7 @@ namespace smt { void mk_iff_cnstr(app * n); void mk_ite_cnstr(app * n); - + bool lit_occs_enabled() const { return m_fparams.m_phase_selection==PS_OCCURRENCE; } void add_lit_occs(clause * cls); @@ -821,7 +821,7 @@ namespace smt { bool_var mk_bool_var(expr * n); - + enode * mk_enode(app * n, bool suppress_args, bool merge_tf, bool cgc_enabled); void attach_th_var(enode * n, theory * th, theory_var v); @@ -830,7 +830,7 @@ namespace smt { justification * mk_justification(Justification const & j) { justification * js = new (m_region) Justification(j); SASSERT(js->in_region()); - if (js->has_del_eh()) + if (js->has_del_eh()) m_justifications.push_back(js); return js; } @@ -851,10 +851,10 @@ namespace smt { unsigned m_num_conflicts_since_lemma_gc; unsigned m_restart_threshold; unsigned m_restart_outer_threshold; - unsigned m_luby_idx; + unsigned m_luby_idx; double m_agility; unsigned m_lemma_gc_threshold; - + void assign_core(literal l, b_justification j, bool decision = false); void trace_assign(literal l, b_justification j, bool decision) const; @@ -880,7 +880,7 @@ namespace smt { friend class set_true_first_trail; void set_true_first_flag(bool_var v); - + bool try_true_first(bool_var v) const { return get_bdata(v).try_true_first(); } bool assume_eq(enode * lhs, enode * rhs); @@ -901,13 +901,13 @@ namespace smt { d.m_phase = phase; } - void force_phase(literal l) { + void force_phase(literal l) { force_phase(l.var(), !l.sign()); } bool contains_instance(quantifier * q, unsigned num_bindings, enode * const * bindings); - bool add_instance(quantifier * q, app * pat, unsigned num_bindings, enode * const * bindings, unsigned max_generation, + bool add_instance(quantifier * q, app * pat, unsigned num_bindings, enode * const * bindings, unsigned max_generation, unsigned min_top_generation, unsigned max_top_generation, ptr_vector & used_enodes); void set_global_generation(unsigned generation) { m_generation = generation; } @@ -960,7 +960,7 @@ namespace smt { void assign_quantifier(quantifier * q); - void set_conflict(b_justification js, literal not_l); + void set_conflict(b_justification js, literal not_l); void set_conflict(b_justification js) { set_conflict(js, null_literal); @@ -999,12 +999,12 @@ namespace smt { #define INV_ACTIVITY_LIMIT 1e-100 void rescale_bool_var_activity(); - + public: void inc_bvar_activity(bool_var v) { double & act = m_activity[v]; act += m_bvar_inc; - if (act > ACTIVITY_LIMIT) + if (act > ACTIVITY_LIMIT) rescale_bool_var_activity(); m_case_split_queue->activity_increased_eh(v); } @@ -1033,7 +1033,7 @@ namespace smt { } return false; } - + bool can_delete(clause * cls) const { if (cls->in_reinit_stack()) return false; @@ -1055,7 +1055,7 @@ namespace smt { bool validate_assumptions(unsigned num_assumptions, expr * const * assumptions); void init_assumptions(unsigned num_assumptions, expr * const * assumptions); - + void reset_assumptions(); void mk_unsat_core(); @@ -1075,9 +1075,9 @@ namespace smt { void tick(unsigned & counter) const; lbool bounded_search(); - + final_check_status final_check(); - + void check_proof(proof * pr); void forget_phase_of_vars_in_current_level(); @@ -1104,7 +1104,7 @@ namespace smt { public: // event handler for relevancy_propagator class - void relevant_eh(expr * n); + void relevant_eh(expr * n); bool is_relevant(expr * n) const { return !relevancy() || is_relevant_core(n); @@ -1128,9 +1128,9 @@ namespace smt { void mark_as_relevant(enode * n) { mark_as_relevant(n->get_owner()); } void mark_as_relevant(bool_var v) { mark_as_relevant(bool_var2expr(v)); } - + void mark_as_relevant(literal l) { mark_as_relevant(l.var()); } - + template relevancy_eh * mk_relevancy_eh(Eh const & eh) { return m_relevancy_propagator->mk_relevancy_eh(eh); @@ -1151,9 +1151,9 @@ namespace smt { void propagate_th_eqs(); void propagate_th_diseqs(); - + bool can_theories_propagate() const; - + bool propagate(); public: @@ -1169,7 +1169,7 @@ namespace smt { // ----------------------------------- // - // Pretty Printing + // Pretty Printing // // ----------------------------------- protected: @@ -1217,7 +1217,7 @@ namespace smt { void display_binary_clauses(std::ostream & out) const; void display_assignment(std::ostream & out) const; - + void display_eqc(std::ostream & out) const; void display_app_enode_map(std::ostream & out) const; @@ -1237,15 +1237,15 @@ namespace smt { void display_lemma_as_smt_problem(std::ostream & out, unsigned num_antecedents, literal const * antecedents, literal consequent = false_literal, symbol const& logic = symbol::null) const; void display_lemma_as_smt_problem(unsigned num_antecedents, literal const * antecedents, literal consequent = false_literal, symbol const& logic = symbol::null) const; - void display_lemma_as_smt_problem(std::ostream & out, unsigned num_antecedents, literal const * antecedents, - unsigned num_antecedent_eqs, enode_pair const * antecedent_eqs, + void display_lemma_as_smt_problem(std::ostream & out, unsigned num_antecedents, literal const * antecedents, + unsigned num_antecedent_eqs, enode_pair const * antecedent_eqs, literal consequent = false_literal, symbol const& logic = symbol::null) const; - void display_lemma_as_smt_problem(unsigned num_antecedents, literal const * antecedents, - unsigned num_antecedent_eqs, enode_pair const * antecedent_eqs, + void display_lemma_as_smt_problem(unsigned num_antecedents, literal const * antecedents, + unsigned num_antecedent_eqs, enode_pair const * antecedent_eqs, literal consequent = false_literal, symbol const& logic = symbol::null) const; - void display_assignment_as_smtlib2(std::ostream& out, symbol const& logic = symbol::null) const; + void display_assignment_as_smtlib2(std::ostream& out, symbol const& logic = symbol::null) const; void display_normalized_enodes(std::ostream & out) const; @@ -1291,13 +1291,13 @@ namespace smt { bool check_invariant() const; bool check_eqc_bool_assignment() const; - + bool check_missing_clause_propagation(clause_vector const & v) const; bool check_missing_bin_clause_propagation() const; bool check_missing_eq_propagation() const; - + bool check_missing_congruence() const; bool check_missing_bool_enode_propagation() const; @@ -1359,7 +1359,7 @@ namespace smt { static literal translate_literal( literal lit, context& src_ctx, context& dst_ctx, vector b2v, ast_translation& tr); - + /* \brief Utilities for consequence finding. */ @@ -1368,7 +1368,7 @@ namespace smt { u_map m_antecedents; void extract_fixed_consequences(literal lit, obj_map& var2val, index_set const& assumptions, expr_ref_vector& conseq); void extract_fixed_consequences(unsigned& idx, obj_map& var2val, index_set const& assumptions, expr_ref_vector& conseq); - + void display_consequence_progress(std::ostream& out, unsigned it, unsigned nv, unsigned fixed, unsigned unfixed, unsigned eq); unsigned delete_unfixed(obj_map& var2val, expr_ref_vector& unfixed); @@ -1380,7 +1380,7 @@ namespace smt { literal mk_diseq(expr* v, expr* val); - void validate_consequences(expr_ref_vector const& assumptions, expr_ref_vector const& vars, + void validate_consequences(expr_ref_vector const& assumptions, expr_ref_vector const& vars, expr_ref_vector const& conseq, expr_ref_vector const& unfixed); bool validate_justification(bool_var v, bool_var_data const& d, b_justification const& j); @@ -1430,18 +1430,18 @@ namespace smt { void pop(unsigned num_scopes); - lbool check(unsigned num_assumptions = 0, expr * const * assumptions = 0, bool reset_cancel = true); + lbool check(unsigned num_assumptions = 0, expr * const * assumptions = 0, bool reset_cancel = true); lbool get_consequences(expr_ref_vector const& assumptions, expr_ref_vector const& vars, expr_ref_vector& conseq, expr_ref_vector& unfixed); lbool find_mutexes(expr_ref_vector const& vars, vector& mutexes); lbool preferred_sat(expr_ref_vector const& asms, vector& cores); - + lbool setup_and_check(bool reset_cancel = true); - + // return 'true' if assertions are inconsistent. - bool reduce_assertions(); + bool reduce_assertions(); bool resource_limits_exceeded(); @@ -1466,15 +1466,15 @@ namespace smt { } bool already_internalized() const { return m_e_internalized_stack.size() > 2 || m_b_internalized_stack.size() > 1; } - + unsigned get_unsat_core_size() const { return m_unsat_core.size(); } - + expr * get_unsat_core_expr(unsigned idx) const { return m_unsat_core.get(idx); } - + void get_model(model_ref & m) const; bool update_model(bool refinalize); @@ -1482,17 +1482,17 @@ namespace smt { void get_proto_model(proto_model_ref & m) const; bool validate_model(); - + unsigned get_num_asserted_formulas() const { return m_asserted_formulas.get_num_formulas(); } unsigned get_asserted_formulas_last_level() const { return m_asserted_formulas.get_formulas_last_level(); } expr * get_asserted_formula(unsigned idx) const { return m_asserted_formulas.get_formula(idx); } - + proof * get_asserted_formula_proof(unsigned idx) const { return m_asserted_formulas.get_formula_proof(idx); } - + expr * const * get_asserted_formulas() const { return m_asserted_formulas.get_formulas(); } - + proof * const * get_asserted_formula_proofs() const { return m_asserted_formulas.get_formula_proofs(); } void get_assumptions_core(ptr_vector & result); @@ -1504,7 +1504,7 @@ namespace smt { void display_unsat_core(std::ostream & out) const; void collect_statistics(::statistics & st) const; - + void display_statistics(std::ostream & out) const; void display_istatistics(std::ostream & out) const; From 384468bc997199bc2442155352999e534f49cd1c Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Tue, 10 Jan 2017 20:21:51 +0000 Subject: [PATCH 463/536] Added option to extend unsat cores with literals that (potentially) provide quantifier instances. --- src/smt/params/smt_params_helper.pyg | 7 +- src/smt/smt_solver.cpp | 182 +++++++++++++++++++++++---- 2 files changed, 160 insertions(+), 29 deletions(-) diff --git a/src/smt/params/smt_params_helper.pyg b/src/smt/params/smt_params_helper.pyg index 739af8bfe..178b2117f 100644 --- a/src/smt/params/smt_params_helper.pyg +++ b/src/smt/params/smt_params_helper.pyg @@ -1,4 +1,4 @@ -def_module_params(module_name='smt', +def_module_params(module_name='smt', class_name='smt_params_helper', description='smt solver based on lazy smt', export=True, @@ -17,7 +17,7 @@ def_module_params(module_name='smt', ('pull_nested_quantifiers', BOOL, False, 'pull nested quantifiers'), ('refine_inj_axioms', BOOL, True, 'refine injectivity axioms'), ('timeout', UINT, UINT_MAX, 'timeout (in milliseconds) (UINT_MAX and 0 mean no timeout)'), - ('rlimit', UINT, 0, 'resource limit (0 means no limit)'), + ('rlimit', UINT, 0, 'resource limit (0 means no limit)'), ('max_conflicts', UINT, UINT_MAX, 'maximum number of conflicts before giving up.'), ('mbqi', BOOL, True, 'model based quantifier instantiation (MBQI)'), ('mbqi.max_cexs', UINT, 1, 'initial maximal number of counterexamples used in MBQI, each counterexample generates a quantifier instantiation'), @@ -62,5 +62,6 @@ def_module_params(module_name='smt', ('dack.gc_inv_decay', DOUBLE, 0.8, 'Dynamic ackermannization garbage collection decay'), ('dack.threshold', UINT, 10, ' number of times the congruence rule must be used before Leibniz\'s axiom is expanded'), ('core.validate', BOOL, False, 'validate unsat core produced by SMT context'), - ('core.minimize', BOOL, False, 'minimize unsat core produced by SMT context') + ('core.minimize', BOOL, False, 'minimize unsat core produced by SMT context'), + ('core.extend_patterns', BOOL, False, 'extend unsat core with literals that trigger (potential) quantifier instances') )) diff --git a/src/smt/smt_solver.cpp b/src/smt/smt_solver.cpp index 2ea4fea20..703e4489e 100644 --- a/src/smt/smt_solver.cpp +++ b/src/smt/smt_solver.cpp @@ -22,42 +22,62 @@ Notes: #include"smt_params.h" #include"smt_params_helper.hpp" #include"mus.h" - +#include"for_each_expr.h" +#include"ast_smt2_pp.h" +#include"func_decl_dependencies.h" +#include"dec_ref_util.h" namespace smt { class solver : public solver_na2as { - smt_params m_smt_params; - params_ref m_params; - smt::kernel m_context; - progress_callback * m_callback; - symbol m_logic; - bool m_minimizing_core; + smt_params m_smt_params; + params_ref m_params; + smt::kernel m_context; + progress_callback * m_callback; + symbol m_logic; + bool m_minimizing_core; + bool m_core_extend_patterns; + obj_map m_name2assertion; + public: - solver(ast_manager & m, params_ref const & p, symbol const & l): + solver(ast_manager & m, params_ref const & p, symbol const & l) : solver_na2as(m), m_smt_params(p), m_params(p), m_context(m, m_smt_params), - m_minimizing_core(false) { + m_minimizing_core(false), + m_core_extend_patterns(false) { m_logic = l; if (m_logic != symbol::null) m_context.set_logic(m_logic); + smt_params_helper smth(p); + m_core_extend_patterns = smth.core_extend_patterns(); } - virtual solver* translate(ast_manager& m, params_ref const& p) { - solver* result = alloc(solver, m, p, m_logic); + virtual solver * translate(ast_manager & m, params_ref const & p) { + solver * result = alloc(solver, m, p, m_logic); smt::kernel::copy(m_context, result->m_context); + + ast_translation translator(get_manager(), m); + obj_map::iterator it = m_name2assertion.begin(); + obj_map::iterator end = m_name2assertion.end(); + for (; it != end; it++) + result->m_name2assertion.insert(translator(it->m_key), + translator(it->m_value)); + return result; } - + virtual ~solver() { + dec_ref_values(get_manager(), m_name2assertion); } virtual void updt_params(params_ref const & p) { m_smt_params.updt_params(p); m_params.copy(p); m_context.updt_params(p); + smt_params_helper smth(p); + m_core_extend_patterns = smth.core_extend_patterns(); } virtual void collect_param_descrs(param_descrs & r) { @@ -81,6 +101,12 @@ namespace smt { m_context.assert_expr(t); } + virtual void assert_expr(expr * t, expr * a) { + solver_na2as::assert_expr(t, a); + get_manager().inc_ref(t); + m_name2assertion.insert(a, t); + } + virtual void push_core() { m_context.push(); } @@ -97,7 +123,7 @@ namespace smt { struct scoped_minimize_core { solver& s; expr_ref_vector m_assumptions; - scoped_minimize_core(solver& s): s(s), m_assumptions(s.m_assumptions) { + scoped_minimize_core(solver& s) : s(s), m_assumptions(s.m_assumptions) { s.m_minimizing_core = true; s.m_assumptions.reset(); } @@ -114,17 +140,19 @@ namespace smt { r.push_back(m_context.get_unsat_core_expr(i)); } - if (m_minimizing_core || smt_params_helper(m_params).core_minimize() == false) { - return; - } - scoped_minimize_core scm(*this); - mus mus(*this); - mus.add_soft(r.size(), r.c_ptr()); - ptr_vector r2; - if (l_true == mus.get_mus(r2)) { - r.reset(); - r.append(r2); + if (m_minimizing_core && smt_params_helper(m_params).core_minimize()) { + scoped_minimize_core scm(*this); + mus mus(*this); + mus.add_soft(r.size(), r.c_ptr()); + ptr_vector r2; + if (l_true == mus.get_mus(r2)) { + r.reset(); + r.append(r2); + } } + + if (m_core_extend_patterns) + add_pattern_literals_to_core(r); } virtual void get_model(model_ref & m) { @@ -149,7 +177,7 @@ namespace smt { r.append(tmp.size(), tmp.c_ptr()); } - virtual ast_manager& get_manager() const { return m_context.m(); } + virtual ast_manager & get_manager() const { return m_context.m(); } virtual void set_progress_callback(progress_callback * callback) { m_callback = callback; @@ -159,12 +187,114 @@ namespace smt { virtual unsigned get_num_assertions() const { return m_context.size(); } - + virtual expr * get_assertion(unsigned idx) const { SASSERT(idx < get_num_assertions()); return m_context.get_formulas()[idx]; - } + } + struct collect_fds_proc { + ast_manager & m; + func_decl_set & m_fds; + collect_fds_proc(ast_manager & m, func_decl_set & fds) : + m(m), m_fds(fds) { + } + void operator()(var * n) {} + void operator()(app * n) { + func_decl * fd = n->get_decl(); + if (fd->get_family_id() == null_family_id) + m_fds.insert_if_not_there(fd); + } + void operator()(quantifier * n) {} + }; + + struct collect_pattern_fds_proc { + ast_manager & m; + expr_fast_mark1 m_visited; + func_decl_set & m_fds; + collect_pattern_fds_proc(ast_manager & m, func_decl_set & fds) : + m(m), m_fds(fds) { + m_visited.reset(); + } + void operator()(var * n) {} + void operator()(app * n) {} + void operator()(quantifier * n) { + collect_fds_proc p(m, m_fds); + + unsigned sz = n->get_num_patterns(); + for (unsigned i = 0; i < sz; i++) + quick_for_each_expr(p, m_visited, n->get_pattern(i)); + + sz = n->get_num_no_patterns(); + for (unsigned i = 0; i < sz; i++) + quick_for_each_expr(p, m_visited, n->get_no_pattern(i)); + } + }; + + void collect_pattern_func_decls(expr_ref & e, func_decl_set & fds) { + collect_pattern_fds_proc p(get_manager(), fds); + expr_mark visited; + for_each_expr(p, visited, e); + } + + void compute_assrtn_fds(ptr_vector & core, vector & assrtn_fds) { + assrtn_fds.resize(m_name2assertion.size()); + obj_map::iterator ait = m_name2assertion.begin(); + obj_map::iterator aend = m_name2assertion.end(); + for (unsigned i = 0; ait != aend; ait++, i++) { + if (core.contains(ait->m_key)) + continue; + collect_fds_proc p(m, assrtn_fds[i]); + expr_fast_mark1 visited; + quick_for_each_expr(p, visited, ait->m_value); + } + } + + bool fds_intersect(func_decl_set & pattern_fds, func_decl_set & assrtn_fds) { + func_decl_set::iterator it = pattern_fds.begin(); + func_decl_set::iterator end = pattern_fds.end(); + for (; it != end; it++) { + func_decl * fd = *it; + if (assrtn_fds.contains(fd)) + return true; + } + return false; + } + + void add_pattern_literals_to_core(ptr_vector & core) { + ast_manager & m = get_manager(); + expr_ref_vector new_core_literals(m); + + func_decl_set pattern_fds; + vector assrtn_fds; + + do { + new_core_literals.reset(); + + unsigned sz = core.size(); + for (unsigned i = 0; i < sz; i++) { + expr_ref name(core[i], m); + expr_ref assrtn(m_name2assertion.find(name), m); + collect_pattern_func_decls(assrtn, pattern_fds); + } + + if (!pattern_fds.empty()) { + if (assrtn_fds.empty()) + compute_assrtn_fds(core, assrtn_fds); + + obj_map::iterator ait = m_name2assertion.begin(); + obj_map::iterator aend = m_name2assertion.end(); + for (unsigned i = 0; ait != aend; ait++, i++) { + if (!core.contains(ait->m_key) && + fds_intersect(pattern_fds, assrtn_fds[i])) + new_core_literals.push_back(ait->m_key); + } + } + + core.append(new_core_literals.size(), new_core_literals.c_ptr()); + } + while (!new_core_literals.empty()); + } }; }; From d8d869822fbe4026e7e9311a6bac8f0a62fdf091 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Tue, 10 Jan 2017 21:04:44 +0000 Subject: [PATCH 464/536] Cleaned up #include in api* objects. --- scripts/update_api.py | 1 + src/api/api_algebraic.cpp | 39 ++++++------ src/api/api_arith.cpp | 25 ++++---- src/api/api_array.cpp | 31 +++++----- src/api/api_bv.cpp | 37 ++++++------ src/api/api_datatype.cpp | 119 ++++++++++++++++++------------------ src/api/api_interp.cpp | 5 +- src/api/api_log.cpp | 1 - src/api/api_pb.cpp | 16 +++-- src/api/api_polynomial.cpp | 5 +- src/api/api_quant.cpp | 121 ++++++++++++++++++------------------- src/api/api_seq.cpp | 37 ++++++------ 12 files changed, 213 insertions(+), 224 deletions(-) diff --git a/scripts/update_api.py b/scripts/update_api.py index e531a103c..b8978ff21 100755 --- a/scripts/update_api.py +++ b/scripts/update_api.py @@ -1574,6 +1574,7 @@ def write_log_h_preamble(log_h): log_h.write('#define _Z3_UNUSED\n') log_h.write('#endif\n') # + log_h.write('#include\n') log_h.write('extern std::ostream * g_z3_log;\n') log_h.write('extern bool g_z3_log_enabled;\n') log_h.write('class z3_log_ctx { bool m_prev; public: z3_log_ctx():m_prev(g_z3_log_enabled) { g_z3_log_enabled = false; } ~z3_log_ctx() { g_z3_log_enabled = m_prev; } bool enabled() const { return m_prev; } };\n') diff --git a/src/api/api_algebraic.cpp b/src/api/api_algebraic.cpp index 2e14a1bd8..c4e4dac5d 100644 --- a/src/api/api_algebraic.cpp +++ b/src/api/api_algebraic.cpp @@ -7,7 +7,7 @@ Module Name: Abstract: - Additional APIs for handling Z3 algebraic numbers encoded as + Additional APIs for handling Z3 algebraic numbers encoded as Z3_ASTs Author: @@ -15,9 +15,8 @@ Author: Leonardo de Moura (leonardo) 2012-12-07 Notes: - + --*/ -#include #include"z3.h" #include"api_log_macros.h" #include"api_context.h" @@ -74,9 +73,9 @@ extern "C" { bool Z3_algebraic_is_value_core(Z3_context c, Z3_ast a) { api::context * _c = mk_c(c); - return - is_expr(a) && - (_c->autil().is_numeral(to_expr(a)) || + return + is_expr(a) && + (_c->autil().is_numeral(to_expr(a)) || _c->autil().is_irrational_algebraic_numeral(to_expr(a))); } @@ -162,9 +161,9 @@ extern "C" { Z3_ast Z3_API Z3_algebraic_add(Z3_context c, Z3_ast a, Z3_ast b) { Z3_TRY; LOG_Z3_algebraic_add(c, a, b); - RESET_ERROR_CODE(); - CHECK_IS_ALGEBRAIC_X(a, 0); - CHECK_IS_ALGEBRAIC_X(b, 0); + RESET_ERROR_CODE(); + CHECK_IS_ALGEBRAIC_X(a, 0); + CHECK_IS_ALGEBRAIC_X(b, 0); BIN_OP(+,add); Z3_CATCH_RETURN(0); } @@ -172,9 +171,9 @@ extern "C" { Z3_ast Z3_API Z3_algebraic_sub(Z3_context c, Z3_ast a, Z3_ast b) { Z3_TRY; LOG_Z3_algebraic_sub(c, a, b); - RESET_ERROR_CODE(); - CHECK_IS_ALGEBRAIC_X(a, 0); - CHECK_IS_ALGEBRAIC_X(b, 0); + RESET_ERROR_CODE(); + CHECK_IS_ALGEBRAIC_X(a, 0); + CHECK_IS_ALGEBRAIC_X(b, 0); BIN_OP(-,sub); Z3_CATCH_RETURN(0); } @@ -182,9 +181,9 @@ extern "C" { Z3_ast Z3_API Z3_algebraic_mul(Z3_context c, Z3_ast a, Z3_ast b) { Z3_TRY; LOG_Z3_algebraic_mul(c, a, b); - RESET_ERROR_CODE(); - CHECK_IS_ALGEBRAIC_X(a, 0); - CHECK_IS_ALGEBRAIC_X(b, 0); + RESET_ERROR_CODE(); + CHECK_IS_ALGEBRAIC_X(a, 0); + CHECK_IS_ALGEBRAIC_X(b, 0); BIN_OP(*,mul); Z3_CATCH_RETURN(0); } @@ -219,8 +218,8 @@ extern "C" { algebraic_numbers::manager & _am = am(c); scoped_anum _r(_am); if (is_rational(c, a)) { - scoped_anum av(_am); - _am.set(av, get_rational(c, a).to_mpq()); + scoped_anum av(_am); + _am.set(av, get_rational(c, a).to_mpq()); _am.root(av, k, _r); } else { @@ -241,8 +240,8 @@ extern "C" { algebraic_numbers::manager & _am = am(c); scoped_anum _r(_am); if (is_rational(c, a)) { - scoped_anum av(_am); - _am.set(av, get_rational(c, a).to_mpq()); + scoped_anum av(_am); + _am.set(av, get_rational(c, a).to_mpq()); _am.power(av, k, _r); } else { @@ -328,7 +327,7 @@ extern "C" { scoped_anum tmp(_am); for (unsigned i = 0; i < n; i++) { if (is_rational(c, a[i])) { - _am.set(tmp, get_rational(c, a[i]).to_mpq()); + _am.set(tmp, get_rational(c, a[i]).to_mpq()); as.push_back(tmp); } else if (is_irrational(c, a[i])) { diff --git a/src/api/api_arith.cpp b/src/api/api_arith.cpp index dcd250c98..51aea9676 100644 --- a/src/api/api_arith.cpp +++ b/src/api/api_arith.cpp @@ -15,7 +15,6 @@ Author: Revision History: --*/ -#include #include"z3.h" #include"api_log_macros.h" #include"api_context.h" @@ -37,7 +36,7 @@ extern "C" { RETURN_Z3(r); Z3_CATCH_RETURN(0); } - + Z3_sort Z3_API Z3_mk_real_sort(Z3_context c) { Z3_TRY; LOG_Z3_mk_real_sort(c); @@ -50,7 +49,7 @@ extern "C" { Z3_ast Z3_API Z3_mk_real(Z3_context c, int num, int den) { Z3_TRY; LOG_Z3_mk_real(c, num, den); - RESET_ERROR_CODE(); + RESET_ERROR_CODE(); if (den == 0) { SET_ERROR_CODE(Z3_INVALID_ARG); RETURN_Z3(0); @@ -60,7 +59,7 @@ extern "C" { RETURN_Z3(of_ast(a)); Z3_CATCH_RETURN(0); } - + MK_ARITH_OP(Z3_mk_add, OP_ADD); MK_ARITH_OP(Z3_mk_mul, OP_MUL); MK_BINARY_ARITH_OP(Z3_mk_power, OP_POWER); @@ -70,17 +69,17 @@ extern "C" { Z3_ast Z3_API Z3_mk_div(Z3_context c, Z3_ast n1, Z3_ast n2) { Z3_TRY; LOG_Z3_mk_div(c, n1, n2); - RESET_ERROR_CODE(); + RESET_ERROR_CODE(); decl_kind k = OP_IDIV; sort* ty = mk_c(c)->m().get_sort(to_expr(n1)); sort* real_ty = mk_c(c)->m().mk_sort(mk_c(c)->get_arith_fid(), REAL_SORT); if (ty == real_ty) { k = OP_DIV; } - expr * args[2] = { to_expr(n1), to_expr(n2) }; - ast* a = mk_c(c)->m().mk_app(mk_c(c)->get_arith_fid(), k, 0, 0, 2, args); - mk_c(c)->save_ast_trail(a); - check_sorts(c, a); + expr * args[2] = { to_expr(n1), to_expr(n2) }; + ast* a = mk_c(c)->m().mk_app(mk_c(c)->get_arith_fid(), k, 0, 0, 2, args); + mk_c(c)->save_ast_trail(a); + check_sorts(c, a); RETURN_Z3(of_ast(a)); Z3_CATCH_RETURN(0); } @@ -142,7 +141,7 @@ extern "C" { rational l; mk_c(c)->autil().am().get_lower(val, l, precision); expr * r = mk_c(c)->autil().mk_numeral(l, false); - mk_c(c)->save_ast_trail(r); + mk_c(c)->save_ast_trail(r); RETURN_Z3(of_expr(r)); Z3_CATCH_RETURN(0); } @@ -160,7 +159,7 @@ extern "C" { rational l; mk_c(c)->autil().am().get_upper(val, l, precision); expr * r = mk_c(c)->autil().mk_numeral(l, false); - mk_c(c)->save_ast_trail(r); + mk_c(c)->save_ast_trail(r); RETURN_Z3(of_expr(r)); Z3_CATCH_RETURN(0); } @@ -176,7 +175,7 @@ extern "C" { RETURN_Z3(0); } expr * r = mk_c(c)->autil().mk_numeral(numerator(val), true); - mk_c(c)->save_ast_trail(r); + mk_c(c)->save_ast_trail(r); RETURN_Z3(of_expr(r)); Z3_CATCH_RETURN(0); } @@ -192,7 +191,7 @@ extern "C" { RETURN_Z3(0); } expr * r = mk_c(c)->autil().mk_numeral(denominator(val), true); - mk_c(c)->save_ast_trail(r); + mk_c(c)->save_ast_trail(r); RETURN_Z3(of_expr(r)); Z3_CATCH_RETURN(0); } diff --git a/src/api/api_array.cpp b/src/api/api_array.cpp index d3dda5d9d..ed431882e 100644 --- a/src/api/api_array.cpp +++ b/src/api/api_array.cpp @@ -15,7 +15,6 @@ Author: Revision History: --*/ -#include #include"z3.h" #include"api_log_macros.h" #include"api_context.h" @@ -27,7 +26,7 @@ extern "C" { Z3_sort Z3_API Z3_mk_array_sort(Z3_context c, Z3_sort domain, Z3_sort range) { Z3_TRY; LOG_Z3_mk_array_sort(c, domain, range); - RESET_ERROR_CODE(); + RESET_ERROR_CODE(); parameter params[2] = { parameter(to_sort(domain)), parameter(to_sort(range)) }; sort * ty = mk_c(c)->m().mk_sort(mk_c(c)->get_array_fid(), ARRAY_SORT, 2, params); mk_c(c)->save_ast_trail(ty); @@ -57,7 +56,7 @@ extern "C" { RETURN_Z3(of_ast(r)); Z3_CATCH_RETURN(0); } - + Z3_ast Z3_API Z3_mk_store(Z3_context c, Z3_ast a, Z3_ast i, Z3_ast v) { Z3_TRY; LOG_Z3_mk_store(c, a, i, v); @@ -82,7 +81,7 @@ extern "C" { RETURN_Z3(of_ast(r)); Z3_CATCH_RETURN(0); } - + Z3_ast Z3_API Z3_mk_map(Z3_context c, Z3_func_decl f, unsigned n, Z3_ast const* args) { Z3_TRY; LOG_Z3_mk_map(c, f, n, args); @@ -94,7 +93,7 @@ extern "C" { ast_manager & m = mk_c(c)->m(); func_decl* _f = to_func_decl(f); expr* const* _args = to_exprs(args); - + ptr_vector domain; for (unsigned i = 0; i < n; ++i) { domain.push_back(m.get_sort(_args[i])); @@ -111,7 +110,7 @@ extern "C" { Z3_ast Z3_API Z3_mk_const_array(Z3_context c, Z3_sort domain, Z3_ast v) { Z3_TRY; LOG_Z3_mk_const_array(c, domain, v); - RESET_ERROR_CODE(); + RESET_ERROR_CODE(); ast_manager & m = mk_c(c)->m(); expr * _v = to_expr(v); sort * _range = m.get_sort(_v); @@ -123,14 +122,14 @@ extern "C" { app * r = m.mk_app(cd, 1, &_v); mk_c(c)->save_ast_trail(r); check_sorts(c, r); - RETURN_Z3(of_ast(r)); + RETURN_Z3(of_ast(r)); Z3_CATCH_RETURN(0); } Z3_ast Z3_API Z3_mk_array_default(Z3_context c, Z3_ast array) { Z3_TRY; LOG_Z3_mk_array_default(c, array); - RESET_ERROR_CODE(); + RESET_ERROR_CODE(); ast_manager & m = mk_c(c)->m(); expr * _a = to_expr(array); @@ -138,12 +137,12 @@ extern "C" { app * r = m.mk_app(f, 1, &_a); mk_c(c)->save_ast_trail(r); check_sorts(c, r); - RETURN_Z3(of_ast(r)); + RETURN_Z3(of_ast(r)); Z3_CATCH_RETURN(0); } Z3_ast mk_app_array_core(Z3_context c, Z3_sort domain, Z3_ast v) { - RESET_ERROR_CODE(); + RESET_ERROR_CODE(); ast_manager & m = mk_c(c)->m(); expr * _v = to_expr(v); sort * _range = m.get_sort(_v); @@ -178,7 +177,7 @@ extern "C" { LOG_Z3_mk_full_set(c, domain); RESET_ERROR_CODE(); Z3_ast r = mk_app_array_core(c, domain, Z3_mk_true(c)); - RETURN_Z3(r); + RETURN_Z3(r); Z3_CATCH_RETURN(0); } @@ -205,8 +204,8 @@ extern "C" { Z3_TRY; LOG_Z3_get_array_sort_domain(c, t); RESET_ERROR_CODE(); - CHECK_VALID_AST(t, 0); - if (to_sort(t)->get_family_id() == mk_c(c)->get_array_fid() && + CHECK_VALID_AST(t, 0); + if (to_sort(t)->get_family_id() == mk_c(c)->get_array_fid() && to_sort(t)->get_decl_kind() == ARRAY_SORT) { Z3_sort r = reinterpret_cast(to_sort(t)->get_parameter(0).get_ast()); RETURN_Z3(r); @@ -215,13 +214,13 @@ extern "C" { RETURN_Z3(0); Z3_CATCH_RETURN(0); } - + Z3_sort Z3_API Z3_get_array_sort_range(Z3_context c, Z3_sort t) { Z3_TRY; LOG_Z3_get_array_sort_range(c, t); - RESET_ERROR_CODE(); + RESET_ERROR_CODE(); CHECK_VALID_AST(t, 0); - if (to_sort(t)->get_family_id() == mk_c(c)->get_array_fid() && + if (to_sort(t)->get_family_id() == mk_c(c)->get_array_fid() && to_sort(t)->get_decl_kind() == ARRAY_SORT) { Z3_sort r = reinterpret_cast(to_sort(t)->get_parameter(1).get_ast()); RETURN_Z3(r); diff --git a/src/api/api_bv.cpp b/src/api/api_bv.cpp index 353cf913c..ff090ef54 100644 --- a/src/api/api_bv.cpp +++ b/src/api/api_bv.cpp @@ -15,7 +15,6 @@ Author: Revision History: --*/ -#include #include"z3.h" #include"api_log_macros.h" #include"api_context.h" @@ -27,7 +26,7 @@ extern "C" { Z3_sort Z3_API Z3_mk_bv_sort(Z3_context c, unsigned sz) { Z3_TRY; LOG_Z3_mk_bv_sort(c, sz); - RESET_ERROR_CODE(); + RESET_ERROR_CODE(); if (sz == 0) { SET_ERROR_CODE(Z3_INVALID_ARG); } @@ -39,7 +38,7 @@ extern "C" { #define MK_BV_UNARY(NAME, OP) MK_UNARY(NAME, mk_c(c)->get_bv_fid(), OP, SKIP) #define MK_BV_BINARY(NAME, OP) MK_BINARY(NAME, mk_c(c)->get_bv_fid(), OP, SKIP) - + MK_BV_UNARY(Z3_mk_bvnot, OP_BNOT); MK_BV_UNARY(Z3_mk_bvredand, OP_BREDAND); MK_BV_UNARY(Z3_mk_bvredor, OP_BREDOR); @@ -75,11 +74,11 @@ extern "C" { expr * _n = to_expr(n); parameter params[2] = { parameter(high), parameter(low) }; expr * a = mk_c(c)->m().mk_app(mk_c(c)->get_bv_fid(), OP_EXTRACT, 2, params, 1, &_n); - mk_c(c)->save_ast_trail(a); + mk_c(c)->save_ast_trail(a); check_sorts(c, a); return of_ast(a); } - + Z3_ast Z3_API Z3_mk_extract(Z3_context c, unsigned high, unsigned low, Z3_ast n) { Z3_TRY; LOG_Z3_mk_extract(c, high, low, n); @@ -88,7 +87,7 @@ extern "C" { RETURN_Z3(r); Z3_CATCH_RETURN(0); } - + #define MK_BV_PUNARY(NAME, OP) \ Z3_ast Z3_API NAME(Z3_context c, unsigned i, Z3_ast n) { \ Z3_TRY; \ @@ -113,7 +112,7 @@ Z3_ast Z3_API NAME(Z3_context c, unsigned i, Z3_ast n) { \ Z3_ast Z3_API Z3_mk_bv2int(Z3_context c, Z3_ast n, Z3_bool is_signed) { Z3_TRY; LOG_Z3_mk_bv2int(c, n, is_signed); - RESET_ERROR_CODE(); + RESET_ERROR_CODE(); Z3_sort int_s = Z3_mk_int_sort(c); if (is_signed) { Z3_ast r = Z3_mk_bv2int(c, n, false); @@ -125,7 +124,7 @@ Z3_ast Z3_API NAME(Z3_context c, unsigned i, Z3_ast n) { \ Z3_inc_ref(c, bound); Z3_ast zero = Z3_mk_int(c, 0, s); Z3_inc_ref(c, zero); - Z3_ast pred = Z3_mk_bvslt(c, n, zero); + Z3_ast pred = Z3_mk_bvslt(c, n, zero); Z3_inc_ref(c, pred); // if n <_sigend 0 then r - s^sz else r Z3_ast args[2] = { r, bound }; @@ -140,19 +139,19 @@ Z3_ast Z3_API NAME(Z3_context c, unsigned i, Z3_ast n) { \ RETURN_Z3(res); } else { - expr * _n = to_expr(n); - parameter p(to_sort(int_s)); - ast* a = mk_c(c)->m().mk_app(mk_c(c)->get_bv_fid(), OP_BV2INT, 1, &p, 1, &_n); - mk_c(c)->save_ast_trail(a); - check_sorts(c, a); - RETURN_Z3(of_ast(a)); + expr * _n = to_expr(n); + parameter p(to_sort(int_s)); + ast* a = mk_c(c)->m().mk_app(mk_c(c)->get_bv_fid(), OP_BV2INT, 1, &p, 1, &_n); + mk_c(c)->save_ast_trail(a); + check_sorts(c, a); + RETURN_Z3(of_ast(a)); } Z3_CATCH_RETURN(0); } /** \brief Create a bit-vector of sort \s with 1 in the most significant bit position. - + The sort \s must be a bit-vector sort. This function is a shorthand for shl(1, N-1) @@ -343,7 +342,7 @@ Z3_ast Z3_API NAME(Z3_context c, unsigned i, Z3_ast n) { \ return Z3_mk_not(c, eq); Z3_CATCH_RETURN(0); } - + // only for signed machine integers Z3_ast Z3_API Z3_mk_bvsdiv_no_overflow(Z3_context c, Z3_ast t1, Z3_ast t2) { Z3_TRY; @@ -369,7 +368,7 @@ Z3_ast Z3_API NAME(Z3_context c, unsigned i, Z3_ast n) { \ return result; Z3_CATCH_RETURN(0); } - + Z3_ast Z3_API Z3_mk_bvsub(Z3_context c, Z3_ast n1, Z3_ast n2) { Z3_TRY; LOG_Z3_mk_bvsub(c, n1, n2); @@ -389,7 +388,7 @@ Z3_ast Z3_API NAME(Z3_context c, unsigned i, Z3_ast n) { \ unsigned Z3_API Z3_get_bv_sort_size(Z3_context c, Z3_sort t) { Z3_TRY; LOG_Z3_get_bv_sort_size(c, t); - RESET_ERROR_CODE(); + RESET_ERROR_CODE(); CHECK_VALID_AST(t, 0); if (to_sort(t)->get_family_id() == mk_c(c)->get_bv_fid() && to_sort(t)->get_decl_kind() == BV_SORT) { return to_sort(t)->get_parameter(0).get_int(); @@ -398,5 +397,5 @@ Z3_ast Z3_API NAME(Z3_context c, unsigned i, Z3_ast n) { \ return 0; Z3_CATCH_RETURN(0); } - + }; diff --git a/src/api/api_datatype.cpp b/src/api/api_datatype.cpp index 706ba9d89..5096c8e80 100644 --- a/src/api/api_datatype.cpp +++ b/src/api/api_datatype.cpp @@ -15,7 +15,6 @@ Author: Revision History: --*/ -#include #include"z3.h" #include"api_log_macros.h" #include"api_context.h" @@ -24,16 +23,16 @@ Revision History: extern "C" { - Z3_sort Z3_API Z3_mk_tuple_sort(Z3_context c, + Z3_sort Z3_API Z3_mk_tuple_sort(Z3_context c, Z3_symbol name, - unsigned num_fields, + unsigned num_fields, Z3_symbol const field_names[], Z3_sort const field_sorts[], Z3_func_decl * mk_tuple_decl, Z3_func_decl proj_decls[]) { Z3_TRY; LOG_Z3_mk_tuple_sort(c, name, num_fields, field_names, field_sorts, mk_tuple_decl, proj_decls); - RESET_ERROR_CODE(); + RESET_ERROR_CODE(); mk_c(c)->reset_last_result(); ast_manager& m = mk_c(c)->m(); datatype_util& dt_util = mk_c(c)->dtutil(); @@ -43,14 +42,14 @@ extern "C" { std::string recognizer_s("is_"); recognizer_s += to_symbol(name).str(); symbol recognizer(recognizer_s.c_str()); - + ptr_vector acc; for (unsigned i = 0; i < num_fields; ++i) { acc.push_back(mk_accessor_decl(to_symbol(field_names[i]), type_ref(to_sort(field_sorts[i])))); } constructor_decl* constrs[1] = { mk_constructor_decl(to_symbol(name), recognizer, acc.size(), acc.c_ptr()) }; - + { datatype_decl * dt = mk_datatype_decl(to_symbol(name), 1, constrs); bool is_ok = mk_c(c)->get_dt_plugin()->mk_datatypes(1, &dt, tuples); @@ -63,7 +62,7 @@ extern "C" { } // create tuple type - SASSERT(tuples.size() == 1); + SASSERT(tuples.size() == 1); tuple = tuples[0].get(); mk_c(c)->save_multiple_ast_trail(tuple); @@ -72,9 +71,9 @@ extern "C" { SASSERT(!dt_util.is_recursive(tuple)); ptr_vector const * decls = dt_util.get_datatype_constructors(tuple); func_decl* decl = (*decls)[0]; - mk_c(c)->save_multiple_ast_trail(decl); + mk_c(c)->save_multiple_ast_trail(decl); *mk_tuple_decl = of_func_decl(decl); - + // Create projections ptr_vector const * accs = dt_util.get_constructor_accessors(decl); if (!accs) { @@ -90,8 +89,8 @@ extern "C" { RETURN_Z3_mk_tuple_sort(of_sort(tuple)); Z3_CATCH_RETURN(0); } - - Z3_sort Z3_API Z3_mk_enumeration_sort(Z3_context c, + + Z3_sort Z3_API Z3_mk_enumeration_sort(Z3_context c, Z3_symbol name, unsigned n, Z3_symbol const enum_names[], @@ -106,7 +105,7 @@ extern "C" { sort_ref_vector sorts(m); sort* e; - + ptr_vector constrs; for (unsigned i = 0; i < n; ++i) { symbol e_name(to_symbol(enum_names[i])); @@ -128,9 +127,9 @@ extern "C" { RETURN_Z3(0); } } - + // create enum type. - SASSERT(sorts.size() == 1); + SASSERT(sorts.size() == 1); e = sorts[0].get(); mk_c(c)->save_multiple_ast_trail(e); @@ -141,10 +140,10 @@ extern "C" { SASSERT(decls && decls->size() == n); for (unsigned i = 0; i < n; ++i) { func_decl* decl = (*decls)[i]; - mk_c(c)->save_multiple_ast_trail(decl); + mk_c(c)->save_multiple_ast_trail(decl); enum_consts[i] = of_func_decl(decl); decl = dt_util.get_constructor_recognizer(decl); - mk_c(c)->save_multiple_ast_trail(decl); + mk_c(c)->save_multiple_ast_trail(decl); enum_testers[i] = of_func_decl(decl); } @@ -168,11 +167,11 @@ extern "C" { ast_manager& m = mk_c(c)->m(); mk_c(c)->reset_last_result(); datatype_util data_util(m); - accessor_decl* head_tail[2] = { + accessor_decl* head_tail[2] = { mk_accessor_decl(symbol("head"), type_ref(to_sort(elem_sort))), mk_accessor_decl(symbol("tail"), type_ref(0)) }; - constructor_decl* constrs[2] = { + constructor_decl* constrs[2] = { mk_constructor_decl(symbol("nil"), symbol("is_nil"), 0, 0), // Leo: SMT 2.0 document uses 'insert' instead of cons mk_constructor_decl(symbol("cons"), symbol("is_cons"), 2, head_tail) @@ -197,22 +196,22 @@ extern "C" { func_decl* f; if (nil_decl) { f = cnstrs[0]; - mk_c(c)->save_multiple_ast_trail(f); + mk_c(c)->save_multiple_ast_trail(f); *nil_decl = of_func_decl(f); } if (is_nil_decl) { f = data_util.get_constructor_recognizer(cnstrs[0]); - mk_c(c)->save_multiple_ast_trail(f); + mk_c(c)->save_multiple_ast_trail(f); *is_nil_decl = of_func_decl(f); } if (cons_decl) { f = cnstrs[1]; - mk_c(c)->save_multiple_ast_trail(f); + mk_c(c)->save_multiple_ast_trail(f); *cons_decl = of_func_decl(f); } if (is_cons_decl) { f = data_util.get_constructor_recognizer(cnstrs[1]); - mk_c(c)->save_multiple_ast_trail(f); + mk_c(c)->save_multiple_ast_trail(f); *is_cons_decl = of_func_decl(f); } if (head_decl) { @@ -220,7 +219,7 @@ extern "C" { SASSERT(acc); SASSERT(acc->size() == 2); f = (*acc)[0]; - mk_c(c)->save_multiple_ast_trail(f); + mk_c(c)->save_multiple_ast_trail(f); *head_decl = of_func_decl(f); } if (tail_decl) { @@ -228,7 +227,7 @@ extern "C" { SASSERT(acc); SASSERT(acc->size() == 2); f = (*acc)[1]; - mk_c(c)->save_multiple_ast_trail(f); + mk_c(c)->save_multiple_ast_trail(f); *tail_decl = of_func_decl(f); } RETURN_Z3_mk_list_sort(of_sort(s)); @@ -255,7 +254,7 @@ extern "C" { ) { Z3_TRY; LOG_Z3_mk_constructor(c, name, tester, num_fields, field_names, sorts, sort_refs); - RESET_ERROR_CODE(); + RESET_ERROR_CODE(); ast_manager& m = mk_c(c)->m(); constructor* cnstr = alloc(constructor, m); cnstr->m_name = to_symbol(name); @@ -291,7 +290,7 @@ extern "C" { if (!f) { SET_ERROR_CODE(Z3_INVALID_ARG); return; - } + } if (constructor_decl) { mk_c(c)->save_multiple_ast_trail(f); *constructor_decl = of_func_decl(f); @@ -301,15 +300,15 @@ extern "C" { mk_c(c)->save_multiple_ast_trail(f2); *tester = of_func_decl(f2); } - + ptr_vector const* accs = data_util.get_constructor_accessors(f); if (!accs && num_fields > 0) { SET_ERROR_CODE(Z3_INVALID_ARG); - return; + return; } for (unsigned i = 0; i < num_fields; ++i) { func_decl* f2 = (*accs)[i]; - mk_c(c)->save_multiple_ast_trail(f2); + mk_c(c)->save_multiple_ast_trail(f2); accessors[i] = of_func_decl(f2); } RETURN_Z3_query_constructor; @@ -324,7 +323,7 @@ extern "C" { Z3_CATCH; } - static datatype_decl* mk_datatype_decl(Z3_context c, + static datatype_decl* mk_datatype_decl(Z3_context c, Z3_symbol name, unsigned num_constructors, Z3_constructor constructors[]) { @@ -342,7 +341,7 @@ extern "C" { } constrs.push_back(mk_constructor_decl(cn->m_name, cn->m_tester, acc.size(), acc.c_ptr())); } - return mk_datatype_decl(to_symbol(name), num_constructors, constrs.c_ptr()); + return mk_datatype_decl(to_symbol(name), num_constructors, constrs.c_ptr()); } Z3_sort Z3_API Z3_mk_datatype(Z3_context c, @@ -352,9 +351,9 @@ extern "C" { Z3_TRY; LOG_Z3_mk_datatype(c, name, num_constructors, constructors); RESET_ERROR_CODE(); - ast_manager& m = mk_c(c)->m(); + ast_manager& m = mk_c(c)->m(); datatype_util data_util(m); - + sort_ref_vector sorts(m); { datatype_decl * data = mk_datatype_decl(c, name, num_constructors, constructors); @@ -370,7 +369,7 @@ extern "C" { mk_c(c)->save_ast_trail(s); ptr_vector const* cnstrs = data_util.get_datatype_constructors(s); - + for (unsigned i = 0; i < num_constructors; ++i) { constructor* cn = reinterpret_cast(constructors[i]); cn->m_constructor = (*cnstrs)[i]; @@ -411,7 +410,7 @@ extern "C" { Z3_TRY; LOG_Z3_mk_datatypes(c, num_sorts, sort_names, sorts, constructor_lists); RESET_ERROR_CODE(); - ast_manager& m = mk_c(c)->m(); + ast_manager& m = mk_c(c)->m(); mk_c(c)->reset_last_result(); datatype_util data_util(m); @@ -423,7 +422,7 @@ extern "C" { sort_ref_vector _sorts(m); bool ok = mk_c(c)->get_dt_plugin()->mk_datatypes(datas.size(), datas.c_ptr(), _sorts); del_datatype_decls(datas.size(), datas.c_ptr()); - + if (!ok) { SET_ERROR_CODE(Z3_INVALID_ARG); return; @@ -437,8 +436,8 @@ extern "C" { constructor_list* cl = reinterpret_cast(constructor_lists[i]); ptr_vector const* cnstrs = data_util.get_datatype_constructors(s); for (unsigned j = 0; j < cl->size(); ++j) { - constructor* cn = (*cl)[j]; - cn->m_constructor = (*cnstrs)[j]; + constructor* cn = (*cl)[j]; + cn->m_constructor = (*cnstrs)[j]; } } RETURN_Z3_mk_datatypes; @@ -452,15 +451,15 @@ extern "C" { CHECK_VALID_AST(t, 0); sort * _t = to_sort(t); datatype_util& dt_util = mk_c(c)->dtutil(); - + if (!dt_util.is_datatype(_t)) { SET_ERROR_CODE(Z3_INVALID_ARG); - return 0; + return 0; } ptr_vector const * decls = dt_util.get_datatype_constructors(_t); if (!decls) { SET_ERROR_CODE(Z3_INVALID_ARG); - return 0; + return 0; } return decls->size(); Z3_CATCH_RETURN(0); @@ -468,7 +467,7 @@ extern "C" { Z3_func_decl get_datatype_sort_constructor_core(Z3_context c, Z3_sort t, unsigned idx) { RESET_ERROR_CODE(); - CHECK_VALID_AST(t, 0); + CHECK_VALID_AST(t, 0); sort * _t = to_sort(t); datatype_util& dt_util = mk_c(c)->dtutil(); if (!dt_util.is_datatype(_t)) { @@ -497,10 +496,10 @@ extern "C" { Z3_func_decl Z3_API Z3_get_datatype_sort_recognizer(Z3_context c, Z3_sort t, unsigned idx) { Z3_TRY; LOG_Z3_get_datatype_sort_recognizer(c, t, idx); - RESET_ERROR_CODE(); + RESET_ERROR_CODE(); sort * _t = to_sort(t); datatype_util& dt_util = mk_c(c)->dtutil(); - + if (!dt_util.is_datatype(_t)) { SET_ERROR_CODE(Z3_INVALID_ARG); RETURN_Z3(0); @@ -520,13 +519,13 @@ extern "C" { Z3_func_decl Z3_API Z3_get_datatype_sort_constructor_accessor(Z3_context c, Z3_sort t, unsigned idx_c, unsigned idx_a) { Z3_TRY; LOG_Z3_get_datatype_sort_constructor_accessor(c, t, idx_c, idx_a); - RESET_ERROR_CODE(); + RESET_ERROR_CODE(); sort * _t = to_sort(t); datatype_util& dt_util = mk_c(c)->dtutil(); - + if (!dt_util.is_datatype(_t)) { SET_ERROR_CODE(Z3_INVALID_ARG); - RETURN_Z3(0); + RETURN_Z3(0); } ptr_vector const * decls = dt_util.get_datatype_constructors(_t); if (!decls || idx_c >= decls->size()) { @@ -536,24 +535,24 @@ extern "C" { func_decl* decl = (*decls)[idx_c]; if (decl->get_arity() <= idx_a) { SET_ERROR_CODE(Z3_INVALID_ARG); - RETURN_Z3(0); + RETURN_Z3(0); } ptr_vector const * accs = dt_util.get_constructor_accessors(decl); SASSERT(accs && accs->size() == decl->get_arity()); if (!accs || accs->size() <= idx_a) { SET_ERROR_CODE(Z3_INVALID_ARG); - RETURN_Z3(0); + RETURN_Z3(0); } decl = (*accs)[idx_a]; mk_c(c)->save_ast_trail(decl); - RETURN_Z3(of_func_decl(decl)); + RETURN_Z3(of_func_decl(decl)); Z3_CATCH_RETURN(0); } Z3_func_decl Z3_API Z3_get_tuple_sort_mk_decl(Z3_context c, Z3_sort t) { Z3_TRY; LOG_Z3_get_tuple_sort_mk_decl(c, t); - RESET_ERROR_CODE(); + RESET_ERROR_CODE(); sort * tuple = to_sort(t); datatype_util& dt_util = mk_c(c)->dtutil(); if (!dt_util.is_datatype(tuple) || dt_util.is_recursive(tuple) || dt_util.get_datatype_num_constructors(tuple) != 1) { @@ -564,34 +563,34 @@ extern "C" { RETURN_Z3(r); Z3_CATCH_RETURN(0); } - + unsigned Z3_API Z3_get_tuple_sort_num_fields(Z3_context c, Z3_sort t) { Z3_TRY; LOG_Z3_get_tuple_sort_num_fields(c, t); - RESET_ERROR_CODE(); + RESET_ERROR_CODE(); sort * tuple = to_sort(t); datatype_util& dt_util = mk_c(c)->dtutil(); if (!dt_util.is_datatype(tuple) || dt_util.is_recursive(tuple) || dt_util.get_datatype_num_constructors(tuple) != 1) { SET_ERROR_CODE(Z3_INVALID_ARG); - return 0; + return 0; } ptr_vector const * decls = dt_util.get_datatype_constructors(tuple); if (!decls || decls->size() != 1) { SET_ERROR_CODE(Z3_INVALID_ARG); - return 0; + return 0; } ptr_vector const * accs = dt_util.get_constructor_accessors((*decls)[0]); if (!accs) { - return 0; + return 0; } return accs->size(); Z3_CATCH_RETURN(0); } - + Z3_func_decl Z3_API Z3_get_tuple_sort_field_decl(Z3_context c, Z3_sort t, unsigned i) { Z3_TRY; LOG_Z3_get_tuple_sort_field_decl(c, t, i); - RESET_ERROR_CODE(); + RESET_ERROR_CODE(); sort * tuple = to_sort(t); datatype_util& dt_util = mk_c(c)->dtutil(); if (!dt_util.is_datatype(tuple) || dt_util.is_recursive(tuple) || dt_util.get_datatype_num_constructors(tuple) != 1) { @@ -619,14 +618,14 @@ extern "C" { } Z3_ast Z3_datatype_update_field( - Z3_context c, Z3_func_decl f, Z3_ast t, Z3_ast v) { + Z3_context c, Z3_func_decl f, Z3_ast t, Z3_ast v) { Z3_TRY; LOG_Z3_datatype_update_field(c, f, t, v); RESET_ERROR_CODE(); ast_manager & m = mk_c(c)->m(); func_decl* _f = to_func_decl(f); expr* _t = to_expr(t); - expr* _v = to_expr(v); + expr* _v = to_expr(v); expr* args[2] = { _t, _v }; sort* domain[2] = { m.get_sort(_t), m.get_sort(_v) }; parameter param(_f); diff --git a/src/api/api_interp.cpp b/src/api/api_interp.cpp index b14f3db72..10aa06568 100644 --- a/src/api/api_interp.cpp +++ b/src/api/api_interp.cpp @@ -15,7 +15,6 @@ Revision History: --*/ -#include #include #include #include"z3.h" @@ -375,7 +374,7 @@ extern "C" { for(int i = 0; i < num_theory; i++) fmlas[i] = Z3_mk_implies(ctx,Z3_mk_true(ctx),fmlas[i]); std::copy(cnsts,cnsts+num,fmlas.begin()+num_theory); - Z3_string smt = Z3_benchmark_to_smtlib_string(ctx,"none","AUFLIA","unknown","",num_fmlas-1,&fmlas[0],fmlas[num_fmlas-1]); + Z3_string smt = Z3_benchmark_to_smtlib_string(ctx,"none","AUFLIA","unknown","",num_fmlas-1,&fmlas[0],fmlas[num_fmlas-1]); std::ofstream f(filename); if(num_theory) f << ";! THEORY=" << num_theory << "\n"; @@ -469,7 +468,7 @@ extern "C" { } f.close(); -#if 0 +#if 0 if(!parents){ diff --git a/src/api/api_log.cpp b/src/api/api_log.cpp index 43cb607c8..43ed98986 100644 --- a/src/api/api_log.cpp +++ b/src/api/api_log.cpp @@ -15,7 +15,6 @@ Author: Revision History: --*/ -#include #include #include"z3.h" #include"api_log_macros.h" diff --git a/src/api/api_pb.cpp b/src/api/api_pb.cpp index ee504146f..f19fd8661 100644 --- a/src/api/api_pb.cpp +++ b/src/api/api_pb.cpp @@ -15,7 +15,6 @@ Author: Revision History: --*/ -#include #include"z3.h" #include"api_log_macros.h" #include"api_context.h" @@ -23,8 +22,8 @@ Revision History: #include"pb_decl_plugin.h" extern "C" { - - Z3_ast Z3_API Z3_mk_atmost(Z3_context c, unsigned num_args, + + Z3_ast Z3_API Z3_mk_atmost(Z3_context c, unsigned num_args, Z3_ast const args[], unsigned k) { Z3_TRY; LOG_Z3_mk_atmost(c, num_args, args, k); @@ -38,9 +37,8 @@ extern "C" { Z3_CATCH_RETURN(0); } - - Z3_ast Z3_API Z3_mk_atleast(Z3_context c, unsigned num_args, - Z3_ast const args[], unsigned k) { + Z3_ast Z3_API Z3_mk_atleast(Z3_context c, unsigned num_args, + Z3_ast const args[], unsigned k) { Z3_TRY; LOG_Z3_mk_atmost(c, num_args, args, k); RESET_ERROR_CODE(); @@ -53,7 +51,7 @@ extern "C" { Z3_CATCH_RETURN(0); } - Z3_ast Z3_API Z3_mk_pble(Z3_context c, unsigned num_args, + Z3_ast Z3_API Z3_mk_pble(Z3_context c, unsigned num_args, Z3_ast const args[], int _coeffs[], int k) { Z3_TRY; @@ -71,7 +69,7 @@ extern "C" { Z3_CATCH_RETURN(0); } - Z3_ast Z3_API Z3_mk_pbge(Z3_context c, unsigned num_args, + Z3_ast Z3_API Z3_mk_pbge(Z3_context c, unsigned num_args, Z3_ast const args[], int _coeffs[], int k) { Z3_TRY; @@ -89,7 +87,7 @@ extern "C" { Z3_CATCH_RETURN(0); } - Z3_ast Z3_API Z3_mk_pbeq(Z3_context c, unsigned num_args, + Z3_ast Z3_API Z3_mk_pbeq(Z3_context c, unsigned num_args, Z3_ast const args[], int _coeffs[], int k) { Z3_TRY; diff --git a/src/api/api_polynomial.cpp b/src/api/api_polynomial.cpp index 979d2ea50..eebe36717 100644 --- a/src/api/api_polynomial.cpp +++ b/src/api/api_polynomial.cpp @@ -14,9 +14,8 @@ Author: Leonardo de Moura (leonardo) 2012-12-08 Notes: - + --*/ -#include #include"z3.h" #include"api_log_macros.h" #include"api_context.h" @@ -35,7 +34,7 @@ namespace api { pmanager::~pmanager() { } - + }; extern "C" { diff --git a/src/api/api_quant.cpp b/src/api/api_quant.cpp index ddcd90cca..bf64aa571 100644 --- a/src/api/api_quant.cpp +++ b/src/api/api_quant.cpp @@ -15,7 +15,6 @@ Author: Revision History: --*/ -#include #include"z3.h" #include"api_log_macros.h" #include"api_context.h" @@ -26,17 +25,17 @@ Revision History: extern "C" { Z3_ast Z3_API Z3_mk_quantifier( - Z3_context c, - Z3_bool is_forall, - unsigned weight, - unsigned num_patterns, Z3_pattern const patterns[], - unsigned num_decls, Z3_sort const sorts[], - Z3_symbol const decl_names[], - Z3_ast body) + Z3_context c, + Z3_bool is_forall, + unsigned weight, + unsigned num_patterns, Z3_pattern const patterns[], + unsigned num_decls, Z3_sort const sorts[], + Z3_symbol const decl_names[], + Z3_ast body) { return Z3_mk_quantifier_ex( - c, - is_forall, + c, + is_forall, weight, 0, 0, @@ -50,15 +49,15 @@ extern "C" { } Z3_ast mk_quantifier_ex_core( - Z3_context c, - Z3_bool is_forall, - unsigned weight, + Z3_context c, + Z3_bool is_forall, + unsigned weight, Z3_symbol quantifier_id, Z3_symbol skolem_id, - unsigned num_patterns, Z3_pattern const patterns[], - unsigned num_no_patterns, Z3_ast const no_patterns[], - unsigned num_decls, Z3_sort const sorts[], - Z3_symbol const decl_names[], + unsigned num_patterns, Z3_pattern const patterns[], + unsigned num_no_patterns, Z3_ast const no_patterns[], + unsigned num_decls, Z3_sort const sorts[], + Z3_symbol const decl_names[], Z3_ast body) { Z3_TRY; RESET_ERROR_CODE(); @@ -86,9 +85,9 @@ extern "C" { expr_ref result(mk_c(c)->m()); if (num_decls > 0) { result = mk_c(c)->m().mk_quantifier( - (0 != is_forall), - names.size(), ts, names.c_ptr(), to_expr(body), - weight, + (0 != is_forall), + names.size(), ts, names.c_ptr(), to_expr(body), + weight, to_symbol(quantifier_id), to_symbol(skolem_id), num_patterns, ps, @@ -104,44 +103,44 @@ extern "C" { } Z3_ast Z3_API Z3_mk_quantifier_ex( - Z3_context c, - Z3_bool is_forall, - unsigned weight, + Z3_context c, + Z3_bool is_forall, + unsigned weight, Z3_symbol quantifier_id, Z3_symbol skolem_id, - unsigned num_patterns, Z3_pattern const patterns[], - unsigned num_no_patterns, Z3_ast const no_patterns[], - unsigned num_decls, Z3_sort const sorts[], - Z3_symbol const decl_names[], + unsigned num_patterns, Z3_pattern const patterns[], + unsigned num_no_patterns, Z3_ast const no_patterns[], + unsigned num_decls, Z3_sort const sorts[], + Z3_symbol const decl_names[], Z3_ast body) { - LOG_Z3_mk_quantifier_ex(c, is_forall, weight, quantifier_id, skolem_id, num_patterns, patterns, + LOG_Z3_mk_quantifier_ex(c, is_forall, weight, quantifier_id, skolem_id, num_patterns, patterns, num_no_patterns, no_patterns, num_decls, sorts, decl_names, body); - Z3_ast r = mk_quantifier_ex_core(c, is_forall, weight, quantifier_id, skolem_id, num_patterns, patterns, + Z3_ast r = mk_quantifier_ex_core(c, is_forall, weight, quantifier_id, skolem_id, num_patterns, patterns, num_no_patterns, no_patterns, num_decls, sorts, decl_names, body); RETURN_Z3(r); } - - Z3_ast Z3_API Z3_mk_forall(Z3_context c, - unsigned weight, - unsigned num_patterns, Z3_pattern const patterns[], - unsigned num_decls, Z3_sort const types[], - Z3_symbol const decl_names[], + + Z3_ast Z3_API Z3_mk_forall(Z3_context c, + unsigned weight, + unsigned num_patterns, Z3_pattern const patterns[], + unsigned num_decls, Z3_sort const types[], + Z3_symbol const decl_names[], Z3_ast body) { return Z3_mk_quantifier(c, 1, weight, num_patterns, patterns, num_decls, types, decl_names, body); } - - Z3_ast Z3_API Z3_mk_exists(Z3_context c, - unsigned weight, - unsigned num_patterns, Z3_pattern const patterns[], - unsigned num_decls, Z3_sort const types[], - Z3_symbol const decl_names[], + + Z3_ast Z3_API Z3_mk_exists(Z3_context c, + unsigned weight, + unsigned num_patterns, Z3_pattern const patterns[], + unsigned num_decls, Z3_sort const types[], + Z3_symbol const decl_names[], Z3_ast body) { return Z3_mk_quantifier(c, 0, weight, num_patterns, patterns, num_decls, types, decl_names, body); } - Z3_ast Z3_API Z3_mk_quantifier_const_ex(Z3_context c, + Z3_ast Z3_API Z3_mk_quantifier_const_ex(Z3_context c, Z3_bool is_forall, unsigned weight, Z3_symbol quantifier_id, @@ -166,7 +165,7 @@ extern "C" { } if (num_bound == 0) { SET_ERROR_CODE(Z3_INVALID_USAGE); - RETURN_Z3(0); + RETURN_Z3(0); } for (unsigned i = 0; i < num_bound; ++i) { app* a = to_app(bound[i]); @@ -191,7 +190,7 @@ extern "C" { app* pat = to_pattern(patterns[i]); SASSERT(mk_c(c)->m().is_pattern(pat)); expr_abstract(mk_c(c)->m(), 0, num_bound, bound_asts.c_ptr(), pat, result); - SASSERT(result.get()->get_kind() == AST_APP); + SASSERT(result.get()->get_kind() == AST_APP); pinned.push_back(result.get()); SASSERT(mk_c(c)->m().is_pattern(result.get())); _patterns.push_back(of_pattern(result.get())); @@ -205,25 +204,25 @@ extern "C" { } app* pat = to_app(to_expr(no_patterns[i])); expr_abstract(mk_c(c)->m(), 0, num_bound, bound_asts.c_ptr(), pat, result); - SASSERT(result.get()->get_kind() == AST_APP); + SASSERT(result.get()->get_kind() == AST_APP); pinned.push_back(result.get()); _no_patterns.push_back(of_ast(result.get())); } expr_ref abs_body(mk_c(c)->m()); expr_abstract(mk_c(c)->m(), 0, num_bound, bound_asts.c_ptr(), to_expr(body), abs_body); - Z3_ast result = mk_quantifier_ex_core(c, is_forall, weight, + Z3_ast result = mk_quantifier_ex_core(c, is_forall, weight, quantifier_id, skolem_id, - num_patterns, _patterns.c_ptr(), + num_patterns, _patterns.c_ptr(), num_no_patterns, _no_patterns.c_ptr(), - names.size(), types.c_ptr(), names.c_ptr(), + names.size(), types.c_ptr(), names.c_ptr(), of_ast(abs_body.get())); RETURN_Z3(result); Z3_CATCH_RETURN(0); } - Z3_ast Z3_API Z3_mk_quantifier_const(Z3_context c, + Z3_ast Z3_API Z3_mk_quantifier_const(Z3_context c, Z3_bool is_forall, unsigned weight, unsigned num_bound, @@ -231,14 +230,14 @@ extern "C" { unsigned num_patterns, Z3_pattern const patterns[], Z3_ast body) { - return Z3_mk_quantifier_const_ex(c, is_forall, weight, 0, 0, - num_bound, bound, + return Z3_mk_quantifier_const_ex(c, is_forall, weight, 0, 0, + num_bound, bound, num_patterns, patterns, 0, 0, body); } - Z3_ast Z3_API Z3_mk_forall_const(Z3_context c, + Z3_ast Z3_API Z3_mk_forall_const(Z3_context c, unsigned weight, unsigned num_bound, Z3_app const bound[], @@ -248,7 +247,7 @@ extern "C" { return Z3_mk_quantifier_const(c, true, weight, num_bound, bound, num_patterns, patterns, body); } - Z3_ast Z3_API Z3_mk_exists_const(Z3_context c, + Z3_ast Z3_API Z3_mk_exists_const(Z3_context c, unsigned weight, unsigned num_bound, Z3_app const bound[], @@ -257,7 +256,7 @@ extern "C" { Z3_ast body) { return Z3_mk_quantifier_const(c, false, weight, num_bound, bound, num_patterns, patterns, body); } - + Z3_pattern Z3_API Z3_mk_pattern(Z3_context c, unsigned num_patterns, Z3_ast const terms[]) { Z3_TRY; LOG_Z3_mk_pattern(c, num_patterns, terms); @@ -273,7 +272,7 @@ extern "C" { RETURN_Z3(of_pattern(a)); Z3_CATCH_RETURN(0); } - + Z3_ast Z3_API Z3_mk_bound(Z3_context c, unsigned index, Z3_sort ty) { Z3_TRY; LOG_Z3_mk_bound(c, index, ty); @@ -436,7 +435,7 @@ extern "C" { else { SET_ERROR_CODE(Z3_SORT_ERROR); return 0; - } + } Z3_CATCH_RETURN(0); } @@ -450,7 +449,7 @@ extern "C" { } else { SET_ERROR_CODE(Z3_SORT_ERROR); - return 0; + return 0; } Z3_CATCH_RETURN(0); } @@ -471,13 +470,13 @@ extern "C" { Z3_CATCH_RETURN(0); } - Z3_ast Z3_API Z3_pattern_to_ast(Z3_context c, Z3_pattern p) { + Z3_ast Z3_API Z3_pattern_to_ast(Z3_context c, Z3_pattern p) { RESET_ERROR_CODE(); - return (Z3_ast)(p); - } + return (Z3_ast)(p); + } Z3_API char const * Z3_pattern_to_string(Z3_context c, Z3_pattern p) { return Z3_ast_to_string(c, reinterpret_cast(p)); } - + }; diff --git a/src/api/api_seq.cpp b/src/api/api_seq.cpp index 138ea6fb0..478ee6274 100644 --- a/src/api/api_seq.cpp +++ b/src/api/api_seq.cpp @@ -16,7 +16,6 @@ Author: Revision History: --*/ -#include #include"z3.h" #include"api_log_macros.h" #include"api_context.h" @@ -28,7 +27,7 @@ extern "C" { Z3_sort Z3_API Z3_mk_seq_sort(Z3_context c, Z3_sort domain) { Z3_TRY; LOG_Z3_mk_seq_sort(c, domain); - RESET_ERROR_CODE(); + RESET_ERROR_CODE(); sort * ty = mk_c(c)->sutil().str.mk_seq(to_sort(domain)); mk_c(c)->save_ast_trail(ty); RETURN_Z3(of_sort(ty)); @@ -38,7 +37,7 @@ extern "C" { Z3_sort Z3_API Z3_mk_re_sort(Z3_context c, Z3_sort domain) { Z3_TRY; LOG_Z3_mk_re_sort(c, domain); - RESET_ERROR_CODE(); + RESET_ERROR_CODE(); sort * ty = mk_c(c)->sutil().re.mk_re(to_sort(domain)); mk_c(c)->save_ast_trail(ty); RETURN_Z3(of_sort(ty)); @@ -48,14 +47,14 @@ extern "C" { Z3_ast Z3_API Z3_mk_string(Z3_context c, Z3_string str) { Z3_TRY; LOG_Z3_mk_string(c, str); - RESET_ERROR_CODE(); + RESET_ERROR_CODE(); zstring s(str, zstring::ascii); app* a = mk_c(c)->sutil().str.mk_string(s); mk_c(c)->save_ast_trail(a); RETURN_Z3(of_ast(a)); Z3_CATCH_RETURN(0); } - + Z3_sort Z3_API Z3_mk_string_sort(Z3_context c) { Z3_TRY; LOG_Z3_mk_string_sort(c); @@ -71,8 +70,8 @@ extern "C" { LOG_Z3_is_seq_sort(c, s); RESET_ERROR_CODE(); bool result = mk_c(c)->sutil().is_seq(to_sort(s)); - return result?Z3_TRUE:Z3_FALSE; - Z3_CATCH_RETURN(Z3_FALSE); + return result?Z3_TRUE:Z3_FALSE; + Z3_CATCH_RETURN(Z3_FALSE); } Z3_bool Z3_API Z3_is_re_sort(Z3_context c, Z3_sort s) { @@ -80,8 +79,8 @@ extern "C" { LOG_Z3_is_re_sort(c, s); RESET_ERROR_CODE(); bool result = mk_c(c)->sutil().is_re(to_sort(s)); - return result?Z3_TRUE:Z3_FALSE; - Z3_CATCH_RETURN(Z3_FALSE); + return result?Z3_TRUE:Z3_FALSE; + Z3_CATCH_RETURN(Z3_FALSE); } Z3_bool Z3_API Z3_is_string_sort(Z3_context c, Z3_sort s) { @@ -89,8 +88,8 @@ extern "C" { LOG_Z3_is_string_sort(c, s); RESET_ERROR_CODE(); bool result = mk_c(c)->sutil().is_string(to_sort(s)); - return result?Z3_TRUE:Z3_FALSE; - Z3_CATCH_RETURN(Z3_FALSE); + return result?Z3_TRUE:Z3_FALSE; + Z3_CATCH_RETURN(Z3_FALSE); } Z3_bool Z3_API Z3_is_string(Z3_context c, Z3_ast s) { @@ -98,7 +97,7 @@ extern "C" { LOG_Z3_is_string(c, s); RESET_ERROR_CODE(); bool result = mk_c(c)->sutil().str.is_string(to_expr(s)); - return result?Z3_TRUE:Z3_FALSE; + return result?Z3_TRUE:Z3_FALSE; Z3_CATCH_RETURN(Z3_FALSE); } @@ -125,7 +124,7 @@ extern "C" { mk_c(c)->save_ast_trail(a); \ RETURN_Z3(of_ast(a)); \ Z3_CATCH_RETURN(0); \ - } + } MK_SORTED(Z3_mk_seq_empty, mk_c(c)->sutil().str.mk_empty); @@ -143,13 +142,13 @@ extern "C" { MK_BINARY(Z3_mk_seq_in_re, mk_c(c)->get_seq_fid(), OP_SEQ_IN_RE, SKIP); Z3_ast Z3_API Z3_mk_re_loop(Z3_context c, Z3_ast r, unsigned lo, unsigned hi) { - Z3_TRY; - LOG_Z3_mk_re_loop(c, r, lo, hi); - RESET_ERROR_CODE(); + Z3_TRY; + LOG_Z3_mk_re_loop(c, r, lo, hi); + RESET_ERROR_CODE(); app* a = hi == 0 ? mk_c(c)->sutil().re.mk_loop(to_expr(r), lo) : mk_c(c)->sutil().re.mk_loop(to_expr(r), lo, hi); - mk_c(c)->save_ast_trail(a); - RETURN_Z3(of_ast(a)); - Z3_CATCH_RETURN(0); + mk_c(c)->save_ast_trail(a); + RETURN_Z3(of_ast(a)); + Z3_CATCH_RETURN(0); } MK_UNARY(Z3_mk_re_plus, mk_c(c)->get_seq_fid(), OP_RE_PLUS, SKIP); From 9f499055826112e9ebc8b2a06bb7576d507aee46 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Tue, 10 Jan 2017 21:05:27 +0000 Subject: [PATCH 465/536] Formatting, whitespace, and Z3_API annotations. --- src/api/z3_api.h | 26 ++++++++++---------------- 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/src/api/z3_api.h b/src/api/z3_api.h index fcf22961c..65c155d63 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -1953,7 +1953,7 @@ extern "C" { The datatype may be recursive. Return the datatype sort. \param c logical context. - \param name name of datatype. + \param name name of datatype. \param num_constructors number of constructors passed in. \param constructors array of constructor containers. @@ -3088,7 +3088,7 @@ extern "C" { \param c logical context. \param numeral A string representing the numeral value in decimal notation. The string may be of the form \code{[num]*[.[num]*][E[+|-][num]+]}. - If the given sort is a real, then the numeral can be a rational, that is, a string of the form \ccode{[num]* / [num]*}. + If the given sort is a real, then the numeral can be a rational, that is, a string of the form \ccode{[num]* / [num]*}. \param ty The sort of the numeral. In the current implementation, the given sort can be an int, real, finite-domain, or bit-vectors of arbitrary size. \sa Z3_mk_int @@ -3393,7 +3393,7 @@ extern "C" { \c lo number of times, and with an unbounded upper bound. def_API('Z3_mk_re_loop', AST, (_in(CONTEXT), _in(AST), _in(UINT), _in(UINT))) - */ + */ Z3_ast Z3_API Z3_mk_re_loop(Z3_context c, Z3_ast r, unsigned lo, unsigned hi); /** @@ -3430,7 +3430,7 @@ extern "C" { def_API('Z3_mk_re_full' ,AST ,(_in(CONTEXT), _in(SORT))) */ Z3_ast Z3_API Z3_mk_re_full(Z3_context c, Z3_sort re); - + /*@}*/ @@ -3966,11 +3966,9 @@ extern "C" { def_API('Z3_mk_atmost', AST, (_in(CONTEXT), _in(UINT), _in_array(1,AST), _in(UINT))) */ - Z3_ast Z3_API Z3_mk_atmost(Z3_context c, unsigned num_args, Z3_ast const args[], unsigned k); - /** \brief Pseudo-Boolean relations. @@ -3978,9 +3976,9 @@ extern "C" { def_API('Z3_mk_atleast', AST, (_in(CONTEXT), _in(UINT), _in_array(1,AST), _in(UINT))) */ - - Z3_ast Z3_mk_atleast(Z3_context c, unsigned num_args, + Z3_ast Z3_API Z3_mk_atleast(Z3_context c, unsigned num_args, Z3_ast const args[], unsigned k); + /** \brief Pseudo-Boolean relations. @@ -3988,12 +3986,10 @@ extern "C" { def_API('Z3_mk_pble', AST, (_in(CONTEXT), _in(UINT), _in_array(1,AST), _in_array(1,INT), _in(INT))) */ - Z3_ast Z3_API Z3_mk_pble(Z3_context c, unsigned num_args, Z3_ast const args[], int coeffs[], int k); - /** \brief Pseudo-Boolean relations. @@ -4001,8 +3997,7 @@ extern "C" { def_API('Z3_mk_pbge', AST, (_in(CONTEXT), _in(UINT), _in_array(1,AST), _in_array(1,INT), _in(INT))) */ - - Z3_ast Z3_mk_pbge(Z3_context c, unsigned num_args, + Z3_ast Z3_API Z3_mk_pbge(Z3_context c, unsigned num_args, Z3_ast const args[], int coeffs[], int k); @@ -4013,7 +4008,6 @@ extern "C" { def_API('Z3_mk_pbeq', AST, (_in(CONTEXT), _in(UINT), _in_array(1,AST), _in_array(1,INT), _in(INT))) */ - Z3_ast Z3_API Z3_mk_pbeq(Z3_context c, unsigned num_args, Z3_ast const args[], int coeffs[], int k); @@ -5228,7 +5222,7 @@ extern "C" { /*@}*/ /** - \brief Return a string describing the given error code. + \brief Return a string describing the given error code. Retained function name for backwards compatibility within v4.1 */ Z3_string Z3_API Z3_get_error_msg_ex(Z3_context c, Z3_error_code err); @@ -6001,11 +5995,11 @@ extern "C" { /** \brief retrieve consequences from solver that determine values of the supplied function symbols. - + def_API('Z3_solver_get_consequences', INT, (_in(CONTEXT), _in(SOLVER), _in(AST_VECTOR), _in(AST_VECTOR), _in(AST_VECTOR))) */ - Z3_lbool Z3_API Z3_solver_get_consequences(Z3_context c, + Z3_lbool Z3_API Z3_solver_get_consequences(Z3_context c, Z3_solver s, Z3_ast_vector assumptions, Z3_ast_vector variables, From 650ea7b9ccd25c1ec3e372baae944a9a0faa73ba Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Wed, 11 Jan 2017 18:40:11 +0000 Subject: [PATCH 466/536] Bugfix for smt.core.extend_patterns --- src/smt/smt_solver.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/smt/smt_solver.cpp b/src/smt/smt_solver.cpp index 703e4489e..c843c2f78 100644 --- a/src/smt/smt_solver.cpp +++ b/src/smt/smt_solver.cpp @@ -103,6 +103,7 @@ namespace smt { virtual void assert_expr(expr * t, expr * a) { solver_na2as::assert_expr(t, a); + SASSERT(!m_name2assertion.contains(a)); get_manager().inc_ref(t); m_name2assertion.insert(a, t); } @@ -112,6 +113,17 @@ namespace smt { } virtual void pop_core(unsigned n) { + unsigned lvl = m_scopes.size(); + SASSERT(n <= lvl); + unsigned new_lvl = lvl - n; + unsigned old_sz = m_scopes[new_lvl]; + for (unsigned i = m_assumptions.size() - 1; i >= old_sz; i--) { + expr * key = m_assumptions[i].get(); + SASSERT(m_name2assertion.contains(key)); + expr * value = m_name2assertion.find(key); + m.dec_ref(value); + m_name2assertion.erase(key); + } m_context.pop(n); } @@ -274,6 +286,7 @@ namespace smt { unsigned sz = core.size(); for (unsigned i = 0; i < sz; i++) { expr_ref name(core[i], m); + SASSERT(m_name2assertion.contains(name)); expr_ref assrtn(m_name2assertion.find(name), m); collect_pattern_func_decls(assrtn, pattern_fds); } From f7ebe1604671e75925b841b397f51c185db03544 Mon Sep 17 00:00:00 2001 From: Daniel Perelman Date: Wed, 11 Jan 2017 16:56:28 -0800 Subject: [PATCH 467/536] Omit '.dll' from library name for DllImport. --- scripts/update_api.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/update_api.py b/scripts/update_api.py index b8978ff21..031b39c75 100755 --- a/scripts/update_api.py +++ b/scripts/update_api.py @@ -365,7 +365,7 @@ def mk_dotnet(dotnet): dotnet.write(' public delegate void Z3_error_handler(Z3_context c, Z3_error_code e);\n\n') dotnet.write(' public class LIB\n') dotnet.write(' {\n') - dotnet.write(' const string Z3_DLL_NAME = \"libz3.dll\";\n' + dotnet.write(' const string Z3_DLL_NAME = \"libz3\";\n' ' \n') dotnet.write(' [DllImport(Z3_DLL_NAME, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]\n') dotnet.write(' public extern static void Z3_set_error_handler(Z3_context a0, Z3_error_handler a1);\n\n') From 3370adcdffd93e00a08ef6dbdf44a3562cb7a1bc Mon Sep 17 00:00:00 2001 From: Daniel Perelman Date: Wed, 11 Jan 2017 17:02:26 -0800 Subject: [PATCH 468/536] Mark void DummyContracts as Conditional to avoid compiling their arguments. --- src/api/dotnet/core/DummyContracts.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/api/dotnet/core/DummyContracts.cs b/src/api/dotnet/core/DummyContracts.cs index e0002e5be..49b498b1a 100644 --- a/src/api/dotnet/core/DummyContracts.cs +++ b/src/api/dotnet/core/DummyContracts.cs @@ -44,15 +44,21 @@ namespace System.Diagnostics.Contracts public static class Contract { + [Conditional("false")] public static void Ensures(bool b) { } + [Conditional("false")] public static void Requires(bool b) { } + [Conditional("false")] public static void Assume(bool b, string msg) { } + [Conditional("false")] public static void Assert(bool b) { } public static bool ForAll(bool b) { return true; } public static bool ForAll(Object c, Func p) { return true; } public static bool ForAll(int from, int to, Predicate p) { return true; } + [Conditional("false")] public static void Invariant(bool b) { } public static T[] Result() { return new T[1]; } + [Conditional("false")] public static void EndContractBlock() { } public static T ValueAtReturn(out T v) { T[] t = new T[1]; v = t[0]; return v; } } From 2458db30cf0329128db4c92e79909284892619f0 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Thu, 12 Jan 2017 12:49:26 +0000 Subject: [PATCH 469/536] Corner-case fix for smt::solver::pop_core --- src/smt/smt_solver.cpp | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/src/smt/smt_solver.cpp b/src/smt/smt_solver.cpp index c843c2f78..f80ff09f4 100644 --- a/src/smt/smt_solver.cpp +++ b/src/smt/smt_solver.cpp @@ -113,16 +113,19 @@ namespace smt { } virtual void pop_core(unsigned n) { - unsigned lvl = m_scopes.size(); - SASSERT(n <= lvl); - unsigned new_lvl = lvl - n; - unsigned old_sz = m_scopes[new_lvl]; - for (unsigned i = m_assumptions.size() - 1; i >= old_sz; i--) { - expr * key = m_assumptions[i].get(); - SASSERT(m_name2assertion.contains(key)); - expr * value = m_name2assertion.find(key); - m.dec_ref(value); - m_name2assertion.erase(key); + unsigned cur_sz = m_assumptions.size(); + if (n > 0 && cur_sz > 0) { + unsigned lvl = m_scopes.size(); + SASSERT(n <= lvl); + unsigned new_lvl = lvl - n; + unsigned old_sz = m_scopes[new_lvl]; + for (unsigned i = cur_sz - 1; i >= old_sz; i--) { + expr * key = m_assumptions[i].get(); + SASSERT(m_name2assertion.contains(key)); + expr * value = m_name2assertion.find(key); + m.dec_ref(value); + m_name2assertion.erase(key); + } } m_context.pop(n); } From 43eb6cc022308c0d027c4053348b202c4420c0c2 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Fri, 13 Jan 2017 20:43:53 +0000 Subject: [PATCH 470/536] CI trigger From 37916fe7e9b17ff296de10e942ce68e548582ce6 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Fri, 13 Jan 2017 21:33:11 +0000 Subject: [PATCH 471/536] Update README.md --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index 502b32147..204fb371e 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,12 @@ Z3 can be built using [Visual Studio][1], a [Makefile][2] or using [CMake][3]. I See the [release notes](RELEASE_NOTES) for notes on various stable releases of Z3. +## Build status + +| Windows | Ubuntu x64 | Ubuntu x86 | Debian x64 | OSX | +| ------- | ---------- | ---------- | ---------- | --- | +![windows-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/4/badge) | ![ubuntu-x64-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/3/badge) | ![ubuntu-x86-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/6/badge) | ![debian-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/5/badge) | ![osx-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/2/badge) + [1]: #building-z3-on-windows-using-visual-studio-command-prompt [2]: #building-z3-using-make-and-gccclang [3]: #building-z3-using-cmake From bc6b3007de3727a284cf5f19c268d52cf4e75313 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 13 Jan 2017 20:53:22 -0800 Subject: [PATCH 472/536] remove unused features related to weighted check-sat Signed-off-by: Nikolaj Bjorner --- contrib/cmake/src/sat/CMakeLists.txt | 2 - src/opt/maxres.cpp | 12 +- src/opt/pb_sls.cpp | 46 +- src/sat/sat_bceq.cpp | 530 -------------------- src/sat/sat_bceq.h | 89 ---- src/sat/sat_config.cpp | 2 - src/sat/sat_config.h | 2 - src/sat/sat_mus.cpp | 37 +- src/sat/sat_mus.h | 2 - src/sat/sat_params.pyg | 2 - src/sat/sat_sls.cpp | 686 -------------------------- src/sat/sat_sls.h | 115 ----- src/sat/sat_solver.cpp | 143 +----- src/sat/sat_solver.h | 16 +- src/sat/sat_solver/inc_sat_solver.cpp | 29 +- src/sat/sat_solver/inc_sat_solver.h | 1 - 16 files changed, 58 insertions(+), 1656 deletions(-) delete mode 100644 src/sat/sat_bceq.cpp delete mode 100644 src/sat/sat_bceq.h delete mode 100644 src/sat/sat_sls.cpp delete mode 100644 src/sat/sat_sls.h diff --git a/contrib/cmake/src/sat/CMakeLists.txt b/contrib/cmake/src/sat/CMakeLists.txt index cfc3835c1..3eec21ec3 100644 --- a/contrib/cmake/src/sat/CMakeLists.txt +++ b/contrib/cmake/src/sat/CMakeLists.txt @@ -2,7 +2,6 @@ z3_add_component(sat SOURCES dimacs.cpp sat_asymm_branch.cpp - sat_bceq.cpp sat_clause.cpp sat_clause_set.cpp sat_clause_use_list.cpp @@ -16,7 +15,6 @@ z3_add_component(sat sat_probing.cpp sat_scc.cpp sat_simplifier.cpp - sat_sls.cpp sat_solver.cpp sat_watched.cpp COMPONENT_DEPENDENCIES diff --git a/src/opt/maxres.cpp b/src/opt/maxres.cpp index 54e7f351c..83f0849b2 100644 --- a/src/opt/maxres.cpp +++ b/src/opt/maxres.cpp @@ -302,17 +302,7 @@ public: } lbool check_sat(unsigned sz, expr* const* asms) { - if (m_st == s_primal_dual && m_c.sat_enabled()) { - rational max_weight = m_upper; - vector weights; - for (unsigned i = 0; i < sz; ++i) { - weights.push_back(get_weight(asms[i])); - } - return inc_sat_check_sat(s(), sz, asms, weights.c_ptr(), max_weight); - } - else { - return s().check_sat(sz, asms); - } + return s().check_sat(sz, asms); } void found_optimum() { diff --git a/src/opt/pb_sls.cpp b/src/opt/pb_sls.cpp index 95b489394..32c144652 100644 --- a/src/opt/pb_sls.cpp +++ b/src/opt/pb_sls.cpp @@ -20,9 +20,49 @@ Notes: #include "smt_literal.h" #include "ast_pp.h" #include "th_rewriter.h" -#include "sat_sls.h" +#include "sat_types.h" namespace smt { + + class index_set { + + unsigned_vector m_elems; + unsigned_vector m_index; + public: + unsigned num_elems() const { return m_elems.size(); } + unsigned operator[](unsigned idx) const { return m_elems[idx]; } + void reset() { m_elems.reset(); m_index.reset(); } + bool empty() const { return m_elems.empty(); } + + bool contains(unsigned idx) const { + return + (idx < m_index.size()) && + (m_index[idx] < m_elems.size()) && + (m_elems[m_index[idx]] == idx); + } + + void insert(unsigned idx) { + m_index.reserve(idx+1); + if (!contains(idx)) { + m_index[idx] = m_elems.size(); + m_elems.push_back(idx); + } + } + + void remove(unsigned idx) { + if (!contains(idx)) return; + unsigned pos = m_index[idx]; + m_elems[pos] = m_elems.back(); + m_index[m_elems[pos]] = pos; + m_elems.pop_back(); + } + + unsigned choose(random_gen& rnd) const { + SASSERT(!empty()); + return m_elems[rnd(num_elems())]; + } + }; + struct pb_sls::imp { struct clause { @@ -73,8 +113,8 @@ namespace smt { expr_ref_vector m_trail; obj_map m_decl2var; // map declarations to Boolean variables. ptr_vector m_var2decl; // reverse map - sat::index_set m_hard_false; // list of hard clauses that are false. - sat::index_set m_soft_false; // list of soft clauses that are false. + index_set m_hard_false; // list of hard clauses that are false. + index_set m_soft_false; // list of soft clauses that are false. unsigned m_max_flips; // maximal number of flips unsigned m_non_greedy_percent; // percent of moves to do non-greedy style random_gen m_rng; diff --git a/src/sat/sat_bceq.cpp b/src/sat/sat_bceq.cpp deleted file mode 100644 index fa0309327..000000000 --- a/src/sat/sat_bceq.cpp +++ /dev/null @@ -1,530 +0,0 @@ -/*++ -Copyright (c) 2014 Microsoft Corporation - -Module Name: - - sat_bceq.cpp - -Abstract: - - Find equivalent literals based on blocked clause decomposition. - -Author: - - Nikolaj Bjorner (nbjorner) 2014-09-27. - - -Revision History: - ---*/ -#include"sat_bceq.h" -#include"sat_solver.h" -#include"trace.h" -#include"bit_vector.h" -#include"map.h" -#include"sat_elim_eqs.h" - -namespace sat { - - void bceq::use_list::init(unsigned num_vars) { - m_clauses.reset(); - m_clauses.resize(2*num_vars); - } - - void bceq::use_list::insert(clause& c) { - unsigned sz = c.size(); - for (unsigned i = 0; i < sz; i++) { - m_clauses[c[i].index()].push_back(&c); - } - } - - void bceq::use_list::erase(clause& c) { - unsigned sz = c.size(); - for (unsigned i = 0; i < sz; i++) { - m_clauses[c[i].index()].erase(&c); - } - } - - ptr_vector& bceq::use_list::get(literal lit) { - return m_clauses[lit.index()]; - } - - bceq::bceq(solver & s): - m_solver(s) { - } - - void bceq::register_clause(clause* cls) { - m_clauses.setx(cls->id(), cls, 0); - } - - void bceq::unregister_clause(clause* cls) { - m_clauses.setx(cls->id(), 0, 0); - } - - void bceq::init() { - m_clauses.reset(); - m_bin_clauses.reset(); - m_L.reset(); - m_R.reset(); - m_L_blits.reset(); - m_R_blits.reset(); - m_bce_use_list.reset(); - clause * const* it = m_solver.begin_clauses(); - clause * const* end = m_solver.end_clauses(); - for (; it != end; ++it) { - clause* cls = *it; - if (!cls->was_removed()) { - m_use_list->insert(*cls); - register_clause(cls); - } - } - bin_clauses bc; - m_solver.collect_bin_clauses(bc, false); // exclude roots. - literal lits[2]; - for (unsigned i = 0; i < bc.size(); ++i) { - lits[0] = bc[i].first; - lits[1] = bc[i].second; - clause* cls = m_solver.m_cls_allocator.mk_clause(2, lits, false); - m_use_list->insert(*cls); - m_bin_clauses.push_back(cls); - register_clause(cls); - } - TRACE("sat", - for (unsigned i = 0; i < m_clauses.size(); ++i) { - clause const* cls = m_clauses[i]; - if (cls) tout << *cls << "\n"; - }); - } - - void bceq::pure_decompose() { - // while F != empty - // pick a clause and variable x in clause. - // get use list U1 of x and U2 of ~x - // assume |U1| >= |U2| - // add U1 to clause set. - for (unsigned i = 0; i < m_clauses.size(); ++i) { - clause* cls = m_clauses[i]; - if (cls) { - SASSERT(i == cls->id()); - pure_decompose((*cls)[0]); - SASSERT(!m_clauses[i]); - } - } - m_L.reverse(); - m_L_blits.reverse(); - } - - void bceq::pure_decompose(literal lit) { - clause_use_list& pos = m_use_list->get(lit); - clause_use_list& neg = m_use_list->get(~lit); - unsigned sz1 = m_L.size(); - unsigned sz2 = m_R.size(); - pure_decompose(pos, m_L); - pure_decompose(neg, m_R); - unsigned delta1 = m_L.size() - sz1; - unsigned delta2 = m_R.size() - sz2; - if (delta1 < delta2) { - m_L_blits.resize(sz1+delta2, ~lit); - m_R_blits.resize(sz2+delta1, lit); - for (unsigned i = 0; i < delta1; ++i) { - std::swap(m_L[sz1 + i], m_R[sz2 + i]); - } - for (unsigned i = delta1; i < delta2; ++i) { - m_L.push_back(m_R[sz2 + i]); - } - m_R.resize(sz2 + delta1); - std::swap(delta1, delta2); - } - else { - m_L_blits.resize(sz1+delta1, lit); - m_R_blits.resize(sz2+delta2, ~lit); - } - TRACE("bceq", tout << lit << " " << "pos: " << delta1 << " " << "neg: " << delta2 << "\n";); - } - - void bceq::pure_decompose(clause_use_list& uses, svector& clauses) { - unsigned sz = uses.size(); - for (unsigned i = 0; i < sz; ++i) { - clause& cls = *uses[i]; - if (!cls.was_removed() && m_clauses[cls.id()]) { - clauses.push_back(&cls); - m_clauses[cls.id()] = 0; - } - } - } - - void bceq::post_decompose() { - m_marked.reset(); - m_marked.resize(2*m_solver.num_vars(), false); - use_list ul; - use_list* save = m_use_list; - m_use_list = &ul; - ul.init(m_solver.num_vars()); - for (unsigned i = 0; i < m_L.size(); ++i) { - ul.insert(*m_L[i]); - } - - // cheap pass: add clauses from R in order - // such that they are blocked with respect to - // predecessors. - m_removed.reset(); - for (unsigned i = 0; i < m_R.size(); ++i) { - literal lit = find_blocked(*m_R[i]); - if (lit != null_literal) { - m_L.push_back(m_R[i]); - m_L_blits.push_back(lit); - ul.insert(*m_R[i]); - m_R[i] = m_R.back(); - m_R_blits[i] = m_R_blits.back(); - m_R.pop_back(); - m_R_blits.pop_back(); - --i; - } - } - // expensive pass: add clauses from R as long - // as BCE produces the empty set of clauses. - m_bce_use_list.init(m_solver.num_vars()); - for (unsigned i = 0; i < m_L.size(); ++i) { - m_bce_use_list.insert(*m_L[i]); - } - for (unsigned i = 0; i < m_R.size(); ++i) { - if (bce(*m_R[i])) { - m_R[i] = m_R.back(); - m_R_blits[i] = m_R_blits.back(); - m_R.pop_back(); - m_R_blits.pop_back(); - --i; - } - } - m_use_list = save; - } - - - // Note: replay blocked clause elimination: - // Suppose C u { c1 } is blocked. - // annotate each clause by blocking literal. - // for new clause c2, check if C u { c2 } is blocked. - // For each c in C record which literal it is blocked. - // (Order the clauses in C by block ordering) - // l | c is blocked, - // -> c2 contains ~l => check if c c2 is blocked - // - bool bceq::bce(clause& cls0) { - IF_VERBOSE(1, verbose_stream() << "bce " << m_L.size() << " " << m_R.size() << " " << cls0 << "\n";); - unsigned_vector& live_clauses = m_live_clauses; - live_clauses.reset(); - m_use_list = &m_bce_use_list; - m_bce_use_list.insert(cls0); - svector& clauses = m_L; - literal_vector& blits = m_L_blits; - clauses.push_back(&cls0); - blits.push_back(null_literal); - bool removed = false; - m_removed.reset(); - for (unsigned i = 0; i < clauses.size(); ++i) { - clause& cls1 = *clauses[i]; - literal lit = find_blocked(cls1); - if (lit == null_literal) { - live_clauses.push_back(i); - } - else { - m_removed.setx(cls1.id(), true, false); - removed = true; - } - } - while (removed) { - removed = false; - //std::cout << live_clauses.size() << " "; - for (unsigned i = 0; i < live_clauses.size(); ++i) { - clause& cls1 = *clauses[live_clauses[i]]; - literal lit = find_blocked(cls1); - if (lit != null_literal) { - m_removed.setx(cls1.id(), true, false); - removed = true; - live_clauses[i] = live_clauses.back(); - live_clauses.pop_back(); - --i; - } - } - } - //std::cout << "\n"; - m_bce_use_list.erase(cls0); - clauses.pop_back(); - blits.pop_back(); - return live_clauses.empty(); - } - - literal bceq::find_blocked(clause const& cls) { - TRACE("bceq", tout << cls << "\n";); - - unsigned sz = cls.size(); - for (unsigned i = 0; i < sz; ++i) { - m_marked[(~cls[i]).index()] = true; - } - literal result = null_literal; - for (unsigned i = 0; i < sz; ++i) { - literal lit = cls[i]; - if (is_blocked(lit)) { - TRACE("bceq", tout << "is blocked " << lit << " : " << cls << "\n";); - result = lit; - break; - } - } - for (unsigned i = 0; i < sz; ++i) { - m_marked[(~cls[i]).index()] = false; - } - return result; - } - - bool bceq::is_blocked(literal lit) const { - clause_use_list& uses = m_use_list->get(~lit); - unsigned sz = uses.size(); - for (unsigned i = 0; i < sz; ++i) { - clause const& cls = *uses[i]; - unsigned sz = cls.size(); - bool is_axiom = m_removed.get(cls.id(), false); - for (unsigned i = 0; !is_axiom && i < sz; ++i) { - is_axiom = m_marked[cls[i].index()] && cls[i] != ~lit; - } - - TRACE("bceq", tout << "resolvent " << lit << " : " << cls << " " << (is_axiom?"axiom":"non-axiom") << "\n";); - if (!is_axiom) { - return false; - } - } - return true; - } - - - void bceq::init_rbits() { - m_rbits.reset(); - for (unsigned i = 0; i < m_solver.num_vars(); ++i) { - uint64 lo = m_rand() + (m_rand() << 16); - uint64 hi = m_rand() + (m_rand() << 16); - m_rbits.push_back(lo + (hi << 32ULL)); - } - } - - void bceq::init_reconstruction_stack() { - m_rstack.reset(); - m_bstack.reset(); - // decomposition already creates a blocked stack in the proper order. - m_rstack.append(m_L); - m_bstack.append(m_L_blits); - } - - uint64 bceq::eval_clause(clause const& cls) const { - uint64 b = 0; - unsigned sz = cls.size(); - for (unsigned i = 0; i < sz; ++i) { - literal lit = cls[i]; - uint64 val = m_rbits[lit.var()]; - if (lit.sign()) { - val = ~val; - } - b |= val; - } - return b; - } - - void bceq::sat_sweep() { - init_rbits(); - init_reconstruction_stack(); - for (unsigned i = 0; i < m_rstack.size(); ++i) { - clause const& cls = *m_rstack[i]; - literal block_lit = m_bstack[i]; - uint64 b = eval_clause(cls); - // v = 0, b = 0 -> v := 1 - // v = 0, b = 1 -> v := 0 - // v = 1, b = 0 -> v := 0 - // v = 1, b = 1 -> v := 1 - m_rbits[block_lit.var()] ^= ~b; - - } - DEBUG_CODE(verify_sweep();); - } - - void bceq::verify_sweep() { - 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; } }; - - struct u64_eq { bool operator()(uint64 u1, uint64 u2) const { return u1 == u2; } }; - - void bceq::extract_partition() { - unsigned num_vars = m_solver.num_vars(); - map table; - union_find<> union_find(m_union_find_ctx); - for (unsigned i = 0; i < num_vars; ++i) { - m_s->mk_var(true, true); - union_find.mk_var(); - } - for (unsigned i = 0; i < m_L.size(); ++i) { - m_s->mk_clause(m_L[i]->size(), m_L[i]->begin()); - } - for (unsigned i = 0; i < num_vars; ++i) { - uint64 val = m_rbits[i]; - unsigned index; - if (table.find(val, index)) { - union_find.merge(i, index); - } - else if (table.find(~val, index)) { - union_find.merge(i, index); - } - else { - table.insert(val, i); - } - } - TRACE("sat", union_find.display(tout);); - - // - // Preliminary version: - // A more appropriate is to walk each pair, - // and refine partition based on SAT results. - // - for (unsigned i = 0; i < num_vars; ++i) { - if (!union_find.is_root(i)) continue; - unsigned v = union_find.next(i); - unsigned last_v = UINT_MAX; - if (!m_solver.was_eliminated(i)) { - last_v = i; - } - while (v != i) { - if (!m_solver.was_eliminated(v)) { - if (last_v != UINT_MAX) { - if (check_equality(v, last_v)) { - // last_v was eliminated. - - } - else { - // TBD: refine partition. - } - } - last_v = v; - } - v = union_find.next(v); - } - } - } - - bool bceq::check_equality(unsigned v1, unsigned v2) { - TRACE("sat", tout << "check: " << v1 << " = " << v2 << "\n";); - uint64 val1 = m_rbits[v1]; - uint64 val2 = m_rbits[v2]; - literal l1 = literal(v1, false); - literal l2 = literal(v2, false); - if (val1 != val2) { - SASSERT(val1 == ~val2); - l2.neg(); - } - if (is_already_equiv(l1, l2)) { - TRACE("sat", tout << "Already equivalent: " << l1 << " " << l2 << "\n";); - return false; - } - - literal lits[2]; - lits[0] = l1; - lits[1] = ~l2; - lbool is_sat = m_s->check(2, lits); - if (is_sat == l_false) { - lits[0] = ~l1; - lits[1] = l2; - is_sat = m_s->check(2, lits); - } - if (is_sat == l_false) { - TRACE("sat", tout << "Found equivalent: " << l1 << " " << l2 << "\n";); - assert_equality(l1, l2); - } - else { - TRACE("sat", tout << "Not equivalent: " << l1 << " " << l2 << "\n";); - // TBD: if is_sat == l_true, then refine partition. - } - return is_sat == l_false; - } - - bool bceq::is_already_equiv(literal l1, literal l2) { - watch_list const& w1 = m_solver.get_wlist(l1); - bool found = false; - for (unsigned i = 0; !found && i < w1.size(); ++i) { - watched const& w = w1[i]; - found = w.is_binary_clause() && w.get_literal() == ~l2; - } - if (!found) return false; - found = false; - watch_list const& w2 = m_solver.get_wlist(~l1); - for (unsigned i = 0; !found && i < w2.size(); ++i) { - watched const& w = w2[i]; - found = w.is_binary_clause() && w.get_literal() == l2; - } - return found; - } - - void bceq::assert_equality(literal l1, literal l2) { - if (l2.sign()) { - l1.neg(); - l2.neg(); - } - literal_vector roots; - bool_var_vector vars; - for (unsigned i = 0; i < m_solver.num_vars(); ++i) { - roots.push_back(literal(i, false)); - } - roots[l2.var()] = l1; - vars.push_back(l2.var()); - elim_eqs elim(m_solver); - IF_VERBOSE(1, - for (unsigned i = 0; i < vars.size(); ++i) { - verbose_stream() << "var: " << vars[i] << " root: " << roots[vars[i]] << "\n"; - }); - elim(roots, vars); - } - - void bceq::cleanup() { - m_solver.del_clauses(m_bin_clauses.begin(), m_bin_clauses.end()); - m_bin_clauses.reset(); - } - - - void bceq::operator()() { - if (!m_solver.m_config.m_bcd) return; - flet _disable_bcd(m_solver.m_config.m_bcd, false); - flet _disable_min(m_solver.m_config.m_core_minimize, false); - flet _disable_opt(m_solver.m_config.m_optimize_model, false); - flet _bound_maxc(m_solver.m_config.m_max_conflicts, 1500); - - use_list ul; - solver s(m_solver.m_params, m_solver.rlimit(), 0); - s.m_config.m_bcd = false; - s.m_config.m_core_minimize = false; - s.m_config.m_optimize_model = false; - s.m_config.m_max_conflicts = 1500; - m_use_list = &ul; - m_s = &s; - ul.init(m_solver.num_vars()); - init(); - pure_decompose(); - post_decompose(); - IF_VERBOSE(1, verbose_stream() << "Decomposed set " << m_L.size() << " rest: " << m_R.size() << "\n";); - - TRACE("sat", - tout << "Decomposed set " << m_L.size() << "\n"; - for (unsigned i = 0; i < m_L.size(); ++i) { - clause const* cls = m_L[i]; - if (cls) tout << *cls << "\n"; - } - tout << "remainder " << m_R.size() << "\n"; - for (unsigned i = 0; i < m_R.size(); ++i) { - clause const* cls = m_R[i]; - if (cls) tout << *cls << "\n"; - } - ); - sat_sweep(); - extract_partition(); - cleanup(); - } -}; diff --git a/src/sat/sat_bceq.h b/src/sat/sat_bceq.h deleted file mode 100644 index c9d01e78b..000000000 --- a/src/sat/sat_bceq.h +++ /dev/null @@ -1,89 +0,0 @@ -/*++ -Copyright (c) 2014 Microsoft Corporation - -Module Name: - - sat_bceq.h - -Abstract: - - Find equivalent literals based on blocked clause decomposition. - -Author: - - Nikolaj Bjorner (nbjorner) 2014-09-27. - -Revision History: - ---*/ -#ifndef SAT_BCEQ_H_ -#define SAT_BCEQ_H_ - -#include"sat_types.h" -#include"union_find.h" - - -namespace sat { - class solver; - - class bceq { - typedef ptr_vector clause_use_list; - class use_list { - vector > m_clauses; - public: - use_list() {} - void init(unsigned num_vars); - void reset() { m_clauses.reset(); } - void erase(clause& c); - void insert(clause& c); - ptr_vector& get(literal lit); - }; - typedef std::pair bin_clause; - typedef svector bin_clauses; - solver & m_solver; - use_list* m_use_list; - use_list m_bce_use_list; - solver* m_s; - random_gen m_rand; - svector m_clauses; - svector m_L; - svector m_R; - literal_vector m_L_blits; - literal_vector m_R_blits; - svector m_bin_clauses; - svector m_rbits; - svector m_rstack; // stack of blocked clauses - literal_vector m_bstack; // stack of blocking literals - svector m_marked; - svector m_removed; // set of clauses removed (not considered in clause set during BCE) - union_find_default_ctx m_union_find_ctx; - unsigned_vector m_live_clauses; - - void init(); - void register_clause(clause* cls); - void unregister_clause(clause* cls); - void pure_decompose(); - void pure_decompose(literal lit); - void pure_decompose(ptr_vector& uses, svector& clauses); - void post_decompose(); - literal find_blocked(clause const& cls); - bool bce(clause& cls); - bool is_blocked(literal lit) const; - void init_rbits(); - void init_reconstruction_stack(); - void sat_sweep(); - void cleanup(); - uint64 eval_clause(clause const& cls) const; - void verify_sweep(); - void extract_partition(); - bool check_equality(unsigned v1, unsigned v2); - bool is_already_equiv(literal l1, literal l2); - void assert_equality(literal l1, literal l2); - public: - bceq(solver & s); - void operator()(); - }; - -}; - -#endif diff --git a/src/sat/sat_config.cpp b/src/sat/sat_config.cpp index 7e0a7c50c..4e01bfe55 100644 --- a/src/sat/sat_config.cpp +++ b/src/sat/sat_config.cpp @@ -111,8 +111,6 @@ namespace sat { m_minimize_lemmas = p.minimize_lemmas(); m_core_minimize = p.core_minimize(); m_core_minimize_partial = p.core_minimize_partial(); - m_optimize_model = p.optimize_model(); - m_bcd = p.bcd(); m_dyn_sub_res = p.dyn_sub_res(); } diff --git a/src/sat/sat_config.h b/src/sat/sat_config.h index 1cdabddef..910ca0360 100644 --- a/src/sat/sat_config.h +++ b/src/sat/sat_config.h @@ -72,8 +72,6 @@ namespace sat { bool m_dyn_sub_res; bool m_core_minimize; bool m_core_minimize_partial; - bool m_optimize_model; - bool m_bcd; symbol m_always_true; diff --git a/src/sat/sat_mus.cpp b/src/sat/sat_mus.cpp index 7b3277b6c..380b8ee94 100644 --- a/src/sat/sat_mus.cpp +++ b/src/sat/sat_mus.cpp @@ -20,11 +20,10 @@ Notes: #include "sat_solver.h" #include "sat_mus.h" -#include "sat_sls.h" namespace sat { - mus::mus(solver& s):s(s), m_is_active(false), m_best_value(0), m_restart(0), m_max_restarts(0) {} + mus::mus(solver& s):s(s), m_is_active(false),m_restart(0), m_max_restarts(0) {} mus::~mus() {} @@ -32,7 +31,6 @@ namespace sat { m_core.reset(); m_mus.reset(); m_model.reset(); - m_best_value = 0; m_max_restarts = (s.m_stats.m_restart - m_restart) + 10; m_restart = s.m_stats.m_restart; } @@ -45,21 +43,13 @@ namespace sat { } void mus::update_model() { - double new_value = s.m_wsls.evaluate_model(s.m_model); if (m_model.empty()) { m_model.append(s.m_model); - m_best_value = new_value; - } - else if (m_best_value > new_value) { - m_model.reset(); - m_model.append(s.m_model); - m_best_value = new_value; } } lbool mus::operator()() { flet _disable_min(s.m_config.m_core_minimize, false); - flet _disable_opt(s.m_config.m_optimize_model, false); flet _is_active(m_is_active, true); IF_VERBOSE(3, verbose_stream() << "(sat.mus " << s.get_core() << ")\n";); reset(); @@ -120,9 +110,6 @@ namespace sat { SASSERT(value_at(lit, s.get_model()) == l_false); mus.push_back(lit); update_model(); - if (!core.empty()) { - // mr(); // TBD: measure - } break; } case l_false: @@ -262,27 +249,5 @@ namespace sat { IF_VERBOSE(3, verbose_stream() << "core verification: " << is_sat << " " << core << "\n";); } - void mus::mr() { - sls sls(s); - literal_vector tabu; - tabu.append(m_mus); - tabu.append(m_core); - bool reuse_model = false; - for (unsigned i = m_mus.size(); i < tabu.size(); ++i) { - tabu[i] = ~tabu[i]; - lbool is_sat = sls(tabu.size(), tabu.c_ptr(), reuse_model); - tabu[i] = ~tabu[i]; - if (is_sat == l_true) { - m_mus.push_back(tabu[i]); - m_core.erase(tabu[i]); - IF_VERBOSE(3, verbose_stream() << "in core " << tabu[i] << "\n";); - reuse_model = true; - } - else { - IF_VERBOSE(3, verbose_stream() << "NOT in core " << tabu[i] << "\n";); - reuse_model = false; - } - } - } } diff --git a/src/sat/sat_mus.h b/src/sat/sat_mus.h index 617bbc757..74f6d75f0 100644 --- a/src/sat/sat_mus.h +++ b/src/sat/sat_mus.h @@ -26,7 +26,6 @@ namespace sat { literal_vector m_mus; bool m_is_active; model m_model; // model obtained during minimal unsat core - double m_best_value; unsigned m_restart; unsigned m_max_restarts; @@ -41,7 +40,6 @@ namespace sat { lbool mus1(); lbool mus2(); lbool qx(literal_set& assignment, literal_set& support, bool has_support); - void mr(); void reset(); void set_core(); void update_model(); diff --git a/src/sat/sat_params.pyg b/src/sat/sat_params.pyg index de1759486..21a50bea2 100644 --- a/src/sat/sat_params.pyg +++ b/src/sat/sat_params.pyg @@ -22,6 +22,4 @@ def_module_params('sat', ('dyn_sub_res', BOOL, True, 'dynamic subsumption resolution for minimizing learned clauses'), ('core.minimize', BOOL, False, 'minimize computed core'), ('core.minimize_partial', BOOL, False, 'apply partial (cheap) core minimization'), - ('optimize_model', BOOL, False, 'enable optimization of soft constraints'), - ('bcd', BOOL, False, 'enable blocked clause decomposition for equality extraction'), ('dimacs.core', BOOL, False, 'extract core from DIMACS benchmarks'))) diff --git a/src/sat/sat_sls.cpp b/src/sat/sat_sls.cpp deleted file mode 100644 index 7efc0ce0b..000000000 --- a/src/sat/sat_sls.cpp +++ /dev/null @@ -1,686 +0,0 @@ -/*++ -Copyright (c) 2014 Microsoft Corporation - -Module Name: - - sat_sls.cpp - -Abstract: - - SLS for clauses in SAT solver - -Author: - - Nikolaj Bjorner (nbjorner) 2014-12-8 - -Notes: - ---*/ - -#include "sat_sls.h" -#include "sat_solver.h" - -namespace sat { - - bool index_set::contains(unsigned idx) const { - return - (idx < m_index.size()) && - (m_index[idx] < m_elems.size()) && - (m_elems[m_index[idx]] == idx); - } - - void index_set::insert(unsigned idx) { - m_index.reserve(idx+1); - if (!contains(idx)) { - m_index[idx] = m_elems.size(); - m_elems.push_back(idx); - } - } - - void index_set::remove(unsigned idx) { - if (!contains(idx)) return; - unsigned pos = m_index[idx]; - m_elems[pos] = m_elems.back(); - m_index[m_elems[pos]] = pos; - m_elems.pop_back(); - } - - unsigned index_set::choose(random_gen& rnd) const { - SASSERT(!empty()); - return m_elems[rnd(num_elems())]; - } - - sls::sls(solver& s): s(s) { - m_prob_choose_min_var = 43; - m_clause_generation = 0; - } - - sls::~sls() { - for (unsigned i = 0; i < m_bin_clauses.size(); ++i) { - m_alloc.del_clause(m_bin_clauses[i]); - } - } - - lbool sls::operator()(unsigned sz, literal const* tabu, bool reuse_model) { - init(sz, tabu, reuse_model); - unsigned i; - for (i = 0; !m_false.empty() && !s.canceled() && i < m_max_tries; ++i) { - flip(); - } - IF_VERBOSE(2, verbose_stream() << "tries " << i << "\n";); - if (m_false.empty()) { - SASSERT(s.check_model(m_model)); - return l_true; - } - return l_undef; - } - - void sls::init(unsigned sz, literal const* tabu, bool reuse_model) { - bool same_generation = (m_clause_generation == s.m_stats.m_non_learned_generation); - if (!same_generation) { - init_clauses(); - init_use(); - IF_VERBOSE(0, verbose_stream() << s.m_stats.m_non_learned_generation << " " << m_clause_generation << "\n";); - } - if (!reuse_model) { - init_model(); - } - init_tabu(sz, tabu); - m_clause_generation = s.m_stats.m_non_learned_generation; - - m_max_tries = 10*(s.num_vars() + m_clauses.size()); - - } - - void sls::init_clauses() { - for (unsigned i = 0; i < m_bin_clauses.size(); ++i) { - m_alloc.del_clause(m_bin_clauses[i]); - } - m_bin_clauses.reset(); - m_clauses.reset(); - clause * const * it = s.begin_clauses(); - clause * const * end = s.end_clauses(); - for (; it != end; ++it) { - m_clauses.push_back(*it); - } - svector bincs; - s.collect_bin_clauses(bincs, false); - literal lits[2]; - for (unsigned i = 0; i < bincs.size(); ++i) { - lits[0] = bincs[i].first; - lits[1] = bincs[i].second; - clause* cl = m_alloc.mk_clause(2, lits, false); - m_clauses.push_back(cl); - m_bin_clauses.push_back(cl); - } - } - - void sls::init_model() { - m_num_true.reset(); - m_model.reset(); - m_model.append(s.get_model()); - unsigned sz = m_clauses.size(); - for (unsigned i = 0; i < sz; ++i) { - clause const& c = *m_clauses[i]; - unsigned n = 0; - unsigned csz = c.size(); - for (unsigned j = 0; j < csz; ++j) { - lbool val = value_at(c[j], m_model); - switch (val) { - case l_true: - ++n; - break; - case l_undef: - ++n; - m_model[c[j].var()] = c[j].sign()?l_false:l_true; - SASSERT(value_at(c[j], m_model) == l_true); - break; - default: - break; - } - } - m_num_true.push_back(n); - if (n == 0) { - m_false.insert(i); - } - } - } - - void sls::init_tabu(unsigned sz, literal const* tabu) { - // our main use is where m_model satisfies all the hard constraints. - // SASSERT(s.check_model(m_model)); - // SASSERT(m_false.empty()); - // ASSERT: m_num_true is correct count. - m_tabu.reset(); - m_tabu.resize(s.num_vars(), false); - for (unsigned i = 0; i < sz; ++i) { - literal lit = tabu[i]; - if (s.m_level[lit.var()] == 0) continue; - if (value_at(lit, m_model) == l_false) { - flip(lit); - } - m_tabu[lit.var()] = true; - } - for (unsigned i = 0; i < s.m_trail.size(); ++i) { - literal lit = s.m_trail[i]; - if (s.m_level[lit.var()] > 0) break; - if (value_at(lit, m_model) != l_true) { - flip(lit); - } - m_tabu[lit.var()] = true; - } - } - - void sls::init_use() { - m_use_list.reset(); - m_use_list.resize(s.num_vars()*2); - unsigned sz = m_clauses.size(); - for (unsigned i = 0; i < sz; ++i) { - clause const& c = *m_clauses[i]; - unsigned csz = c.size(); - for (unsigned j = 0; j < csz; ++j) { - m_use_list[c[j].index()].push_back(i); - } - } - DEBUG_CODE(check_use_list();); - } - - unsigned_vector const& sls::get_use(literal lit) { - SASSERT(lit.index() < m_use_list.size()); - return m_use_list[lit.index()]; - } - - unsigned sls::get_break_count(literal lit, unsigned min_break) { - SASSERT(value_at(lit, m_model) == l_false); - unsigned result = 0; - unsigned_vector const& uses = get_use(~lit); - unsigned sz = uses.size(); - for (unsigned i = 0; i < sz; ++i) { - if (m_num_true[uses[i]] == 1) { - ++result; - if (result > min_break) return result; - } - } - return result; - } - - bool sls::pick_flip(literal& lit) { - unsigned clause_idx = m_false.choose(m_rand); - clause const& c = *m_clauses[clause_idx]; - SASSERT(!c.satisfied_by(m_model)); - unsigned min_break = UINT_MAX; - unsigned sz = c.size(); - m_min_vars.reset(); - for (unsigned i = 0; i < sz; ++i) { - lit = c[i]; - if (m_tabu[lit.var()]) continue; - unsigned break_count = get_break_count(lit, min_break); - if (break_count < min_break) { - min_break = break_count; - m_min_vars.reset(); - m_min_vars.push_back(lit); - } - else if (break_count == min_break) { - m_min_vars.push_back(lit); - } - } - if (min_break == 0 || (!m_min_vars.empty() && m_rand(100) >= m_prob_choose_min_var)) { - lit = m_min_vars[m_rand(m_min_vars.size())]; - return true; - } - else if (min_break == UINT_MAX) { - return false; - } - else { - lit = c[m_rand(c.size())]; - return !m_tabu[lit.var()]; - } - } - - void sls::flip() { - literal lit; - if (pick_flip(lit)) { - flip(lit); - } - } - - void sls::flip(literal lit) { - //IF_VERBOSE(0, verbose_stream() << lit << " ";); - SASSERT(value_at(lit, m_model) == l_false); - SASSERT(!m_tabu[lit.var()]); - m_model[lit.var()] = lit.sign()?l_false:l_true; - SASSERT(value_at(lit, m_model) == l_true); - unsigned_vector const& use1 = get_use(lit); - unsigned sz = use1.size(); - for (unsigned i = 0; i < sz; ++i) { - unsigned cl = use1[i]; - m_num_true[cl]++; - SASSERT(m_num_true[cl] <= m_clauses[cl]->size()); - if (m_num_true[cl] == 1) m_false.remove(cl); - } - unsigned_vector const& use2 = get_use(~lit); - sz = use2.size(); - for (unsigned i = 0; i < sz; ++i) { - unsigned cl = use2[i]; - SASSERT(m_num_true[cl] > 0); - m_num_true[cl]--; - if (m_num_true[cl] == 0) m_false.insert(cl); - } - } - - void sls::check_invariant() { - 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() { - 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; - } - SASSERT(found); - } - }); - } - - void sls::display(std::ostream& out) const { - out << "Model\n"; - for (bool_var v = 0; v < m_model.size(); ++v) { - out << v << ": " << m_model[v] << "\n"; - } - out << "Clauses\n"; - unsigned sz = m_false.num_elems(); - for (unsigned i = 0; i < sz; ++i) { - out << *m_clauses[m_false[i]] << "\n"; - } - for (unsigned i = 0; i < m_clauses.size(); ++i) { - if (m_false.contains(i)) continue; - clause const& c = *m_clauses[i]; - out << c << " " << m_num_true[i] << "\n"; - } - bool has_tabu = false; - for (unsigned i = 0; !has_tabu && i < m_tabu.size(); ++i) { - has_tabu = m_tabu[i]; - } - if (has_tabu) { - out << "Tabu: "; - for (unsigned i = 0; i < m_tabu.size(); ++i) { - if (m_tabu[i]) { - literal lit(i, false); - if (value_at(lit, m_model) == l_false) lit.neg(); - out << lit << " "; - } - } - out << "\n"; - } - } - - - wsls::wsls(solver& s): - sls(s) - { - m_smoothing_probability = 1; // 1/1000 - } - - wsls::~wsls() {} - - void wsls::set_soft(unsigned sz, literal const* lits, double const* weights) { - m_soft.reset(); - m_weights.reset(); - m_soft.append(sz, lits); - m_weights.append(sz, weights); - } - - void wsls::opt(unsigned sz, literal const* tabu, bool reuse_model) { - init(sz, tabu, reuse_model); - - // - // Initialize m_clause_weights, m_hscore, m_sscore. - // - m_best_value = m_false.empty()?evaluate_model(m_model):-1.0; - m_best_model.reset(); - m_clause_weights.reset(); - m_hscore.reset(); - m_sscore.reset(); - m_H.reset(); - m_S.reset(); - m_best_model.append(s.get_model()); - m_clause_weights.resize(m_clauses.size(), 1); - m_sscore.resize(s.num_vars(), 0.0); - m_hscore.resize(s.num_vars(), 0); - for (unsigned i = 0; i < m_soft.size(); ++i) { - literal lit = m_soft[i]; - m_sscore[lit.var()] = m_weights[i]; - if (value_at(lit, m_model) == l_true) { - m_sscore[lit.var()] = -m_sscore[lit.var()]; - } - } - for (bool_var i = 0; i < s.num_vars(); ++i) { - m_hscore[i] = compute_hscore(i); - refresh_scores(i); - } - DEBUG_CODE(check_invariant();); - unsigned i = 0; - for (; !s.canceled() && m_best_value > 0 && i < m_max_tries; ++i) { - wflip(); - if (m_false.empty()) { - double val = evaluate_model(m_model); - if (val < m_best_value || m_best_value < 0.0) { - m_best_value = val; - m_best_model.reset(); - m_best_model.append(m_model); - s.set_model(m_best_model); - IF_VERBOSE(1, verbose_stream() << "new value: " << val << " @ " << i << "\n";); - if (i*2 > m_max_tries) { - m_max_tries *= 2; - } - } - } - } - TRACE("sat", display(tout);); - IF_VERBOSE(0, verbose_stream() << "tries " << i << "\n";); - } - - void wsls::wflip() { - literal lit; - if (pick_wflip(lit)) { - // IF_VERBOSE(0, verbose_stream() << lit << " ";); - wflip(lit); - } - } - - bool wsls::pick_wflip(literal & lit) { - unsigned idx; - if (!m_H.empty()) { - idx = m_H.choose(m_rand); - lit = literal(idx, false); - if (value_at(lit, m_model) == l_true) lit.neg(); - SASSERT(value_at(lit, m_model) == l_false); - TRACE("sat", tout << "flip H(" << m_H.num_elems() << ") " << lit << "\n";); - } - else if (!m_S.empty()) { - double score = 0.0; - m_min_vars.reset(); - for (unsigned i = 0; i < m_S.num_elems(); ++i) { - unsigned v = m_S[i]; - SASSERT(m_sscore[v] > 0.0); - if (m_sscore[v] > score) { - m_min_vars.reset(); - m_min_vars.push_back(literal(v, false)); - score = m_sscore[v]; - } - else if (m_sscore[v] == score) { - m_min_vars.push_back(literal(v, false)); - } - } - lit = m_min_vars[m_rand(m_min_vars.size())]; // pick with largest sscore. - SASSERT(value_at(lit, m_model) == l_false); - TRACE("sat", tout << "flip S(" << m_min_vars.size() << "," << score << ") " << lit << "\n";); - } - else { - update_hard_weights(); - if (!m_false.empty()) { - unsigned cls_idx = m_false.choose(m_rand); - clause const& c = *m_clauses[cls_idx]; - lit = c[m_rand(c.size())]; - TRACE("sat", tout << "flip hard(" << m_false.num_elems() << "," << c.size() << ") " << lit << "\n";); - } - else { - m_min_vars.reset(); - for (unsigned i = 0; i < m_soft.size(); ++i) { - lit = m_soft[i]; - if (value_at(lit, m_model) == l_false) { - m_min_vars.push_back(lit); - } - } - if (m_min_vars.empty()) { - SASSERT(m_best_value == 0.0); - UNREACHABLE(); // we should have exited the main loop before. - return false; - } - else { - lit = m_min_vars[m_rand(m_min_vars.size())]; - } - TRACE("sat", tout << "flip soft(" << m_min_vars.size() << ", " << m_sscore[lit.var()] << ") " << lit << "\n";); - - } - SASSERT(value_at(lit, m_model) == l_false); - } - return !m_tabu[lit.var()]; - } - - void wsls::wflip(literal lit) { - flip(lit); - unsigned v = lit.var(); - m_sscore[v] = -m_sscore[v]; - m_hscore[v] = compute_hscore(v); - refresh_scores(v); - recompute_hscores(lit); - } - - void wsls::update_hard_weights() { - unsigned csz = m_clauses.size(); - if (m_smoothing_probability >= m_rand(1000)) { - for (unsigned i = 0; i < csz; ++i) { - if (m_clause_weights[i] > 1 && !m_false.contains(i)) { - --m_clause_weights[i]; - if (m_num_true[i] == 1) { - clause const& c = *m_clauses[i]; - unsigned sz = c.size(); - for (unsigned j = 0; j < sz; ++j) { - if (value_at(c[j], m_model) == l_true) { - ++m_hscore[c[j].var()]; - refresh_scores(c[j].var()); - break; - } - } - } - } - } - } - else { - for (unsigned i = 0; i < csz; ++i) { - if (m_false.contains(i)) { - ++m_clause_weights[i]; - clause const& c = *m_clauses[i]; - unsigned sz = c.size(); - for (unsigned j = 0; j < sz; ++j) { - ++m_hscore[c[j].var()]; - refresh_scores(c[j].var()); - } - } - } - } - DEBUG_CODE(check_invariant();); - } - - double wsls::evaluate_model(model& mdl) { - SASSERT(m_false.empty()); - double result = 0.0; - for (unsigned i = 0; i < m_soft.size(); ++i) { - literal lit = m_soft[i]; - if (value_at(lit, mdl) != l_true) { - result += m_weights[i]; - } - } - return result; - } - - int wsls::compute_hscore(bool_var v) { - literal lit(v, false); - if (value_at(lit, m_model) == l_false) { - lit.neg(); - } - SASSERT(value_at(lit, m_model) == l_true); - int hs = 0; - unsigned_vector const& use1 = get_use(~lit); - unsigned sz = use1.size(); - for (unsigned i = 0; i < sz; ++i) { - unsigned cl = use1[i]; - if (m_num_true[cl] == 0) { - SASSERT(m_false.contains(cl)); - hs += m_clause_weights[cl]; - } - else { - SASSERT(!m_false.contains(cl)); - } - } - unsigned_vector const& use2 = get_use(lit); - sz = use2.size(); - for (unsigned i = 0; i < sz; ++i) { - unsigned cl = use2[i]; - if (m_num_true[cl] == 1) { - SASSERT(!m_false.contains(cl)); - hs -= m_clause_weights[cl]; - } - } - return hs; - } - - void wsls::recompute_hscores(literal lit) { - SASSERT(value_at(lit, m_model) == l_true); - 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) { - unsigned cl = use1[i]; - TRACE("sat", tout << *m_clauses[cl] << " " << m_num_true[cl] << "\n";); - SASSERT(m_num_true[cl] > 0); - if (m_num_true[cl] == 1) { - // num_true 0 -> 1 - // other literals don't have upside any more. - // subtract one from all other literals - adjust_all_values(lit, cl, -static_cast(m_clause_weights[cl])); - } - else if (m_num_true[cl] == 2) { - // num_true 1 -> 2, previous critical literal is no longer critical - adjust_pivot_value(lit, cl, +m_clause_weights[cl]); - } - } - unsigned_vector const& use2 = get_use(~lit); - sz = use2.size(); - for (unsigned i = 0; i < sz; ++i) { - unsigned cl = use2[i]; - TRACE("sat", tout << *m_clauses[cl] << " " << m_num_true[cl] << "\n";); - if (m_num_true[cl] == 0) { - // num_true 1 -> 0 - // all variables became critical. - adjust_all_values(~lit, cl, +m_clause_weights[cl]); - } - else if (m_num_true[cl] == 1) { - adjust_pivot_value(~lit, cl, -static_cast(m_clause_weights[cl])); - } - // else n+1 -> n >= 2 - } - } - - void wsls::adjust_all_values(literal lit, unsigned cl, int delta) { - clause const& c = *m_clauses[cl]; - unsigned sz = c.size(); - TRACE("sat", tout << lit << " " << c << " delta: " << delta << " nt: " << m_num_true[cl] << "\n";); - for (unsigned i = 0; i < sz; ++i) { - literal lit2 = c[i]; - if (lit2 != lit) { - TRACE("sat", tout << lit2.var() << " := " << m_hscore[lit2.var()] << "\n";); - m_hscore[lit2.var()] += delta; - TRACE("sat", tout << lit2.var() << " := " << m_hscore[lit2.var()] << "\n";); - refresh_scores(lit2.var()); - } - } - } - - void wsls::adjust_pivot_value(literal lit, unsigned cl, int delta) { - clause const& c = *m_clauses[cl]; - unsigned csz = c.size(); - for (unsigned j = 0; j < csz; ++j) { - literal lit2 = c[j]; - if (lit2 != lit && value_at(lit2, m_model) == l_true) { - TRACE("sat", tout << lit2.var() << " := " << m_hscore[lit2.var()] << "\n";); - m_hscore[lit2.var()] += delta; - TRACE("sat", tout << lit2.var() << " := " << m_hscore[lit2.var()] << "\n";); - refresh_scores(lit2.var()); - break; - } - } - } - - void wsls::refresh_scores(bool_var v) { - if (m_hscore[v] > 0 && !m_tabu[v] && m_sscore[v] == 0) { - m_H.insert(v); - } - else { - m_H.remove(v); - } - if (m_sscore[v] > 0) { - if (m_hscore[v] == 0 && !m_tabu[v]) { - m_S.insert(v); - } - else { - m_S.remove(v); - } - } - else if (m_sscore[v] < 0) { - m_S.remove(v); - } - } - - void wsls::check_invariant() { - sls::check_invariant(); - // 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)) - 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 { - sls::display(out); - out << "Best model\n"; - for (bool_var v = 0; v < m_best_model.size(); ++v) { - out << v << ": " << m_best_model[v] << " h: " << m_hscore[v]; - if (m_sscore[v] != 0.0) out << " s: " << m_sscore[v]; - out << "\n"; - } - } - -}; - diff --git a/src/sat/sat_sls.h b/src/sat/sat_sls.h deleted file mode 100644 index f1bf55543..000000000 --- a/src/sat/sat_sls.h +++ /dev/null @@ -1,115 +0,0 @@ -/*++ -Copyright (c) 2014 Microsoft Corporation - -Module Name: - - sat_sls.h - -Abstract: - - SLS for clauses in SAT solver - -Author: - - Nikolaj Bjorner (nbjorner) 2014-12-8 - -Notes: - ---*/ -#ifndef SAT_SLS_H_ -#define SAT_SLS_H_ - -#include "util.h" -#include "sat_simplifier.h" - -namespace sat { - - class index_set { - unsigned_vector m_elems; - unsigned_vector m_index; - public: - unsigned num_elems() const { return m_elems.size(); } - unsigned operator[](unsigned idx) const { return m_elems[idx]; } - void reset() { m_elems.reset(); m_index.reset(); } - bool empty() const { return m_elems.empty(); } - bool contains(unsigned idx) const; - void insert(unsigned idx); - void remove(unsigned idx); - unsigned choose(random_gen& rnd) const; - }; - - class sls { - protected: - solver& s; - random_gen m_rand; - unsigned m_max_tries; - unsigned m_prob_choose_min_var; // number between 0 and 99. - unsigned m_clause_generation; - ptr_vector m_clauses; // vector of all clauses. - index_set m_false; // clauses currently false - vector m_use_list; // use lists for literals - unsigned_vector m_num_true; // per clause, count of # true literals - svector m_min_vars; // literals with smallest break count - model m_model; // current model - clause_allocator m_alloc; // clause allocator - clause_vector m_bin_clauses; // binary clauses - svector m_tabu; // variables that cannot be swapped - public: - sls(solver& s); - virtual ~sls(); - lbool operator()(unsigned sz, literal const* tabu, bool reuse_model); - void set_max_tries(unsigned mx) { m_max_tries = mx; } - virtual void display(std::ostream& out) const; - protected: - void init(unsigned sz, literal const* tabu, bool reuse_model); - void init_tabu(unsigned sz, literal const* tabu); - void init_model(); - void init_use(); - void init_clauses(); - unsigned_vector const& get_use(literal lit); - void flip(literal lit); - virtual void check_invariant(); - void check_use_list(); - private: - bool pick_flip(literal& lit); - void flip(); - unsigned get_break_count(literal lit, unsigned min_break); - }; - - /** - \brief sls with weighted soft clauses. - */ - class wsls : public sls { - unsigned_vector m_clause_weights; - svector m_hscore; - svector m_sscore; - literal_vector m_soft; - svector m_weights; - double m_best_value; - model m_best_model; - index_set m_H, m_S; - unsigned m_smoothing_probability; - public: - wsls(solver& s); - virtual ~wsls(); - void set_soft(unsigned sz, literal const* lits, double const* weights); - bool has_soft() const { return !m_soft.empty(); } - void opt(unsigned sz, literal const* tabu, bool reuse_model); - virtual void display(std::ostream& out) const; - double evaluate_model(model& mdl); - private: - void wflip(); - void wflip(literal lit); - void update_hard_weights(); - bool pick_wflip(literal & lit); - virtual void check_invariant(); - void refresh_scores(bool_var v); - int compute_hscore(bool_var v); - void recompute_hscores(literal lit); - void adjust_all_values(literal lit, unsigned cl, int delta); - void adjust_pivot_value(literal lit, unsigned cl, int delta); - }; - -}; - -#endif diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 10c97b296..1ed343efa 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -20,7 +20,6 @@ Revision History: #include"sat_integrity_checker.h" #include"luby.h" #include"trace.h" -#include"sat_bceq.h" #include"max_cliques.h" // define to update glue during propagation @@ -42,7 +41,6 @@ namespace sat { m_asymm_branch(*this, p), m_probing(*this, p), m_mus(*this), - m_wsls(*this), m_inconsistent(false), m_num_frozen(0), m_activity_inc(128), @@ -55,7 +53,6 @@ namespace sat { m_conflicts = 0; m_next_simplify = 0; m_num_checkpoints = 0; - m_initializing_preferred = false; } solver::~solver() { @@ -713,7 +710,7 @@ namespace sat { // Search // // ----------------------- - lbool solver::check(unsigned num_lits, literal const* lits, double const* weights, double max_weight) { + lbool solver::check(unsigned num_lits, literal const* lits) { pop_to_base_level(); IF_VERBOSE(2, verbose_stream() << "(sat.sat-solver)\n";); SASSERT(scope_lvl() == 0); @@ -728,7 +725,7 @@ namespace sat { init_search(); propagate(false); if (inconsistent()) return l_false; - init_assumptions(num_lits, lits, weights, max_weight); + init_assumptions(num_lits, lits); propagate(false); if (check_inconsistent()) return l_false; cleanup(); @@ -914,12 +911,11 @@ namespace sat { } } - void solver::init_assumptions(unsigned num_lits, literal const* lits, double const* weights, double max_weight) { + void solver::init_assumptions(unsigned num_lits, literal const* lits) { if (num_lits == 0 && m_user_scope_literals.empty()) { return; } - retry_init_assumptions: reset_assumptions(); push(); @@ -943,16 +939,6 @@ namespace sat { assign(nlit, justification()); } - if (weights && !inconsistent()) { - if (m_config.m_optimize_model) { - m_wsls.set_soft(num_lits, lits, weights); - } - if (!init_weighted_assumptions(num_lits, lits, weights, max_weight)) { - goto retry_init_assumptions; - } - return; - } - for (unsigned i = 0; !inconsistent() && i < num_lits; ++i) { literal lit = lits[i]; SASSERT(is_external(lit.var())); @@ -962,109 +948,6 @@ namespace sat { } - bool solver::init_weighted_assumptions(unsigned num_lits, literal const* lits, double const* weights, double max_weight) { - flet _min1(m_config.m_core_minimize, false); - m_weight = 0; - m_blocker.reset(); - svector values; - unsigned num_cores = 0; - for (unsigned i = 0; !inconsistent() && i < num_lits; ++i) { - literal lit = lits[i]; - SASSERT(is_external(lit.var())); - TRACE("sat", tout << "propagate: " << lit << " " << value(lit) << "\n";); - SASSERT(m_scope_lvl == 1); - add_assumption(lit); - switch(value(lit)) { - case l_undef: - values.push_back(l_true); - assign(lit, justification()); - if (num_cores*2 >= num_lits) { - break; - } - propagate(false); - if (inconsistent()) { - flet _init(m_initializing_preferred, true); - while (inconsistent()) { - if (!resolve_conflict()) { - return true; - } - propagate(true); - } - if (m_scope_lvl == 0) { - return false; - } - // backjump to last consistent assumption: - unsigned j; - m_weight = 0; - m_blocker.reset(); - for (j = 0; j < i && value(lits[j]) == values[j]; ++j) { - if (values[j] == l_false) { - m_weight += weights[j]; - m_blocker.push_back(lits[j]); - } - } - SASSERT(value(lits[j]) != values[j]); - SASSERT(j <= i); - SASSERT(j == 0 || value(lits[j-1]) == values[j-1]); - for (unsigned k = i; k >= j; --k) { - if (is_assumption(lits[k])) { - pop_assumption(); - } - } - values.resize(j); - TRACE("sat", tout << "backjump " << (i - j + 1) << " steps " << num_cores << "\n";); - i = j - 1; - } - break; - - case l_false: - ++num_cores; - values.push_back(l_false); - SASSERT(!inconsistent()); - set_conflict(justification(), ~lit); - m_conflict_lvl = scope_lvl(); - resolve_conflict_for_unsat_core(); - IF_VERBOSE(3, verbose_stream() << "(sat.core: " << m_core << ")\n";); - update_min_core(); - SASSERT(m_min_core_valid); - m_weight += weights[i]; - if (m_weight <= max_weight) { - m_blocker.push_back(lit); - } - TRACE("sat", tout << "core: " << m_core << "\nassumptions: " << m_assumptions << "\n";); - SASSERT(m_core.size() <= m_assumptions.size()); - SASSERT(m_assumptions.size() <= i+1); - if (m_core.size() <= 3) { - m_inconsistent = true; - TRACE("opt", tout << "found small core: " << m_core << "\n";); - IF_VERBOSE(11, verbose_stream() << "(sat.core: " << m_core << ")\n";); - return true; - } - pop_assumption(); - m_inconsistent = false; - break; - case l_true: - values.push_back(l_true); - SASSERT(m_justification[lit.var()].get_kind() != justification::NONE || lvl(lit) == 0); - break; - } - } - TRACE("sat", tout << "initialized\n";); - IF_VERBOSE(11, verbose_stream() << "(sat.blocker: " << m_blocker << "\nCore: " << m_min_core << ")\n";); - if (m_weight >= max_weight) { - // block the current correction set candidate. - ++m_stats.m_blocked_corr_sets; - TRACE("opt", tout << "blocking soft correction set: " << m_blocker << "\n";); - IF_VERBOSE(11, verbose_stream() << "blocking " << m_blocker << "\n";); - pop_to_base_level(); - mk_clause_core(m_blocker); - return false; - } - return true; - } - - - void solver::update_min_core() { if (!m_min_core_valid || m_core.size() < m_min_core.size()) { m_min_core.reset(); @@ -1148,11 +1031,6 @@ namespace sat { m_min_core_valid = false; m_min_core.reset(); TRACE("sat", display(tout);); - - if (m_config.m_bcd) { - bceq bc(*this); - bc(); - } } /** @@ -1244,9 +1122,6 @@ namespace sat { m_model[v] = value(v); } TRACE("sat_mc_bug", m_mc.display(tout);); - if (m_config.m_optimize_model) { - m_wsls.opt(0, 0, false); - } m_mc(m_model); TRACE("sat", for (bool_var v = 0; v < num; v++) tout << v << ": " << m_model[v] << "\n";); @@ -1673,10 +1548,6 @@ namespace sat { if (m_not_l == literal()) tout << "null literal\n"; else tout << m_not_l << "\n";); - if (m_initializing_preferred) { - SASSERT(m_conflict_lvl <= 1); - return resolve_conflict_for_init(); - } if (m_conflict_lvl <= 1 && tracking_assumptions()) { resolve_conflict_for_unsat_core(); return false; @@ -3184,10 +3055,10 @@ namespace sat { if (asms.empty()) { bool_var v = mk_var(true, false); literal lit(v, false); - init_assumptions(1, &lit, 0, 0); + init_assumptions(1, &lit); } else { - init_assumptions(asms.size(), asms.c_ptr(), 0, 0); + init_assumptions(asms.size(), asms.c_ptr()); } propagate(false); if (check_inconsistent()) return l_false; @@ -3249,10 +3120,10 @@ namespace sat { if (asms.empty()) { bool_var v = mk_var(true, false); literal lit(v, false); - init_assumptions(1, &lit, 0, 0); + init_assumptions(1, &lit); } else { - init_assumptions(asms.size(), asms.c_ptr(), 0, 0); + init_assumptions(asms.size(), asms.c_ptr()); } propagate(false); if (check_inconsistent()) return l_false; diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index 1700dfb7e..d89afd898 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -33,7 +33,6 @@ Revision History: #include"sat_iff3_finder.h" #include"sat_probing.h" #include"sat_mus.h" -#include"sat_sls.h" #include"params.h" #include"statistics.h" #include"stopwatch.h" @@ -86,7 +85,6 @@ namespace sat { asymm_branch m_asymm_branch; probing m_probing; mus m_mus; // MUS for minimal core extraction - wsls m_wsls; // SLS facility for MaxSAT use bool m_inconsistent; // A conflict is usually a single justification. That is, a justification // for false. If m_not_l is not null_literal, then m_conflict is a @@ -141,9 +139,6 @@ namespace sat { friend class probing; friend class iff3_finder; friend class mus; - friend class sls; - friend class wsls; - friend class bceq; friend struct mk_stat; public: solver(params_ref const & p, reslimit& l, extension * ext); @@ -280,10 +275,7 @@ namespace sat { // // ----------------------- public: - lbool check(unsigned num_lits = 0, literal const* lits = 0) { - return check(num_lits, lits, 0, 0); - } - lbool check(unsigned num_lits, literal const* lits, double const* weights, double max_weight); + lbool check(unsigned num_lits = 0, literal const* lits = 0); model const & get_model() const { return m_model; } bool model_is_current() const { return m_model_is_current; } @@ -311,11 +303,7 @@ namespace sat { literal_vector m_min_core; bool m_min_core_valid; - literal_vector m_blocker; - double m_weight; - bool m_initializing_preferred; - void init_assumptions(unsigned num_lits, literal const* lits, double const* weights, double max_weight); - bool init_weighted_assumptions(unsigned num_lits, literal const* lits, double const* weights, double max_weight); + void init_assumptions(unsigned num_lits, literal const* lits); void reassert_min_core(); void update_min_core(); void resolve_weighted(); diff --git a/src/sat/sat_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp index b7ce92108..33d10f428 100644 --- a/src/sat/sat_solver/inc_sat_solver.cpp +++ b/src/sat/sat_solver/inc_sat_solver.cpp @@ -105,13 +105,8 @@ public: virtual void set_progress_callback(progress_callback * callback) {} - virtual lbool check_sat(unsigned num_assumptions, expr * const * assumptions) { - return check_sat(num_assumptions, assumptions, 0, 0); - } - void display_weighted(std::ostream& out, unsigned sz, expr * const * assumptions, unsigned const* weights) { - m_weights.reset(); if (weights != 0) { for (unsigned i = 0; i < sz; ++i) m_weights.push_back(weights[i]); } @@ -131,15 +126,11 @@ public: for (unsigned i = 0; i < m_asms.size(); ++i) { nweights.push_back((unsigned) m_weights[i]); } + m_weights.reset(); m_solver.display_wcnf(out, m_asms.size(), m_asms.c_ptr(), nweights.c_ptr()); } - lbool check_sat(unsigned sz, expr * const * assumptions, double const* weights, double max_weight) { - m_weights.reset(); - if (weights != 0) { - m_weights.append(sz, weights); - } - SASSERT(m_weights.empty() == (m_weights.c_ptr() == 0)); + virtual lbool check_sat(unsigned sz, expr * const * assumptions) { m_solver.pop_to_base_level(); dep2asm_t dep2asm; m_model = 0; @@ -148,10 +139,10 @@ public: r = internalize_assumptions(sz, assumptions, dep2asm); if (r != l_true) return r; - r = m_solver.check(m_asms.size(), m_asms.c_ptr(), m_weights.c_ptr(), max_weight); + r = m_solver.check(m_asms.size(), m_asms.c_ptr()); switch (r) { case l_true: - if (sz > 0 && !weights) { + if (sz > 0) { check_assumptions(dep2asm); } break; @@ -675,18 +666,6 @@ solver* mk_inc_sat_solver(ast_manager& m, params_ref const& p) { } -lbool inc_sat_check_sat(solver& _s, unsigned sz, expr*const* soft, rational const* _weights, rational const& max_weight) { - inc_sat_solver& s = dynamic_cast(_s); - vector weights; - for (unsigned i = 0; _weights && i < sz; ++i) { - weights.push_back(_weights[i].get_double()); - } - params_ref p; - p.set_bool("minimize_core", false); - s.updt_params(p); - return s.check_sat(sz, soft, weights.c_ptr(), max_weight.get_double()); -} - void inc_sat_display(std::ostream& out, solver& _s, unsigned sz, expr*const* soft, rational const* _weights) { inc_sat_solver& s = dynamic_cast(_s); vector weights; diff --git a/src/sat/sat_solver/inc_sat_solver.h b/src/sat/sat_solver/inc_sat_solver.h index 028f71b06..4b0bea50e 100644 --- a/src/sat/sat_solver/inc_sat_solver.h +++ b/src/sat/sat_solver/inc_sat_solver.h @@ -24,7 +24,6 @@ Notes: solver* mk_inc_sat_solver(ast_manager& m, params_ref const& p); -lbool inc_sat_check_sat(solver& s, unsigned sz, expr*const* soft, rational const* weights, rational const& max_weight); void inc_sat_display(std::ostream& out, solver& s, unsigned sz, expr*const* soft, rational const* _weights); From d8e4966a11887bc22d7b84e8da251500860bd174 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Sat, 14 Jan 2017 14:18:37 +0000 Subject: [PATCH 473/536] Added win64 build badge --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 204fb371e..e0821ac79 100644 --- a/README.md +++ b/README.md @@ -12,9 +12,9 @@ See the [release notes](RELEASE_NOTES) for notes on various stable releases of Z ## Build status -| Windows | Ubuntu x64 | Ubuntu x86 | Debian x64 | OSX | -| ------- | ---------- | ---------- | ---------- | --- | -![windows-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/4/badge) | ![ubuntu-x64-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/3/badge) | ![ubuntu-x86-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/6/badge) | ![debian-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/5/badge) | ![osx-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/2/badge) +| Windows x86 | Windows x64 | Ubuntu x64 | Ubuntu x86 | Debian x64 | OSX | +| ----------- | ----------- | ---------- | ---------- | ---------- | --- | +![win32-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/4/badge) | ![win64-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/7/badge) | ![ubuntu-x64-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/3/badge) | ![ubuntu-x86-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/6/badge) | ![debian-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/5/badge) | ![osx-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/2/badge) [1]: #building-z3-on-windows-using-visual-studio-command-prompt [2]: #building-z3-using-make-and-gccclang From b30f3a6dbd570988f9cce3d949036ed0562782a3 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Sat, 14 Jan 2017 14:56:25 +0000 Subject: [PATCH 474/536] Separated win32/64 builds --- scripts/mk_win_dist.py | 88 +++++++++++++++++++++++++++++------------- 1 file changed, 61 insertions(+), 27 deletions(-) diff --git a/scripts/mk_win_dist.py b/scripts/mk_win_dist.py index 92d89480f..9d3abaf2c 100644 --- a/scripts/mk_win_dist.py +++ b/scripts/mk_win_dist.py @@ -29,6 +29,9 @@ DOTNET_KEY_FILE=None JAVA_ENABLED=True GIT_HASH=False PYTHON_ENABLED=True +X86ONLY=False +X64ONLY=False +MAKEJOBS=getenv("MAKEJOBS", 24) def set_verbose(flag): global VERBOSE @@ -63,11 +66,13 @@ def display_help(): print(" --nojava do not include Java bindings in the binary distribution files.") print(" --nopython do not include Python bindings in the binary distribution files.") print(" --githash include git hash in the Zip file.") + print(" --x86-only x86 dist only.") + print(" --x64-only x64 dist only.") exit(0) # Parse configuration option for mk_make script def parse_options(): - global FORCE_MK, JAVA_ENABLED, GIT_HASH, DOTNET_ENABLED, DOTNET_KEY_FILE, PYTHON_ENABLED + global FORCE_MK, JAVA_ENABLED, GIT_HASH, DOTNET_ENABLED, DOTNET_KEY_FILE, PYTHON_ENABLED, X86ONLY, X64ONLY path = BUILD_DIR options, remainder = getopt.gnu_getopt(sys.argv[1:], 'b:hsf', ['build=', 'help', @@ -77,7 +82,9 @@ def parse_options(): 'nodotnet', 'dotnet-key=', 'githash', - 'nopython' + 'nopython', + 'x86-only', + 'x64-only' ]) for opt, arg in options: if opt in ('-b', '--build'): @@ -100,6 +107,10 @@ def parse_options(): JAVA_ENABLED = False elif opt == '--githash': GIT_HASH = True + elif opt == '--x86-only' and not X64ONLY: + X86ONLY = True + elif opt == '--x64-only' and not X86ONLY: + X64ONLY = True else: raise MKException("Invalid command line option '%s'" % opt) set_build_dir(path) @@ -111,7 +122,8 @@ def check_build_dir(path): # Create a build directory using mk_make.py def mk_build_dir(path, x64): if not check_build_dir(path) or FORCE_MK: - opts = ["python", os.path.join('scripts', 'mk_make.py'), "--parallel=24", "-b", path] + parallel = '--parallel=' + MAKEJOBS + opts = ["python", os.path.join('scripts', 'mk_make.py'), parallel, "-b", path] if DOTNET_ENABLED: opts.append('--dotnet') if not DOTNET_KEY_FILE is None: @@ -160,7 +172,7 @@ def exec_cmds(cmds): return res # Compile Z3 (if x64 == True, then it builds it in x64 mode). -def mk_z3_core(x64): +def mk_z3(x64): cmds = [] if x64: cmds.append('call "%VCINSTALLDIR%vcvarsall.bat" amd64') @@ -172,9 +184,9 @@ def mk_z3_core(x64): if exec_cmds(cmds) != 0: raise MKException("Failed to make z3, x64: %s" % x64) -def mk_z3(): - mk_z3_core(False) - mk_z3_core(True) +def mk_z3s(): + mk_z3(False) + mk_z3(True) def get_z3_name(x64): major, minor, build, revision = get_version() @@ -187,7 +199,7 @@ def get_z3_name(x64): else: return 'z3-%s.%s.%s-%s-win' % (major, minor, build, platform) -def mk_dist_dir_core(x64): +def mk_dist_dir(x64): if x64: platform = "x64" build_path = BUILD_X64_DIR @@ -204,14 +216,14 @@ def mk_dist_dir_core(x64): if is_verbose(): print("Generated %s distribution folder at '%s'" % (platform, dist_path)) -def mk_dist_dir(): - mk_dist_dir_core(False) - mk_dist_dir_core(True) +def mk_dist_dirs(): + mk_dist_dir(False) + mk_dist_dir(True) def get_dist_path(x64): return get_z3_name(x64) -def mk_zip_core(x64): +def mk_zip(x64): dist_path = get_dist_path(x64) old = os.getcwd() try: @@ -228,7 +240,7 @@ def mk_zip_core(x64): os.chdir(old) # Create a zip file for each platform -def mk_zip(): +def mk_zips(): mk_zip_core(False) mk_zip_core(True) @@ -238,7 +250,7 @@ VS_RUNTIME_PATS = [re.compile('vcomp.*\.dll'), re.compile('msvcr.*\.dll')] # Copy Visual Studio Runtime libraries -def cp_vs_runtime_core(x64): +def cp_vs_runtime(x64): if x64: platform = "x64" @@ -262,27 +274,49 @@ def cp_vs_runtime_core(x64): if is_verbose(): print("Copied '%s' to '%s'" % (f, bin_dist_path)) -def cp_vs_runtime(): - cp_vs_runtime_core(True) - cp_vs_runtime_core(False) +def cp_vs_runtimes(): + cp_vs_runtime(True) + cp_vs_runtime(False) -def cp_license(): - shutil.copy("LICENSE.txt", os.path.join(DIST_DIR, get_dist_path(True))) - shutil.copy("LICENSE.txt", os.path.join(DIST_DIR, get_dist_path(False))) +def cp_license(x64): + shutil.copy("LICENSE.txt", os.path.join(DIST_DIR, get_dist_path(x64))) + +def cp_licenses(): + cp_license(True) + cp_license(False) # Entry point def main(): if os.name != 'nt': raise MKException("This script is for Windows only") + parse_options() check_vc_cmd_prompt() - mk_build_dirs() - mk_z3() - init_project_def() - mk_dist_dir() - cp_license() - cp_vs_runtime() - mk_zip() + + if X86ONLY: + mk_build_dir(BUILD_X86_DIR, False) + mk_z3(False) + init_project_def() + mk_dist_dir(False) + cp_license(False) + cp_vs_runtime(False) + mk_zip(False) + elif X64ONLY: + mk_build_dir(BUILD_X64_DIR, True) + mk_z3(True) + init_project_def() + mk_dist_dir(True) + cp_license(True) + cp_vs_runtime(True) + mk_zip(True) + else: + mk_build_dirs() + mk_z3s() + init_project_def() + mk_dist_dirs() + cp_licenses() + cp_vs_runtime() + mk_zip() main() From 340ba7780e012b45b4c5ce3be6077495f3591db5 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Sat, 14 Jan 2017 18:57:10 +0000 Subject: [PATCH 475/536] Added MAKEJOBS env var to mk_unix_dist.py --- scripts/mk_unix_dist.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scripts/mk_unix_dist.py b/scripts/mk_unix_dist.py index 527797e66..488bc4364 100644 --- a/scripts/mk_unix_dist.py +++ b/scripts/mk_unix_dist.py @@ -27,6 +27,7 @@ DOTNET_KEY_FILE=None JAVA_ENABLED=True GIT_HASH=False PYTHON_ENABLED=True +MAKEJOBS=getenv("MAKEJOBS", '8') def set_verbose(flag): global VERBOSE @@ -139,7 +140,7 @@ class cd: def mk_z3(): with cd(BUILD_DIR): try: - return subprocess.call(['make', '-j', '8']) + return subprocess.call(['make', '-j', MAKEJOBS]) except: return 1 From 7df803c131a1acaa1f3138aa2af8006c712f48ad Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 15 Jan 2017 11:52:48 -0800 Subject: [PATCH 476/536] Fix unsound handling of upper bounds in wmax, thanks to Patrick Trentin for report and careful repros #847 Signed-off-by: Nikolaj Bjorner --- src/opt/maxres.cpp | 38 +++++++++++++++++++------------------- src/opt/wmax.cpp | 8 +++++--- src/sat/sat_solver.cpp | 37 +++++++++++++++++-------------------- src/sat/sat_solver.h | 6 ++---- src/smt/theory_wmaxsat.cpp | 2 +- 5 files changed, 44 insertions(+), 47 deletions(-) diff --git a/src/opt/maxres.cpp b/src/opt/maxres.cpp index 83f0849b2..7abbd48ee 100644 --- a/src/opt/maxres.cpp +++ b/src/opt/maxres.cpp @@ -93,7 +93,7 @@ private: mss m_mss; expr_ref_vector m_trail; strategy_t m_st; - rational m_max_upper; + rational m_max_upper; model_ref m_csmodel; unsigned m_correction_set_size; bool m_found_feasible_optimum; @@ -109,6 +109,7 @@ private: bool m_pivot_on_cs; // prefer smaller correction set to core. bool m_dump_benchmarks; // display benchmarks (into wcnf format) + std::string m_trace_id; typedef ptr_vector exprs; @@ -150,9 +151,7 @@ public: return is_uninterp_const(l) || (m.is_not(l, l) && is_uninterp_const(l)); - } - - + } void add_soft(expr* e, rational const& w) { TRACE("opt", tout << mk_pp(e, m) << " |-> " << w << "\n";); @@ -290,7 +289,7 @@ public: index = next_index(asms, index); } first = false; - IF_VERBOSE(3, verbose_stream() << "weight: " << get_weight(asms[0].get()) << " " << get_weight(asms[index-1].get()) << " num soft: " << index << "\n";); + // IF_VERBOSE(3, verbose_stream() << "weight: " << get_weight(asms[0].get()) << " " << get_weight(asms[index-1].get()) << " num soft: " << index << "\n";); m_last_index = index; is_sat = check_sat(index, asms.c_ptr()); } @@ -490,7 +489,7 @@ public: TRACE("opt", display_vec(tout << "minimized core: ", core);); IF_VERBOSE(10, display_vec(verbose_stream() << "core: ", core);); max_resolve(core, w); - fml = mk_not(m, mk_and(m, m_B.size(), m_B.c_ptr())); + fml = mk_not(m, mk_and(m, core.size(), core.c_ptr())); s().assert_expr(fml); m_lower += w; if (m_st == s_primal_dual) { @@ -530,7 +529,10 @@ public: } lbool minimize_core(exprs& core) { - if (m_c.sat_enabled() || core.empty()) { + if (core.empty()) { + return l_true; + } + if (m_c.sat_enabled()) { return l_true; } m_mus.reset(); @@ -607,8 +609,8 @@ public: // Soundness of this rule can be established using MaxRes // for (unsigned i = 1; i < core.size(); ++i) { - expr* b_i = m_B[i-1].get(); - expr* b_i1 = m_B[i].get(); + expr* b_i = core[i-1]; + expr* b_i1 = core[i]; if (i == 1) { d = to_app(b_i); } @@ -658,8 +660,8 @@ public: // d_i => d_{i-1} or b_{i-1} // for (unsigned i = 1; i < cs.size(); ++i) { - expr* b_i = m_B[i-1].get(); - expr* b_i1 = m_B[i].get(); + expr* b_i = cs[i - 1]; + expr* b_i1 = cs[i]; cls = m.mk_or(b_i, d); if (i > 2) { d = mk_fresh_bool("d"); @@ -680,10 +682,11 @@ public: s().assert_expr(fml); m_defs.push_back(fml); new_assumption(asum, w); + fml = m.mk_and(b_i1, cls); update_model(asum, fml); } - fml = m.mk_or(m_B.size(), m_B.c_ptr()); + fml = m.mk_or(cs.size(), cs.c_ptr()); s().assert_expr(fml); } @@ -739,7 +742,7 @@ public: nsoft.push_back(mk_not(m, m_soft[i])); } fml = u.mk_lt(nsoft.size(), m_weights.c_ptr(), nsoft.c_ptr(), m_upper); - s().assert_expr(fml); + s().assert_expr(fml); } bool is_true(model* mdl, expr* e) { @@ -757,10 +760,9 @@ public: } bool is_true(expr_ref_vector const& es) { - for (unsigned i = 0; i < es.size(); ++i) { - if (!is_true(es[i])) return false; - } - return true; + unsigned i = 0; + for (; i < es.size() && is_true(es[i]); ++i) { } + return i == es.size(); } void remove_soft(exprs const& core, expr_ref_vector& asms) { @@ -780,7 +782,6 @@ public: virtual void updt_params(params_ref& p) { maxsmt_solver_base::updt_params(p); opt_params _p(p); - m_hill_climb = _p.maxres_hill_climb(); m_add_upper_bound_block = _p.maxres_add_upper_bound_block(); m_max_num_cores = _p.maxres_max_num_cores(); @@ -858,7 +859,6 @@ public: IF_VERBOSE(0, verbose_stream() << "assignment is infeasible\n";); } } - }; opt::maxsmt_solver_base* opt::mk_maxres( diff --git a/src/opt/wmax.cpp b/src/opt/wmax.cpp index 228e14cd6..690e2000b 100644 --- a/src/opt/wmax.cpp +++ b/src/opt/wmax.cpp @@ -62,20 +62,21 @@ namespace opt { } m_upper = m_lower; bool was_sat = false; - expr_ref_vector disj(m), asms(m); + expr_ref_vector asms(m); vector cores; obj_map::iterator it = soft.begin(), end = soft.end(); for (; it != end; ++it) { expr* c = assert_weighted(wth(), it->m_key, it->m_value); if (!is_true(it->m_key)) { - disj.push_back(m.mk_not(c)); m_upper += it->m_value; } } wth().init_min_cost(m_upper - m_lower); - s().assert_expr(mk_or(disj)); trace_bounds("wmax"); + TRACE("opt", + s().display(tout); tout << "\n"; + tout << "lower: " << m_lower << " upper: " << m_upper << "\n";); while (!m.canceled() && m_lower < m_upper) { //mk_assumptions(asms); //is_sat = s().preferred_sat(asms, cores); @@ -84,6 +85,7 @@ namespace opt { is_sat = l_undef; } if (is_sat == l_false) { + TRACE("opt", tout << "Unsat\n";); break; } if (is_sat == l_true) { diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 1ed343efa..eec94879a 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -211,7 +211,7 @@ namespace sat { if (propagate_bin_clause(l1, l2)) { if (scope_lvl() == 0) return; - if (!learned) + if (!learned) m_clauses_to_reinit.push_back(clause_wrapper(l1, l2)); } m_stats.m_mk_bin_clause++; @@ -234,19 +234,18 @@ namespace sat { } void solver::push_reinit_stack(clause & c) { + TRACE("sat_reinit", tout << "adding to reinit stack: " << c << "\n";); m_clauses_to_reinit.push_back(clause_wrapper(c)); - c.set_reinit_stack(true); + c.set_reinit_stack(true); } + clause * solver::mk_ter_clause(literal * lits, bool learned) { m_stats.m_mk_ter_clause++; clause * r = m_cls_allocator.mk_clause(3, lits, learned); - bool reinit; - attach_ter_clause(*r, reinit); - if (!learned && reinit) { - TRACE("sat_reinit", tout << "adding to reinit stack: " << *r << "\n";); - push_reinit_stack(*r); - } + bool reinit = attach_ter_clause(*r); + if (reinit && !learned) push_reinit_stack(*r); + if (learned) m_learned.push_back(r); else @@ -254,8 +253,8 @@ namespace sat { return r; } - void solver::attach_ter_clause(clause & c, bool & reinit) { - reinit = false; + bool solver::attach_ter_clause(clause & c) { + bool reinit = false; m_watches[(~c[0]).index()].push_back(watched(c[1], c[2])); m_watches[(~c[1]).index()].push_back(watched(c[0], c[2])); m_watches[(~c[2]).index()].push_back(watched(c[0], c[1])); @@ -276,18 +275,15 @@ namespace sat { reinit = true; } } + return reinit; } clause * solver::mk_nary_clause(unsigned num_lits, literal * lits, bool learned) { m_stats.m_mk_clause++; clause * r = m_cls_allocator.mk_clause(num_lits, lits, learned); SASSERT(!learned || r->is_learned()); - bool reinit; - attach_nary_clause(*r, reinit); - if (!learned && reinit) { - TRACE("sat_reinit", tout << "adding to reinit stack: " << *r << "\n";); - push_reinit_stack(*r); - } + bool reinit = attach_nary_clause(*r); + if (reinit && !learned) push_reinit_stack(*r); if (learned) m_learned.push_back(r); else @@ -295,8 +291,8 @@ namespace sat { return r; } - void solver::attach_nary_clause(clause & c, bool & reinit) { - reinit = false; + bool solver::attach_nary_clause(clause & c) { + bool reinit = false; clause_offset cls_off = m_cls_allocator.get_offset(&c); if (scope_lvl() > 0) { if (c.is_learned()) { @@ -325,15 +321,16 @@ namespace sat { literal block_lit = c[some_idx]; m_watches[(~c[0]).index()].push_back(watched(block_lit, cls_off)); m_watches[(~c[1]).index()].push_back(watched(block_lit, cls_off)); + return reinit; } void solver::attach_clause(clause & c, bool & reinit) { SASSERT(c.size() > 2); reinit = false; if (c.size() == 3) - attach_ter_clause(c, reinit); + reinit = attach_ter_clause(c); else - attach_nary_clause(c, reinit); + reinit = attach_nary_clause(c); } /** diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index d89afd898..f28d0aa5b 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -184,11 +184,9 @@ namespace sat { void mk_bin_clause(literal l1, literal l2, bool learned); bool propagate_bin_clause(literal l1, literal l2); clause * mk_ter_clause(literal * lits, bool learned); - void attach_ter_clause(clause & c, bool & reinit); - void attach_ter_clause(clause & c) { bool reinit; attach_ter_clause(c, reinit); } + bool attach_ter_clause(clause & c); clause * mk_nary_clause(unsigned num_lits, literal * lits, bool learned); - void attach_nary_clause(clause & c, bool & reinit); - void attach_nary_clause(clause & c) { bool reinit; attach_nary_clause(c, reinit); } + bool attach_nary_clause(clause & c); void attach_clause(clause & c, bool & reinit); void attach_clause(clause & c) { bool reinit; attach_clause(c, reinit); } unsigned select_watch_lit(clause const & cls, unsigned starting_at) const; diff --git a/src/smt/theory_wmaxsat.cpp b/src/smt/theory_wmaxsat.cpp index e396b67cc..3f153f500 100644 --- a/src/smt/theory_wmaxsat.cpp +++ b/src/smt/theory_wmaxsat.cpp @@ -180,7 +180,7 @@ namespace smt { final_check_status theory_wmaxsat::final_check_eh() { if (m_normalize) normalize(); - // std::cout << "cost: " << m_zcost << " min cost: " << m_zmin_cost << "\n"; + TRACE("opt", tout << "cost: " << m_zcost << " min cost: " << m_zmin_cost << "\n";); return FC_DONE; } From dd0d3d4510694132051801f05a5e3627406ba3ef Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 15 Jan 2017 11:59:09 -0800 Subject: [PATCH 477/536] use stirngs for env variables Signed-off-by: Nikolaj Bjorner --- scripts/mk_win_dist.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/mk_win_dist.py b/scripts/mk_win_dist.py index 9d3abaf2c..aed64d40e 100644 --- a/scripts/mk_win_dist.py +++ b/scripts/mk_win_dist.py @@ -31,7 +31,7 @@ GIT_HASH=False PYTHON_ENABLED=True X86ONLY=False X64ONLY=False -MAKEJOBS=getenv("MAKEJOBS", 24) +MAKEJOBS=getenv("MAKEJOBS", "24") def set_verbose(flag): global VERBOSE From 24eae3f6e0ad81c843d2de242b85002a8fe9314c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 15 Jan 2017 12:06:56 -0800 Subject: [PATCH 478/536] fix crash with unary xor #870 Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/bool_rewriter.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/ast/rewriter/bool_rewriter.cpp b/src/ast/rewriter/bool_rewriter.cpp index 05f47ada7..f6597fbc5 100644 --- a/src/ast/rewriter/bool_rewriter.cpp +++ b/src/ast/rewriter/bool_rewriter.cpp @@ -59,9 +59,12 @@ br_status bool_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * co mk_implies(args[0], args[1], result); return BR_DONE; case OP_XOR: - SASSERT(num_args == 2); - mk_xor(args[0], args[1], result); - return BR_DONE; + switch (num_args) { + case 0: return BR_FAILED; + case 1: result = args[0]; return BR_DONE; + case 2: mk_xor(args[0], args[1], result); return BR_DONE; + default: UNREACHABLE(); return BR_FAILED; + } default: return BR_FAILED; } From c4c9de08383bbe55d0f1d43e6f6c511fb43adc8d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 15 Jan 2017 20:09:27 -0800 Subject: [PATCH 479/536] fix memory leaks from cancellations Signed-off-by: Nikolaj Bjorner --- src/muz/pdr/pdr_context.cpp | 47 ++++++++++++++++++++++---------- src/muz/pdr/pdr_context.h | 6 ++-- src/muz/pdr/pdr_dl_interface.cpp | 6 +--- src/smt/asserted_formulas.cpp | 4 +-- 4 files changed, 39 insertions(+), 24 deletions(-) diff --git a/src/muz/pdr/pdr_context.cpp b/src/muz/pdr/pdr_context.cpp index 32f8e1ef1..587488fc9 100644 --- a/src/muz/pdr/pdr_context.cpp +++ b/src/muz/pdr/pdr_context.cpp @@ -575,7 +575,7 @@ namespace pdr { // Predicates that are variable representatives. Other predicates at // positions the variables occur are made equivalent with these. expr_ref_vector conj(m); - app_ref_vector& var_reprs = *(alloc(app_ref_vector, m)); + app_ref_vector var_reprs(m); ptr_vector aux_vars; unsigned ut_size = rule.get_uninterpreted_tail_size(); @@ -584,8 +584,9 @@ namespace pdr { init_atom(pts, rule.get_head(), var_reprs, conj, UINT_MAX); for (unsigned i = 0; i < ut_size; ++i) { if (rule.is_neg_tail(i)) { - dealloc(&var_reprs); - throw default_exception("PDR does not support negated predicates in rule tails"); + char const* msg = "PDR does not supported negated predicates in rule tails"; + IF_VERBOSE(0, verbose_stream() << msg << "\n";); + throw default_exception(msg); } init_atom(pts, rule.get_tail(i), var_reprs, conj, i); } @@ -600,14 +601,14 @@ namespace pdr { flatten_and(tail); for (unsigned i = 0; i < tail.size(); ++i) { expr_ref tmp(m); - var_subst(m, false)(tail[i].get(), var_reprs.size(), (expr*const*)var_reprs.c_ptr(), tmp); + var_subst vs(m, false); + vs(tail[i].get(), var_reprs.size(), (expr*const*)var_reprs.c_ptr(), tmp); conj.push_back(tmp); TRACE("pdr", tout << mk_pp(tail[i].get(), m) << "\n" << mk_pp(tmp, m) << "\n";); if (!is_ground(tmp)) { std::stringstream msg; msg << "PDR cannot solve non-ground tails: " << tmp; IF_VERBOSE(0, verbose_stream() << msg.str() << "\n";); - dealloc(&var_reprs); throw default_exception(msg.str()); } } @@ -631,7 +632,7 @@ namespace pdr { m_rule2transition.insert(&rule, fml.get()); rules.push_back(&rule); } - m_rule2inst.insert(&rule, &var_reprs); + m_rule2inst.insert(&rule, alloc(app_ref_vector, var_reprs)); m_rule2vars.insert(&rule, aux_vars); TRACE("pdr", tout << rule.get_decl()->get_name() << "\n"; @@ -1468,13 +1469,20 @@ namespace pdr { reset(); } - void context::reset() { - TRACE("pdr", tout << "\n";); - decl2rel::iterator it = m_rels.begin(), end = m_rels.end(); + void context::reset(decl2rel& rels) { + decl2rel::iterator it = rels.begin(), end = rels.end(); for (; it != end; ++it) { dealloc(it->m_value); } - m_rels.reset(); + rels.reset(); + } + + void context::reset(bool full) { + TRACE("pdr", tout << "reset\n";); + reset(m_rels); + if (full) { + reset(m_rels_tmp); + } m_search.reset(); m_query = 0; m_last_result = l_undef; @@ -1496,6 +1504,7 @@ namespace pdr { e->get_data().m_value->add_rule(pred_rules[i]); } } + TRACE("pdr", tout << "adding rules\n";); datalog::rule_set::iterator rit = rules.begin(), rend = rules.end(); for (; rit != rend; ++rit) { datalog::rule* r = *rit; @@ -1510,6 +1519,7 @@ namespace pdr { } } // Initialize use list dependencies + TRACE("pdr", tout << "initialize use list dependencies\n";); decl2rel::iterator it = rels.begin(), end = rels.end(); for (; it != end; ++it) { func_decl* pred = it->m_key; @@ -1523,9 +1533,11 @@ namespace pdr { } } + TRACE("pdr", tout << "initialize predicate transformers\n";); // Initialize the predicate transformers. it = rels.begin(), end = rels.end(); for (; it != end; ++it) { + SASSERT(it->m_value); pred_transformer& rel = *it->m_value; rel.initialize(rels); TRACE("pdr", rel.display(tout); ); @@ -1533,21 +1545,24 @@ namespace pdr { } void context::update_rules(datalog::rule_set& rules) { - decl2rel rels; + TRACE("pdr", tout << "update rules\n";); + reset(m_rels_tmp); init_core_generalizers(rules); - init_rules(rules, rels); - decl2rel::iterator it = rels.begin(), end = rels.end(); + init_rules(rules, m_rels_tmp); + decl2rel::iterator it = m_rels_tmp.begin(), end = m_rels_tmp.end(); for (; it != end; ++it) { pred_transformer* pt = 0; if (m_rels.find(it->m_key, pt)) { it->m_value->inherit_properties(*pt); } } - reset(); - it = rels.begin(), end = rels.end(); + reset(false); + it = m_rels_tmp.begin(), end = m_rels_tmp.end(); for (; it != end; ++it) { m_rels.insert(it->m_key, it->m_value); } + m_rels_tmp.reset(); + TRACE("pdr", tout << "done update rules\n";); } unsigned context::get_num_levels(func_decl* p) { @@ -1875,6 +1890,7 @@ namespace pdr { } lbool context::solve() { + TRACE("pdr", tout << "solve\n";); m_last_result = l_undef; try { solve_impl(); @@ -2090,6 +2106,7 @@ namespace pdr { } case l_undef: { TRACE("pdr", tout << "unknown state: " << mk_pp(m_pm.mk_and(cube), m) << "\n";); + IF_VERBOSE(1, verbose_stream() << "unknown state\n";); throw unknown_exception(); } } diff --git a/src/muz/pdr/pdr_context.h b/src/muz/pdr/pdr_context.h index c3567bdd8..a32a65c48 100644 --- a/src/muz/pdr/pdr_context.h +++ b/src/muz/pdr/pdr_context.h @@ -328,6 +328,7 @@ namespace pdr { datalog::context* m_context; manager m_pm; decl2rel m_rels; // Map from relation predicate to fp-operator. + decl2rel m_rels_tmp; func_decl_ref m_query_pred; pred_transformer* m_query; mutable model_search m_search; @@ -370,6 +371,8 @@ namespace pdr { void reset_core_generalizers(); + void reset(decl2rel& rels); + void validate(); void validate_proof(); void validate_search(); @@ -410,8 +413,7 @@ namespace pdr { lbool solve(); - - void reset(); + void reset(bool full = true); void set_query(func_decl* q) { m_query_pred = q; } diff --git a/src/muz/pdr/pdr_dl_interface.cpp b/src/muz/pdr/pdr_dl_interface.cpp index 761b730ce..5f4a200fc 100644 --- a/src/muz/pdr/pdr_dl_interface.cpp +++ b/src/muz/pdr/pdr_dl_interface.cpp @@ -19,12 +19,8 @@ Revision History: #include "dl_context.h" #include "dl_mk_coi_filter.h" -#include "dl_mk_interp_tail_simplifier.h" -#include "dl_mk_subsumption_checker.h" -#include "dl_mk_rule_inliner.h" #include "dl_rule.h" #include "dl_rule_transformer.h" -#include "smt2parser.h" #include "pdr_context.h" #include "pdr_dl_interface.h" #include "dl_rule_set.h" @@ -164,7 +160,7 @@ lbool dl_interface::query(expr * query) { m_context->set_proof_converter(m_ctx.get_proof_converter()); m_context->set_model_converter(m_ctx.get_model_converter()); m_context->set_query(query_pred); - m_context->set_axioms(bg_assertion); + m_context->set_axioms(bg_assertion); m_context->update_rules(m_pdr_rules); if (m_pdr_rules.get_rules().empty()) { diff --git a/src/smt/asserted_formulas.cpp b/src/smt/asserted_formulas.cpp index 3c67cadcf..26395f9ab 100644 --- a/src/smt/asserted_formulas.cpp +++ b/src/smt/asserted_formulas.cpp @@ -184,13 +184,13 @@ void asserted_formulas::get_assertions(ptr_vector & result) { } void asserted_formulas::push_scope() { - SASSERT(inconsistent() || m_asserted_qhead == m_asserted_formulas.size()); + SASSERT(inconsistent() || m_asserted_qhead == m_asserted_formulas.size() || m_manager.canceled()); TRACE("asserted_formulas_scopes", tout << "push:\n"; display(tout);); m_scopes.push_back(scope()); m_macro_manager.push_scope(); scope & s = m_scopes.back(); s.m_asserted_formulas_lim = m_asserted_formulas.size(); - SASSERT(inconsistent() || s.m_asserted_formulas_lim == m_asserted_qhead); + SASSERT(inconsistent() || s.m_asserted_formulas_lim == m_asserted_qhead || m_manager.canceled()); s.m_inconsistent_old = m_inconsistent; m_defined_names.push(); m_bv_sharing.push_scope(); From dc543a7ee727b112d0dec16cff05b446396cec13 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 15 Jan 2017 21:13:22 -0800 Subject: [PATCH 480/536] update macro_util logging to uniform format Signed-off-by: Nikolaj Bjorner --- src/api/api_datalog.cpp | 2 +- src/ast/macros/macro_util.cpp | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/api/api_datalog.cpp b/src/api/api_datalog.cpp index cc512c08e..8843256c6 100644 --- a/src/api/api_datalog.cpp +++ b/src/api/api_datalog.cpp @@ -290,8 +290,8 @@ extern "C" { r = to_fixedpoint_ref(d)->ctx().query(to_expr(q)); } catch (z3_exception& ex) { - mk_c(c)->handle_exception(ex); r = l_undef; + mk_c(c)->handle_exception(ex); } to_fixedpoint_ref(d)->ctx().cleanup(); } diff --git a/src/ast/macros/macro_util.cpp b/src/ast/macros/macro_util.cpp index 027cce09d..97b44d4cd 100644 --- a/src/ast/macros/macro_util.cpp +++ b/src/ast/macros/macro_util.cpp @@ -466,7 +466,7 @@ void macro_util::normalize_expr(app * head, expr * t, expr_ref & norm_t) const { if (v->get_idx() > max_var_idx) max_var_idx = v->get_idx(); } - TRACE("normalize_expr_bug", + TRACE("macro_util", tout << "head: " << mk_pp(head, m_manager) << "\n"; tout << "applying substitution to:\n" << mk_bounded_pp(t, m_manager) << "\n";); for (unsigned i = 0; i < num_args; i++) { @@ -489,7 +489,7 @@ void macro_util::normalize_expr(app * head, expr * t, expr_ref & norm_t) const { if (changed) { // REMARK: t may have nested quantifiers... So, I must use the std order for variable substitution. var_subst subst(m_manager, true); - TRACE("macro_util_bug", + TRACE("macro_util", tout << "head: " << mk_pp(head, m_manager) << "\n"; tout << "applying substitution to:\n" << mk_ll_pp(t, m_manager) << "\nsubstitution:\n"; for (unsigned i = 0; i < var_mapping.size(); i++) { @@ -604,12 +604,12 @@ void hint_to_macro_head(ast_manager & m, app * head, unsigned num_decls, app_ref is_hint_head(head, vars) must also return true */ bool macro_util::is_poly_hint(expr * n, app * head, expr * exception) { - TRACE("macro_util_hint", tout << "is_poly_hint n:\n" << mk_pp(n, m_manager) << "\nhead:\n" << mk_pp(head, m_manager) << "\nexception:\n"; + TRACE("macro_util", tout << "is_poly_hint n:\n" << mk_pp(n, m_manager) << "\nhead:\n" << mk_pp(head, m_manager) << "\nexception:\n"; if (exception) tout << mk_pp(exception, m_manager); else tout << ""; tout << "\n";); ptr_buffer vars; if (!is_hint_head(head, vars)) { - TRACE("macro_util_hint", tout << "failed because head is not hint head\n";); + TRACE("macro_util", tout << "failed because head is not hint head\n";); return false; } func_decl * f = head->get_decl(); @@ -626,11 +626,11 @@ bool macro_util::is_poly_hint(expr * n, app * head, expr * exception) { for (unsigned i = 0; i < num_args; i++) { expr * arg = args[i]; if (arg != exception && (occurs(f, arg) || !vars_of_is_subset(arg, vars))) { - TRACE("macro_util_hint", tout << "failed because of:\n" << mk_pp(arg, m_manager) << "\n";); + TRACE("macro_util", tout << "failed because of:\n" << mk_pp(arg, m_manager) << "\n";); return false; } } - TRACE("macro_util_hint", tout << "succeeded\n";); + TRACE("macro_util", tout << "succeeded\n";); return true; } @@ -831,7 +831,7 @@ void macro_util::collect_arith_macro_candidates(expr * lhs, expr * rhs, expr * a } void macro_util::collect_arith_macro_candidates(expr * atom, unsigned num_decls, macro_candidates & r) { - TRACE("macro_util_hint", tout << "collect_arith_macro_candidates:\n" << mk_pp(atom, m_manager) << "\n";); + TRACE("macro_util", tout << "collect_arith_macro_candidates:\n" << mk_pp(atom, m_manager) << "\n";); if (!m_manager.is_eq(atom) && !is_le_ge(atom)) return; expr * lhs = to_app(atom)->get_arg(0); From 24e4f19d76c17574bb6c9d1d64b22f6dd316978e Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Mon, 16 Jan 2017 14:08:21 +0000 Subject: [PATCH 481/536] build fix --- scripts/mk_win_dist.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/mk_win_dist.py b/scripts/mk_win_dist.py index 9d3abaf2c..0e7fab490 100644 --- a/scripts/mk_win_dist.py +++ b/scripts/mk_win_dist.py @@ -315,7 +315,7 @@ def main(): init_project_def() mk_dist_dirs() cp_licenses() - cp_vs_runtime() + cp_vs_runtimes() mk_zip() main() From 00a50eea7f439fad4ba8bb981eedf15e076bfb41 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Mon, 16 Jan 2017 15:05:58 +0000 Subject: [PATCH 482/536] Added (include ...) SMT2 command. --- src/shell/smtlib_frontend.cpp | 2 ++ src/smt/smt2_extra_cmds.cpp | 47 +++++++++++++++++++++++++++++++++++ src/smt/smt2_extra_cmds.h | 26 +++++++++++++++++++ 3 files changed, 75 insertions(+) create mode 100644 src/smt/smt2_extra_cmds.cpp create mode 100644 src/smt/smt2_extra_cmds.h diff --git a/src/shell/smtlib_frontend.cpp b/src/shell/smtlib_frontend.cpp index 31c964ae0..c9fa69221 100644 --- a/src/shell/smtlib_frontend.cpp +++ b/src/shell/smtlib_frontend.cpp @@ -29,6 +29,7 @@ Revision History: #include"opt_cmds.h" #include"polynomial_cmds.h" #include"subpaving_cmds.h" +#include"smt2_extra_cmds.h" #include"smt_strategic_solver.h" #include"smt_solver.h" @@ -113,6 +114,7 @@ unsigned read_smtlib2_commands(char const * file_name) { install_polynomial_cmds(ctx); install_subpaving_cmds(ctx); install_opt_cmds(ctx); + install_smt2_extra_cmds(ctx); g_cmd_context = &ctx; signal(SIGINT, on_ctrl_c); diff --git a/src/smt/smt2_extra_cmds.cpp b/src/smt/smt2_extra_cmds.cpp new file mode 100644 index 000000000..866a1178e --- /dev/null +++ b/src/smt/smt2_extra_cmds.cpp @@ -0,0 +1,47 @@ +/*++ +Copyright (c) 2011 Microsoft Corporation + +Module Name: + + smt2_extra_cmds.cpp + +Abstract: + + Additional SMT-specific commands. + +Author: + + Christoph (cwinter) 2017-01-16 + +Notes: + +--*/ +#include"cmd_context.h" +#include"smt2parser.h" +#include"smt2_extra_cmds.h" + +class include_cmd : public cmd { + char const * m_filename; +public: + include_cmd() : cmd("include"), m_filename(0) {} + virtual char const * get_usage() const { return ""; } + virtual char const * get_descr(cmd_context & ctx) const { return "include a file"; } + virtual unsigned get_arity() const { return 1; } + virtual cmd_arg_kind next_arg_kind(cmd_context & ctx) const { return CPK_STRING; } + virtual void set_next_arg(cmd_context & ctx, char const * val) { m_filename = val; } + virtual void failure_cleanup(cmd_context & ctx) {} + virtual void execute(cmd_context & ctx) { + std::ifstream is(m_filename); + if (is.bad() || is.fail()) + throw cmd_exception(std::string("failed to open file '") + m_filename + "'"); + parse_smt2_commands(ctx, is, false); + is.close(); + } + virtual void prepare(cmd_context & ctx) { reset(ctx); } + virtual void reset(cmd_context & ctx) { m_filename = 0; } + virtual void finalize(cmd_context & ctx) { reset(ctx); } +}; + +void install_smt2_extra_cmds(cmd_context & ctx) { + ctx.insert(alloc(include_cmd)); +} \ No newline at end of file diff --git a/src/smt/smt2_extra_cmds.h b/src/smt/smt2_extra_cmds.h new file mode 100644 index 000000000..947f5ed7a --- /dev/null +++ b/src/smt/smt2_extra_cmds.h @@ -0,0 +1,26 @@ +/*++ +Copyright (c) 2011 Microsoft Corporation + +Module Name: + + smt2_extra_cmds.h + +Abstract: + + Additional SMT-specific commands. + +Author: + + Christoph (cwinter) 2017-01-16 + +Notes: + +--*/ +#ifndef SMT2_EXTRA_CMDS_H_ +#define SMT2_EXTRA_CMDS_H_ + +class cmd_context; + +void install_smt2_extra_cmds(cmd_context & ctx); + +#endif /* SMT2_EXTRA_CMDS_H_ */ From 090a331d79648b7eb76a49ac1fd22c80a63a19a8 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Mon, 9 Jan 2017 14:51:01 +0000 Subject: [PATCH 483/536] Added filenames to error messages for when we have more than one file. --- src/parsers/smt2/smt2parser.cpp | 195 ++++++++++++++++---------------- src/parsers/smt2/smt2parser.h | 2 +- 2 files changed, 101 insertions(+), 96 deletions(-) diff --git a/src/parsers/smt2/smt2parser.cpp b/src/parsers/smt2/smt2parser.cpp index bb0c5bfb9..d2b55af1d 100644 --- a/src/parsers/smt2/smt2parser.cpp +++ b/src/parsers/smt2/smt2parser.cpp @@ -109,7 +109,6 @@ namespace smt2 { typedef std::pair named_expr; named_expr m_last_named_expr; - ast_manager & m() const { return m_ctx.m(); } pdecl_manager & pm() const { return m_ctx.pm(); } sexpr_manager & sm() const { return m_ctx.sm(); } @@ -117,7 +116,7 @@ namespace smt2 { bool m_ignore_user_patterns; bool m_ignore_bad_patterns; bool m_display_error_for_vs; - + bool ignore_user_patterns() const { return m_ignore_user_patterns; } bool ignore_bad_patterns() const { return m_ignore_bad_patterns; } bool use_vs_format() const { return m_display_error_for_vs; } @@ -129,7 +128,7 @@ namespace smt2 { m_decl(d), m_spos(spos) { } }; - + typedef psort_frame sort_frame; enum expr_frame_kind { EF_APP, EF_LET, EF_LET_DECL, EF_QUANT, EF_ATTR_EXPR, EF_PATTERN }; @@ -138,17 +137,17 @@ namespace smt2 { expr_frame_kind m_kind; expr_frame(expr_frame_kind k):m_kind(k) {} }; - + struct app_frame : public expr_frame { symbol m_f; unsigned m_expr_spos; unsigned m_param_spos; bool m_as_sort; app_frame(symbol const & f, unsigned expr_spos, unsigned param_spos, bool as_sort): - expr_frame(EF_APP), - m_f(f), - m_expr_spos(expr_spos), - m_param_spos(param_spos), + expr_frame(EF_APP), + m_f(f), + m_expr_spos(expr_spos), + m_param_spos(param_spos), m_as_sort(as_sort) {} }; @@ -163,8 +162,8 @@ namespace smt2 { unsigned m_sort_spos; unsigned m_expr_spos; quant_frame(bool forall, unsigned pat_spos, unsigned nopat_spos, unsigned sym_spos, unsigned sort_spos, unsigned expr_spos): - expr_frame(EF_QUANT), m_forall(forall), m_weight(1), - m_pat_spos(pat_spos), m_nopat_spos(nopat_spos), + expr_frame(EF_QUANT), m_forall(forall), m_weight(1), + m_pat_spos(pat_spos), m_nopat_spos(nopat_spos), m_sym_spos(sym_spos), m_sort_spos(sort_spos), m_expr_spos(expr_spos) {} }; @@ -175,7 +174,7 @@ namespace smt2 { unsigned m_expr_spos; let_frame(unsigned sym_spos, unsigned expr_spos):expr_frame(EF_LET), m_in_decls(true), m_sym_spos(sym_spos), m_expr_spos(expr_spos) {} }; - + struct let_decl_frame : public expr_frame { let_decl_frame():expr_frame(EF_LET_DECL) {} }; @@ -186,9 +185,9 @@ namespace smt2 { unsigned m_expr_spos; symbol m_last_symbol; attr_expr_frame(expr_frame * prev, unsigned sym_spos, unsigned expr_spos): - expr_frame(EF_ATTR_EXPR), - m_prev(prev), - m_sym_spos(sym_spos), + expr_frame(EF_ATTR_EXPR), + m_prev(prev), + m_sym_spos(sym_spos), m_expr_spos(expr_spos) {} }; @@ -228,12 +227,12 @@ namespace smt2 { m_expr_stack = alloc(expr_ref_vector, m()); return *(m_expr_stack.get()); } - + template static unsigned size(scoped_ptr & v) { return v.get() == 0 ? 0 : v->size(); } - + template static void shrink(scoped_ptr & v, unsigned old_sz) { if (v.get() == 0) { @@ -255,7 +254,7 @@ namespace smt2 { m_nopattern_stack = alloc(expr_ref_vector, m()); return *(m_nopattern_stack.get()); } - + svector & symbol_stack() { return m_symbol_stack; } @@ -328,7 +327,7 @@ namespace smt2 { bool sync_after_error() { while (true) { try { - while (curr_is_rparen()) + while (curr_is_rparen()) next(); if (m_num_open_paren < 0) m_num_open_paren = 0; @@ -337,7 +336,7 @@ namespace smt2 { SASSERT(m_num_open_paren >= 0); while (m_num_open_paren > 0 || !curr_is_lparen()) { TRACE("sync", tout << "sync(): curr: " << curr() << "\n"; - tout << "m_num_open_paren: " << m_num_open_paren << ", line: " << m_scanner.get_line() << ", pos: " + tout << "m_num_open_paren: " << m_num_open_paren << ", line: " << m_scanner.get_line() << ", pos: " << m_scanner.get_pos() << "\n";); if (curr() == scanner::EOF_TOKEN) { return false; @@ -365,7 +364,7 @@ namespace smt2 { } throw parser_exception(msg); } - + symbol const & curr_id() const { return m_scanner.get_id(); } rational curr_numeral() const { return m_scanner.get_number(); } @@ -402,15 +401,20 @@ namespace smt2 { void check_int_or_float(char const * msg) { if (!curr_is_int() && !curr_is_float()) throw parser_exception(msg); } void check_float(char const * msg) { if (!curr_is_float()) throw parser_exception(msg); } + char const * m_current_file; + void set_current_file(char const * s) { m_current_file = s; } + void error(unsigned line, unsigned pos, char const * msg) { m_ctx.set_cancel(false); if (use_vs_format()) { m_ctx.diagnostic_stream() << "Z3(" << line << ", " << pos << "): ERROR: " << msg; if (msg[strlen(msg)-1] != '\n') - m_ctx.diagnostic_stream() << std::endl; + m_ctx.diagnostic_stream() << std::endl; } else { - m_ctx.regular_stream() << "(error \"line " << line << " column " << pos << ": " << escaped(msg, true) << "\")" << std::endl; + m_ctx.regular_stream() << "(error \""; + if (m_current_file) m_ctx.regular_stream() << m_current_file << ": "; + m_ctx.regular_stream()<< "line " << line << " column " << pos << ": " << escaped(msg, true) << "\")" << std::endl; } if (m_ctx.exit_on_error()) { exit(1); @@ -431,7 +435,7 @@ namespace smt2 { m_ctx.regular_stream() << "(error : " << escaped(msg, true) << "\")" << std::endl; } } - + void unknown_sort(symbol id, char const* context = "") { std::string msg = context; if (context[0]) msg += ": "; @@ -444,10 +448,10 @@ namespace smt2 { unsigned num_parens = 0; do { switch (curr()) { - case scanner::LEFT_PAREN: - num_parens++; + case scanner::LEFT_PAREN: + num_parens++; break; - case scanner::RIGHT_PAREN: + case scanner::RIGHT_PAREN: if (num_parens == 0) throw parser_exception("invalid s-expression, unexpected ')'"); num_parens--; @@ -565,7 +569,7 @@ namespace smt2 { else { if (ignore_unknow_sort) return 0; - unknown_sort(id); + unknown_sort(id); UNREACHABLE(); return 0; } @@ -579,7 +583,7 @@ namespace smt2 { check_identifier("invalid indexed sort, symbol expected"); symbol id = curr_id(); psort_decl * d = m_ctx.find_psort_decl(id); - if (d == 0) + if (d == 0) unknown_sort(id); next(); sbuffer args; @@ -604,13 +608,13 @@ namespace smt2 { SASSERT(curr_is_identifier()); symbol id = curr_id(); psort_decl * d = m_ctx.find_psort_decl(id); - if (d == 0) + if (d == 0) unknown_sort(id); next(); void * mem = m_stack.allocate(sizeof(psort_frame)); new (mem) psort_frame(*this, d, psort_stack().size()); } - + void pop_psort_app_frame() { SASSERT(curr_is_rparen()); psort_frame * fr = static_cast(m_stack.top()); @@ -647,7 +651,7 @@ namespace smt2 { else { check_lparen_next("invalid sort, symbol, '_' or '(' expected"); if (!curr_is_identifier()) - throw parser_exception("invalid sort, symbol or '_' expected"); + throw parser_exception("invalid sort, symbol or '_' expected"); if (curr_id_is_underscore()) { psort_stack().push_back(pm().mk_psort_cnst(parse_indexed_sort())); } @@ -665,13 +669,13 @@ namespace smt2 { SASSERT(curr_is_identifier()); symbol id = curr_id(); psort_decl * d = m_ctx.find_psort_decl(id); - if (d == 0) + if (d == 0) unknown_sort(id); next(); void * mem = m_stack.allocate(sizeof(sort_frame)); new (mem) sort_frame(*this, d, sort_stack().size()); } - + void pop_sort_app_frame() { SASSERT(curr_is_rparen()); sort_frame * fr = static_cast(m_stack.top()); @@ -710,8 +714,8 @@ namespace smt2 { } else { check_lparen_next("invalid sort, symbol, '_' or '(' expected"); - if (!curr_is_identifier()) - throw parser_exception(std::string(context) + " invalid sort, symbol or '_' expected"); + if (!curr_is_identifier()) + throw parser_exception(std::string(context) + " invalid sort, symbol or '_' expected"); if (curr_id_is_underscore()) { sort_stack().push_back(parse_indexed_sort()); } @@ -726,7 +730,7 @@ namespace smt2 { } unsigned parse_sorts(char const* context) { - unsigned sz = 0; + unsigned sz = 0; check_lparen_next(context); while (!curr_is_rparen()) { parse_sort(context); @@ -949,7 +953,7 @@ namespace smt2 { } // parse expression state - enum pe_state { + enum pe_state { PES_EXPR, // expecting PES_DECL, // expecting ( ) PES_PATTERN, @@ -1015,7 +1019,7 @@ namespace smt2 { else { // just consume pattern next(); - consume_sexpr(); + consume_sexpr(); } } else if (id == m_nopattern) { @@ -1036,7 +1040,7 @@ namespace smt2 { str << "unknown attribute " << id; warning_msg("%s", str.str().c_str()); next(); - // just consume the + // just consume the consume_sexpr(); } if (curr_is_rparen()) @@ -1051,13 +1055,13 @@ namespace smt2 { switch (fr->m_kind) { case EF_LET: return static_cast(fr)->m_in_decls ? PES_DECL : PES_EXPR; - case EF_ATTR_EXPR: + case EF_ATTR_EXPR: return consume_attributes(static_cast(fr)); default: return PES_EXPR; } } - + void parse_numeral(bool is_int) { SASSERT(!is_int || curr_is_int()); SASSERT(is_int || curr_is_float()); @@ -1095,7 +1099,7 @@ namespace smt2 { expr_stack().push_back(0); // empty pattern return; } - + if (curr_is_lparen()) { // multi-pattern void * mem = m_stack.allocate(sizeof(pattern_frame)); @@ -1185,9 +1189,9 @@ namespace smt2 { SASSERT(curr_id_is_forall() || curr_id_is_exists()); SASSERT(!is_forall || curr_id_is_forall()); SASSERT(is_forall || curr_id_is_exists()); - next(); + next(); void * mem = m_stack.allocate(sizeof(quant_frame)); - new (mem) quant_frame(is_forall, pattern_stack().size(), nopattern_stack().size(), symbol_stack().size(), + new (mem) quant_frame(is_forall, pattern_stack().size(), nopattern_stack().size(), symbol_stack().size(), sort_stack().size(), expr_stack().size()); m_num_expr_frames++; unsigned num_vars = parse_sorted_vars(); @@ -1229,11 +1233,11 @@ namespace smt2 { next(); return r; } - check_lparen_next("invalid (indexed) identifier, '(_' or symbol expected"); + check_lparen_next("invalid (indexed) identifier, '(_' or symbol expected"); return parse_indexed_identifier_core(); } - // parse: + // parse: // 'as' ')' // '_' + ')' // 'as' (|)+ ')' ')' @@ -1255,7 +1259,7 @@ namespace smt2 { } } - // parse: + // parse: // // '(' 'as' ')' // '(' '_' + ')' @@ -1281,8 +1285,8 @@ namespace smt2 { throw parser_exception(msg.c_str()); } - rational m_last_bv_numeral; // for bv, bvbin, bvhex - + rational m_last_bv_numeral; // for bv, bvbin, bvhex + // return true if *s == [0-9]+ bool is_bv_decimal(char const * s) { TRACE("is_bv_num", tout << "is_bv_decimal: " << s << "\n";); @@ -1321,7 +1325,7 @@ namespace smt2 { return false; return true; } - + // return true if *s == hex[0-9,a-f,A-F]+ bool is_bv_hex(char const * s) { SASSERT(*s == 'h'); @@ -1329,7 +1333,7 @@ namespace smt2 { if (*s != 'e') return false; ++s; if (*s != 'x') return false; - ++s; + ++s; rational & n = m_last_bv_numeral; unsigned i = 0; n = rational(0); @@ -1340,7 +1344,7 @@ namespace smt2 { } else if ('a' <= *s && *s <= 'f') { n *= rational(16); - n += rational(10 + (*s - 'a')); + n += rational(10 + (*s - 'a')); } else if ('A' <= *s && *s <= 'F') { n *= rational(16); @@ -1357,11 +1361,11 @@ namespace smt2 { } } - // Return true if + // Return true if // n == bv[0-9]+ OR // n == bvhex[0-9,a-f,A-F]+ OR - // n == bvbin[0-1]+ - // It store the bit-vector value in m_last_bv_numeral + // n == bvbin[0-1]+ + // It store the bit-vector value in m_last_bv_numeral bool is_bv_num(symbol const & n) { char const * s = n.bare_str(); if (*s != 'b') return false; @@ -1405,7 +1409,7 @@ namespace smt2 { } next(); } - + // if has_as == true, then the sort of t must be equal to sort_stack().pop_back() // if that is the case, pop the top of sort_stack() void check_qualifier(expr * t, bool has_as) { @@ -1543,7 +1547,7 @@ namespace smt2 { unsigned num_args = expr_stack().size() - fr->m_expr_spos; unsigned num_indices = m_param_stack.size() - fr->m_param_spos; expr_ref t_ref(m()); - m_ctx.mk_app(fr->m_f, + m_ctx.mk_app(fr->m_f, num_args, expr_stack().c_ptr() + fr->m_expr_spos, num_indices, @@ -1627,7 +1631,7 @@ namespace smt2 { fr->m_qid = symbol(m_scanner.get_line()); if (!m().is_bool(expr_stack().back())) throw parser_exception("quantifier body must be a Boolean expression"); - quantifier * new_q = m().mk_quantifier(fr->m_forall, + quantifier * new_q = m().mk_quantifier(fr->m_forall, num_decls, sort_stack().c_ptr() + fr->m_sort_spos, symbol_stack().c_ptr() + fr->m_sym_spos, @@ -1688,7 +1692,7 @@ namespace smt2 { case EF_APP: pop_app_frame(static_cast(fr)); break; - case EF_LET: + case EF_LET: pop_let_frame(static_cast(fr)); break; case EF_LET_DECL: @@ -1714,7 +1718,7 @@ namespace smt2 { void parse_expr() { m_num_expr_frames = 0; do { - TRACE("parse_expr", tout << "curr(): " << curr() << ", m_num_expr_frames: " << m_num_expr_frames + TRACE("parse_expr", tout << "curr(): " << curr() << ", m_num_expr_frames: " << m_num_expr_frames << ", expr_stack().size(): " << expr_stack().size() << "\n";); if (curr_is_rparen()) { if (m_num_expr_frames == 0) @@ -1798,7 +1802,7 @@ namespace smt2 { SASSERT(curr_is_identifier()); SASSERT(curr_id() == m_declare_sort); next(); - + check_identifier("invalid sort declaration, symbol expected"); symbol id = curr_id(); if (m_ctx.find_psort_decl(id) != 0) @@ -1812,7 +1816,7 @@ namespace smt2 { check_int("invalid sort declaration, arity () or ')' expected"); rational n = curr_numeral(); if (!n.is_unsigned()) - throw parser_exception("invalid sort declaration, arity is too big to fit in an unsigned machine integer"); + throw parser_exception("invalid sort declaration, arity is too big to fit in an unsigned machine integer"); psort_decl * decl = pm().mk_psort_user_decl(n.get_unsigned(), id, 0); m_ctx.insert(decl); next(); @@ -1872,12 +1876,12 @@ namespace smt2 { } void parse_define_fun_rec() { - // ( define-fun-rec hfun_defi ) + // ( define-fun-rec hfun_defi ) SASSERT(curr_is_identifier()); SASSERT(curr_id() == m_define_fun_rec); SASSERT(m_num_bindings == 0); next(); - + expr_ref_vector binding(m()); svector ids; func_decl_ref f(m()); @@ -1890,7 +1894,7 @@ namespace smt2 { } void parse_define_funs_rec() { - // ( define-funs-rec ( hfun_decin+1 ) ( htermin+1 ) ) + // ( define-funs-rec ( hfun_decin+1 ) ( htermin+1 ) ) SASSERT(curr_is_identifier()); SASSERT(curr_id() == m_define_funs_rec); SASSERT(m_num_bindings == 0); @@ -1920,14 +1924,14 @@ namespace smt2 { check_lparen("invalid recursive function definition, '(' expected"); next(); - + parse_rec_fun_decl(f, binding, id); decls.push_back(f); bindings.push_back(binding); ids.push_back(id); check_rparen("invalid recursive function definition, ')' expected"); - next(); + next(); } next(); } @@ -1950,7 +1954,7 @@ namespace smt2 { sort_stack().shrink(sort_spos); expr_stack().shrink(expr_spos); m_env.end_scope(); - m_num_bindings = 0; + m_num_bindings = 0; } void parse_rec_fun_bodies(func_decl_ref_vector const& decls, vector const& bindings, vector >const & ids) { @@ -1963,10 +1967,10 @@ namespace smt2 { } if (i != decls.size()) { - throw parser_exception("the number of declarations does not match number of supplied definitions"); + throw parser_exception("the number of declarations does not match number of supplied definitions"); } check_rparen("invalid recursive function definition, ')' expected"); - next(); + next(); } void parse_rec_fun_body(func_decl* f, expr_ref_vector const& bindings, svector const& ids) { @@ -1980,19 +1984,19 @@ namespace smt2 { for (unsigned i = 0; i < num_vars; ++i) { m_env.insert(ids[i], local(bindings[i], num_vars)); } - parse_expr(); + parse_expr(); body = expr_stack().back(); expr_stack().pop_back(); symbol_stack().shrink(sym_spos); m_env.end_scope(); - m_num_bindings = 0; + m_num_bindings = 0; if (m().get_sort(body) != f->get_range()) { std::ostringstream buffer; buffer << "invalid function definition, sort mismatch. Expcected " - << mk_pp(f->get_range(), m()) << " but function body has sort " + << mk_pp(f->get_range(), m()) << " but function body has sort " << mk_pp(m().get_sort(body), m()); throw parser_exception(buffer.str().c_str()); - } + } m_ctx.insert_rec_fun(f, bindings, ids, body); } @@ -2185,7 +2189,7 @@ namespace smt2 { unsigned spos = expr_stack().size(); check_lparen_next("invalid check-sat-assuming command, '(', expected"); parse_assumptions(); - check_rparen_next("invalid check-sat-assuming command, ')', expected"); + check_rparen_next("invalid check-sat-assuming command, ')', expected"); m_ctx.check_sat(expr_stack().size() - spos, expr_stack().c_ptr() + spos); next(); expr_stack().shrink(spos); @@ -2201,7 +2205,7 @@ namespace smt2 { m_scanner.start_caching(); m_cache_end = 0; m_cached_strings.resize(0); - + check_lparen_next("invalid get-value command, '(' expected"); while (!curr_is_rparen()) { parse_expr(); @@ -2241,7 +2245,7 @@ namespace smt2 { SASSERT(curr_id() == m_reset); next(); check_rparen("invalid reset command, ')' expected"); - m_ctx.reset(); + m_ctx.reset(); reset(); m_ctx.print_success(); next(); @@ -2323,7 +2327,7 @@ namespace smt2 { } next(); } - + void parse_next_cmd_arg() { SASSERT(m_curr_cmd != 0); cmd_arg_kind k = m_curr_cmd->next_arg_kind(m_ctx); @@ -2332,7 +2336,7 @@ namespace smt2 { check_int("invalid command argument, unsigned integer expected"); rational n = curr_numeral(); if (!n.is_unsigned()) - throw parser_exception("invalid command argument, numeral is too big to fit in an unsigned machine integer"); + throw parser_exception("invalid command argument, numeral is too big to fit in an unsigned machine integer"); m_curr_cmd->set_next_arg(m_ctx, n.get_unsigned()); next(); break; @@ -2445,7 +2449,7 @@ namespace smt2 { m_curr_cmd = m_ctx.find_cmd(s); if (m_curr_cmd == 0) { parse_unknown_cmd(); - return; + return; } next(); unsigned arity = m_curr_cmd->get_arity(); @@ -2475,14 +2479,14 @@ namespace smt2 { return; } else { - if (arity != VAR_ARITY && i == arity) + if (arity != VAR_ARITY && i == arity) throw parser_exception("invalid command, too many arguments"); parse_next_cmd_arg(); } i++; } } - + void parse_cmd() { SASSERT(curr_is_lparen()); int line = m_scanner.get_line(); @@ -2531,7 +2535,7 @@ namespace smt2 { return; } if (s == m_declare_datatypes) { - parse_declare_datatypes(); + parse_declare_datatypes(); return; } if (s == m_get_value) { @@ -2558,8 +2562,8 @@ namespace smt2 { } public: - parser(cmd_context & ctx, std::istream & is, bool interactive, params_ref const & p): - m_ctx(ctx), + parser(cmd_context & ctx, std::istream & is, bool interactive, params_ref const & p, char const * filename=0): + m_ctx(ctx), m_params(p), m_scanner(ctx, is, interactive), m_curr(scanner::NULL_TOKEN), @@ -2597,14 +2601,15 @@ namespace smt2 { m_check_sat_assuming("check-sat-assuming"), m_define_fun_rec("define-fun-rec"), m_define_funs_rec("define-funs-rec"), - m_underscore("_"), - m_num_open_paren(0) { + m_underscore("_"), + m_num_open_paren(0), + m_current_file(filename) { // the following assertion does not hold if ctx was already attached to an AST manager before the parser object is created. // SASSERT(!m_ctx.has_manager()); - + updt_params(); } - + ~parser() { reset_stack(); } @@ -2615,7 +2620,7 @@ namespace smt2 { m_ignore_bad_patterns = p.ignore_bad_patterns(); m_display_error_for_vs = p.error_for_visual_studio(); } - + void reset() { reset_stack(); m_num_bindings = 0; @@ -2630,7 +2635,7 @@ namespace smt2 { m_env .reset(); m_sort_id2param_idx .reset(); m_dt_name2idx .reset(); - + m_bv_util = 0; m_arith_util = 0; m_seq_util = 0; @@ -2680,9 +2685,9 @@ namespace smt2 { return !found_errors; } catch (parser_exception & ex) { - if (ex.has_pos()) + if (ex.has_pos()) error(ex.line(), ex.pos(), ex.msg()); - else + else error(ex.msg()); } catch (ast_exception & ex) { @@ -2705,8 +2710,8 @@ namespace smt2 { }; }; -bool parse_smt2_commands(cmd_context & ctx, std::istream & is, bool interactive, params_ref const & ps) { - smt2::parser p(ctx, is, interactive, ps); +bool parse_smt2_commands(cmd_context & ctx, std::istream & is, bool interactive, params_ref const & ps, char const * filename) { + smt2::parser p(ctx, is, interactive, ps, filename); return p(); } diff --git a/src/parsers/smt2/smt2parser.h b/src/parsers/smt2/smt2parser.h index 5b4384917..77fd41d5d 100644 --- a/src/parsers/smt2/smt2parser.h +++ b/src/parsers/smt2/smt2parser.h @@ -21,6 +21,6 @@ Revision History: #include"cmd_context.h" -bool parse_smt2_commands(cmd_context & ctx, std::istream & is, bool interactive = false, params_ref const & p = params_ref()); +bool parse_smt2_commands(cmd_context & ctx, std::istream & is, bool interactive = false, params_ref const & p = params_ref(), char const * filename = 0); #endif From e472a8d4cfe36df6a68d0b4e285e9a3410d6ff8a Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Mon, 16 Jan 2017 15:46:58 +0000 Subject: [PATCH 484/536] Enabled filenames in error messages during inclusion of files. --- src/smt/smt2_extra_cmds.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/smt/smt2_extra_cmds.cpp b/src/smt/smt2_extra_cmds.cpp index 866a1178e..901810442 100644 --- a/src/smt/smt2_extra_cmds.cpp +++ b/src/smt/smt2_extra_cmds.cpp @@ -34,7 +34,7 @@ public: std::ifstream is(m_filename); if (is.bad() || is.fail()) throw cmd_exception(std::string("failed to open file '") + m_filename + "'"); - parse_smt2_commands(ctx, is, false); + parse_smt2_commands(ctx, is, false, params_ref(), m_filename); is.close(); } virtual void prepare(cmd_context & ctx) { reset(ctx); } From 625681f82f3ac3e86c4fe6755c4939bf477af6f7 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Mon, 16 Jan 2017 15:59:16 +0000 Subject: [PATCH 485/536] Updated cmake build --- contrib/cmake/src/smt/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/contrib/cmake/src/smt/CMakeLists.txt b/contrib/cmake/src/smt/CMakeLists.txt index 035ac07c9..bd8ad3f31 100644 --- a/contrib/cmake/src/smt/CMakeLists.txt +++ b/contrib/cmake/src/smt/CMakeLists.txt @@ -43,6 +43,7 @@ z3_add_component(smt smt_statistics.cpp smt_theory.cpp smt_value_sort.cpp + smt2_extra_cmds.cpp theory_arith.cpp theory_array_base.cpp theory_array.cpp From 0fae048e3e00f380bea70cb863625097f4854a46 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Tue, 17 Jan 2017 12:58:32 +0000 Subject: [PATCH 486/536] Windows build fix. --- scripts/mk_win_dist.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/mk_win_dist.py b/scripts/mk_win_dist.py index eb9f707a2..11048650f 100644 --- a/scripts/mk_win_dist.py +++ b/scripts/mk_win_dist.py @@ -316,7 +316,7 @@ def main(): mk_dist_dirs() cp_licenses() cp_vs_runtimes() - mk_zip() + mk_zips() main() From 6d34899c463db50cf4248c6e4f2451e6003919e7 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Tue, 17 Jan 2017 15:44:03 +0000 Subject: [PATCH 487/536] Bugfix for macro finder. Fixes #832. --- src/ast/macros/macro_manager.cpp | 18 +++++------ src/ast/macros/macro_util.cpp | 51 ++++++++++++++++---------------- src/ast/macros/macro_util.h | 16 +++++----- 3 files changed, 42 insertions(+), 43 deletions(-) diff --git a/src/ast/macros/macro_manager.cpp b/src/ast/macros/macro_manager.cpp index 75b4e55f4..b17e1ce28 100644 --- a/src/ast/macros/macro_manager.cpp +++ b/src/ast/macros/macro_manager.cpp @@ -106,7 +106,7 @@ bool macro_manager::insert(func_decl * f, quantifier * m, proof * pr) { if (!m_deps.insert(f, s)) { return false; } - + // add macro m_decl2macro.insert(f, m); m_decls.push_back(f); @@ -117,8 +117,8 @@ bool macro_manager::insert(func_decl * f, quantifier * m, proof * pr) { } TRACE("macro_insert", tout << "A macro was successfully created for: " << f->get_name() << "\n";); - - // Nothing's forbidden anymore; if something's bad, we detected it earlier. + + // Nothing's forbidden anymore; if something's bad, we detected it earlier. // mark_forbidden(m->get_expr()); return true; } @@ -144,7 +144,7 @@ namespace macro_manager_ns { \brief Mark all func_decls used in exprs as forbidden. */ void macro_manager::mark_forbidden(unsigned n, expr * const * exprs) { - expr_mark visited; + expr_mark visited; macro_manager_ns::proc p(m_forbidden_set, m_forbidden); for (unsigned i = 0; i < n; i++) for_each_expr(p, visited, exprs[i]); @@ -187,9 +187,9 @@ func_decl * macro_manager::get_macro_interpretation(unsigned i, expr_ref & inter app * head; expr * def; get_head_def(q, f, head, def); - TRACE("macro_bug", + TRACE("macro_bug", tout << f->get_name() << "\n" << mk_pp(head, m_manager) << "\n" << mk_pp(q, m_manager) << "\n";); - m_util.mk_macro_interpretation(head, def, interp); + m_util.mk_macro_interpretation(head, q->get_num_decls(), def, interp); return f; } @@ -237,7 +237,7 @@ void macro_manager::macro_expander::reduce1_quantifier(quantifier * q) { erase_patterns = true; } for (unsigned i = 0; !erase_patterns && i < q->get_num_no_patterns(); i++) { - if (q->get_no_pattern(i) != new_q->get_no_pattern(i)) + if (q->get_no_pattern(i) != new_q->get_no_pattern(i)) erase_patterns = true; } } @@ -254,7 +254,7 @@ bool macro_manager::macro_expander::get_subst(expr * _n, expr_ref & r, proof_ref return false; app * n = to_app(_n); quantifier * q = 0; - func_decl * d = n->get_decl(); + func_decl * d = n->get_decl(); TRACE("macro_manager_bug", tout << "trying to expand:\n" << mk_pp(n, m) << "\nd:\n" << d->get_name() << "\n";); if (m_macro_manager.m_decl2macro.find(d, q)) { TRACE("macro_manager", tout << "expanding: " << mk_pp(n, m) << "\n";); @@ -308,7 +308,7 @@ void macro_manager::expand_macros(expr * n, proof * pr, expr_ref & r, proof_ref if (r.get() == old_n.get()) return; old_n = r; - old_pr = new_pr; + old_pr = new_pr; } } else { diff --git a/src/ast/macros/macro_util.cpp b/src/ast/macros/macro_util.cpp index 97b44d4cd..99732871c 100644 --- a/src/ast/macros/macro_util.cpp +++ b/src/ast/macros/macro_util.cpp @@ -405,7 +405,7 @@ bool macro_util::is_quasi_macro_head(expr * n, unsigned num_decls) const { \brief Convert a quasi-macro head into a macro head, and store the conditions under which it is valid in cond. */ -void macro_util::quasi_macro_head_to_macro_head(app * qhead, unsigned num_decls, app_ref & head, expr_ref & cond) const { +void macro_util::quasi_macro_head_to_macro_head(app * qhead, unsigned & num_decls, app_ref & head, expr_ref & cond) const { unsigned num_args = qhead->get_num_args(); sbuffer found_vars; found_vars.resize(num_decls, false); @@ -431,6 +431,7 @@ void macro_util::quasi_macro_head_to_macro_head(app * qhead, unsigned num_decls, } get_basic_simp()->mk_and(new_conds.size(), new_conds.c_ptr(), cond); head = m_manager.mk_app(qhead->get_decl(), new_args.size(), new_args.c_ptr()); + num_decls = next_var_idx; } /** @@ -440,10 +441,10 @@ void macro_util::quasi_macro_head_to_macro_head(app * qhead, unsigned num_decls, See normalize_expr */ -void macro_util::mk_macro_interpretation(app * head, expr * def, expr_ref & interp) const { +void macro_util::mk_macro_interpretation(app * head, unsigned num_decls, expr * def, expr_ref & interp) const { SASSERT(is_macro_head(head, head->get_num_args())); SASSERT(!occurs(head->get_decl(), def)); - normalize_expr(head, def, interp); + normalize_expr(head, num_decls, def, interp); } /** @@ -456,36 +457,27 @@ void macro_util::mk_macro_interpretation(app * head, expr * def, expr_ref & inte f(x_1, x_2) --> f(x_0, x_1) f(x_3, x_2) --> f(x_0, x_1) */ -void macro_util::normalize_expr(app * head, expr * t, expr_ref & norm_t) const { - expr_ref_buffer var_mapping(m_manager); +void macro_util::normalize_expr(app * head, unsigned num_decls, expr * t, expr_ref & norm_t) const { + expr_ref_buffer var_mapping(m_manager); + var_mapping.resize(num_decls); bool changed = false; unsigned num_args = head->get_num_args(); - unsigned max_var_idx = 0; - for (unsigned i = 0; i < num_args; i++) { - var const * v = to_var(head->get_arg(i)); - if (v->get_idx() > max_var_idx) - max_var_idx = v->get_idx(); - } TRACE("macro_util", tout << "head: " << mk_pp(head, m_manager) << "\n"; tout << "applying substitution to:\n" << mk_bounded_pp(t, m_manager) << "\n";); for (unsigned i = 0; i < num_args; i++) { var * v = to_var(head->get_arg(i)); - if (v->get_idx() != i) { + unsigned vi = v->get_idx(); + SASSERT(vi < num_decls); + if (vi != i) { changed = true; var_ref new_var(m_manager.mk_var(i, v->get_sort()), m_manager); - var_mapping.setx(max_var_idx - v->get_idx(), new_var); + var_mapping.setx(num_decls - vi - 1, new_var); } else - var_mapping.setx(max_var_idx - i, v); + var_mapping.setx(num_decls - i - 1, v); } - for (unsigned i = num_args; i <= max_var_idx; i++) - // CMW: Won't be used, but dictates a larger binding size, - // so that the indexes between here and in the rewriter match. - // It's possible that we don't see the true max idx of all vars here. - var_mapping.setx(max_var_idx - i, 0); - if (changed) { // REMARK: t may have nested quantifiers... So, I must use the std order for variable substitution. var_subst subst(m_manager, true); @@ -573,7 +565,7 @@ bool is_hint_atom(expr * lhs, expr * rhs) { return !occurs(to_app(lhs)->get_decl(), rhs) && vars_of_is_subset(rhs, vars); } -void hint_to_macro_head(ast_manager & m, app * head, unsigned num_decls, app_ref & new_head) { +void hint_to_macro_head(ast_manager & m, app * head, unsigned & num_decls, app_ref & new_head) { unsigned num_args = head->get_num_args(); ptr_buffer new_args; sbuffer found_vars; @@ -595,6 +587,7 @@ void hint_to_macro_head(ast_manager & m, app * head, unsigned num_decls, app_ref new_args.push_back(new_var); } new_head = m.mk_app(head->get_decl(), new_args.size(), new_args.c_ptr()); + num_decls = next_var_idx; } /** @@ -671,12 +664,12 @@ void macro_util::macro_candidates::insert(func_decl * f, expr * def, expr * cond // // ----------------------------- -void macro_util::insert_macro(app * head, expr * def, expr * cond, bool ineq, bool satisfy_atom, bool hint, macro_candidates & r) { +void macro_util::insert_macro(app * head, unsigned num_decls, expr * def, expr * cond, bool ineq, bool satisfy_atom, bool hint, macro_candidates & r) { expr_ref norm_def(m_manager); expr_ref norm_cond(m_manager); - normalize_expr(head, def, norm_def); + normalize_expr(head, num_decls, def, norm_def); if (cond != 0) - normalize_expr(head, cond, norm_cond); + normalize_expr(head, num_decls, cond, norm_cond); else if (!hint) norm_cond = m_manager.mk_true(); SASSERT(!hint || norm_cond.get() == 0); @@ -698,11 +691,14 @@ void macro_util::insert_quasi_macro(app * head, unsigned num_decls, expr * def, } else { hint_to_macro_head(m_manager, head, num_decls, new_head); + TRACE("macro_util", + tout << "hint macro head: " << mk_ismt2_pp(new_head, m_manager) << std::endl; + tout << "hint macro def: " << mk_ismt2_pp(def, m_manager) << std::endl; ); } - insert_macro(new_head, def, new_cond, ineq, satisfy_atom, hint, r); + insert_macro(new_head, num_decls, def, new_cond, ineq, satisfy_atom, hint, r); } else { - insert_macro(head, def, cond, ineq, satisfy_atom, hint, r); + insert_macro(head, num_decls, def, cond, ineq, satisfy_atom, hint, r); } } @@ -879,6 +875,9 @@ void macro_util::collect_arith_macro_candidates(expr * atom, unsigned num_decls, */ void macro_util::collect_macro_candidates_core(expr * atom, unsigned num_decls, macro_candidates & r) { expr* lhs, *rhs; + + TRACE("macro_util", tout << "Candidate check for: " << mk_ismt2_pp(atom, m_manager) << std::endl;); + if (m_manager.is_eq(atom, lhs, rhs) || m_manager.is_iff(atom, lhs, rhs)) { if (is_quasi_macro_head(lhs, num_decls) && !is_forbidden(to_app(lhs)->get_decl()) && diff --git a/src/ast/macros/macro_util.h b/src/ast/macros/macro_util.h index 18b00c1f7..033f6ecb4 100644 --- a/src/ast/macros/macro_util.h +++ b/src/ast/macros/macro_util.h @@ -74,9 +74,9 @@ private: void collect_arith_macros(expr * n, unsigned num_decls, unsigned max_macros, bool allow_cond_macros, macro_candidates & r); - void normalize_expr(app * head, expr * t, expr_ref & norm_t) const; - void insert_macro(app * head, expr * def, expr * cond, bool ineq, bool satisfy_atom, bool hint, macro_candidates & r); - void insert_quasi_macro(app * head, unsigned num_decls, expr * def, expr * cond, bool ineq, bool satisfy_atom, bool hint, + void normalize_expr(app * head, unsigned num_decls, expr * t, expr_ref & norm_t) const; + void insert_macro(app * head, unsigned num_decls, expr * def, expr * cond, bool ineq, bool satisfy_atom, bool hint, macro_candidates & r); + void insert_quasi_macro(app * head, unsigned num_decls, expr * def, expr * cond, bool ineq, bool satisfy_atom, bool hint, macro_candidates & r); expr * m_curr_clause; // auxiliary var used in collect_macro_candidates. @@ -105,7 +105,7 @@ public: bool is_left_simple_macro(expr * n, unsigned num_decls, app_ref & head, expr_ref & def) const; bool is_right_simple_macro(expr * n, unsigned num_decls, app_ref & head, expr_ref & def) const; bool is_simple_macro(expr * n, unsigned num_decls, app_ref& head, expr_ref & def) const { - return is_left_simple_macro(n, num_decls, head, def) || is_right_simple_macro(n, num_decls, head, def); + return is_left_simple_macro(n, num_decls, head, def) || is_right_simple_macro(n, num_decls, head, def); } bool is_arith_macro(expr * n, unsigned num_decls, app_ref & head, expr_ref & def, bool & inv) const; @@ -113,20 +113,20 @@ public: bool inv; return is_arith_macro(n, num_decls, head, def, inv); } - + bool is_pseudo_head(expr * n, unsigned num_decls, app_ref & head, app_ref & t); bool is_pseudo_predicate_macro(expr * n, app_ref & head, app_ref & t, expr_ref & def); bool is_quasi_macro_head(expr * n, unsigned num_decls) const; - void quasi_macro_head_to_macro_head(app * qhead, unsigned num_decls, app_ref & head, expr_ref & cond) const; + void quasi_macro_head_to_macro_head(app * qhead, unsigned & num_decls, app_ref & head, expr_ref & cond) const; - void mk_macro_interpretation(app * head, expr * def, expr_ref & interp) const; + void mk_macro_interpretation(app * head, unsigned num_decls, expr * def, expr_ref & interp) const; void collect_macro_candidates(expr * atom, unsigned num_decls, macro_candidates & r); void collect_macro_candidates(quantifier * q, macro_candidates & r); // - // Auxiliary goodness that allows us to manipulate BV and Arith polynomials. + // Auxiliary goodness that allows us to manipulate BV and Arith polynomials. // bool is_bv(expr * n) const; bool is_bv_sort(sort * s) const; From 873d975c77abeeb58fc170e8c8e03e671ff39bd4 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 17 Jan 2017 13:41:15 -0800 Subject: [PATCH 488/536] fix bug in consequence extraction: the order of bcp is not fixed between restarts, so the order of unit literals may not be preserved. This is relatively rare, so we optimize for the case where we assume bcp preserves order (and maybe miss some consequences) Signed-off-by: Nikolaj Bjorner --- src/sat/sat_solver.cpp | 28 +++++++++++++++++++++++----- src/sat/sat_solver.h | 6 ++++-- 2 files changed, 27 insertions(+), 7 deletions(-) diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index eec94879a..37fb971fd 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -3227,20 +3227,32 @@ namespace sat { SASSERT(!inconsistent()); unsigned sz = m_trail.size(); for (unsigned i = start; i < sz && lvl(m_trail[i]) <= 1; ++i) { - extract_fixed_consequences(m_trail[i], assumptions, unfixed, conseq); + if (!extract_fixed_consequences(m_trail[i], assumptions, unfixed, conseq)) { + for (i = 0; i < sz && lvl(m_trail[i]) <= 1; ++i) { + VERIFY(extract_fixed_consequences(m_trail[i], assumptions, unfixed, conseq)); + } + break; + } } start = sz; } - void solver::extract_assumptions(literal lit, index_set& s) { + bool solver::check_domain(literal lit, literal lit2) { + return m_antecedents.contains(lit2.var()); + } + + bool solver::extract_assumptions(literal lit, index_set& s) { justification js = m_justification[lit.var()]; switch (js.get_kind()) { case justification::NONE: break; case justification::BINARY: + if (!check_domain(lit, js.get_literal())) return false; s |= m_antecedents.find(js.get_literal().var()); break; case justification::TERNARY: + if (!check_domain(lit, js.get_literal1())) return false; + if (!check_domain(lit, js.get_literal2())) return false; s |= m_antecedents.find(js.get_literal1().var()); s |= m_antecedents.find(js.get_literal2().var()); break; @@ -3248,6 +3260,7 @@ namespace sat { clause & c = *(m_cls_allocator.get_clause(js.get_clause_offset())); for (unsigned i = 0; i < c.size(); ++i) { if (c[i] != lit) { + if (!check_domain(lit, c[i])) return false; s |= m_antecedents.find(c[i].var()); } } @@ -3258,6 +3271,7 @@ namespace sat { literal_vector::iterator it = m_ext_antecedents.begin(); literal_vector::iterator end = m_ext_antecedents.end(); for (; it != end; ++it) { + if (!check_domain(lit, *it)) return false; s |= m_antecedents.find(it->var()); } break; @@ -3267,6 +3281,7 @@ namespace sat { break; } TRACE("sat", display_index_set(tout << lit << ": " , s) << "\n";); + return true; } std::ostream& solver::display_index_set(std::ostream& out, index_set const& s) const { @@ -3279,17 +3294,19 @@ namespace sat { } - void solver::extract_fixed_consequences(literal lit, literal_set const& assumptions, bool_var_set& unfixed, vector& conseq) { + bool solver::extract_fixed_consequences(literal lit, literal_set const& assumptions, bool_var_set& unfixed, vector& conseq) { index_set s; if (m_antecedents.contains(lit.var())) { - return; + return true; } if (assumptions.contains(lit)) { s.insert(lit.index()); } else { + if (!extract_assumptions(lit, s)) { + return false; + } add_assumption(lit); - extract_assumptions(lit, s); } m_antecedents.insert(lit.var(), s); if (unfixed.contains(lit.var())) { @@ -3302,6 +3319,7 @@ namespace sat { unfixed.remove(lit.var()); conseq.push_back(cons); } + return true; } void solver::asymmetric_branching() { diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index f28d0aa5b..dcf7e2acb 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -439,7 +439,9 @@ namespace sat { u_map m_antecedents; vector m_binary_clause_graph; - void extract_assumptions(literal lit, index_set& s); + bool extract_assumptions(literal lit, index_set& s); + + bool check_domain(literal lit, literal lit2); std::ostream& display_index_set(std::ostream& out, index_set const& s) const; @@ -451,7 +453,7 @@ namespace sat { void extract_fixed_consequences(unsigned& start, literal_set const& assumptions, bool_var_set& unfixed, vector& conseq); - void extract_fixed_consequences(literal lit, literal_set const& assumptions, bool_var_set& unfixed, vector& conseq); + bool extract_fixed_consequences(literal lit, literal_set const& assumptions, bool_var_set& unfixed, vector& conseq); void update_unfixed_literals(literal_set& unfixed_lits, bool_var_set& unfixed_vars); From 0aa912371b3ea5ca92aa10b34b7fb25bc6372536 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 17 Jan 2017 14:19:24 -0800 Subject: [PATCH 489/536] Another fix for #847. Reset wmax theory solver state between lex calls, otherwise it uses stale constraints Signed-off-by: Nikolaj Bjorner --- src/opt/maxsmt.cpp | 15 +++++++++++---- src/opt/opt_solver.cpp | 7 +------ src/opt/opt_solver.h | 1 - src/opt/wmax.cpp | 1 + src/smt/smt_context.cpp | 1 + 5 files changed, 14 insertions(+), 11 deletions(-) diff --git a/src/opt/maxsmt.cpp b/src/opt/maxsmt.cpp index 97b6a5293..f93291599 100644 --- a/src/opt/maxsmt.cpp +++ b/src/opt/maxsmt.cpp @@ -55,15 +55,18 @@ namespace opt { void maxsmt_solver_base::commit_assignment() { expr_ref tmp(m); - rational k(0); + rational k(0), cost(0); for (unsigned i = 0; i < m_soft.size(); ++i) { if (get_assignment(i)) { k += m_weights[i]; } + else { + cost += m_weights[i]; + } } pb_util pb(m); tmp = pb.mk_ge(m_weights.size(), m_weights.c_ptr(), m_soft.c_ptr(), k); - TRACE("opt", tout << tmp << "\n";); + TRACE("opt", tout << "cost: " << cost << "\n" << tmp << "\n";); s().assert_expr(tmp); } @@ -140,7 +143,9 @@ namespace opt { m_wth = s.ensure_wmax_theory(); } maxsmt_solver_base::scoped_ensure_theory::~scoped_ensure_theory() { - //m_wth->reset_local(); + if (m_wth) { + m_wth->reset_local(); + } } smt::theory_wmaxsat& maxsmt_solver_base::scoped_ensure_theory::operator()() { return *m_wth; } @@ -226,7 +231,9 @@ namespace opt { m_msolver = 0; symbol const& maxsat_engine = m_c.maxsat_engine(); IF_VERBOSE(1, verbose_stream() << "(maxsmt)\n";); - TRACE("opt", tout << "maxsmt\n";); + TRACE("opt", tout << "maxsmt\n"; + s().display(tout); tout << "\n"; + ); if (m_soft_constraints.empty() || maxsat_engine == symbol("maxres") || maxsat_engine == symbol::null) { m_msolver = mk_maxres(m_c, m_index, m_weights, m_soft_constraints); } diff --git a/src/opt/opt_solver.cpp b/src/opt/opt_solver.cpp index 42129be70..351141a3f 100644 --- a/src/opt/opt_solver.cpp +++ b/src/opt/opt_solver.cpp @@ -327,12 +327,7 @@ namespace opt { SASSERT(idx < get_num_assertions()); return m_context.get_formulas()[idx]; } - - std::ostream& opt_solver::display(std::ostream & out) const { - m_context.display(out); - return out; - } - + smt::theory_var opt_solver::add_objective(app* term) { smt::theory_var v = get_optimizer().add_objective(term); m_objective_vars.push_back(v); diff --git a/src/opt/opt_solver.h b/src/opt/opt_solver.h index cdaad3cf2..27168e2ca 100644 --- a/src/opt/opt_solver.h +++ b/src/opt/opt_solver.h @@ -104,7 +104,6 @@ namespace opt { virtual void set_progress_callback(progress_callback * callback); virtual unsigned get_num_assertions() const; virtual expr * get_assertion(unsigned idx) const; - virtual std::ostream& display(std::ostream & out) const; virtual ast_manager& get_manager() const { return m; } virtual lbool find_mutexes(expr_ref_vector const& vars, vector& mutexes); virtual lbool preferred_sat(expr_ref_vector const& asms, vector& cores); diff --git a/src/opt/wmax.cpp b/src/opt/wmax.cpp index 690e2000b..9708bdc8f 100644 --- a/src/opt/wmax.cpp +++ b/src/opt/wmax.cpp @@ -64,6 +64,7 @@ namespace opt { bool was_sat = false; expr_ref_vector asms(m); vector cores; + obj_map::iterator it = soft.begin(), end = soft.end(); for (; it != end; ++it) { expr* c = assert_weighted(wth(), it->m_key, it->m_value); diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index ea97d1a64..c7aecca88 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -1795,6 +1795,7 @@ namespace smt { void context::set_conflict(b_justification js, literal not_l) { if (!inconsistent()) { + TRACE("set_conflict", display_literal_verbose(tout, not_l); display(tout, js); ); m_conflict = js; m_not_l = not_l; } From a334020f2cf2731ffa60e188e08d985038944f7a Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Wed, 18 Jan 2017 12:32:02 +0000 Subject: [PATCH 490/536] Added .NET 3.5 solution/project files --- examples/dotnet/Program.cs | 4 + .../Example/Properties/AssemblyInfo.cs | 36 ++ .../dotnet/dotnet35/Microsoft.Z3.NET35.csproj | 325 ++++++++++++++++++ .../dotnet/dotnet35/Microsoft.Z3.NET35.sln | 48 +++ .../dotnet35/Properties/AssemblyInfo.cs | 38 ++ .../dotnet35/Properties/AssemblyInfo.cs.in | 38 ++ src/api/dotnet/{ => dotnet35}/Readme.NET35 | 3 +- src/api/dotnet/dotnet35/packages.config | 4 + 8 files changed, 495 insertions(+), 1 deletion(-) create mode 100644 src/api/dotnet/dotnet35/Example/Properties/AssemblyInfo.cs create mode 100644 src/api/dotnet/dotnet35/Microsoft.Z3.NET35.csproj create mode 100644 src/api/dotnet/dotnet35/Microsoft.Z3.NET35.sln create mode 100644 src/api/dotnet/dotnet35/Properties/AssemblyInfo.cs create mode 100644 src/api/dotnet/dotnet35/Properties/AssemblyInfo.cs.in rename src/api/dotnet/{ => dotnet35}/Readme.NET35 (87%) create mode 100644 src/api/dotnet/dotnet35/packages.config diff --git a/examples/dotnet/Program.cs b/examples/dotnet/Program.cs index 5b10dadd0..20bb012b1 100644 --- a/examples/dotnet/Program.cs +++ b/examples/dotnet/Program.cs @@ -818,6 +818,7 @@ namespace test_mapi BigIntCheck(ctx, ctx.MkReal("234234333/2")); +#if !FRAMEWORK_LT_4 string bn = "1234567890987654321"; if (ctx.MkInt(bn).BigInteger.ToString() != bn) @@ -828,6 +829,7 @@ namespace test_mapi if (ctx.MkBV(bn, 32).BigInteger.ToString() == bn) throw new TestFailedException(); +#endif // Error handling test. try @@ -1094,8 +1096,10 @@ namespace test_mapi static void BigIntCheck(Context ctx, RatNum r) { +#if !FRAMEWORK_LT_4 Console.WriteLine("Num: " + r.BigIntNumerator); Console.WriteLine("Den: " + r.BigIntDenominator); +#endif } /// diff --git a/src/api/dotnet/dotnet35/Example/Properties/AssemblyInfo.cs b/src/api/dotnet/dotnet35/Example/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..ef95285e0 --- /dev/null +++ b/src/api/dotnet/dotnet35/Example/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("Example")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("Example")] +[assembly: AssemblyCopyright("Copyright © 2017")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("7a55be70-b47a-42c0-bb06-a6c3c3102947")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/src/api/dotnet/dotnet35/Microsoft.Z3.NET35.csproj b/src/api/dotnet/dotnet35/Microsoft.Z3.NET35.csproj new file mode 100644 index 000000000..7eaf16fd4 --- /dev/null +++ b/src/api/dotnet/dotnet35/Microsoft.Z3.NET35.csproj @@ -0,0 +1,325 @@ + + + + Debug + AnyCPU + 8.0.30703 + 2.0 + {EC3DB697-B734-42F7-9468-5B62821EEB5A} + Library + Properties + Microsoft.Z3 + Microsoft.Z3 + v3.5 + 512 + + + 0 + + + true + full + false + Debug\ + TRACE;DEBUG;FRAMEWORK_LT_4 + prompt + 4 + true + Debug\Microsoft.Z3.XML + False + False + True + False + False + True + False + True + True + False + False + False + True + False + False + False + True + False + False + True + True + True + False + False + + + + + + + True + Full + %28none%29 + 2 + + + pdbonly + true + Release\ + FRAMEWORK_LT_4 + prompt + 4 + true + Release\Microsoft.Z3.xml + x86 + + + true + + + + + + + false + + + + packages\Code.Contract.1.0.0\lib\net35\Microsoft.Contracts.dll + True + + + + + + + AlgebraicNum.cs + + + ApplyResult.cs + + + ArithExpr.cs + + + ArithSort.cs + + + ArrayExpr.cs + + + ArraySort.cs + + + AST.cs + + + ASTMap.cs + + + ASTVector.cs + + + BitVecExpr.cs + + + BitVecNum.cs + + + BitVecSort.cs + + + BoolExpr.cs + + + BoolSort.cs + + + Constructor.cs + + + ConstructorList.cs + + + Context.cs + + + DatatypeExpr.cs + + + DatatypeSort.cs + + + Deprecated.cs + + + Enumerations.cs + + + EnumSort.cs + + + Expr.cs + + + FiniteDomainExpr.cs + + + FiniteDomainNum.cs + + + FiniteDomainSort.cs + + + Fixedpoint.cs + + + FPExpr.cs + + + FPNum.cs + + + FPRMExpr.cs + + + FPRMNum.cs + + + FPRMSort.cs + + + FPSort.cs + + + FuncDecl.cs + + + FuncInterp.cs + + + Global.cs + + + Goal.cs + + + IDecRefQueue.cs + + + InterpolationContext.cs + + + IntExpr.cs + + + IntNum.cs + + + IntSort.cs + + + IntSymbol.cs + + + ListSort.cs + + + Log.cs + + + Model.cs + + + Native.cs + + + Optimize.cs + + + ParamDescrs.cs + + + Params.cs + + + Pattern.cs + + + Probe.cs + + + Quantifier.cs + + + RatNum.cs + + + RealExpr.cs + + + RealSort.cs + + + ReExpr.cs + + + RelationSort.cs + + + ReSort.cs + + + SeqExpr.cs + + + SeqSort.cs + + + SetSort.cs + + + Solver.cs + + + Sort.cs + + + Statistics.cs + + + Status.cs + + + StringSymbol.cs + + + Symbol.cs + + + Tactic.cs + + + TupleSort.cs + + + UninterpretedSort.cs + + + Version.cs + + + Z3Exception.cs + + + Z3Object.cs + + + + + + + + + + + \ No newline at end of file diff --git a/src/api/dotnet/dotnet35/Microsoft.Z3.NET35.sln b/src/api/dotnet/dotnet35/Microsoft.Z3.NET35.sln new file mode 100644 index 000000000..c71a920a2 --- /dev/null +++ b/src/api/dotnet/dotnet35/Microsoft.Z3.NET35.sln @@ -0,0 +1,48 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 14 +VisualStudioVersion = 14.0.25420.1 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Z3.NET35", "Microsoft.Z3.NET35.csproj", "{EC3DB697-B734-42F7-9468-5B62821EEB5A}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Example", "Example\Example.csproj", "{7A55BE70-B47A-42C0-BB06-A6C3C3102947}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|Any CPU = Release|Any CPU + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {EC3DB697-B734-42F7-9468-5B62821EEB5A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {EC3DB697-B734-42F7-9468-5B62821EEB5A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {EC3DB697-B734-42F7-9468-5B62821EEB5A}.Debug|x64.ActiveCfg = Debug|Any CPU + {EC3DB697-B734-42F7-9468-5B62821EEB5A}.Debug|x64.Build.0 = Debug|Any CPU + {EC3DB697-B734-42F7-9468-5B62821EEB5A}.Debug|x86.ActiveCfg = Debug|Any CPU + {EC3DB697-B734-42F7-9468-5B62821EEB5A}.Debug|x86.Build.0 = Debug|Any CPU + {EC3DB697-B734-42F7-9468-5B62821EEB5A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {EC3DB697-B734-42F7-9468-5B62821EEB5A}.Release|Any CPU.Build.0 = Release|Any CPU + {EC3DB697-B734-42F7-9468-5B62821EEB5A}.Release|x64.ActiveCfg = Release|Any CPU + {EC3DB697-B734-42F7-9468-5B62821EEB5A}.Release|x64.Build.0 = Release|Any CPU + {EC3DB697-B734-42F7-9468-5B62821EEB5A}.Release|x86.ActiveCfg = Release|Any CPU + {EC3DB697-B734-42F7-9468-5B62821EEB5A}.Release|x86.Build.0 = Release|Any CPU + {7A55BE70-B47A-42C0-BB06-A6C3C3102947}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7A55BE70-B47A-42C0-BB06-A6C3C3102947}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7A55BE70-B47A-42C0-BB06-A6C3C3102947}.Debug|x64.ActiveCfg = Debug|Any CPU + {7A55BE70-B47A-42C0-BB06-A6C3C3102947}.Debug|x64.Build.0 = Debug|Any CPU + {7A55BE70-B47A-42C0-BB06-A6C3C3102947}.Debug|x86.ActiveCfg = Debug|Any CPU + {7A55BE70-B47A-42C0-BB06-A6C3C3102947}.Debug|x86.Build.0 = Debug|Any CPU + {7A55BE70-B47A-42C0-BB06-A6C3C3102947}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7A55BE70-B47A-42C0-BB06-A6C3C3102947}.Release|Any CPU.Build.0 = Release|Any CPU + {7A55BE70-B47A-42C0-BB06-A6C3C3102947}.Release|x64.ActiveCfg = Release|Any CPU + {7A55BE70-B47A-42C0-BB06-A6C3C3102947}.Release|x64.Build.0 = Release|Any CPU + {7A55BE70-B47A-42C0-BB06-A6C3C3102947}.Release|x86.ActiveCfg = Release|Any CPU + {7A55BE70-B47A-42C0-BB06-A6C3C3102947}.Release|x86.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/src/api/dotnet/dotnet35/Properties/AssemblyInfo.cs b/src/api/dotnet/dotnet35/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..fb4319002 --- /dev/null +++ b/src/api/dotnet/dotnet35/Properties/AssemblyInfo.cs @@ -0,0 +1,38 @@ +using System; +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Security.Permissions; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("Z3 .NET Interface")] +[assembly: AssemblyDescription(".NET Interface to the Z3 Theorem Prover")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Microsoft Corporation")] +[assembly: AssemblyProduct("Z3")] +[assembly: AssemblyCopyright("Copyright (C) 2006-2015 Microsoft Corporation")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("4853ed71-2078-40f4-8117-bc46646bce0e")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("4.2.0.0")] +[assembly: AssemblyVersion("4.5.1.6031")] +[assembly: AssemblyFileVersion("4.5.1.6031")] diff --git a/src/api/dotnet/dotnet35/Properties/AssemblyInfo.cs.in b/src/api/dotnet/dotnet35/Properties/AssemblyInfo.cs.in new file mode 100644 index 000000000..e5a85f16f --- /dev/null +++ b/src/api/dotnet/dotnet35/Properties/AssemblyInfo.cs.in @@ -0,0 +1,38 @@ +using System; +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Security.Permissions; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("Z3 .NET Interface")] +[assembly: AssemblyDescription(".NET Interface to the Z3 Theorem Prover")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Microsoft Corporation")] +[assembly: AssemblyProduct("Z3")] +[assembly: AssemblyCopyright("Copyright (C) 2006-2015 Microsoft Corporation")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("4853ed71-2078-40f4-8117-bc46646bce0e")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("4.2.0.0")] +[assembly: AssemblyVersion("@VER_MAJOR@.@VER_MINOR@.@VER_BUILD@.@VER_REVISION@")] +[assembly: AssemblyFileVersion("@VER_MAJOR@.@VER_MINOR@.@VER_BUILD@.@VER_REVISION@")] diff --git a/src/api/dotnet/Readme.NET35 b/src/api/dotnet/dotnet35/Readme.NET35 similarity index 87% rename from src/api/dotnet/Readme.NET35 rename to src/api/dotnet/dotnet35/Readme.NET35 index 73743fd15..f8c2958ee 100644 --- a/src/api/dotnet/Readme.NET35 +++ b/src/api/dotnet/dotnet35/Readme.NET35 @@ -6,4 +6,5 @@ In the project properties of Microsoft.Z3.csproj: - Under 'Application': Change Target framework to .NET Framework 3.5 - Under 'Build': Add FRAMEWORK_LT_4 to the condidional compilation symbols - Remove the reference to System.Numerics -- Install the NuGet Package "Microsoft Code Contracts for Net3.5" +- Install the NuGet Package "Microsoft Code Contracts for Net3.5": + In the Package Manager Console enter Install-Package Code.Contract diff --git a/src/api/dotnet/dotnet35/packages.config b/src/api/dotnet/dotnet35/packages.config new file mode 100644 index 000000000..daa06aed7 --- /dev/null +++ b/src/api/dotnet/dotnet35/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file From 5c1ffe13d1de90ed04f142cfe10bc26634f37393 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Wed, 18 Jan 2017 13:06:28 +0000 Subject: [PATCH 491/536] x64 build fix for .NET 3.5 API --- src/api/dotnet/dotnet35/Example/App.config | 6 ++ .../dotnet/dotnet35/Example/Example.csproj | 78 +++++++++++++++++++ .../Example/Properties/AssemblyInfo.cs | 2 +- .../dotnet/dotnet35/Microsoft.Z3.NET35.csproj | 22 ++++++ .../dotnet/dotnet35/Microsoft.Z3.NET35.sln | 30 +++---- 5 files changed, 122 insertions(+), 16 deletions(-) create mode 100644 src/api/dotnet/dotnet35/Example/App.config create mode 100644 src/api/dotnet/dotnet35/Example/Example.csproj diff --git a/src/api/dotnet/dotnet35/Example/App.config b/src/api/dotnet/dotnet35/Example/App.config new file mode 100644 index 000000000..88fa4027b --- /dev/null +++ b/src/api/dotnet/dotnet35/Example/App.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/src/api/dotnet/dotnet35/Example/Example.csproj b/src/api/dotnet/dotnet35/Example/Example.csproj new file mode 100644 index 000000000..2b096ed40 --- /dev/null +++ b/src/api/dotnet/dotnet35/Example/Example.csproj @@ -0,0 +1,78 @@ + + + + + Debug + AnyCPU + {2A8E577B-7B6D-4CA9-832A-CA2EEC314812} + Exe + Properties + Example + Example + v4.5.2 + 512 + true + + + AnyCPU + true + full + false + bin\Debug\ + TRACE;DEBUG;FRAMEWORK_LT_4 + prompt + 4 + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE;FRAMEWORK_LT_4 + prompt + 4 + + + true + bin\x64\Debug\ + TRACE;DEBUG;FRAMEWORK_LT_4 + full + x64 + prompt + MinimumRecommendedRules.ruleset + true + + + bin\x64\Release\ + TRACE;FRAMEWORK_LT_4 + true + pdbonly + x64 + prompt + MinimumRecommendedRules.ruleset + true + + + + Program.cs + + + + + + + + + {ec3db697-b734-42f7-9468-5b62821eeb5a} + Microsoft.Z3.NET35 + + + + + \ No newline at end of file diff --git a/src/api/dotnet/dotnet35/Example/Properties/AssemblyInfo.cs b/src/api/dotnet/dotnet35/Example/Properties/AssemblyInfo.cs index ef95285e0..ed0d8454f 100644 --- a/src/api/dotnet/dotnet35/Example/Properties/AssemblyInfo.cs +++ b/src/api/dotnet/dotnet35/Example/Properties/AssemblyInfo.cs @@ -20,7 +20,7 @@ using System.Runtime.InteropServices; [assembly: ComVisible(false)] // The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("7a55be70-b47a-42c0-bb06-a6c3c3102947")] +[assembly: Guid("2a8e577b-7b6d-4ca9-832a-ca2eec314812")] // Version information for an assembly consists of the following four values: // diff --git a/src/api/dotnet/dotnet35/Microsoft.Z3.NET35.csproj b/src/api/dotnet/dotnet35/Microsoft.Z3.NET35.csproj index 7eaf16fd4..d278b4f1d 100644 --- a/src/api/dotnet/dotnet35/Microsoft.Z3.NET35.csproj +++ b/src/api/dotnet/dotnet35/Microsoft.Z3.NET35.csproj @@ -82,6 +82,28 @@ false + + true + bin\x64\Debug\ + TRACE;DEBUG;FRAMEWORK_LT_4 + true + Debug\Microsoft.Z3.XML + full + x64 + prompt + MinimumRecommendedRules.ruleset + + + bin\x64\Release\ + FRAMEWORK_LT_4 + true + Release\Microsoft.Z3.xml + true + pdbonly + x64 + prompt + MinimumRecommendedRules.ruleset + packages\Code.Contract.1.0.0\lib\net35\Microsoft.Contracts.dll diff --git a/src/api/dotnet/dotnet35/Microsoft.Z3.NET35.sln b/src/api/dotnet/dotnet35/Microsoft.Z3.NET35.sln index c71a920a2..b6e252684 100644 --- a/src/api/dotnet/dotnet35/Microsoft.Z3.NET35.sln +++ b/src/api/dotnet/dotnet35/Microsoft.Z3.NET35.sln @@ -5,7 +5,7 @@ VisualStudioVersion = 14.0.25420.1 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Z3.NET35", "Microsoft.Z3.NET35.csproj", "{EC3DB697-B734-42F7-9468-5B62821EEB5A}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Example", "Example\Example.csproj", "{7A55BE70-B47A-42C0-BB06-A6C3C3102947}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Example", "Example\Example.csproj", "{2A8E577B-7B6D-4CA9-832A-CA2EEC314812}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -25,22 +25,22 @@ Global {EC3DB697-B734-42F7-9468-5B62821EEB5A}.Debug|x86.Build.0 = Debug|Any CPU {EC3DB697-B734-42F7-9468-5B62821EEB5A}.Release|Any CPU.ActiveCfg = Release|Any CPU {EC3DB697-B734-42F7-9468-5B62821EEB5A}.Release|Any CPU.Build.0 = Release|Any CPU - {EC3DB697-B734-42F7-9468-5B62821EEB5A}.Release|x64.ActiveCfg = Release|Any CPU - {EC3DB697-B734-42F7-9468-5B62821EEB5A}.Release|x64.Build.0 = Release|Any CPU + {EC3DB697-B734-42F7-9468-5B62821EEB5A}.Release|x64.ActiveCfg = Release|x64 + {EC3DB697-B734-42F7-9468-5B62821EEB5A}.Release|x64.Build.0 = Release|x64 {EC3DB697-B734-42F7-9468-5B62821EEB5A}.Release|x86.ActiveCfg = Release|Any CPU {EC3DB697-B734-42F7-9468-5B62821EEB5A}.Release|x86.Build.0 = Release|Any CPU - {7A55BE70-B47A-42C0-BB06-A6C3C3102947}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {7A55BE70-B47A-42C0-BB06-A6C3C3102947}.Debug|Any CPU.Build.0 = Debug|Any CPU - {7A55BE70-B47A-42C0-BB06-A6C3C3102947}.Debug|x64.ActiveCfg = Debug|Any CPU - {7A55BE70-B47A-42C0-BB06-A6C3C3102947}.Debug|x64.Build.0 = Debug|Any CPU - {7A55BE70-B47A-42C0-BB06-A6C3C3102947}.Debug|x86.ActiveCfg = Debug|Any CPU - {7A55BE70-B47A-42C0-BB06-A6C3C3102947}.Debug|x86.Build.0 = Debug|Any CPU - {7A55BE70-B47A-42C0-BB06-A6C3C3102947}.Release|Any CPU.ActiveCfg = Release|Any CPU - {7A55BE70-B47A-42C0-BB06-A6C3C3102947}.Release|Any CPU.Build.0 = Release|Any CPU - {7A55BE70-B47A-42C0-BB06-A6C3C3102947}.Release|x64.ActiveCfg = Release|Any CPU - {7A55BE70-B47A-42C0-BB06-A6C3C3102947}.Release|x64.Build.0 = Release|Any CPU - {7A55BE70-B47A-42C0-BB06-A6C3C3102947}.Release|x86.ActiveCfg = Release|Any CPU - {7A55BE70-B47A-42C0-BB06-A6C3C3102947}.Release|x86.Build.0 = Release|Any CPU + {2A8E577B-7B6D-4CA9-832A-CA2EEC314812}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2A8E577B-7B6D-4CA9-832A-CA2EEC314812}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2A8E577B-7B6D-4CA9-832A-CA2EEC314812}.Debug|x64.ActiveCfg = Debug|Any CPU + {2A8E577B-7B6D-4CA9-832A-CA2EEC314812}.Debug|x64.Build.0 = Debug|Any CPU + {2A8E577B-7B6D-4CA9-832A-CA2EEC314812}.Debug|x86.ActiveCfg = Debug|Any CPU + {2A8E577B-7B6D-4CA9-832A-CA2EEC314812}.Debug|x86.Build.0 = Debug|Any CPU + {2A8E577B-7B6D-4CA9-832A-CA2EEC314812}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2A8E577B-7B6D-4CA9-832A-CA2EEC314812}.Release|Any CPU.Build.0 = Release|Any CPU + {2A8E577B-7B6D-4CA9-832A-CA2EEC314812}.Release|x64.ActiveCfg = Release|x64 + {2A8E577B-7B6D-4CA9-832A-CA2EEC314812}.Release|x64.Build.0 = Release|x64 + {2A8E577B-7B6D-4CA9-832A-CA2EEC314812}.Release|x86.ActiveCfg = Release|Any CPU + {2A8E577B-7B6D-4CA9-832A-CA2EEC314812}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE From 43d083bafb58aac211f3dad151c2ad7da91e1d30 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Thu, 19 Jan 2017 11:19:29 +0000 Subject: [PATCH 492/536] Windows build fix. --- scripts/mk_win_dist.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/mk_win_dist.py b/scripts/mk_win_dist.py index 11048650f..66f44426f 100644 --- a/scripts/mk_win_dist.py +++ b/scripts/mk_win_dist.py @@ -241,8 +241,8 @@ def mk_zip(x64): # Create a zip file for each platform def mk_zips(): - mk_zip_core(False) - mk_zip_core(True) + mk_zip(False) + mk_zip(True) VS_RUNTIME_PATS = [re.compile('vcomp.*\.dll'), From e23509797a81c2730b066ea85330b1411e409324 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 19 Jan 2017 19:28:20 -0800 Subject: [PATCH 493/536] access parameters from Python API Signed-off-by: Nikolaj Bjorner --- src/api/python/z3/z3.py | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index 01dacace7..a6f91a0a2 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -691,6 +691,30 @@ class FuncDeclRef(AstRef): """ return Z3_get_decl_kind(self.ctx_ref(), self.ast) + def params(self): + ctx = self.ctx + n = Z3_get_decl_num_parameters(self.ctx_ref(), self.ast) + result = [ None for i in range(n) ] + for i in range(n): + k = Z3_get_decl_parameter_kind(self.ctx_ref(), self.ast, i) + if k == Z3_PARAMETER_INT: + result[i] = Z3_get_decl_int_parameter(self.ctx_ref(), self.ast, i) + elif k == Z3_PARAMETER_DOUBLE: + result[i] = Z3_get_decl_double_parameter(self.ctx_ref(), self.ast, i) + elif k == Z3_PARAMETER_RATIONAL: + result[i] = Z3_get_decl_rational_parameter(self.ctx_ref(), self.ast, i) + elif k == Z3_PARAMETER_SYMBOL: + result[i] = Z3_get_decl_symbol_parameter(self.ctx_ref(), self.ast, i) + elif k == Z3_PARAMETER_SORT: + result[i] = SortRef(Z3_get_decl_sort_parameter(self.ctx_ref(), self.ast, i), ctx) + elif k == Z3_PARAMETER_AST: + result[i] = ExprRef(Z3_get_decl_ast_parameter(self.ctx_ref(), self.ast, i), ctx) + elif k == Z3_PARAMETER_FUNC_DECL: + result[i] = FuncDeclRef(Z3_get_decl_func_decl_parameter(self.ctx_ref(), self.ast, i), ctx) + else: + assert(False) + return result + def __call__(self, *args): """Create a Z3 application expression using the function `self`, and the given arguments. @@ -2637,6 +2661,13 @@ class RatNumRef(ArithRef): """ return self.denominator().as_long() + def is_int(self): + return self.denominator().is_int() and self.denominator_as_long() == 1 + + def as_long(self): + _z3_assert(self.is_int(), "Expected integer fraction") + return self.numerator_as_long() + def as_decimal(self, prec): """ Return a Z3 rational value as a string in decimal notation using at most `prec` decimal places. From adf8072eaacea187a60ff3690a6b0aaa12b586af Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Sat, 21 Jan 2017 12:28:37 +0000 Subject: [PATCH 494/536] Added option to limit the distance of unsat core extension through patterns. --- src/smt/params/smt_params_helper.pyg | 3 ++- src/smt/smt_solver.cpp | 11 ++++++++--- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/smt/params/smt_params_helper.pyg b/src/smt/params/smt_params_helper.pyg index 178b2117f..a3f163ed4 100644 --- a/src/smt/params/smt_params_helper.pyg +++ b/src/smt/params/smt_params_helper.pyg @@ -63,5 +63,6 @@ def_module_params(module_name='smt', ('dack.threshold', UINT, 10, ' number of times the congruence rule must be used before Leibniz\'s axiom is expanded'), ('core.validate', BOOL, False, 'validate unsat core produced by SMT context'), ('core.minimize', BOOL, False, 'minimize unsat core produced by SMT context'), - ('core.extend_patterns', BOOL, False, 'extend unsat core with literals that trigger (potential) quantifier instances') + ('core.extend_patterns', BOOL, False, 'extend unsat core with literals that trigger (potential) quantifier instances'), + ('core.extend_patterns.max_distance', UINT, UINT_MAX, 'limits the distance of a pattern-extended unsat core') )) diff --git a/src/smt/smt_solver.cpp b/src/smt/smt_solver.cpp index f80ff09f4..ab6be5d91 100644 --- a/src/smt/smt_solver.cpp +++ b/src/smt/smt_solver.cpp @@ -37,6 +37,7 @@ namespace smt { symbol m_logic; bool m_minimizing_core; bool m_core_extend_patterns; + unsigned m_core_extend_patterns_max_distance; obj_map m_name2assertion; public: @@ -46,12 +47,14 @@ namespace smt { m_params(p), m_context(m, m_smt_params), m_minimizing_core(false), - m_core_extend_patterns(false) { + m_core_extend_patterns(false), + m_core_extend_patterns_max_distance(UINT_MAX) { m_logic = l; if (m_logic != symbol::null) m_context.set_logic(m_logic); smt_params_helper smth(p); m_core_extend_patterns = smth.core_extend_patterns(); + m_core_extend_patterns_max_distance = smth.core_extend_patterns_max_distance(); } virtual solver * translate(ast_manager & m, params_ref const & p) { @@ -283,7 +286,7 @@ namespace smt { func_decl_set pattern_fds; vector assrtn_fds; - do { + for (unsigned d = 0; d < m_core_extend_patterns_max_distance; d++) { new_core_literals.reset(); unsigned sz = core.size(); @@ -308,8 +311,10 @@ namespace smt { } core.append(new_core_literals.size(), new_core_literals.c_ptr()); + + if (new_core_literals.empty()) + break; } - while (!new_core_literals.empty()); } }; }; From 4ec4abd7e38a2a5a1794ddd6a51a8a7b10a2feab Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 23 Jan 2017 13:31:43 -0800 Subject: [PATCH 495/536] fix test for int-value Signed-off-by: Nikolaj Bjorner --- src/api/python/z3/z3.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index a6f91a0a2..c54cd6091 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -2394,7 +2394,7 @@ def is_int_value(a): >>> is_int_value(RealVal(1)) False """ - return is_arith(a) and a.is_int() and _is_numeral(a.ctx, a.as_ast()) + return isinstance(a, IntNumRef) def is_rational_value(a): """Return `True` if `a` is rational value of sort Real. From 60783e5696e4a741e7ff4aaeb4eb979d3c4bd77c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 25 Jan 2017 13:26:58 -0800 Subject: [PATCH 496/536] fix regression for z3num Signed-off-by: Nikolaj Bjorner --- src/api/python/z3/z3.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index c54cd6091..77b74336e 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -2394,7 +2394,7 @@ def is_int_value(a): >>> is_int_value(RealVal(1)) False """ - return isinstance(a, IntNumRef) + return is_arith(a) and a.is_int() and _is_numeral(a.ctx, a.as_ast()) def is_rational_value(a): """Return `True` if `a` is rational value of sort Real. @@ -2662,6 +2662,12 @@ class RatNumRef(ArithRef): return self.denominator().as_long() def is_int(self): + return False + + def is_real(self): + return True + + def is_int_value(self): return self.denominator().is_int() and self.denominator_as_long() == 1 def as_long(self): From 4782e19086d751147a7cfc654846ac455c0a7d15 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 25 Jan 2017 16:21:51 -0800 Subject: [PATCH 497/536] fix bug in sat-simplifier decreasing heap values of variables that are not in the heap Signed-off-by: Nikolaj Bjorner --- src/sat/sat_simplifier.cpp | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/src/sat/sat_simplifier.cpp b/src/sat/sat_simplifier.cpp index c42572f1e..62fb99a11 100644 --- a/src/sat/sat_simplifier.cpp +++ b/src/sat/sat_simplifier.cpp @@ -896,7 +896,7 @@ namespace sat { unsigned idx = l.index(); if (m_queue.contains(idx)) m_queue.decreased(idx); - else + else m_queue.insert(idx); } literal next() { SASSERT(!empty()); return to_literal(m_queue.erase_min()); } @@ -918,16 +918,19 @@ namespace sat { } void insert(literal l) { - bool_var v = l.var(); - if (s.is_external(v) || s.was_eliminated(v)) - return; m_queue.insert(l); } + bool process_var(bool_var v) { + return !s.is_external(v) && !s.was_eliminated(v); + } + void operator()(unsigned num_vars) { for (bool_var v = 0; v < num_vars; v++) { - insert(literal(v, false)); - insert(literal(v, true)); + if (process_var(v)) { + insert(literal(v, false)); + insert(literal(v, true)); + } } while (!m_queue.empty()) { s.checkpoint(); @@ -941,9 +944,9 @@ namespace sat { void process(literal l) { TRACE("blocked_clause", tout << "processing: " << l << "\n";); model_converter::entry * new_entry = 0; - if (s.is_external(l.var()) || s.was_eliminated(l.var())) + if (!process_var(l.var())) { return; - + } { m_to_remove.reset(); { @@ -963,8 +966,10 @@ namespace sat { mc.insert(*new_entry, c); unsigned sz = c.size(); for (unsigned i = 0; i < sz; i++) { - if (c[i] != l) - m_queue.decreased(~c[i]); + literal lit = c[i]; + if (lit != l && process_var(lit.var())) { + m_queue.decreased(~lit); + } } } s.unmark_all(c); From 777091e653f0674a81e374634da9e3195ef50cd1 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 25 Jan 2017 18:09:27 -0800 Subject: [PATCH 498/536] fix part 1 of #875 Signed-off-by: Nikolaj Bjorner --- src/smt/smt_context.cpp | 2 ++ src/smt/theory_seq.cpp | 28 +++++++++++++++------------- 2 files changed, 17 insertions(+), 13 deletions(-) diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index c7aecca88..3c88a75a2 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -2031,11 +2031,13 @@ namespace smt { v.shrink(old_size); } +#if 0 void context::mark_as_deleted(clause * cls) { SASSERT(!cls->deleted()); remove_cls_occs(cls); cls->mark_as_deleted(m_manager); } +#endif /** \brief Undo variable assignments. diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index ed95ef8d7..cdea02c48 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -2958,22 +2958,19 @@ void theory_seq::tightest_prefix(expr* s, expr* x) { let i = Index(t, s, offset): offset >= len(t) => i = -1 - - offset fixed to 0: - len(t) != 0 & !contains(t, s) => i = -1 - len(t) != 0 & contains(t, s) => t = xsy & i = len(x) + + + offset = 0 & len(t) != 0 & contains(t, s) => t = xsy & i = len(x) tightest_prefix(x, s) - offset not fixed: 0 <= offset < len(t) => xy = t & len(x) = offset & (-1 = indexof(y, s, 0) => -1 = i) & (indexof(y, s, 0) >= 0 => indexof(t, s, 0) + offset = i) - if offset < 0 - under specified + offset < 0 => i = -1 optional lemmas: (len(s) > len(t) -> i = -1) @@ -2987,17 +2984,19 @@ void theory_seq::add_indexof_axiom(expr* i) { expr_ref minus_one(m_autil.mk_int(-1), m); expr_ref zero(m_autil.mk_int(0), m); expr_ref xsy(m); + + literal cnt = mk_literal(m_util.str.mk_contains(t, s)); + literal i_eq_m1 = mk_eq(i, minus_one, false); + add_axiom(cnt, i_eq_m1); + literal s_eq_empty = mk_eq_empty(s); + add_axiom(~s_eq_empty, mk_eq(i, zero, false)); + add_axiom(s_eq_empty, ~mk_eq_empty(t), i_eq_m1); if (!offset || (m_autil.is_numeral(offset, r) && r.is_zero())) { expr_ref x = mk_skolem(m_indexof_left, t, s); expr_ref y = mk_skolem(m_indexof_right, t, s); xsy = mk_concat(x, s, y); expr_ref lenx(m_util.str.mk_length(x), m); - literal cnt = mk_literal(m_util.str.mk_contains(t, s)); - literal s_eq_empty = mk_eq_empty(s); - add_axiom(cnt, mk_eq(i, minus_one, false)); - add_axiom(~s_eq_empty, mk_eq(i, zero, false)); - add_axiom(s_eq_empty, ~mk_eq_empty(t), mk_eq(i, minus_one, false)); add_axiom(~cnt, s_eq_empty, mk_seq_eq(t, xsy)); add_axiom(~cnt, s_eq_empty, mk_eq(i, lenx, false)); tightest_prefix(s, x); @@ -3024,10 +3023,13 @@ void theory_seq::add_indexof_axiom(expr* i) { add_axiom(~offset_ge_0, offset_ge_len, mk_seq_eq(t, mk_concat(x, y))); add_axiom(~offset_ge_0, offset_ge_len, mk_eq(m_util.str.mk_length(x), offset, false)); add_axiom(~offset_ge_0, offset_ge_len, - ~mk_eq(indexof0, minus_one, false), mk_eq(i, minus_one, false)); + ~mk_eq(indexof0, minus_one, false), i_eq_m1); add_axiom(~offset_ge_0, offset_ge_len, ~mk_literal(m_autil.mk_ge(indexof0, zero)), mk_eq(offset_p_indexof0, i, false)); + + // offset < 0 => -1 = i + add_axiom(offset_ge_0, i_eq_m1); } } From 7386e2f3e942b025d8266323dc299055a7dd1efa Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 25 Jan 2017 18:29:30 -0800 Subject: [PATCH 499/536] add warning for scearios of #876 Signed-off-by: Nikolaj Bjorner --- src/smt/theory_seq.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index cdea02c48..3e1436aa6 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -3819,6 +3819,15 @@ void theory_seq::new_eq_eh(dependency* deps, enode* n1, enode* n2) { solve_eqs(m_eqs.size()-1); enforce_length_coherence(n1, n2); } + else if (n1 != n2 && m_util.is_re(n1->get_owner())) { + warning_msg("equality between regular expressions is not yet supported"); + eautomaton* a1 = get_automaton(n1->get_owner()); + eautomaton* a2 = get_automaton(n2->get_owner()); + // eautomaton* b1 = mk_difference(*a1, *a2); + // eautomaton* b2 = mk_difference(*a2, *a1); + // eautomaton* c = mk_union(*b1, *b2); + // then some emptiness check. + } } void theory_seq::new_diseq_eh(theory_var v1, theory_var v2) { From a0a81fc2d7c46283c2a37b3ffdf923701a3484dd Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 26 Jan 2017 08:37:37 -0800 Subject: [PATCH 500/536] add format #879 Signed-off-by: Nikolaj Bjorner --- scripts/update_api.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/update_api.py b/scripts/update_api.py index 031b39c75..38b6213c1 100755 --- a/scripts/update_api.py +++ b/scripts/update_api.py @@ -942,7 +942,7 @@ def def_API(name, result, params): log_c.write(" Au(a%s);\n" % sz) exe_c.write("in.get_int_array(%s)" % i) else: - error ("unsupported parameter for %s, %s" % (ty, name, p)) + error ("unsupported parameter for %s, %s, %s" % (ty, name, p)) elif kind == OUT_ARRAY: sz = param_array_capacity_pos(p) sz_p = params[sz] From 962979b09c991fc47a02e10afb07d68a353308ff Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 26 Jan 2017 13:28:40 -0800 Subject: [PATCH 501/536] rework sat.mus to use restart count for bounded minimization Signed-off-by: Nikolaj Bjorner --- src/sat/sat_mus.cpp | 59 +++++++++++++++++--------------------------- src/sat/sat_mus.h | 3 +-- src/sat/sat_solver.h | 1 + 3 files changed, 24 insertions(+), 39 deletions(-) diff --git a/src/sat/sat_mus.cpp b/src/sat/sat_mus.cpp index 380b8ee94..06851d10d 100644 --- a/src/sat/sat_mus.cpp +++ b/src/sat/sat_mus.cpp @@ -23,7 +23,7 @@ Notes: namespace sat { - mus::mus(solver& s):s(s), m_is_active(false),m_restart(0), m_max_restarts(0) {} + mus::mus(solver& s):s(s), m_is_active(false), m_max_num_restarts(UINT_MAX) {} mus::~mus() {} @@ -31,8 +31,6 @@ namespace sat { m_core.reset(); m_mus.reset(); m_model.reset(); - m_max_restarts = (s.m_stats.m_restart - m_restart) + 10; - m_restart = s.m_stats.m_restart; } void mus::set_core() { @@ -49,12 +47,12 @@ namespace sat { } lbool mus::operator()() { + m_max_num_restarts = s.m_config.m_core_minimize_partial ? s.num_restarts() + 10 : UINT_MAX; flet _disable_min(s.m_config.m_core_minimize, false); flet _is_active(m_is_active, true); - IF_VERBOSE(3, verbose_stream() << "(sat.mus " << s.get_core() << ")\n";); + IF_VERBOSE(3, verbose_stream() << "(sat.mus size: " << s.get_core().size() << " core: [" << s.get_core() << "])\n";); reset(); lbool r = mus1(); - m_restart = s.m_stats.m_restart; return r; } @@ -63,13 +61,13 @@ namespace sat { TRACE("sat", tout << "old core: " << s.get_core() << "\n";); literal_vector& core = get_core(); literal_vector& mus = m_mus; - if (core.size() > 64) { + if (!minimize_partial && core.size() > 64) { return mus2(); } - unsigned delta_time = 0; - unsigned core_miss = 0; while (!core.empty()) { - IF_VERBOSE(3, verbose_stream() << "(opt.mus reducing core: " << core.size() << " mus: " << mus.size() << ")\n";); + IF_VERBOSE(1, verbose_stream() << "(sat.mus num-to-process: " << core.size() << " mus: " << mus.size(); + if (minimize_partial) verbose_stream() << " max-restarts: " << m_max_num_restarts; + verbose_stream() << ")\n";); TRACE("sat", tout << "core: " << core << "\n"; tout << "mus: " << mus << "\n";); @@ -78,34 +76,35 @@ namespace sat { set_core(); return l_undef; } - if (minimize_partial && 3*delta_time > core.size() && core.size() < mus.size()) { - break; - } unsigned num_literals = core.size() + mus.size(); if (num_literals <= 2) { // IF_VERBOSE(0, verbose_stream() << "num literals: " << core << " " << mus << "\n";); break; } - if (s.m_config.m_core_minimize_partial && s.m_stats.m_restart - m_restart > m_max_restarts) { - IF_VERBOSE(1, verbose_stream() << "(sat restart budget exceeded)\n";); - set_core(); - return l_true; - } literal lit = core.back(); core.pop_back(); lbool is_sat; { + flet _restart_bound(s.m_config.m_restart_max, m_max_num_restarts); scoped_append _sa(mus, core); mus.push_back(~lit); is_sat = s.check(mus.size(), mus.c_ptr()); TRACE("sat", tout << "mus: " << mus << "\n";); } + IF_VERBOSE(1, verbose_stream() << "(sat.mus " << is_sat << ")\n";); switch (is_sat) { case l_undef: - core.push_back(lit); - set_core(); - return l_undef; + if (!s.canceled()) { + // treat restart max as sat, so literal is in the mus + mus.push_back(lit); + } + else { + core.push_back(lit); + set_core(); + return l_undef; + } + break; case l_true: { SASSERT(value_at(lit, s.get_model()) == l_false); mus.push_back(lit); @@ -115,11 +114,9 @@ namespace sat { case l_false: literal_vector const& new_core = s.get_core(); if (new_core.contains(~lit)) { - IF_VERBOSE(3, verbose_stream() << "miss core " << lit << "\n";); - ++core_miss; + IF_VERBOSE(3, verbose_stream() << "(sat.mus unit reduction, literal is in both cores " << lit << ")\n";); } else { - core_miss = 0; TRACE("sat", tout << "core: " << new_core << " mus: " << mus << "\n";); core.reset(); for (unsigned i = 0; i < new_core.size(); ++i) { @@ -131,14 +128,6 @@ namespace sat { } break; } - - unsigned new_num_literals = core.size() + mus.size(); - if (new_num_literals == num_literals) { - delta_time++; - } - else { - delta_time = 0; - } } set_core(); IF_VERBOSE(3, verbose_stream() << "(sat.mus.new " << s.m_core << ")\n";); @@ -159,13 +148,9 @@ namespace sat { lbool mus::qx(literal_set& assignment, literal_set& support, bool has_support) { lbool is_sat = l_true; - if (s.m_config.m_core_minimize_partial && s.m_stats.m_restart - m_restart > m_max_restarts) { - IF_VERBOSE(1, verbose_stream() << "(sat restart budget exceeded)\n";); - return l_true; - } if (has_support) { scoped_append _sa(m_mus, support.to_vector()); - is_sat = s.check(m_mus.size(), m_mus.c_ptr()); + is_sat = s.check(m_mus.size(), m_mus.c_ptr()); switch (is_sat) { case l_false: { literal_set core(s.get_core()); @@ -173,7 +158,7 @@ namespace sat { assignment.reset(); return l_true; } - case l_undef: + case l_undef: return l_undef; case l_true: update_model(); diff --git a/src/sat/sat_mus.h b/src/sat/sat_mus.h index 74f6d75f0..946f66ed6 100644 --- a/src/sat/sat_mus.h +++ b/src/sat/sat_mus.h @@ -26,8 +26,7 @@ namespace sat { literal_vector m_mus; bool m_is_active; model m_model; // model obtained during minimal unsat core - unsigned m_restart; - unsigned m_max_restarts; + unsigned m_max_num_restarts; public: diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index dcf7e2acb..aa7e6edea 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -209,6 +209,7 @@ namespace sat { bool inconsistent() const { return m_inconsistent; } unsigned num_vars() const { return m_level.size(); } unsigned num_clauses() const; + unsigned num_restarts() const { return m_restarts; } bool is_external(bool_var v) const { return m_external[v] != 0; } bool was_eliminated(bool_var v) const { return m_eliminated[v] != 0; } unsigned scope_lvl() const { return m_scope_lvl; } From b70f1f0319a0d7f607f3f752e21a4957ee020645 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 27 Jan 2017 09:47:18 -0800 Subject: [PATCH 502/536] fix overflow exposed in #880 Signed-off-by: Nikolaj Bjorner --- src/smt/smt_solver.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/smt/smt_solver.cpp b/src/smt/smt_solver.cpp index ab6be5d91..59a5ddf8f 100644 --- a/src/smt/smt_solver.cpp +++ b/src/smt/smt_solver.cpp @@ -122,7 +122,8 @@ namespace smt { SASSERT(n <= lvl); unsigned new_lvl = lvl - n; unsigned old_sz = m_scopes[new_lvl]; - for (unsigned i = cur_sz - 1; i >= old_sz; i--) { + for (unsigned i = cur_sz; i > old_sz; ) { + --i; expr * key = m_assumptions[i].get(); SASSERT(m_name2assertion.contains(key)); expr * value = m_name2assertion.find(key); From 5796e150886e7479c5e35261cd4cda12b0593af9 Mon Sep 17 00:00:00 2001 From: Doug Woos Date: Fri, 27 Jan 2017 11:06:14 -0800 Subject: [PATCH 503/536] Thread labels through tactic system --- src/cmd_context/tactic_cmds.cpp | 21 ++++++++++++-- src/smt/tactic/smt_tactic.cpp | 8 ++++-- src/solver/tactic2solver.cpp | 3 +- src/tactic/filter_model_converter.cpp | 3 ++ src/tactic/filter_model_converter.h | 2 ++ src/tactic/model_converter.cpp | 40 ++++++++++++++++++++++++++- src/tactic/model_converter.h | 4 +++ src/tactic/tactic.cpp | 8 ++++-- src/tactic/tactic.h | 2 +- 9 files changed, 82 insertions(+), 9 deletions(-) diff --git a/src/cmd_context/tactic_cmds.cpp b/src/cmd_context/tactic_cmds.cpp index 86900e175..158f361dd 100644 --- a/src/cmd_context/tactic_cmds.cpp +++ b/src/cmd_context/tactic_cmds.cpp @@ -165,7 +165,23 @@ public: } }; -typedef simple_check_sat_result check_sat_tactic_result; +struct check_sat_tactic_result : public simple_check_sat_result { +public: + svector labels; + + check_sat_tactic_result(ast_manager & m) : simple_check_sat_result(m) { + } + + virtual void get_labels(svector & r) { + r.append(labels); + } + + virtual void add_labels(svector & r) { + labels.append(r); + } +}; + +typedef svector & labels_ref; class check_sat_using_tactict_cmd : public exec_given_tactic_cmd { public: @@ -189,6 +205,7 @@ public: ast_manager & m = ctx.m(); unsigned timeout = p.get_uint("timeout", ctx.params().m_timeout); unsigned rlimit = p.get_uint("rlimit", ctx.params().m_rlimit); + svector labels; goal_ref g = alloc(goal, m, ctx.produce_proofs(), ctx.produce_models(), ctx.produce_unsat_cores()); assert_exprs_from(ctx, *g); TRACE("check_sat_using", g->display(tout);); @@ -208,7 +225,7 @@ public: cmd_context::scoped_watch sw(ctx); lbool r = l_undef; try { - r = check_sat(t, g, md, pr, core, reason_unknown); + r = check_sat(t, g, md, result->labels, pr, core, reason_unknown); ctx.display_sat_result(r); result->set_status(r); if (r == l_undef) { diff --git a/src/smt/tactic/smt_tactic.cpp b/src/smt/tactic/smt_tactic.cpp index f2fbcf6d9..d9e6da303 100644 --- a/src/smt/tactic/smt_tactic.cpp +++ b/src/smt/tactic/smt_tactic.cpp @@ -256,7 +256,9 @@ public: if (in->models_enabled()) { model_ref md; m_ctx->get_model(md); - mc = model2model_converter(md.get()); + buffer r; + m_ctx->get_relevant_labels(0, r); + mc = model_and_labels2model_converter(md.get(), r); mc = concat(fmc.get(), mc.get()); } pc = 0; @@ -308,7 +310,9 @@ public: if (in->models_enabled()) { model_ref md; m_ctx->get_model(md); - mc = model2model_converter(md.get()); + buffer r; + m_ctx->get_relevant_labels(0, r); + mc = model_and_labels2model_converter(md.get(), r); } pc = 0; core = 0; diff --git a/src/solver/tactic2solver.cpp b/src/solver/tactic2solver.cpp index f53301948..586d59d4f 100644 --- a/src/solver/tactic2solver.cpp +++ b/src/solver/tactic2solver.cpp @@ -144,8 +144,9 @@ lbool tactic2solver::check_sat_core(unsigned num_assumptions, expr * const * ass proof_ref pr(m); expr_dependency_ref core(m); std::string reason_unknown = "unknown"; + svector labels; try { - switch (::check_sat(*m_tactic, g, md, pr, core, reason_unknown)) { + switch (::check_sat(*m_tactic, g, md, labels, pr, core, reason_unknown)) { case l_true: m_result->set_status(l_true); break; diff --git a/src/tactic/filter_model_converter.cpp b/src/tactic/filter_model_converter.cpp index ba6ee4f0d..247f2e91d 100644 --- a/src/tactic/filter_model_converter.cpp +++ b/src/tactic/filter_model_converter.cpp @@ -51,6 +51,9 @@ void filter_model_converter::operator()(model_ref & old_model, unsigned goal_idx TRACE("filter_mc", tout << "after filter_model_converter\n"; model_v2_pp(tout, *old_model);); } +void filter_model_converter::operator()(svector & labels, unsigned goal_idx) { +} + void filter_model_converter::display(std::ostream & out) { out << "(filter-model-converter"; for (unsigned i = 0; i < m_decls.size(); i++) { diff --git a/src/tactic/filter_model_converter.h b/src/tactic/filter_model_converter.h index 6fc8fdd77..0b67a6c5a 100644 --- a/src/tactic/filter_model_converter.h +++ b/src/tactic/filter_model_converter.h @@ -32,6 +32,8 @@ public: virtual void operator()(model_ref & md, unsigned goal_idx); + virtual void operator()(svector & labels, unsigned goal_idx); + virtual void operator()(model_ref & md) { operator()(md, 0); } // TODO: delete virtual void cancel() {} diff --git a/src/tactic/model_converter.cpp b/src/tactic/model_converter.cpp index 7ac3e898a..061d12afa 100644 --- a/src/tactic/model_converter.cpp +++ b/src/tactic/model_converter.cpp @@ -33,6 +33,12 @@ public: this->m_c1->operator()(m, 0); } + virtual void operator()(svector & r, unsigned goal_idx) { + this->m_c2->operator()(r, goal_idx); + this->m_c1->operator()(r, 0); + } + + virtual char const * get_name() const { return "concat-model-converter"; } virtual model_converter * translate(ast_translation & translator) { @@ -76,6 +82,24 @@ public: } UNREACHABLE(); } + + virtual void operator()(svector & r, unsigned goal_idx) { + unsigned num = this->m_c2s.size(); + for (unsigned i = 0; i < num; i++) { + if (goal_idx < this->m_szs[i]) { + // found the model converter that should be used + model_converter * c2 = this->m_c2s[i]; + if (c2) + c2->operator()(r, goal_idx); + if (m_c1) + this->m_c1->operator()(r, i); + return; + } + // invalid goal + goal_idx -= this->m_szs[i]; + } + UNREACHABLE(); + } virtual char const * get_name() const { return "concat-star-model-converter"; } @@ -102,8 +126,12 @@ model_converter * concat(model_converter * mc1, unsigned num, model_converter * class model2mc : public model_converter { model_ref m_model; + buffer m_labels; public: model2mc(model * m):m_model(m) {} + + model2mc(model * m, buffer r):m_model(m), m_labels(r) {} + virtual ~model2mc() {} virtual void operator()(model_ref & m) { @@ -114,7 +142,11 @@ public: m = m_model; } - virtual void cancel() { + virtual void operator()(svector & r, unsigned goal_idx) { + r.append(m_labels.size(), m_labels.c_ptr()); + } + + virtual void cancel() { } virtual void display(std::ostream & out) { @@ -135,6 +167,12 @@ model_converter * model2model_converter(model * m) { return alloc(model2mc, m); } +model_converter * model_and_labels2model_converter(model * m, buffer & r) { + if (m == 0) + return 0; + return alloc(model2mc, m, r); +} + void model_converter2model(ast_manager & mng, model_converter * mc, model_ref & m) { if (mc) { m = alloc(model, mng); diff --git a/src/tactic/model_converter.h b/src/tactic/model_converter.h index 00c50a15f..4395fc546 100644 --- a/src/tactic/model_converter.h +++ b/src/tactic/model_converter.h @@ -32,6 +32,8 @@ public: SASSERT(goal_idx == 0); operator()(m); } + + virtual void operator()(svector & r, unsigned goal_idx) {} virtual model_converter * translate(ast_translation & translator) = 0; }; @@ -49,6 +51,8 @@ model_converter * concat(model_converter * mc1, unsigned num, model_converter * model_converter * model2model_converter(model * m); +model_converter * model_and_labels2model_converter(model * m, buffer &r); + void model_converter2model(ast_manager & mng, model_converter * mc, model_ref & m); void apply(model_converter_ref & mc, model_ref & m, unsigned gidx); diff --git a/src/tactic/tactic.cpp b/src/tactic/tactic.cpp index 92e916d80..6eec018c7 100644 --- a/src/tactic/tactic.cpp +++ b/src/tactic/tactic.cpp @@ -174,7 +174,7 @@ void exec(tactic & t, goal_ref const & in, goal_ref_buffer & result, model_conve } } -lbool check_sat(tactic & t, goal_ref & g, model_ref & md, proof_ref & pr, expr_dependency_ref & core, std::string & reason_unknown) { +lbool check_sat(tactic & t, goal_ref & g, model_ref & md, svector & labels, proof_ref & pr, expr_dependency_ref & core, std::string & reason_unknown) { bool models_enabled = g->models_enabled(); bool proofs_enabled = g->proofs_enabled(); bool cores_enabled = g->unsat_core_enabled(); @@ -199,6 +199,7 @@ lbool check_sat(tactic & t, goal_ref & g, model_ref & md, proof_ref & pr, expr_d if (is_decided_sat(r)) { if (models_enabled) { + (*mc)(labels, 0); model_converter2model(m, mc.get(), md); if (!md) { // create empty model. @@ -215,7 +216,10 @@ lbool check_sat(tactic & t, goal_ref & g, model_ref & md, proof_ref & pr, expr_d return l_false; } else { - if (models_enabled) model_converter2model(m, mc.get(), md); + if (models_enabled) { + model_converter2model(m, mc.get(), md); + (*mc)(labels, 0); + } reason_unknown = "incomplete"; return l_undef; } diff --git a/src/tactic/tactic.h b/src/tactic/tactic.h index a9e50ff10..7c65c83e5 100644 --- a/src/tactic/tactic.h +++ b/src/tactic/tactic.h @@ -153,7 +153,7 @@ public: #define MK_SIMPLE_TACTIC_FACTORY(NAME, ST) MK_TACTIC_FACTORY(NAME, return ST;) void exec(tactic & t, goal_ref const & in, goal_ref_buffer & result, model_converter_ref & mc, proof_converter_ref & pc, expr_dependency_ref & core); -lbool check_sat(tactic & t, goal_ref & g, model_ref & md, proof_ref & pr, expr_dependency_ref & core, std::string & reason_unknown); +lbool check_sat(tactic & t, goal_ref & g, model_ref & md, svector & labels, proof_ref & pr, expr_dependency_ref & core, std::string & reason_unknown); // Throws an exception if goal \c in requires proof generation. void fail_if_proof_generation(char const * tactic_name, goal_ref const & in); From a9d61d48ae5c21ee6bfafbd6baa244f8cbb53a1d Mon Sep 17 00:00:00 2001 From: Doug Woos Date: Fri, 21 Oct 2016 12:08:46 -0700 Subject: [PATCH 504/536] Add basic Sine Qua Non filtering --- contrib/cmake/src/tactic/CMakeLists.txt | 1 + src/tactic/sine_filter.cpp | 252 ++++++++++++++++++++++++ src/tactic/sine_filter.h | 28 +++ 3 files changed, 281 insertions(+) create mode 100644 src/tactic/sine_filter.cpp create mode 100644 src/tactic/sine_filter.h diff --git a/contrib/cmake/src/tactic/CMakeLists.txt b/contrib/cmake/src/tactic/CMakeLists.txt index 318803cd2..324d8089b 100644 --- a/contrib/cmake/src/tactic/CMakeLists.txt +++ b/contrib/cmake/src/tactic/CMakeLists.txt @@ -12,6 +12,7 @@ z3_add_component(tactic probe.cpp proof_converter.cpp replace_proof_converter.cpp + sine_filter.cpp tactical.cpp tactic.cpp COMPONENT_DEPENDENCIES diff --git a/src/tactic/sine_filter.cpp b/src/tactic/sine_filter.cpp new file mode 100644 index 000000000..15f0fca7a --- /dev/null +++ b/src/tactic/sine_filter.cpp @@ -0,0 +1,252 @@ +/*++ +Copyright (c) 2016 Microsoft Corporation + +Module Name: + + sine_filter.cpp + +Abstract: + + Tactic that performs Sine Qua Non premise selection + +Revision History: +--*/ + +#include "sine_filter.h" +#include "tactical.h" +#include "filter_model_converter.h" +#include "datatype_decl_plugin.h" +#include "rewriter_def.h" +#include "filter_model_converter.h" +#include "extension_model_converter.h" +#include "var_subst.h" +#include "ast_util.h" +#include "obj_pair_hashtable.h" + +#if 0 +TODO documentation here +#endif + + +class sine_tactic : public tactic { + + ast_manager& m; + params_ref m_params; + datatype_util m_dt; + ref m_ext; + ref m_filter; + unsigned m_num_transformed; + +public: + + sine_tactic(ast_manager& m, params_ref const& p): + m(m), m_params(p), m_dt(m) {} + + virtual tactic * translate(ast_manager & m) { + return alloc(sine_tactic, m, m_params); + } + + virtual void updt_params(params_ref const & p) { + } + + virtual void collect_param_descrs(param_descrs & r) { + } + + virtual void operator()(goal_ref const & g, + goal_ref_buffer & result, + model_converter_ref & mc, + proof_converter_ref & pc, + expr_dependency_ref & core) { + mc = 0; pc = 0; core = 0; + + TRACE("sine", g->display(tout);); + TRACE("sine", tout << g->size();); + ptr_vector new_forms; + filter_expressions(g, new_forms); + TRACE("sine", tout << new_forms.size();); + g->reset(); + for (unsigned i = 0; i < new_forms.size(); i++) { + g->assert_expr(new_forms.get(i), 0, 0); + } + g->inc_depth(); + g->updt_prec(goal::OVER); + result.push_back(g.get()); + TRACE("sine", result[0]->display(tout);); + SASSERT(g->is_well_sorted()); + filter_model_converter * fmc = alloc(filter_model_converter, m); + mc = fmc; + } + + virtual void cleanup() { + } + +private: + + // is this a user-defined symbol name? + bool is_name(func_decl * f) { + return f->get_family_id() < 0; + } + + typedef std::pair t_work_item; + + t_work_item work_item(expr *e, expr *root) { + return std::pair(e, root); + } + + void find_constants(expr *e, obj_hashtable &consts) { + ptr_vector stack; + stack.push_back(e); + expr *curr; + while (!stack.empty()) { + curr = stack.back(); + stack.pop_back(); + if (is_app(curr)) { + app *a = to_app(curr); + func_decl *f = a->get_decl(); + if (is_name(f) && !consts.contains(f)) { + consts.insert(f); + } + } + } + } + + bool quantifier_matches(quantifier *q, + obj_hashtable const & consts, + ptr_vector & next_consts) { + TRACE("sine", tout << "size of consts is "; tout << consts.size(); tout << "\n";); + for (obj_hashtable::iterator constit = consts.begin(), constend = consts.end(); constit != constend; constit++) { + TRACE("sine", tout << *constit; tout << "\n";); + } + bool matched = false; + for (int i = 0; i < q->get_num_patterns(); i++) { + bool p_matched = true; + vector stack; + expr *curr; + // patterns are wrapped with "pattern" + stack.push_back(to_app(q->get_pattern(i))->get_arg(0)); + while (!stack.empty()) { + curr = stack.back(); + stack.pop_back(); + if (is_app(curr)) { + app *a = to_app(curr); + func_decl *f = a->get_decl(); + if (!consts.contains(f)) { + TRACE("sine", tout << f; tout << "\n";); + p_matched = false; + next_consts.push_back(f); + break; + } + for (int j = 0; j < a->get_num_args(); j++) { + stack.push_back(a->get_arg(j)); + } + } + } + if (p_matched) { + matched = true; + break; + } + } + return matched; + } + + void filter_expressions(goal_ref const & g, ptr_vector & new_exprs) { + obj_map > const2exp; + obj_map > exp2const; + obj_map > const2quantifier; + obj_hashtable consts; + vector stack; + for (int i = 0; i < g->size(); i++) { + stack.push_back(work_item(g->form(i), g->form(i))); + } + t_work_item curr; + while (!stack.empty()) { + curr = stack.back(); + stack.pop_back(); + if (is_app(curr.first)) { + app *a = to_app(curr.first); + func_decl *f = a->get_decl(); + if (is_name(f)) { + if (!consts.contains(f)) { + consts.insert(f); + if (const2quantifier.contains(f)) { + for (obj_pair_hashtable::iterator it = const2quantifier[f].begin(), end = const2quantifier[f].end(); it != end; it++) { + stack.push_back(*it); + } + const2quantifier.remove(f); + } + } + if (!const2exp.contains(f)) { + const2exp.insert(f, obj_hashtable()); + } + if (!const2exp[f].contains(curr.second)) { + const2exp[f].insert(curr.second); + } + if (!exp2const.contains(curr.second)) { + exp2const.insert(curr.second, obj_hashtable()); + } + if (!exp2const[curr.second].contains(f)) { + exp2const[curr.second].insert(f); + } + } + for (int i = 0; i < a->get_num_args(); i++) { + stack.push_back(work_item(a->get_arg(i), curr.second)); + } + } + else if (is_quantifier(curr.first)) { + quantifier *q = to_quantifier(curr.first); + if (q->is_forall()) { + if (q->has_patterns()) { + ptr_vector next_consts; + if (quantifier_matches(q, consts, next_consts)) { + stack.push_back(work_item(q->get_expr(), curr.second)); + } + else { + for (unsigned i = 0; i < next_consts.size(); i++) { + func_decl *c = next_consts.get(i); + if (!const2quantifier.contains(c)) { + const2quantifier.insert(c, obj_pair_hashtable()); + } + if (!const2quantifier[c].contains(curr)) { + const2quantifier[c].insert(curr); + } + } + } + } + else { + stack.push_back(work_item(q->get_expr(), curr.second)); + } + } + else if (q->is_exists()) { + stack.push_back(work_item(q->get_expr(), curr.second)); + } + } + } + // ok, now we just need to find the connected component of the last term + + obj_hashtable visited; + ptr_vector to_visit; + to_visit.push_back(g->form(g->size() - 1)); + expr *visiting; + while (!to_visit.empty()) { + visiting = to_visit.back(); + to_visit.pop_back(); + visited.insert(visiting); + for (obj_hashtable::iterator constit = exp2const[visiting].begin(), constend = exp2const[visiting].end(); constit != constend; constit++) { + for (obj_hashtable::iterator exprit = const2exp[*constit].begin(), exprend = const2exp[*constit].end(); exprit != exprend; exprit++) { + if (!visited.contains(*exprit)) { + to_visit.push_back(*exprit); + } + } + } + } + for (int i = 0; i < g->size(); i++) { + if (visited.contains(g->form(i))) { + new_exprs.push_back(g->form(i)); + } + } + } +}; + +tactic * mk_sine_tactic(ast_manager & m, params_ref const & p) { + return alloc(sine_tactic, m, p); +} diff --git a/src/tactic/sine_filter.h b/src/tactic/sine_filter.h new file mode 100644 index 000000000..9b9e279a4 --- /dev/null +++ b/src/tactic/sine_filter.h @@ -0,0 +1,28 @@ +/*++ +Copyright (c) 2016 Microsoft Corporation + +Module Name: + + sine_filter.h + +Abstract: + + Tactic that performs Sine Qua Non premise selection + +Revision History: + +--*/ +#ifndef SINE_TACTIC_H_ +#define SINE_TACTIC_H_ + +#include"params.h" +class ast_manager; +class tactic; + +tactic * mk_sine_tactic(ast_manager & m, params_ref const & p = params_ref()); + +/* + ADD_TACTIC("sine-filter", "eliminate premises using Sine Qua Non", "mk_sine_tactic(m, p)") +*/ + +#endif From 37ee4c95c3a2d963002fab22b0f698191d0e92d8 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 30 Jan 2017 02:09:08 -0800 Subject: [PATCH 505/536] adding parallel threads Signed-off-by: Nikolaj Bjorner --- contrib/cmake/src/sat/CMakeLists.txt | 1 + src/api/c++/z3++.h | 1 + src/sat/sat_config.cpp | 1 + src/sat/sat_config.h | 1 + src/sat/sat_par.cpp | 45 ++++++++ src/sat/sat_par.h | 39 +++++++ src/sat/sat_params.pyg | 1 + src/sat/sat_solver.cpp | 146 ++++++++++++++++++++++++-- src/sat/sat_solver.h | 10 ++ src/sat/sat_solver/inc_sat_solver.cpp | 3 + src/smt/theory_seq.cpp | 4 +- src/tactic/tactical.cpp | 7 -- src/util/rlimit.h | 9 ++ 13 files changed, 250 insertions(+), 18 deletions(-) create mode 100644 src/sat/sat_par.cpp create mode 100644 src/sat/sat_par.h diff --git a/contrib/cmake/src/sat/CMakeLists.txt b/contrib/cmake/src/sat/CMakeLists.txt index 3eec21ec3..d88a73708 100644 --- a/contrib/cmake/src/sat/CMakeLists.txt +++ b/contrib/cmake/src/sat/CMakeLists.txt @@ -12,6 +12,7 @@ z3_add_component(sat sat_integrity_checker.cpp sat_model_converter.cpp sat_mus.cpp + sat_par.cpp sat_probing.cpp sat_scc.cpp sat_simplifier.cpp diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index 1556064d6..979d9aed7 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -1816,6 +1816,7 @@ namespace z3 { fmls, fml)); } + param_descrs get_param_descrs() { return param_descrs(ctx(), Z3_solver_get_param_descrs(ctx(), m_solver)); } }; diff --git a/src/sat/sat_config.cpp b/src/sat/sat_config.cpp index 4e01bfe55..ccf538dfe 100644 --- a/src/sat/sat_config.cpp +++ b/src/sat/sat_config.cpp @@ -77,6 +77,7 @@ namespace sat { m_burst_search = p.burst_search(); m_max_conflicts = p.max_conflicts(); + m_num_parallel = p.parallel_threads(); // These parameters are not exposed m_simplify_mult1 = _p.get_uint("simplify_mult1", 300); diff --git a/src/sat/sat_config.h b/src/sat/sat_config.h index 910ca0360..405cbd092 100644 --- a/src/sat/sat_config.h +++ b/src/sat/sat_config.h @@ -57,6 +57,7 @@ namespace sat { unsigned m_random_seed; unsigned m_burst_search; unsigned m_max_conflicts; + unsigned m_num_parallel; unsigned m_simplify_mult1; double m_simplify_mult2; diff --git a/src/sat/sat_par.cpp b/src/sat/sat_par.cpp new file mode 100644 index 000000000..7a185a3b5 --- /dev/null +++ b/src/sat/sat_par.cpp @@ -0,0 +1,45 @@ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + sat_par.cpp + +Abstract: + + Utilities for parallel SAT solving. + +Author: + + Nikolaj Bjorner (nbjorner) 2017-1-29. + +Revision History: + +--*/ +#include "sat_par.h" + + +namespace sat { + + par::par() {} + + void par::exchange(literal_vector const& in, unsigned& limit, literal_vector& out) { + #pragma omp critical (par_solver) + { + if (limit < m_units.size()) { + // this might repeat some literals. + out.append(m_units.size() - limit, m_units.c_ptr() + limit); + } + for (unsigned i = 0; i < in.size(); ++i) { + literal lit = in[i]; + if (!m_unit_set.contains(lit.index())) { + m_unit_set.insert(lit.index()); + m_units.push_back(lit); + } + } + limit = m_units.size(); + } + } + +}; + diff --git a/src/sat/sat_par.h b/src/sat/sat_par.h new file mode 100644 index 000000000..2b2592de7 --- /dev/null +++ b/src/sat/sat_par.h @@ -0,0 +1,39 @@ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + sat_par.h + +Abstract: + + Utilities for parallel SAT solving. + +Author: + + Nikolaj Bjorner (nbjorner) 2017-1-29. + +Revision History: + +--*/ +#ifndef SAT_PAR_H_ +#define SAT_PAR_H_ + +#include"sat_types.h" +#include"hashtable.h" +#include"map.h" + +namespace sat { + + class par { + typedef hashtable index_set; + literal_vector m_units; + index_set m_unit_set; + public: + par(); + void exchange(literal_vector const& in, unsigned& limit, literal_vector& out); + }; + +}; + +#endif diff --git a/src/sat/sat_params.pyg b/src/sat/sat_params.pyg index 21a50bea2..60708fd5c 100644 --- a/src/sat/sat_params.pyg +++ b/src/sat/sat_params.pyg @@ -22,4 +22,5 @@ def_module_params('sat', ('dyn_sub_res', BOOL, True, 'dynamic subsumption resolution for minimizing learned clauses'), ('core.minimize', BOOL, False, 'minimize computed core'), ('core.minimize_partial', BOOL, False, 'apply partial (cheap) core minimization'), + ('parallel_threads', UINT, 1, 'number of parallel threads to use'), ('dimacs.core', BOOL, False, 'extract core from DIMACS benchmarks'))) diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 37fb971fd..bf3dc1988 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -35,6 +35,7 @@ namespace sat { m_rlimit(l), m_config(p), m_ext(ext), + m_par(0), m_cleaner(*this), m_simplifier(*this, p), m_scc(*this, p), @@ -72,6 +73,8 @@ namespace sat { void solver::copy(solver const & src) { SASSERT(m_mc.empty() && src.m_mc.empty()); + SASSERT(scope_lvl() == 0); + SASSERT(src.scope_lvl() == 0); // create new vars if (num_vars() < src.num_vars()) { for (bool_var v = num_vars(); v < src.num_vars(); v++) { @@ -81,19 +84,25 @@ namespace sat { VERIFY(v == mk_var(ext, dvar)); } } + unsigned sz = src.scope_lvl() == 0 ? src.m_trail.size() : src.m_scopes[0].m_trail_lim; + for (unsigned i = 0; i < sz; ++i) { + assign(src.m_trail[i], justification()); + } + { // copy binary clauses - vector::const_iterator it = src.m_watches.begin(); - vector::const_iterator end = src.m_watches.begin(); - for (unsigned l_idx = 0; it != end; ++it, ++l_idx) { - watch_list const & wlist = *it; + unsigned sz = src.m_watches.size(); + for (unsigned l_idx = 0; l_idx < sz; ++l_idx) { literal l = ~to_literal(l_idx); - watch_list::const_iterator it2 = wlist.begin(); - watch_list::const_iterator end2 = wlist.end(); - for (; it2 != end2; ++it2) { - if (!it2->is_binary_non_learned_clause()) + watch_list const & wlist = src.m_watches[l_idx]; + watch_list::const_iterator it = wlist.begin(); + watch_list::const_iterator end = wlist.end(); + for (; it != end; ++it) { + if (!it->is_binary_non_learned_clause()) + continue; + literal l2 = it->get_literal(); + if (l.index() > l2.index()) continue; - literal l2 = it2->get_literal(); mk_clause_core(l, l2); } } @@ -711,6 +720,9 @@ namespace sat { pop_to_base_level(); IF_VERBOSE(2, verbose_stream() << "(sat.sat-solver)\n";); SASSERT(scope_lvl() == 0); + if (m_config.m_num_parallel > 0 && !m_par) { + return check_par(num_lits, lits); + } #ifdef CLONE_BEFORE_SOLVING if (m_mc.empty()) { m_clone = alloc(solver, m_params, 0 /* do not clone extension */); @@ -759,6 +771,7 @@ namespace sat { restart(); simplify_problem(); + exchange_par(); if (check_inconsistent()) return l_false; gc(); @@ -774,6 +787,121 @@ namespace sat { } } + enum par_exception_kind { + DEFAULT_EX, + ERROR_EX + }; + + lbool solver::check_par(unsigned num_lits, literal const* lits) { + int num_threads = static_cast(m_config.m_num_parallel); + scoped_limits scoped_rlimit(rlimit()); + vector rlims(num_threads); + ptr_vector solvers(num_threads); + sat::par par; + for (int i = 0; i < num_threads; ++i) { + m_params.set_uint("random_seed", i); + solvers[i] = alloc(sat::solver, m_params, rlims[i], 0); + solvers[i]->copy(*this); + solvers[i]->set_par(&par); + scoped_rlimit.push_child(&solvers[i]->rlimit()); + } + int finished_id = -1; + std::string ex_msg; + par_exception_kind ex_kind; + unsigned error_code = 0; + lbool result = l_undef; + #pragma omp parallel for + for (int i = 0; i < num_threads; ++i) { + try { + lbool r = solvers[i]->check(num_lits, lits); + bool first = false; + #pragma omp critical (par_solver) + { + if (finished_id == UINT_MAX) { + finished_id = i; + first = true; + result = r; + } + } + if (first) { + if (r == l_true) { + set_model(solvers[i]->get_model()); + } + else if (r == l_false) { + m_core.reset(); + m_core.append(solvers[i]->get_core()); + } + for (int j = 0; j < num_threads; ++j) { + if (i != j) { + rlims[j].cancel(); + } + } + } + } + catch (z3_error & err) { + if (i == 0) { + error_code = err.error_code(); + ex_kind = ERROR_EX; + } + } + catch (z3_exception & ex) { + if (i == 0) { + ex_msg = ex.msg(); + ex_kind = DEFAULT_EX; + } + } + } + for (int i = 0; i < num_threads; ++i) { + dealloc(solvers[i]); + } + if (finished_id == -1) { + switch (ex_kind) { + case ERROR_EX: throw z3_error(error_code); + default: throw default_exception(ex_msg.c_str()); + } + } + return result; + + } + + /* + \brief import lemmas/units from parallel sat solvers. + */ + void solver::exchange_par() { + if (m_par && scope_lvl() == 0) { + unsigned num_in = 0, num_out = 0; + SASSERT(scope_lvl() == 0); // parallel with assumptions is TBD + literal_vector in, out; + for (unsigned i = m_par_limit_out; i < m_trail.size(); ++i) { + literal lit = m_trail[i]; + if (lit.var() < m_par_num_vars) { + ++num_out; + out.push_back(lit); + } + } + m_par_limit_out = m_trail.size(); + m_par->exchange(out, m_par_limit_in, in); + for (unsigned i = 0; !inconsistent() && i < in.size(); ++i) { + literal lit = in[i]; + SASSERT(lit.var() < m_par_num_vars); + if (lvl(lit.var()) != 0 || value(lit) != l_true) { + ++num_in; + assign(lit, justification()); + } + } + if (num_in > 0 || num_out > 0) { + IF_VERBOSE(1, verbose_stream() << "(sat-sync out: " << num_out << " in: " << num_in << ")\n";); + } + } + } + + void solver::set_par(par* p) { + m_par = p; + m_par_num_vars = num_vars(); + m_par_limit_in = 0; + m_par_limit_out = 0; + } + bool_var solver::next_var() { bool_var next; diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index aa7e6edea..54b8a9bb2 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -33,6 +33,7 @@ Revision History: #include"sat_iff3_finder.h" #include"sat_probing.h" #include"sat_mus.h" +#include"sat_par.h" #include"params.h" #include"statistics.h" #include"stopwatch.h" @@ -74,6 +75,7 @@ namespace sat { config m_config; stats m_stats; extension * m_ext; + par* m_par; random_gen m_rand; clause_allocator m_cls_allocator; cleaner m_cleaner; @@ -128,6 +130,10 @@ namespace sat { literal_set m_assumption_set; // set of enabled assumptions literal_vector m_core; // unsat core + unsigned m_par_limit_in; + unsigned m_par_limit_out; + unsigned m_par_num_vars; + void del_clauses(clause * const * begin, clause * const * end); friend class integrity_checker; @@ -241,7 +247,9 @@ namespace sat { m_num_checkpoints = 0; if (memory::get_allocation_size() > m_config.m_max_memory) throw solver_exception(Z3_MAX_MEMORY_MSG); } + void set_par(par* p); bool canceled() { return !m_rlimit.inc(); } + config const& get_config() { return m_config; } typedef std::pair bin_clause; protected: watch_list & get_wlist(literal l) { return m_watches[l.index()]; } @@ -317,6 +325,8 @@ namespace sat { bool check_model(model const & m) const; void restart(); void sort_watch_lits(); + void exchange_par(); + lbool check_par(unsigned num_lits, literal const* lits); // ----------------------- // diff --git a/src/sat/sat_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp index 33d10f428..65a7b021c 100644 --- a/src/sat/sat_solver/inc_sat_solver.cpp +++ b/src/sat/sat_solver/inc_sat_solver.cpp @@ -140,6 +140,7 @@ public: if (r != l_true) return r; r = m_solver.check(m_asms.size(), m_asms.c_ptr()); + switch (r) { case l_true: if (sz > 0) { @@ -276,6 +277,8 @@ public: return r; } + + virtual lbool find_mutexes(expr_ref_vector const& vars, vector& mutexes) { sat::literal_vector ls; u_map lit2var; diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index 3e1436aa6..d5251c56b 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -2940,8 +2940,8 @@ void theory_seq::deque_axiom(expr* n) { encode that s is not contained in of xs1 where s1 is all of s, except the last element. - lit or s = "" or s = s1*(unit c) - lit or s = "" or !contains(x*s1, s) + s = "" or s = s1*(unit c) + s = "" or !contains(x*s1, s) */ void theory_seq::tightest_prefix(expr* s, expr* x) { expr_ref s1 = mk_first(s); diff --git a/src/tactic/tactical.cpp b/src/tactic/tactical.cpp index 4cb212265..33f8325fb 100644 --- a/src/tactic/tactical.cpp +++ b/src/tactic/tactical.cpp @@ -461,13 +461,6 @@ enum par_exception_kind { class par_tactical : public or_else_tactical { - struct scoped_limits { - reslimit& m_limit; - unsigned m_sz; - scoped_limits(reslimit& lim): m_limit(lim), m_sz(0) {} - ~scoped_limits() { for (unsigned i = 0; i < m_sz; ++i) m_limit.pop_child(); } - void push_child(reslimit* lim) { m_limit.push_child(lim); ++m_sz; } - }; public: par_tactical(unsigned num, tactic * const * ts):or_else_tactical(num, ts) {} diff --git a/src/util/rlimit.h b/src/util/rlimit.h index 913984768..283d7613d 100644 --- a/src/util/rlimit.h +++ b/src/util/rlimit.h @@ -61,4 +61,13 @@ public: }; +struct scoped_limits { + reslimit& m_limit; + unsigned m_sz; + scoped_limits(reslimit& lim): m_limit(lim), m_sz(0) {} + ~scoped_limits() { for (unsigned i = 0; i < m_sz; ++i) m_limit.pop_child(); } + void push_child(reslimit* lim) { m_limit.push_child(lim); ++m_sz; } +}; + + #endif From 0e966f21ffa13f075cd1256903f10c58e75e45d7 Mon Sep 17 00:00:00 2001 From: martin-neuhaeusser Date: Mon, 30 Jan 2017 17:28:24 +0100 Subject: [PATCH 506/536] Fix off-by-one bug in array indexing in the OCaml bindings This patch fixes an off-by-one bug that occurred in the construction of output arrays in the OCaml bindings. --- scripts/update_api.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/update_api.py b/scripts/update_api.py index 38b6213c1..26f19cc1c 100755 --- a/scripts/update_api.py +++ b/scripts/update_api.py @@ -1477,10 +1477,10 @@ def mk_z3native_stubs_c(ml_src_dir, ml_output_dir): # C interface pts = ml_plus_type(ts) pops = ml_plus_ops_type(ts) if ml_has_plus_type(ts): - ml_wrapper.write(' %s _a%dp = %s_mk(ctx_p, (%s) _a%d[_i]);\n' % (pts, i, pts, ml_minus_type(ts), i)) + ml_wrapper.write(' %s _a%dp = %s_mk(ctx_p, (%s) _a%d[_i - 1]);\n' % (pts, i, pts, ml_minus_type(ts), i)) ml_wrapper.write(' %s\n' % ml_alloc_and_store(pt, 'tmp_val', '_a%dp' % i)) else: - ml_wrapper.write(' %s\n' % ml_alloc_and_store(pt, 'tmp_val', '_a%d[_i]' % i)) + ml_wrapper.write(' %s\n' % ml_alloc_and_store(pt, 'tmp_val', '_a%d[_i - 1]' % i)) ml_wrapper.write(' _iter = caml_alloc(2,0);\n') ml_wrapper.write(' Store_field(_iter, 0, tmp_val);\n') ml_wrapper.write(' Store_field(_iter, 1, _a%s_val);\n' % i) From 76bc4f0b38ed9778c0eefdb259cb98a9f5acf905 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 30 Jan 2017 11:30:42 -0800 Subject: [PATCH 507/536] refine parsat Signed-off-by: Nikolaj Bjorner --- src/sat/sat_solver.cpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index bf3dc1988..071c0c2a8 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -72,9 +72,9 @@ namespace sat { } void solver::copy(solver const & src) { + pop_to_base_level(); SASSERT(m_mc.empty() && src.m_mc.empty()); SASSERT(scope_lvl() == 0); - SASSERT(src.scope_lvl() == 0); // create new vars if (num_vars() < src.num_vars()) { for (bool_var v = num_vars(); v < src.num_vars(); v++) { @@ -120,6 +120,9 @@ namespace sat { mk_clause_core(buffer); } } + + m_user_scope_literals.reset(); + m_user_scope_literals.append(src.m_user_scope_literals); } // ----------------------- @@ -800,6 +803,9 @@ namespace sat { sat::par par; for (int i = 0; i < num_threads; ++i) { m_params.set_uint("random_seed", i); + if (i < num_threads/2) { + m_params.set_sym("phase", symbol("random")); + } solvers[i] = alloc(sat::solver, m_params, rlims[i], 0); solvers[i]->copy(*this); solvers[i]->set_par(&par); @@ -869,17 +875,18 @@ namespace sat { */ void solver::exchange_par() { if (m_par && scope_lvl() == 0) { + unsigned sz = scope_lvl() == 0 ? m_trail.size() : m_scopes[0].m_trail_lim; unsigned num_in = 0, num_out = 0; SASSERT(scope_lvl() == 0); // parallel with assumptions is TBD literal_vector in, out; - for (unsigned i = m_par_limit_out; i < m_trail.size(); ++i) { + for (unsigned i = m_par_limit_out; i < sz; ++i) { literal lit = m_trail[i]; if (lit.var() < m_par_num_vars) { ++num_out; out.push_back(lit); } } - m_par_limit_out = m_trail.size(); + m_par_limit_out = sz; m_par->exchange(out, m_par_limit_in, in); for (unsigned i = 0; !inconsistent() && i < in.size(); ++i) { literal lit = in[i]; From 379181092032b105c35d2b0576233633d212e97e Mon Sep 17 00:00:00 2001 From: Doug Woos Date: Mon, 30 Jan 2017 15:09:57 -0800 Subject: [PATCH 508/536] add const & --- src/tactic/model_converter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tactic/model_converter.cpp b/src/tactic/model_converter.cpp index 061d12afa..efe80f226 100644 --- a/src/tactic/model_converter.cpp +++ b/src/tactic/model_converter.cpp @@ -130,7 +130,7 @@ class model2mc : public model_converter { public: model2mc(model * m):m_model(m) {} - model2mc(model * m, buffer r):m_model(m), m_labels(r) {} + model2mc(model * m, buffer const & r):m_model(m), m_labels(r) {} virtual ~model2mc() {} From 8196173e293032fb298ebd9b8e25907725a7201e Mon Sep 17 00:00:00 2001 From: Doug Woos Date: Mon, 30 Jan 2017 15:50:34 -0800 Subject: [PATCH 509/536] Introduce and use labels_vec --- src/cmd_context/tactic_cmds.cpp | 6 ++---- src/solver/tactic2solver.cpp | 2 +- src/tactic/model_converter.cpp | 6 +++--- src/tactic/model_converter.h | 4 +++- src/tactic/tactic.cpp | 2 +- src/tactic/tactic.h | 2 +- 6 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/cmd_context/tactic_cmds.cpp b/src/cmd_context/tactic_cmds.cpp index 158f361dd..4febb1597 100644 --- a/src/cmd_context/tactic_cmds.cpp +++ b/src/cmd_context/tactic_cmds.cpp @@ -167,7 +167,7 @@ public: struct check_sat_tactic_result : public simple_check_sat_result { public: - svector labels; + labels_vec labels; check_sat_tactic_result(ast_manager & m) : simple_check_sat_result(m) { } @@ -181,8 +181,6 @@ public: } }; -typedef svector & labels_ref; - class check_sat_using_tactict_cmd : public exec_given_tactic_cmd { public: check_sat_using_tactict_cmd(): @@ -205,7 +203,7 @@ public: ast_manager & m = ctx.m(); unsigned timeout = p.get_uint("timeout", ctx.params().m_timeout); unsigned rlimit = p.get_uint("rlimit", ctx.params().m_rlimit); - svector labels; + labels_vec labels; goal_ref g = alloc(goal, m, ctx.produce_proofs(), ctx.produce_models(), ctx.produce_unsat_cores()); assert_exprs_from(ctx, *g); TRACE("check_sat_using", g->display(tout);); diff --git a/src/solver/tactic2solver.cpp b/src/solver/tactic2solver.cpp index 586d59d4f..6b1a7916f 100644 --- a/src/solver/tactic2solver.cpp +++ b/src/solver/tactic2solver.cpp @@ -144,7 +144,7 @@ lbool tactic2solver::check_sat_core(unsigned num_assumptions, expr * const * ass proof_ref pr(m); expr_dependency_ref core(m); std::string reason_unknown = "unknown"; - svector labels; + labels_vec labels; try { switch (::check_sat(*m_tactic, g, md, labels, pr, core, reason_unknown)) { case l_true: diff --git a/src/tactic/model_converter.cpp b/src/tactic/model_converter.cpp index efe80f226..6f6dd3da1 100644 --- a/src/tactic/model_converter.cpp +++ b/src/tactic/model_converter.cpp @@ -33,7 +33,7 @@ public: this->m_c1->operator()(m, 0); } - virtual void operator()(svector & r, unsigned goal_idx) { + virtual void operator()(labels_vec & r, unsigned goal_idx) { this->m_c2->operator()(r, goal_idx); this->m_c1->operator()(r, 0); } @@ -83,7 +83,7 @@ public: UNREACHABLE(); } - virtual void operator()(svector & r, unsigned goal_idx) { + virtual void operator()(labels_vec & r, unsigned goal_idx) { unsigned num = this->m_c2s.size(); for (unsigned i = 0; i < num; i++) { if (goal_idx < this->m_szs[i]) { @@ -142,7 +142,7 @@ public: m = m_model; } - virtual void operator()(svector & r, unsigned goal_idx) { + virtual void operator()(labels_vec & r, unsigned goal_idx) { r.append(m_labels.size(), m_labels.c_ptr()); } diff --git a/src/tactic/model_converter.h b/src/tactic/model_converter.h index 4395fc546..e2bc3cf83 100644 --- a/src/tactic/model_converter.h +++ b/src/tactic/model_converter.h @@ -23,6 +23,8 @@ Notes: #include"converter.h" #include"ref.h" +class labels_vec : public svector {}; + class model_converter : public converter { public: virtual void operator()(model_ref & m) {} // TODO: delete @@ -33,7 +35,7 @@ public: operator()(m); } - virtual void operator()(svector & r, unsigned goal_idx) {} + virtual void operator()(labels_vec & r, unsigned goal_idx) {} virtual model_converter * translate(ast_translation & translator) = 0; }; diff --git a/src/tactic/tactic.cpp b/src/tactic/tactic.cpp index 6eec018c7..0a95e8f65 100644 --- a/src/tactic/tactic.cpp +++ b/src/tactic/tactic.cpp @@ -174,7 +174,7 @@ void exec(tactic & t, goal_ref const & in, goal_ref_buffer & result, model_conve } } -lbool check_sat(tactic & t, goal_ref & g, model_ref & md, svector & labels, proof_ref & pr, expr_dependency_ref & core, std::string & reason_unknown) { +lbool check_sat(tactic & t, goal_ref & g, model_ref & md, labels_vec & labels, proof_ref & pr, expr_dependency_ref & core, std::string & reason_unknown) { bool models_enabled = g->models_enabled(); bool proofs_enabled = g->proofs_enabled(); bool cores_enabled = g->unsat_core_enabled(); diff --git a/src/tactic/tactic.h b/src/tactic/tactic.h index 7c65c83e5..645b53681 100644 --- a/src/tactic/tactic.h +++ b/src/tactic/tactic.h @@ -153,7 +153,7 @@ public: #define MK_SIMPLE_TACTIC_FACTORY(NAME, ST) MK_TACTIC_FACTORY(NAME, return ST;) void exec(tactic & t, goal_ref const & in, goal_ref_buffer & result, model_converter_ref & mc, proof_converter_ref & pc, expr_dependency_ref & core); -lbool check_sat(tactic & t, goal_ref & g, model_ref & md, svector & labels, proof_ref & pr, expr_dependency_ref & core, std::string & reason_unknown); +lbool check_sat(tactic & t, goal_ref & g, model_ref & md, labels_vec & labels, proof_ref & pr, expr_dependency_ref & core, std::string & reason_unknown); // Throws an exception if goal \c in requires proof generation. void fail_if_proof_generation(char const * tactic_name, goal_ref const & in); From 1d1949e39597d30811ddba520f841594bd58df3e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 30 Jan 2017 18:30:06 -0800 Subject: [PATCH 510/536] ensure that parallel threads are only invoked when thread count > 1 Signed-off-by: Nikolaj Bjorner --- src/sat/sat_solver.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 071c0c2a8..e06ed3971 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -723,7 +723,7 @@ namespace sat { pop_to_base_level(); IF_VERBOSE(2, verbose_stream() << "(sat.sat-solver)\n";); SASSERT(scope_lvl() == 0); - if (m_config.m_num_parallel > 0 && !m_par) { + if (m_config.m_num_parallel > 1 && !m_par) { return check_par(num_lits, lits); } #ifdef CLONE_BEFORE_SOLVING @@ -823,7 +823,7 @@ namespace sat { bool first = false; #pragma omp critical (par_solver) { - if (finished_id == UINT_MAX) { + if (finished_id == -1) { finished_id = i; first = true; result = r; From b00c4d2e64ad0aaa15f8a7dc5252ead76eac7a08 Mon Sep 17 00:00:00 2001 From: Doug Woos Date: Mon, 30 Jan 2017 20:54:24 -0800 Subject: [PATCH 511/536] add name --- src/tactic/sine_filter.cpp | 4 ++++ src/tactic/sine_filter.h | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/src/tactic/sine_filter.cpp b/src/tactic/sine_filter.cpp index 15f0fca7a..2052035f7 100644 --- a/src/tactic/sine_filter.cpp +++ b/src/tactic/sine_filter.cpp @@ -9,6 +9,10 @@ Abstract: Tactic that performs Sine Qua Non premise selection +Author: + + Doug Woos + Revision History: --*/ diff --git a/src/tactic/sine_filter.h b/src/tactic/sine_filter.h index 9b9e279a4..769ef474f 100644 --- a/src/tactic/sine_filter.h +++ b/src/tactic/sine_filter.h @@ -9,6 +9,10 @@ Abstract: Tactic that performs Sine Qua Non premise selection +Author: + + Doug Woos + Revision History: --*/ From da63f6b0ffce1b11260bc505cbfa01efb66b1ecf Mon Sep 17 00:00:00 2001 From: Doug Woos Date: Mon, 30 Jan 2017 20:54:33 -0800 Subject: [PATCH 512/536] delete comment --- src/tactic/sine_filter.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/tactic/sine_filter.cpp b/src/tactic/sine_filter.cpp index 2052035f7..d76e8f6b5 100644 --- a/src/tactic/sine_filter.cpp +++ b/src/tactic/sine_filter.cpp @@ -27,11 +27,6 @@ Revision History: #include "ast_util.h" #include "obj_pair_hashtable.h" -#if 0 -TODO documentation here -#endif - - class sine_tactic : public tactic { ast_manager& m; From c0bb6dd2be9cabb4cc774babb6bae9a530298161 Mon Sep 17 00:00:00 2001 From: Doug Woos Date: Mon, 30 Jan 2017 20:54:40 -0800 Subject: [PATCH 513/536] delete unused args --- src/tactic/sine_filter.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/tactic/sine_filter.cpp b/src/tactic/sine_filter.cpp index d76e8f6b5..60482d86e 100644 --- a/src/tactic/sine_filter.cpp +++ b/src/tactic/sine_filter.cpp @@ -31,15 +31,11 @@ class sine_tactic : public tactic { ast_manager& m; params_ref m_params; - datatype_util m_dt; - ref m_ext; - ref m_filter; - unsigned m_num_transformed; public: sine_tactic(ast_manager& m, params_ref const& p): - m(m), m_params(p), m_dt(m) {} + m(m), m_params(p) {} virtual tactic * translate(ast_manager & m) { return alloc(sine_tactic, m, m_params); From 89ba99918eed693a97b4378b448726e1758e2e90 Mon Sep 17 00:00:00 2001 From: Doug Woos Date: Mon, 30 Jan 2017 21:02:09 -0800 Subject: [PATCH 514/536] reindent --- src/tactic/sine_filter.cpp | 302 ++++++++++++++++++------------------- 1 file changed, 151 insertions(+), 151 deletions(-) diff --git a/src/tactic/sine_filter.cpp b/src/tactic/sine_filter.cpp index 60482d86e..f5ecc36a3 100644 --- a/src/tactic/sine_filter.cpp +++ b/src/tactic/sine_filter.cpp @@ -3,15 +3,15 @@ Copyright (c) 2016 Microsoft Corporation Module Name: - sine_filter.cpp + sine_filter.cpp Abstract: - Tactic that performs Sine Qua Non premise selection + Tactic that performs Sine Qua Non premise selection Author: - Doug Woos + Doug Woos Revision History: --*/ @@ -35,7 +35,7 @@ class sine_tactic : public tactic { public: sine_tactic(ast_manager& m, params_ref const& p): - m(m), m_params(p) {} + m(m), m_params(p) {} virtual tactic * translate(ast_manager & m) { return alloc(sine_tactic, m, m_params); @@ -61,7 +61,7 @@ public: TRACE("sine", tout << new_forms.size();); g->reset(); for (unsigned i = 0; i < new_forms.size(); i++) { - g->assert_expr(new_forms.get(i), 0, 0); + g->assert_expr(new_forms.get(i), 0, 0); } g->inc_depth(); g->updt_prec(goal::OVER); @@ -77,169 +77,169 @@ public: private: - // is this a user-defined symbol name? - bool is_name(func_decl * f) { - return f->get_family_id() < 0; - } + // is this a user-defined symbol name? + bool is_name(func_decl * f) { + return f->get_family_id() < 0; + } - typedef std::pair t_work_item; + typedef std::pair t_work_item; - t_work_item work_item(expr *e, expr *root) { - return std::pair(e, root); - } + t_work_item work_item(expr *e, expr *root) { + return std::pair(e, root); + } - void find_constants(expr *e, obj_hashtable &consts) { - ptr_vector stack; - stack.push_back(e); - expr *curr; - while (!stack.empty()) { - curr = stack.back(); - stack.pop_back(); - if (is_app(curr)) { - app *a = to_app(curr); - func_decl *f = a->get_decl(); - if (is_name(f) && !consts.contains(f)) { - consts.insert(f); + void find_constants(expr *e, obj_hashtable &consts) { + ptr_vector stack; + stack.push_back(e); + expr *curr; + while (!stack.empty()) { + curr = stack.back(); + stack.pop_back(); + if (is_app(curr)) { + app *a = to_app(curr); + func_decl *f = a->get_decl(); + if (is_name(f) && !consts.contains(f)) { + consts.insert(f); + } + } } - } } - } - bool quantifier_matches(quantifier *q, - obj_hashtable const & consts, - ptr_vector & next_consts) { - TRACE("sine", tout << "size of consts is "; tout << consts.size(); tout << "\n";); - for (obj_hashtable::iterator constit = consts.begin(), constend = consts.end(); constit != constend; constit++) { - TRACE("sine", tout << *constit; tout << "\n";); - } - bool matched = false; - for (int i = 0; i < q->get_num_patterns(); i++) { - bool p_matched = true; - vector stack; - expr *curr; - // patterns are wrapped with "pattern" - stack.push_back(to_app(q->get_pattern(i))->get_arg(0)); - while (!stack.empty()) { - curr = stack.back(); - stack.pop_back(); - if (is_app(curr)) { - app *a = to_app(curr); - func_decl *f = a->get_decl(); - if (!consts.contains(f)) { - TRACE("sine", tout << f; tout << "\n";); - p_matched = false; - next_consts.push_back(f); - break; - } - for (int j = 0; j < a->get_num_args(); j++) { - stack.push_back(a->get_arg(j)); - } + bool quantifier_matches(quantifier *q, + obj_hashtable const & consts, + ptr_vector & next_consts) { + TRACE("sine", tout << "size of consts is "; tout << consts.size(); tout << "\n";); + for (obj_hashtable::iterator constit = consts.begin(), constend = consts.end(); constit != constend; constit++) { + TRACE("sine", tout << *constit; tout << "\n";); } - } - if (p_matched) { - matched = true; - break; - } + bool matched = false; + for (int i = 0; i < q->get_num_patterns(); i++) { + bool p_matched = true; + vector stack; + expr *curr; + // patterns are wrapped with "pattern" + stack.push_back(to_app(q->get_pattern(i))->get_arg(0)); + while (!stack.empty()) { + curr = stack.back(); + stack.pop_back(); + if (is_app(curr)) { + app *a = to_app(curr); + func_decl *f = a->get_decl(); + if (!consts.contains(f)) { + TRACE("sine", tout << f; tout << "\n";); + p_matched = false; + next_consts.push_back(f); + break; + } + for (int j = 0; j < a->get_num_args(); j++) { + stack.push_back(a->get_arg(j)); + } + } + } + if (p_matched) { + matched = true; + break; + } + } + return matched; } - return matched; - } - void filter_expressions(goal_ref const & g, ptr_vector & new_exprs) { - obj_map > const2exp; - obj_map > exp2const; - obj_map > const2quantifier; - obj_hashtable consts; - vector stack; - for (int i = 0; i < g->size(); i++) { - stack.push_back(work_item(g->form(i), g->form(i))); - } - t_work_item curr; - while (!stack.empty()) { - curr = stack.back(); - stack.pop_back(); - if (is_app(curr.first)) { - app *a = to_app(curr.first); - func_decl *f = a->get_decl(); - if (is_name(f)) { - if (!consts.contains(f)) { - consts.insert(f); - if (const2quantifier.contains(f)) { - for (obj_pair_hashtable::iterator it = const2quantifier[f].begin(), end = const2quantifier[f].end(); it != end; it++) { - stack.push_back(*it); - } - const2quantifier.remove(f); - } - } - if (!const2exp.contains(f)) { - const2exp.insert(f, obj_hashtable()); - } - if (!const2exp[f].contains(curr.second)) { - const2exp[f].insert(curr.second); - } - if (!exp2const.contains(curr.second)) { - exp2const.insert(curr.second, obj_hashtable()); - } - if (!exp2const[curr.second].contains(f)) { - exp2const[curr.second].insert(f); - } + void filter_expressions(goal_ref const & g, ptr_vector & new_exprs) { + obj_map > const2exp; + obj_map > exp2const; + obj_map > const2quantifier; + obj_hashtable consts; + vector stack; + for (int i = 0; i < g->size(); i++) { + stack.push_back(work_item(g->form(i), g->form(i))); } - for (int i = 0; i < a->get_num_args(); i++) { - stack.push_back(work_item(a->get_arg(i), curr.second)); - } - } - else if (is_quantifier(curr.first)) { - quantifier *q = to_quantifier(curr.first); - if (q->is_forall()) { - if (q->has_patterns()) { - ptr_vector next_consts; - if (quantifier_matches(q, consts, next_consts)) { - stack.push_back(work_item(q->get_expr(), curr.second)); - } - else { - for (unsigned i = 0; i < next_consts.size(); i++) { - func_decl *c = next_consts.get(i); - if (!const2quantifier.contains(c)) { - const2quantifier.insert(c, obj_pair_hashtable()); + t_work_item curr; + while (!stack.empty()) { + curr = stack.back(); + stack.pop_back(); + if (is_app(curr.first)) { + app *a = to_app(curr.first); + func_decl *f = a->get_decl(); + if (is_name(f)) { + if (!consts.contains(f)) { + consts.insert(f); + if (const2quantifier.contains(f)) { + for (obj_pair_hashtable::iterator it = const2quantifier[f].begin(), end = const2quantifier[f].end(); it != end; it++) { + stack.push_back(*it); + } + const2quantifier.remove(f); + } + } + if (!const2exp.contains(f)) { + const2exp.insert(f, obj_hashtable()); + } + if (!const2exp[f].contains(curr.second)) { + const2exp[f].insert(curr.second); + } + if (!exp2const.contains(curr.second)) { + exp2const.insert(curr.second, obj_hashtable()); + } + if (!exp2const[curr.second].contains(f)) { + exp2const[curr.second].insert(f); + } } - if (!const2quantifier[c].contains(curr)) { - const2quantifier[c].insert(curr); + for (int i = 0; i < a->get_num_args(); i++) { + stack.push_back(work_item(a->get_arg(i), curr.second)); + } + } + else if (is_quantifier(curr.first)) { + quantifier *q = to_quantifier(curr.first); + if (q->is_forall()) { + if (q->has_patterns()) { + ptr_vector next_consts; + if (quantifier_matches(q, consts, next_consts)) { + stack.push_back(work_item(q->get_expr(), curr.second)); + } + else { + for (unsigned i = 0; i < next_consts.size(); i++) { + func_decl *c = next_consts.get(i); + if (!const2quantifier.contains(c)) { + const2quantifier.insert(c, obj_pair_hashtable()); + } + if (!const2quantifier[c].contains(curr)) { + const2quantifier[c].insert(curr); + } + } + } + } + else { + stack.push_back(work_item(q->get_expr(), curr.second)); + } + } + else if (q->is_exists()) { + stack.push_back(work_item(q->get_expr(), curr.second)); } - } } - } - else { - stack.push_back(work_item(q->get_expr(), curr.second)); - } } - else if (q->is_exists()) { - stack.push_back(work_item(q->get_expr(), curr.second)); - } - } - } - // ok, now we just need to find the connected component of the last term + // ok, now we just need to find the connected component of the last term - obj_hashtable visited; - ptr_vector to_visit; - to_visit.push_back(g->form(g->size() - 1)); - expr *visiting; - while (!to_visit.empty()) { - visiting = to_visit.back(); - to_visit.pop_back(); - visited.insert(visiting); - for (obj_hashtable::iterator constit = exp2const[visiting].begin(), constend = exp2const[visiting].end(); constit != constend; constit++) { - for (obj_hashtable::iterator exprit = const2exp[*constit].begin(), exprend = const2exp[*constit].end(); exprit != exprend; exprit++) { - if (!visited.contains(*exprit)) { - to_visit.push_back(*exprit); - } + obj_hashtable visited; + ptr_vector to_visit; + to_visit.push_back(g->form(g->size() - 1)); + expr *visiting; + while (!to_visit.empty()) { + visiting = to_visit.back(); + to_visit.pop_back(); + visited.insert(visiting); + for (obj_hashtable::iterator constit = exp2const[visiting].begin(), constend = exp2const[visiting].end(); constit != constend; constit++) { + for (obj_hashtable::iterator exprit = const2exp[*constit].begin(), exprend = const2exp[*constit].end(); exprit != exprend; exprit++) { + if (!visited.contains(*exprit)) { + to_visit.push_back(*exprit); + } + } + } + } + for (int i = 0; i < g->size(); i++) { + if (visited.contains(g->form(i))) { + new_exprs.push_back(g->form(i)); + } } - } } - for (int i = 0; i < g->size(); i++) { - if (visited.contains(g->form(i))) { - new_exprs.push_back(g->form(i)); - } - } - } }; tactic * mk_sine_tactic(ast_manager & m, params_ref const & p) { From d9e43f0e6d592d6b385b673a3c1dc8e12ca753c4 Mon Sep 17 00:00:00 2001 From: Doug Woos Date: Tue, 31 Jan 2017 11:47:44 -0800 Subject: [PATCH 515/536] use insert_if_not_there --- src/tactic/sine_filter.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tactic/sine_filter.cpp b/src/tactic/sine_filter.cpp index f5ecc36a3..71ae58f8c 100644 --- a/src/tactic/sine_filter.cpp +++ b/src/tactic/sine_filter.cpp @@ -98,8 +98,8 @@ private: if (is_app(curr)) { app *a = to_app(curr); func_decl *f = a->get_decl(); - if (is_name(f) && !consts.contains(f)) { - consts.insert(f); + if (is_name(f)) { + consts.insert_if_not_there(f); } } } From bdfa84c6fe135ba863093001cfedeb9c21baa432 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 31 Jan 2017 13:22:03 -0800 Subject: [PATCH 516/536] fix issues with running parallel solver: random strategy should not be a default on all solvers. Also reuse base solver Signed-off-by: Nikolaj Bjorner --- src/sat/sat_solver.cpp | 38 ++++++++++++++++++++++++++------------ 1 file changed, 26 insertions(+), 12 deletions(-) diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index e06ed3971..acfd79b90 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -797,29 +797,39 @@ namespace sat { lbool solver::check_par(unsigned num_lits, literal const* lits) { int num_threads = static_cast(m_config.m_num_parallel); + int num_extra_solvers = num_threads - 1; scoped_limits scoped_rlimit(rlimit()); - vector rlims(num_threads); - ptr_vector solvers(num_threads); + vector rlims(num_extra_solvers); + ptr_vector solvers(num_extra_solvers); sat::par par; - for (int i = 0; i < num_threads; ++i) { - m_params.set_uint("random_seed", i); - if (i < num_threads/2) { + symbol saved_phase = m_params.get_sym("phase", symbol("caching")); + for (int i = 0; i < num_extra_solvers; ++i) { + m_params.set_uint("random_seed", i + m_config.m_random_seed); + if (i == 1 + num_threads/2) { m_params.set_sym("phase", symbol("random")); - } + } solvers[i] = alloc(sat::solver, m_params, rlims[i], 0); solvers[i]->copy(*this); solvers[i]->set_par(&par); - scoped_rlimit.push_child(&solvers[i]->rlimit()); + scoped_rlimit.push_child(&solvers[i]->rlimit()); } + m_params.set_sym("phase", saved_phase); int finished_id = -1; std::string ex_msg; par_exception_kind ex_kind; unsigned error_code = 0; lbool result = l_undef; + flet _overwrite_thread_number(m_config.m_num_parallel, 1); #pragma omp parallel for for (int i = 0; i < num_threads; ++i) { try { - lbool r = solvers[i]->check(num_lits, lits); + lbool r = l_undef; + if (i < num_extra_solvers) { + r = solvers[i]->check(num_lits, lits); + } + else { + r = check(num_lits, lits); + } bool first = false; #pragma omp critical (par_solver) { @@ -830,14 +840,14 @@ namespace sat { } } if (first) { - if (r == l_true) { + if (r == l_true && i < num_extra_solvers) { set_model(solvers[i]->get_model()); } - else if (r == l_false) { + else if (r == l_false && i < num_extra_solvers) { m_core.reset(); m_core.append(solvers[i]->get_core()); } - for (int j = 0; j < num_threads; ++j) { + for (int j = 0; j < num_extra_solvers; ++j) { if (i != j) { rlims[j].cancel(); } @@ -857,7 +867,11 @@ namespace sat { } } } - for (int i = 0; i < num_threads; ++i) { + if (finished_id != -1 && finished_id < num_extra_solvers) { + m_stats = solvers[finished_id]->m_stats; + } + + for (int i = 0; i < num_extra_solvers; ++i) { dealloc(solvers[i]); } if (finished_id == -1) { From f015e3e4cc13f77cce3cd626b756abdd6f014236 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 31 Jan 2017 17:17:58 -0800 Subject: [PATCH 517/536] fix bug in propagation of parameters to combined solvers Signed-off-by: Nikolaj Bjorner --- src/sat/sat_config.cpp | 1 + src/sat/sat_solver.cpp | 5 +++-- src/solver/solver.h | 2 +- src/solver/solver2tactic.cpp | 1 + src/solver/tactic2solver.cpp | 2 +- 5 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/sat/sat_config.cpp b/src/sat/sat_config.cpp index ccf538dfe..9206ea8bc 100644 --- a/src/sat/sat_config.cpp +++ b/src/sat/sat_config.cpp @@ -35,6 +35,7 @@ namespace sat { m_glue("glue"), m_glue_psm("glue_psm"), m_psm_glue("psm_glue") { + m_num_parallel = 1; updt_params(p); } diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index acfd79b90..fff9ee6e4 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -804,7 +804,7 @@ namespace sat { sat::par par; symbol saved_phase = m_params.get_sym("phase", symbol("caching")); for (int i = 0; i < num_extra_solvers; ++i) { - m_params.set_uint("random_seed", i + m_config.m_random_seed); + m_params.set_uint("random_seed", m_rand()); if (i == 1 + num_threads/2) { m_params.set_sym("phase", symbol("random")); } @@ -813,13 +813,13 @@ namespace sat { solvers[i]->set_par(&par); scoped_rlimit.push_child(&solvers[i]->rlimit()); } + set_par(&par); m_params.set_sym("phase", saved_phase); int finished_id = -1; std::string ex_msg; par_exception_kind ex_kind; unsigned error_code = 0; lbool result = l_undef; - flet _overwrite_thread_number(m_config.m_num_parallel, 1); #pragma omp parallel for for (int i = 0; i < num_threads; ++i) { try { @@ -867,6 +867,7 @@ namespace sat { } } } + set_par(0); if (finished_id != -1 && finished_id < num_extra_solvers) { m_stats = solvers[finished_id]->m_stats; } diff --git a/src/solver/solver.h b/src/solver/solver.h index d5d9ccfd5..6b9d38f29 100644 --- a/src/solver/solver.h +++ b/src/solver/solver.h @@ -54,7 +54,7 @@ public: /** \brief Update the solver internal settings. */ - virtual void updt_params(params_ref const & p) {} + virtual void updt_params(params_ref const & p) { } /** \brief Store in \c r a description of the configuration diff --git a/src/solver/solver2tactic.cpp b/src/solver/solver2tactic.cpp index 21ecdec32..1a02c97e6 100644 --- a/src/solver/solver2tactic.cpp +++ b/src/solver/solver2tactic.cpp @@ -93,6 +93,7 @@ public: {} virtual void updt_params(params_ref const & p) { + m_params.append(p); m_solver->updt_params(p); } diff --git a/src/solver/tactic2solver.cpp b/src/solver/tactic2solver.cpp index 34d2edd3c..150b19395 100644 --- a/src/solver/tactic2solver.cpp +++ b/src/solver/tactic2solver.cpp @@ -96,7 +96,7 @@ tactic2solver::~tactic2solver() { } void tactic2solver::updt_params(params_ref const & p) { - m_params = p; + m_params.append(p); } void tactic2solver::collect_param_descrs(param_descrs & r) { From 4d8d705b3f72cb0b78c4c4e8779203e5c6e16a7a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 1 Feb 2017 08:02:24 -0800 Subject: [PATCH 518/536] bypass combined solver when logic is set to QF_BV or QF_FD Signed-off-by: Nikolaj Bjorner --- src/tactic/portfolio/smt_strategic_solver.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/tactic/portfolio/smt_strategic_solver.cpp b/src/tactic/portfolio/smt_strategic_solver.cpp index d2414ec72..16e59302b 100644 --- a/src/tactic/portfolio/smt_strategic_solver.cpp +++ b/src/tactic/portfolio/smt_strategic_solver.cpp @@ -98,13 +98,19 @@ tactic * mk_tactic_for_logic(ast_manager & m, params_ref const & p, symbol const return mk_default_tactic(m, p); } -static solver* mk_solver_for_logic(ast_manager & m, params_ref const & p, symbol const& logic) { +static solver* mk_special_solver_for_logic(ast_manager & m, params_ref const & p, symbol const& logic) { bv_rewriter rw(m); if (logic == "QF_BV" && rw.hi_div0()) return mk_inc_sat_solver(m, p); if (logic == "QF_FD") return mk_fd_solver(m, p); - return mk_smt_solver(m, p, logic); + return 0; +} + +static solver* mk_solver_for_logic(ast_manager & m, params_ref const & p, symbol const& logic) { + solver* s = mk_special_solver_for_logic(m, p, logic); + if (!s) s = mk_smt_solver(m, p, logic); + return s; } class smt_strategic_solver_factory : public solver_factory { @@ -119,6 +125,8 @@ public: l = m_logic; else l = logic; + solver* s = mk_special_solver_for_logic(m, p, l); + if (s) return s; tactic * t = mk_tactic_for_logic(m, p, l); return mk_combined_solver(mk_tactic2solver(m, t, p, proofs_enabled, models_enabled, unsat_core_enabled, l), mk_solver_for_logic(m, p, l), From 40177f7bac4ab9615a32728154f6fd1fa6c8fcf9 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 1 Feb 2017 08:05:04 -0800 Subject: [PATCH 519/536] bypass combined solver when logic is set to QF_FD Signed-off-by: Nikolaj Bjorner --- src/tactic/portfolio/smt_strategic_solver.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/tactic/portfolio/smt_strategic_solver.cpp b/src/tactic/portfolio/smt_strategic_solver.cpp index 16e59302b..a4a579ddd 100644 --- a/src/tactic/portfolio/smt_strategic_solver.cpp +++ b/src/tactic/portfolio/smt_strategic_solver.cpp @@ -99,17 +99,18 @@ tactic * mk_tactic_for_logic(ast_manager & m, params_ref const & p, symbol const } static solver* mk_special_solver_for_logic(ast_manager & m, params_ref const & p, symbol const& logic) { - bv_rewriter rw(m); - if (logic == "QF_BV" && rw.hi_div0()) - return mk_inc_sat_solver(m, p); if (logic == "QF_FD") return mk_fd_solver(m, p); return 0; } static solver* mk_solver_for_logic(ast_manager & m, params_ref const & p, symbol const& logic) { + bv_rewriter rw(m); solver* s = mk_special_solver_for_logic(m, p, logic); - if (!s) s = mk_smt_solver(m, p, logic); + if (!s && logic == "QF_BV" && rw.hi_div0()) + s = mk_inc_sat_solver(m, p); + if (!s) + s = mk_smt_solver(m, p, logic); return s; } From 256a0e2d8291b722bf286a828f481f98d28fe568 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 1 Feb 2017 12:12:26 -0800 Subject: [PATCH 520/536] move exchange par Signed-off-by: Nikolaj Bjorner --- src/sat/sat_solver.cpp | 9 ++++----- src/sat/sat_solver.h | 1 + 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index fff9ee6e4..376b4f8d5 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -84,7 +84,7 @@ namespace sat { VERIFY(v == mk_var(ext, dvar)); } } - unsigned sz = src.scope_lvl() == 0 ? src.m_trail.size() : src.m_scopes[0].m_trail_lim; + unsigned sz = src.init_trail_size(); for (unsigned i = 0; i < sz; ++i) { assign(src.m_trail[i], justification()); } @@ -774,7 +774,6 @@ namespace sat { restart(); simplify_problem(); - exchange_par(); if (check_inconsistent()) return l_false; gc(); @@ -890,9 +889,8 @@ namespace sat { */ void solver::exchange_par() { if (m_par && scope_lvl() == 0) { - unsigned sz = scope_lvl() == 0 ? m_trail.size() : m_scopes[0].m_trail_lim; + unsigned sz = init_trail_size(); unsigned num_in = 0, num_out = 0; - SASSERT(scope_lvl() == 0); // parallel with assumptions is TBD literal_vector in, out; for (unsigned i = m_par_limit_out; i < sz; ++i) { literal lit = m_trail[i]; @@ -2546,6 +2544,7 @@ namespace sat { void solver::pop_reinit(unsigned num_scopes) { pop(num_scopes); + exchange_par(); reinit_assumptions(); } @@ -2865,7 +2864,7 @@ namespace sat { } void solver::display_units(std::ostream & out) const { - unsigned end = scope_lvl() == 0 ? m_trail.size() : m_scopes[0].m_trail_lim; + unsigned end = init_trail_size(); for (unsigned i = 0; i < end; i++) { out << m_trail[i] << " "; } diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index 54b8a9bb2..f910e374f 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -223,6 +223,7 @@ namespace sat { lbool value(bool_var v) const { return static_cast(m_assignment[literal(v, false).index()]); } unsigned lvl(bool_var v) const { return m_level[v]; } unsigned lvl(literal l) const { return m_level[l.var()]; } + unsigned init_trail_size() const { return scope_lvl() == 0 ? m_trail.size() : m_scopes[0].m_trail_lim; } void assign(literal l, justification j) { TRACE("sat_assign", tout << l << " previous value: " << value(l) << "\n";); switch (value(l)) { From 9cfd412cd0f2fbc389eaed51cc585604304f143e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 1 Feb 2017 15:28:29 -0800 Subject: [PATCH 521/536] enable pb theory always as pb terms can be introduced during transformations. Issue #884 Signed-off-by: Nikolaj Bjorner --- src/opt/opt_context.cpp | 8 ++++---- src/sat/sat_simplifier.cpp | 1 - 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 46122d619..56b152caa 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -570,11 +570,11 @@ namespace opt { m_opt_solver = alloc(opt_solver, m, m_params, m_fm); m_opt_solver->set_logic(m_logic); m_solver = m_opt_solver.get(); + m_opt_solver->ensure_pb(); - if (opt_params(m_params).priority() == symbol("pareto") || - (opt_params(m_params).priority() == symbol("lex") && m_objectives.size() > 1)) { - m_opt_solver->ensure_pb(); - } + //if (opt_params(m_params).priority() == symbol("pareto") || + // (opt_params(m_params).priority() == symbol("lex") && m_objectives.size() > 1)) { + //} } void context::setup_arith_solver() { diff --git a/src/sat/sat_simplifier.cpp b/src/sat/sat_simplifier.cpp index 62fb99a11..bd975115b 100644 --- a/src/sat/sat_simplifier.cpp +++ b/src/sat/sat_simplifier.cpp @@ -154,7 +154,6 @@ namespace sat { if (!m_subsumption && !m_elim_blocked_clauses && !m_resolution) return; - initialize(); CASSERT("sat_solver", s.check_invariant()); From a147e2bc3530da587c4128eeae020cd33e3bbdaf Mon Sep 17 00:00:00 2001 From: Doug Woos Date: Wed, 1 Feb 2017 16:20:40 -0800 Subject: [PATCH 522/536] use is_uninterp --- src/tactic/sine_filter.cpp | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/src/tactic/sine_filter.cpp b/src/tactic/sine_filter.cpp index 71ae58f8c..43c15bf74 100644 --- a/src/tactic/sine_filter.cpp +++ b/src/tactic/sine_filter.cpp @@ -77,11 +77,6 @@ public: private: - // is this a user-defined symbol name? - bool is_name(func_decl * f) { - return f->get_family_id() < 0; - } - typedef std::pair t_work_item; t_work_item work_item(expr *e, expr *root) { @@ -97,8 +92,8 @@ private: stack.pop_back(); if (is_app(curr)) { app *a = to_app(curr); - func_decl *f = a->get_decl(); - if (is_name(f)) { + if (is_uninterp(a)) { + func_decl *f = a->get_decl(); consts.insert_if_not_there(f); } } @@ -159,8 +154,8 @@ private: stack.pop_back(); if (is_app(curr.first)) { app *a = to_app(curr.first); - func_decl *f = a->get_decl(); - if (is_name(f)) { + if (is_uninterp(a)) { + func_decl *f = a->get_decl(); if (!consts.contains(f)) { consts.insert(f); if (const2quantifier.contains(f)) { From 44c417904b268c6bbb175082c81f58c0ada1a422 Mon Sep 17 00:00:00 2001 From: Doug Woos Date: Wed, 1 Feb 2017 16:21:01 -0800 Subject: [PATCH 523/536] correctly pretty-print --- src/tactic/sine_filter.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/tactic/sine_filter.cpp b/src/tactic/sine_filter.cpp index 43c15bf74..059608b4c 100644 --- a/src/tactic/sine_filter.cpp +++ b/src/tactic/sine_filter.cpp @@ -26,6 +26,7 @@ Revision History: #include "var_subst.h" #include "ast_util.h" #include "obj_pair_hashtable.h" +#include "ast_pp.h" class sine_tactic : public tactic { @@ -121,7 +122,7 @@ private: app *a = to_app(curr); func_decl *f = a->get_decl(); if (!consts.contains(f)) { - TRACE("sine", tout << f; tout << "\n";); + TRACE("sine", tout << mk_pp(f, m) << "\n";); p_matched = false; next_consts.push_back(f); break; From d6fbfe401e282f3a86abbe21a5363256996e3ea6 Mon Sep 17 00:00:00 2001 From: Doug Woos Date: Wed, 1 Feb 2017 16:21:15 -0800 Subject: [PATCH 524/536] add and use new is_pattern recognizer --- src/ast/ast.cpp | 16 ++++++++++++++++ src/ast/ast.h | 2 ++ src/tactic/sine_filter.cpp | 6 ++++-- 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/src/ast/ast.cpp b/src/ast/ast.cpp index 440179ba8..7be7300a2 100644 --- a/src/ast/ast.cpp +++ b/src/ast/ast.cpp @@ -2326,6 +2326,22 @@ bool ast_manager::is_pattern(expr const * n) const { return true; } + +bool ast_manager::is_pattern(expr const * n, ptr_vector &args) { + if (!is_app_of(n, m_pattern_family_id, OP_PATTERN)) { + return false; + } + for (unsigned i = 0; i < to_app(n)->get_num_args(); ++i) { + expr *arg = to_app(n)->get_arg(i); + if (!is_app(arg)) { + return false; + } + args.push_back(arg); + } + return true; +} + + quantifier * ast_manager::mk_quantifier(bool forall, unsigned num_decls, sort * const * decl_sorts, symbol const * decl_names, expr * body, int weight , symbol const & qid, symbol const & skid, unsigned num_patterns, expr * const * patterns, diff --git a/src/ast/ast.h b/src/ast/ast.h index 47ea0f812..9259d5431 100644 --- a/src/ast/ast.h +++ b/src/ast/ast.h @@ -1840,6 +1840,8 @@ public: bool is_pattern(expr const * n) const; + bool is_pattern(expr const *n, ptr_vector &args); + public: quantifier * mk_quantifier(bool forall, unsigned num_decls, sort * const * decl_sorts, symbol const * decl_names, expr * body, diff --git a/src/tactic/sine_filter.cpp b/src/tactic/sine_filter.cpp index 059608b4c..e180eea5e 100644 --- a/src/tactic/sine_filter.cpp +++ b/src/tactic/sine_filter.cpp @@ -111,10 +111,12 @@ private: bool matched = false; for (int i = 0; i < q->get_num_patterns(); i++) { bool p_matched = true; - vector stack; + ptr_vector stack; expr *curr; // patterns are wrapped with "pattern" - stack.push_back(to_app(q->get_pattern(i))->get_arg(0)); + if (!m.is_pattern(q->get_pattern(i), stack)) { + continue; + } while (!stack.empty()) { curr = stack.back(); stack.pop_back(); From 2e89c2de3d3eafcc45cd1539642dda1e9c2d0ee7 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 2 Feb 2017 09:35:04 -0800 Subject: [PATCH 525/536] add par_or tactic to C++ API. #873 Signed-off-by: Nikolaj Bjorner --- src/api/c++/z3++.h | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index 979d9aed7..37e6448c9 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -1933,6 +1933,7 @@ namespace z3 { friend tactic repeat(tactic const & t, unsigned max); friend tactic with(tactic const & t, params const & p); friend tactic try_for(tactic const & t, unsigned ms); + friend tactic par_or(unsigned n, tactic const* tactics); param_descrs get_param_descrs() { return param_descrs(ctx(), Z3_tactic_get_param_descrs(ctx(), m_tactic)); } }; @@ -1966,7 +1967,14 @@ namespace z3 { t.check_error(); return tactic(t.ctx(), r); } - + inline tactic par_or(unsigned n, tactic const* tactics) { + if (n == 0) { + throw exception("a non-zero number of tactics need to be passed to par_or"); + } + array buffer(n); + for (unsigned i = 0; i < n; ++i) buffer[i] = tactics[i]; + return tactic(tactics[0].ctx(), Z3_tactic_par_or(tactics[0].ctx(), n, buffer.ptr())); + } class probe : public object { Z3_probe m_probe; From 9ca52a3361208ac0b038bf15478b448ed415f00b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 2 Feb 2017 10:19:11 -0800 Subject: [PATCH 526/536] fix bug in lexicographic handling in maxres: previous assumptions were not committed in corner cases Signed-off-by: Nikolaj Bjorner --- src/opt/maxres.cpp | 18 +++++++++++++----- src/sat/sat_clause.cpp | 4 ++-- src/sat/sat_solver.cpp | 10 ++++------ src/sat/sat_solver/inc_sat_solver.cpp | 3 --- src/shell/opt_frontend.cpp | 15 +++++++++++++++ 5 files changed, 34 insertions(+), 16 deletions(-) diff --git a/src/opt/maxres.cpp b/src/opt/maxres.cpp index 7abbd48ee..7e9381e1d 100644 --- a/src/opt/maxres.cpp +++ b/src/opt/maxres.cpp @@ -193,7 +193,6 @@ public: trace(); if (is_sat != l_true) return is_sat; while (m_lower < m_upper) { - if (m_lower >= m_upper) break; TRACE("opt", display_vec(tout, m_asms); s().display(tout); @@ -206,6 +205,7 @@ public: } switch (is_sat) { case l_true: + SASSERT(is_true(m_asms)); found_optimum(); return l_true; case l_false: @@ -223,6 +223,7 @@ public: break; } } + found_optimum(); trace(); return l_true; } @@ -296,18 +297,24 @@ public: } else { is_sat = check_sat(asms.size(), asms.c_ptr()); - } + } return is_sat; } lbool check_sat(unsigned sz, expr* const* asms) { - return s().check_sat(sz, asms); + lbool r = s().check_sat(sz, asms); + if (r == l_true) { + model_ref mdl; + s().get_model(mdl); + if (mdl.get()) { + update_assignment(mdl.get()); + } + } + return r; } void found_optimum() { IF_VERBOSE(1, verbose_stream() << "found optimum\n";); - s().get_model(m_model); - SASSERT(is_true(m_asms)); rational upper(0); for (unsigned i = 0; i < m_soft.size(); ++i) { m_assignment[i] = is_true(m_soft[i]); @@ -742,6 +749,7 @@ public: nsoft.push_back(mk_not(m, m_soft[i])); } fml = u.mk_lt(nsoft.size(), m_weights.c_ptr(), nsoft.c_ptr(), m_upper); + TRACE("opt", tout << "block upper bound " << fml << "\n";);; s().assert_expr(fml); } diff --git a/src/sat/sat_clause.cpp b/src/sat/sat_clause.cpp index 15c14c31b..1efbd6758 100644 --- a/src/sat/sat_clause.cpp +++ b/src/sat/sat_clause.cpp @@ -198,13 +198,13 @@ namespace sat { size_t size = clause::get_obj_size(num_lits); void * mem = m_allocator.allocate(size); clause * cls = new (mem) clause(m_id_gen.mk(), num_lits, lits, learned); - TRACE("sat", tout << "alloc: " << cls->id() << " " << cls << " " << *cls << " " << (learned?"l":"a") << "\n";); + TRACE("sat", tout << "alloc: " << cls->id() << " " << *cls << " " << (learned?"l":"a") << "\n";); SASSERT(!learned || cls->is_learned()); return cls; } void clause_allocator::del_clause(clause * cls) { - TRACE("sat", tout << "delete: " << cls->id() << " " << cls << " " << *cls << "\n";); + TRACE("sat", tout << "delete: " << cls->id() << " " << *cls << "\n";); m_id_gen.recycle(cls->id()); #if defined(_AMD64_) #if defined(Z3DEBUG) diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index fff9ee6e4..fb2b3139a 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -192,7 +192,7 @@ namespace sat { } clause * solver::mk_clause_core(unsigned num_lits, literal * lits, bool learned) { - TRACE("sat", tout << "mk_clause: " << mk_lits_pp(num_lits, lits) << "\n";); + TRACE("sat", tout << "mk_clause: " << mk_lits_pp(num_lits, lits) << (learned?" learned":" aux") << "\n";); if (!learned) { bool keep = simplify_clause(num_lits, lits); TRACE("sat_mk_clause", tout << "mk_clause (after simp), keep: " << keep << "\n" << mk_lits_pp(num_lits, lits) << "\n";); @@ -502,7 +502,7 @@ namespace sat { void solver::assign_core(literal l, justification j) { SASSERT(value(l) == l_undef); - TRACE("sat_assign_core", tout << l << "\n";); + TRACE("sat_assign_core", tout << l << " " << j << " level: " << scope_lvl() << "\n";); if (scope_lvl() == 0) j = justification(); // erase justification for level 0 m_assignment[l.index()] = l_true; @@ -1072,9 +1072,7 @@ namespace sat { } TRACE("sat", - for (unsigned i = 0; i < num_lits; ++i) - tout << lits[i] << " "; - tout << "\n"; + tout << literal_vector(num_lits, lits) << "\n"; if (!m_user_scope_literals.empty()) { tout << "user literals: " << m_user_scope_literals << "\n"; } @@ -2041,7 +2039,7 @@ namespace sat { } } - literal consequent = m_not_l; + literal consequent = m_not_l; justification js = m_conflict; diff --git a/src/sat/sat_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp index 65a7b021c..83c31715d 100644 --- a/src/sat/sat_solver/inc_sat_solver.cpp +++ b/src/sat/sat_solver/inc_sat_solver.cpp @@ -273,12 +273,9 @@ public: conseq.push_back(cons); } } - return r; } - - virtual lbool find_mutexes(expr_ref_vector const& vars, vector& mutexes) { sat::literal_vector ls; u_map lit2var; diff --git a/src/shell/opt_frontend.cpp b/src/shell/opt_frontend.cpp index a45800c62..760fdcf54 100644 --- a/src/shell/opt_frontend.cpp +++ b/src/shell/opt_frontend.cpp @@ -351,6 +351,21 @@ static unsigned parse_opt(std::istream& in, bool is_wcnf) { case l_false: std::cout << "unsat\n"; break; case l_undef: std::cout << "unknown\n"; break; } + DEBUG_CODE( + if (false && r == l_true) { + model_ref mdl; + opt.get_model(mdl); + expr_ref_vector hard(m); + opt.get_hard_constraints(hard); + for (unsigned i = 0; i < hard.size(); ++i) { + std::cout << "validate: " << i << "\n"; + expr_ref tmp(m); + VERIFY(mdl->eval(hard[i].get(), tmp)); + if (!m.is_true(tmp)) { + std::cout << tmp << "\n"; + } + } + }); } catch (z3_exception & ex) { std::cerr << ex.msg() << "\n"; From d6b4e9948959513431bca4d8cd18f06c26bed4f9 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Sun, 5 Feb 2017 16:03:00 +0000 Subject: [PATCH 527/536] Fixed signed/unsigned warnings --- src/tactic/sine_filter.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/tactic/sine_filter.cpp b/src/tactic/sine_filter.cpp index e180eea5e..f2d6a9653 100644 --- a/src/tactic/sine_filter.cpp +++ b/src/tactic/sine_filter.cpp @@ -109,7 +109,7 @@ private: TRACE("sine", tout << *constit; tout << "\n";); } bool matched = false; - for (int i = 0; i < q->get_num_patterns(); i++) { + for (unsigned i = 0; i < q->get_num_patterns(); i++) { bool p_matched = true; ptr_vector stack; expr *curr; @@ -129,7 +129,7 @@ private: next_consts.push_back(f); break; } - for (int j = 0; j < a->get_num_args(); j++) { + for (unsigned j = 0; j < a->get_num_args(); j++) { stack.push_back(a->get_arg(j)); } } @@ -148,7 +148,7 @@ private: obj_map > const2quantifier; obj_hashtable consts; vector stack; - for (int i = 0; i < g->size(); i++) { + for (unsigned i = 0; i < g->size(); i++) { stack.push_back(work_item(g->form(i), g->form(i))); } t_work_item curr; @@ -181,7 +181,7 @@ private: exp2const[curr.second].insert(f); } } - for (int i = 0; i < a->get_num_args(); i++) { + for (unsigned i = 0; i < a->get_num_args(); i++) { stack.push_back(work_item(a->get_arg(i), curr.second)); } } @@ -232,7 +232,7 @@ private: } } } - for (int i = 0; i < g->size(); i++) { + for (unsigned i = 0; i < g->size(); i++) { if (visited.contains(g->form(i))) { new_exprs.push_back(g->form(i)); } From 54280b6cc508d7c6ce9867a4ade36a2a2f6782a3 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Sun, 5 Feb 2017 17:20:45 +0000 Subject: [PATCH 528/536] Fixed model-converter segfault in ::check_sat. Relates to #881 --- src/tactic/tactic.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/tactic/tactic.cpp b/src/tactic/tactic.cpp index 9315f73b0..e6f342300 100644 --- a/src/tactic/tactic.cpp +++ b/src/tactic/tactic.cpp @@ -200,7 +200,8 @@ lbool check_sat(tactic & t, goal_ref & g, model_ref & md, labels_vec & labels, p if (is_decided_sat(r)) { if (models_enabled) { - (*mc)(labels, 0); + if (mc) + (*mc)(labels, 0); model_converter2model(m, mc.get(), md); if (!md) { // create empty model. From e4411265ea6c78c2aa00df9860d5b25ab47ac42d Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Sun, 5 Feb 2017 17:53:44 +0000 Subject: [PATCH 529/536] Fixed model-converter segfault in ::check_sat. Relates to #881 --- src/tactic/tactic.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/tactic/tactic.cpp b/src/tactic/tactic.cpp index e6f342300..67fce1486 100644 --- a/src/tactic/tactic.cpp +++ b/src/tactic/tactic.cpp @@ -220,7 +220,8 @@ lbool check_sat(tactic & t, goal_ref & g, model_ref & md, labels_vec & labels, p else { if (models_enabled) { model_converter2model(m, mc.get(), md); - (*mc)(labels, 0); + if (mc) + (*mc)(labels, 0); } reason_unknown = "incomplete"; return l_undef; From 3a0e9e8f53de9058f1813b8c461a3cc1fcc3c06d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 11 Feb 2017 11:31:13 -0500 Subject: [PATCH 530/536] add itos/stoi conversion to API. Issue #895 Signed-off-by: Nikolaj Bjorner --- src/api/api_ast.cpp | 47 +++++++++++++++++++++------------------ src/api/api_seq.cpp | 4 ++++ src/api/c++/z3++.h | 11 +++++++++ src/api/dotnet/Context.cs | 23 +++++++++++++++++++ src/api/python/z3/z3.py | 28 +++++++++++++++++++++-- src/api/z3_api.h | 19 ++++++++++++++++ 6 files changed, 108 insertions(+), 24 deletions(-) diff --git a/src/api/api_ast.cpp b/src/api/api_ast.cpp index fd2776079..c9cdc6ab3 100644 --- a/src/api/api_ast.cpp +++ b/src/api/api_ast.cpp @@ -1110,29 +1110,32 @@ extern "C" { if (mk_c(c)->get_seq_fid() == _d->get_family_id()) { switch (_d->get_decl_kind()) { - case Z3_OP_SEQ_UNIT: return Z3_OP_SEQ_UNIT; - case Z3_OP_SEQ_EMPTY: return Z3_OP_SEQ_EMPTY; - case Z3_OP_SEQ_CONCAT: return Z3_OP_SEQ_CONCAT; - case Z3_OP_SEQ_PREFIX: return Z3_OP_SEQ_PREFIX; - case Z3_OP_SEQ_SUFFIX: return Z3_OP_SEQ_SUFFIX; - case Z3_OP_SEQ_CONTAINS: return Z3_OP_SEQ_CONTAINS; - case Z3_OP_SEQ_EXTRACT: return Z3_OP_SEQ_EXTRACT; - case Z3_OP_SEQ_REPLACE: return Z3_OP_SEQ_REPLACE; - case Z3_OP_SEQ_AT: return Z3_OP_SEQ_AT; - case Z3_OP_SEQ_LENGTH: return Z3_OP_SEQ_LENGTH; - case Z3_OP_SEQ_INDEX: return Z3_OP_SEQ_INDEX; - case Z3_OP_SEQ_TO_RE: return Z3_OP_SEQ_TO_RE; - case Z3_OP_SEQ_IN_RE: return Z3_OP_SEQ_IN_RE; + case OP_SEQ_UNIT: return Z3_OP_SEQ_UNIT; + case OP_SEQ_EMPTY: return Z3_OP_SEQ_EMPTY; + case OP_SEQ_CONCAT: return Z3_OP_SEQ_CONCAT; + case OP_SEQ_PREFIX: return Z3_OP_SEQ_PREFIX; + case OP_SEQ_SUFFIX: return Z3_OP_SEQ_SUFFIX; + case OP_SEQ_CONTAINS: return Z3_OP_SEQ_CONTAINS; + case OP_SEQ_EXTRACT: return Z3_OP_SEQ_EXTRACT; + case OP_SEQ_REPLACE: return Z3_OP_SEQ_REPLACE; + case OP_SEQ_AT: return Z3_OP_SEQ_AT; + case OP_SEQ_LENGTH: return Z3_OP_SEQ_LENGTH; + case OP_SEQ_INDEX: return Z3_OP_SEQ_INDEX; + case OP_SEQ_TO_RE: return Z3_OP_SEQ_TO_RE; + case OP_SEQ_IN_RE: return Z3_OP_SEQ_IN_RE; - case Z3_OP_RE_PLUS: return Z3_OP_RE_PLUS; - case Z3_OP_RE_STAR: return Z3_OP_RE_STAR; - case Z3_OP_RE_OPTION: return Z3_OP_RE_OPTION; - case Z3_OP_RE_CONCAT: return Z3_OP_RE_CONCAT; - case Z3_OP_RE_UNION: return Z3_OP_RE_UNION; - case Z3_OP_RE_INTERSECT: return Z3_OP_RE_INTERSECT; - case Z3_OP_RE_LOOP: return Z3_OP_RE_LOOP; - case Z3_OP_RE_FULL_SET: return Z3_OP_RE_FULL_SET; - case Z3_OP_RE_EMPTY_SET: return Z3_OP_RE_EMPTY_SET; + case OP_STRING_STOI: return Z3_OP_STR_TO_INT; + case OP_STRING_ITOS: return Z3_OP_INT_TO_STR; + + case OP_RE_PLUS: return Z3_OP_RE_PLUS; + case OP_RE_STAR: return Z3_OP_RE_STAR; + case OP_RE_OPTION: return Z3_OP_RE_OPTION; + case OP_RE_CONCAT: return Z3_OP_RE_CONCAT; + case OP_RE_UNION: return Z3_OP_RE_UNION; + case OP_RE_INTERSECT: return Z3_OP_RE_INTERSECT; + case OP_RE_LOOP: return Z3_OP_RE_LOOP; + case OP_RE_FULL_SET: return Z3_OP_RE_FULL_SET; + case OP_RE_EMPTY_SET: return Z3_OP_RE_EMPTY_SET; default: return Z3_OP_INTERNAL; } diff --git a/src/api/api_seq.cpp b/src/api/api_seq.cpp index 478ee6274..986e6f497 100644 --- a/src/api/api_seq.cpp +++ b/src/api/api_seq.cpp @@ -141,6 +141,10 @@ extern "C" { MK_UNARY(Z3_mk_seq_to_re, mk_c(c)->get_seq_fid(), OP_SEQ_TO_RE, SKIP); MK_BINARY(Z3_mk_seq_in_re, mk_c(c)->get_seq_fid(), OP_SEQ_IN_RE, SKIP); + MK_UNARY(Z3_mk_int_to_str, mk_c(c)->get_seq_fid(), OP_STRING_ITOS, SKIP); + MK_UNARY(Z3_mk_str_to_int, mk_c(c)->get_seq_fid(), OP_STRING_STOI, SKIP); + + Z3_ast Z3_API Z3_mk_re_loop(Z3_context c, Z3_ast r, unsigned lo, unsigned hi) { Z3_TRY; LOG_Z3_mk_re_loop(c, r, lo, hi); diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index 979d9aed7..e5d0acaab 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -964,6 +964,17 @@ namespace z3 { check_error(); return expr(ctx(), r); } + expr stoi() const { + Z3_ast r = Z3_mk_str_to_int(ctx(), *this); + check_error(); + return expr(ctx(), r); + } + expr itos() const { + Z3_ast r = Z3_mk_int_to_str(ctx(), *this); + check_error(); + return expr(ctx(), r); + } + friend expr range(expr const& lo, expr const& hi); /** \brief create a looping regular expression. diff --git a/src/api/dotnet/Context.cs b/src/api/dotnet/Context.cs index f5c4dc99d..a656be3eb 100644 --- a/src/api/dotnet/Context.cs +++ b/src/api/dotnet/Context.cs @@ -2420,6 +2420,29 @@ namespace Microsoft.Z3 return new SeqExpr(this, Native.Z3_mk_string(nCtx, s)); } + /// + /// Convert an integer expression to a string. + /// + public SeqExpr IntToString(Expr e) + { + Contract.Requires(e != null); + Contract.Requires(e is ArithExpr); + Contract.Ensures(Contract.Result() != null); + return new SeqExpr(this, Native.Z3_mk_int_to_str(nCtx, e.NativeObject)); + } + + /// + /// Convert an integer expression to a string. + /// + public IntExpr StringToInt(Expr e) + { + Contract.Requires(e != null); + Contract.Requires(e is SeqExpr); + Contract.Ensures(Contract.Result() != null); + return new IntExpr(this, Native.Z3_mk_str_to_int(nCtx, e.NativeObject)); + } + + /// /// Concatentate sequences. /// diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index 77b74336e..f1fde1720 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -1011,6 +1011,7 @@ def _coerce_exprs(a, b, ctx=None): b = s.cast(b) return (a, b) + def _reduce(f, l, a): r = a for e in l: @@ -1296,7 +1297,7 @@ class BoolSortRef(SortRef): if isinstance(val, bool): return BoolVal(val, self.ctx) if __debug__: - _z3_assert(is_expr(val), "True, False or Z3 Boolean expression expected") + _z3_assert(is_expr(val), "True, False or Z3 Boolean expression expected. Received %s" % val) _z3_assert(self.eq(val.sort()), "Value cannot be converted into a Z3 Boolean value") return val @@ -2012,7 +2013,7 @@ class ArithSortRef(SortRef): if self.is_real(): return RealVal(val, self.ctx) if __debug__: - _z3_assert(False, "int, long, float, string (numeral), or Z3 Integer/Real expression expected") + _z3_assert(False, "int, long, float, string (numeral), or Z3 Integer/Real expression expected. Got %s" % self) def is_arith_sort(s): """Return `True` if s is an arithmetical sort (type). @@ -9660,6 +9661,29 @@ def Length(s): s = _coerce_seq(s) return ArithRef(Z3_mk_seq_length(s.ctx_ref(), s.as_ast()), s.ctx) +def StrToInt(s): + """Convert string expression to integer + >>> a = StrToInt("1") + >>> simplify(1 == a) + True + >>> b = StrToInt("2") + >>> simplify(1 == b) + False + >>> c = StrToInt(IntToStr(2)) + >>> simplify(1 == c) + False + """ + s = _coerce_seq(s) + return ArithRef(Z3_mk_str_to_int(s.ctx_ref(), s.as_ast()), s.ctx) + + +def IntToStr(s): + """Convert integer expression to string""" + if not is_expr(s): + s = _py2expr(s) + return SeqRef(Z3_mk_int_to_str(s.ctx_ref(), s.as_ast()), s.ctx) + + def Re(s, ctx=None): """The regular expression that accepts sequence 's' >>> s1 = Re("ab") diff --git a/src/api/z3_api.h b/src/api/z3_api.h index 65c155d63..ee35c002e 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -1152,6 +1152,10 @@ typedef enum { Z3_OP_SEQ_TO_RE, Z3_OP_SEQ_IN_RE, + // strings + Z3_OP_STR_TO_INT, + Z3_OP_INT_TO_STR, + // regular expressions Z3_OP_RE_PLUS, Z3_OP_RE_STAR, @@ -3325,6 +3329,21 @@ extern "C" { */ Z3_ast Z3_API Z3_mk_seq_index(Z3_context c, Z3_ast s, Z3_ast substr, Z3_ast offset); + /** + \brief Convert string to integer. + + def_API('Z3_mk_str_to_int' ,AST ,(_in(CONTEXT), _in(AST))) + */ + Z3_ast Z3_API Z3_mk_str_to_int(Z3_context c, Z3_ast s); + + + /** + \brief Integer to string conversion. + + def_API('Z3_mk_int_to_str' ,AST ,(_in(CONTEXT), _in(AST))) + */ + Z3_ast Z3_API Z3_mk_int_to_str(Z3_context c, Z3_ast s); + /** \brief Create a regular expression that accepts the sequence \c seq. From b42973152fea616fd634dfb4c8a231e898b079a3 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 11 Feb 2017 12:02:32 -0500 Subject: [PATCH 531/536] fix model generation for non-linear expressions, reported by Martin Suda and Giles Reger Signed-off-by: Nikolaj Bjorner --- src/smt/theory_arith.h | 1 + src/smt/theory_arith_core.h | 6 +++++- src/smt/theory_arith_nl.h | 12 +++++++++--- 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/src/smt/theory_arith.h b/src/smt/theory_arith.h index 5a0f8db95..77882f186 100644 --- a/src/smt/theory_arith.h +++ b/src/smt/theory_arith.h @@ -946,6 +946,7 @@ namespace smt { // // ----------------------------------- typedef int_hashtable > row_set; + bool m_model_depends_on_computed_epsilon; unsigned m_nl_rounds; bool m_nl_gb_exhausted; unsigned m_nl_strategy_idx; // for fairness diff --git a/src/smt/theory_arith_core.h b/src/smt/theory_arith_core.h index 9db5e8c72..513cf36a4 100644 --- a/src/smt/theory_arith_core.h +++ b/src/smt/theory_arith_core.h @@ -1405,6 +1405,7 @@ namespace smt { template final_check_status theory_arith::final_check_core() { + m_model_depends_on_computed_epsilon = false; unsigned old_idx = m_final_check_idx; final_check_status result = FC_DONE; final_check_status ok; @@ -1669,6 +1670,7 @@ namespace smt { m_liberal_final_check(true), m_changed_assignment(false), m_assume_eq_head(0), + m_model_depends_on_computed_epsilon(false), m_nl_rounds(0), m_nl_gb_exhausted(false), m_nl_new_exprs(m), @@ -3220,7 +3222,9 @@ namespace smt { m_factory = alloc(arith_factory, get_manager()); m.register_factory(m_factory); compute_epsilon(); - refine_epsilon(); + if (!m_model_depends_on_computed_epsilon) { + refine_epsilon(); + } } template diff --git a/src/smt/theory_arith_nl.h b/src/smt/theory_arith_nl.h index dd91ffbfb..52a117cd5 100644 --- a/src/smt/theory_arith_nl.h +++ b/src/smt/theory_arith_nl.h @@ -638,6 +638,7 @@ namespace smt { if (!val.get_infinitesimal().is_zero() && !computed_epsilon) { compute_epsilon(); computed_epsilon = true; + m_model_depends_on_computed_epsilon = true; } return val.get_rational().to_rational() + m_epsilon.to_rational() * val.get_infinitesimal().to_rational(); } @@ -652,14 +653,18 @@ namespace smt { bool theory_arith::check_monomial_assignment(theory_var v, bool & computed_epsilon) { SASSERT(is_pure_monomial(var2expr(v))); expr * m = var2expr(v); - rational val(1); + rational val(1), v_val; for (unsigned i = 0; i < to_app(m)->get_num_args(); i++) { expr * arg = to_app(m)->get_arg(i); theory_var curr = expr2var(arg); SASSERT(curr != null_theory_var); - val *= get_value(curr, computed_epsilon); + v_val = get_value(curr, computed_epsilon); + TRACE("non_linear", tout << mk_pp(arg, get_manager()) << " = " << v_val << "\n";); + val *= v_val; } - return get_value(v, computed_epsilon) == val; + v_val = get_value(v, computed_epsilon); + TRACE("non_linear", tout << "v" << v << " := " << v_val << " == " << val << "\n";); + return v_val == val; } @@ -2356,6 +2361,7 @@ namespace smt { */ template final_check_status theory_arith::process_non_linear() { + m_model_depends_on_computed_epsilon = false; if (m_nl_monomials.empty()) return FC_DONE; From 4c6efbbc8bce874cedbf8ffb14a3b883df62e767 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 11 Feb 2017 16:02:51 -0500 Subject: [PATCH 532/536] expose numerator/denominators for Martin and Giles Signed-off-by: Nikolaj Bjorner --- src/api/c++/z3++.h | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index e5d0acaab..e60809646 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -758,6 +758,20 @@ namespace z3 { return result; } + expr numerator() const { + assert(is_numeral()); + Z3_ast r = Z3_get_numerator(ctx(), m_ast); + check_error(); + return expr(ctx(),r); + } + + + expr denominator() const { + assert(is_numeral()); + Z3_ast r = Z3_get_denominator(ctx(), m_ast); + check_error(); + return expr(ctx(),r); + } operator Z3_app() const { assert(is_app()); return reinterpret_cast(m_ast); } From b3dabc7ccf9fde3997d8aaf1c3c61fd708a24803 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 11 Feb 2017 16:28:15 -0500 Subject: [PATCH 533/536] add missing mod/rem/is_int functionality to C++ API Signed-off-by: Nikolaj Bjorner --- src/api/c++/z3++.h | 72 ++++++++++++++++++++++++++++++++-------------- 1 file changed, 50 insertions(+), 22 deletions(-) diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index e60809646..d8027fbbc 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -435,6 +435,8 @@ namespace z3 { Z3_ast_kind kind() const { Z3_ast_kind r = Z3_get_ast_kind(ctx(), m_ast); check_error(); return r; } unsigned hash() const { unsigned r = Z3_get_ast_hash(ctx(), m_ast); check_error(); return r; } friend std::ostream & operator<<(std::ostream & out, ast const & n); + std::string to_string() const { return std::string(Z3_ast_to_string(ctx(), m_ast)); } + /** \brief Return true if the ASTs are structurally identical. @@ -757,7 +759,11 @@ namespace z3 { } return result; } - + + Z3_lbool bool_value() const { + return Z3_get_bool_value(ctx(), m_ast); + } + expr numerator() const { assert(is_numeral()); Z3_ast r = Z3_get_numerator(ctx(), m_ast); @@ -889,13 +895,23 @@ namespace z3 { friend expr operator*(expr const & a, int b); friend expr operator*(int a, expr const & b); - /** - \brief Power operator - */ + /* \brief Power operator */ friend expr pw(expr const & a, expr const & b); friend expr pw(expr const & a, int b); friend expr pw(int a, expr const & b); + /* \brief mod operator */ + friend expr mod(expr const& a, expr const& b); + friend expr mod(expr const& a, int b); + friend expr mod(int a, expr const& b); + + /* \brief rem operator */ + friend expr rem(expr const& a, expr const& b); + friend expr rem(expr const& a, int b); + friend expr rem(int a, expr const& b); + + friend expr is_int(expr const& e); + friend expr operator/(expr const & a, expr const & b); friend expr operator/(expr const & a, int b); friend expr operator/(int a, expr const & b); @@ -1026,34 +1042,46 @@ namespace z3 { }; +#define _Z3_MK_BIN_(a, b, binop) \ + check_context(a, b); \ + Z3_ast r = binop(a.ctx(), a, b); \ + a.check_error(); \ + return expr(a.ctx(), r); \ + + inline expr implies(expr const & a, expr const & b) { - check_context(a, b); - assert(a.is_bool() && b.is_bool()); - Z3_ast r = Z3_mk_implies(a.ctx(), a, b); - a.check_error(); - return expr(a.ctx(), r); + assert(a.is_bool() && b.is_bool()); + _Z3_MK_BIN_(a, b, Z3_mk_implies); } inline expr implies(expr const & a, bool b) { return implies(a, a.ctx().bool_val(b)); } inline expr implies(bool a, expr const & b) { return implies(b.ctx().bool_val(a), b); } - inline expr pw(expr const & a, expr const & b) { - assert(a.is_arith() && b.is_arith()); - check_context(a, b); - Z3_ast r = Z3_mk_power(a.ctx(), a, b); - a.check_error(); - return expr(a.ctx(), r); - } + inline expr pw(expr const & a, expr const & b) { _Z3_MK_BIN_(a, b, Z3_mk_power); } inline expr pw(expr const & a, int b) { return pw(a, a.ctx().num_val(b, a.get_sort())); } inline expr pw(int a, expr const & b) { return pw(b.ctx().num_val(a, b.get_sort()), b); } + inline expr mod(expr const& a, expr const& b) { _Z3_MK_BIN_(a, b, Z3_mk_mod); } + inline expr mod(expr const & a, int b) { return mod(a, a.ctx().num_val(b, a.get_sort())); } + inline expr mod(int a, expr const & b) { return mod(b.ctx().num_val(a, b.get_sort()), b); } - inline expr operator!(expr const & a) { - assert(a.is_bool()); - Z3_ast r = Z3_mk_not(a.ctx(), a); - a.check_error(); - return expr(a.ctx(), r); - } + inline expr rem(expr const& a, expr const& b) { _Z3_MK_BIN_(a, b, Z3_mk_rem); } + inline expr rem(expr const & a, int b) { return rem(a, a.ctx().num_val(b, a.get_sort())); } + inline expr rem(int a, expr const & b) { return rem(b.ctx().num_val(a, b.get_sort()), b); } + +#undef _Z3_MK_BIN_ + +#define _Z3_MK_UN_(a, mkun) \ + Z3_ast r = mkun(a.ctx(), a); \ + a.check_error(); \ + return expr(a.ctx(), r); \ + + + inline expr operator!(expr const & a) { assert(a.is_bool()); _Z3_MK_UN_(a, Z3_mk_not); } + + inline expr is_int(expr const& e) { _Z3_MK_UN_(e, Z3_mk_is_int); } + +#undef _Z3_MK_UN_ inline expr operator&&(expr const & a, expr const & b) { check_context(a, b); From 6fcba26ea6c695628fa701aee0e8cf78141ba8d0 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 12 Feb 2017 09:56:49 -0800 Subject: [PATCH 534/536] make parameters accessible from expressions. Issue #896 Signed-off-by: Nikolaj Bjorner --- src/api/python/z3/z3.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index f1fde1720..6729d99b5 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -868,6 +868,9 @@ class ExprRef(AstRef): _args, sz = _to_ast_array((a, b)) return BoolRef(Z3_mk_distinct(self.ctx_ref(), 2, _args), self.ctx) + def params(self): + return self.decl().params() + def decl(self): """Return the Z3 function declaration associated with a Z3 application. From e7a21dfac21c6f34576a7475b520695e5b5fb9fa Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 13 Feb 2017 08:16:39 -0800 Subject: [PATCH 535/536] add par_and_then Signed-off-by: Nikolaj Bjorner --- src/api/c++/z3++.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index 37e6448c9..e655815ca 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -1934,6 +1934,7 @@ namespace z3 { friend tactic with(tactic const & t, params const & p); friend tactic try_for(tactic const & t, unsigned ms); friend tactic par_or(unsigned n, tactic const* tactics); + friend tactic par_and_then(tactic const& t1, tactic const& t2); param_descrs get_param_descrs() { return param_descrs(ctx(), Z3_tactic_get_param_descrs(ctx(), m_tactic)); } }; @@ -1976,6 +1977,13 @@ namespace z3 { return tactic(tactics[0].ctx(), Z3_tactic_par_or(tactics[0].ctx(), n, buffer.ptr())); } + inline tactic par_and_then(tactic const & t1, tactic const & t2) { + check_context(t1, t2); + Z3_tactic r = Z3_tactic_par_and_then(t1.ctx(), t1, t2); + t1.check_error(); + return tactic(t1.ctx(), r); + } + class probe : public object { Z3_probe m_probe; void init(Z3_probe s) { From c67cf1653ca51d47bee7eaeee43bf3f8e5f3e3ea Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 15 Feb 2017 08:46:58 -0800 Subject: [PATCH 536/536] use non _ method from z3printer module so to be resilient against how _ is handled as indicator of private functions Signed-off-by: Nikolaj Bjorner --- src/api/python/z3/z3printer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/python/z3/z3printer.py b/src/api/python/z3/z3printer.py index 8a67fa911..aef71be2f 100644 --- a/src/api/python/z3/z3printer.py +++ b/src/api/python/z3/z3printer.py @@ -678,7 +678,7 @@ class Formatter: if self.fpa_pretty: if self.is_infix(k) and n >= 3: rm = a.arg(0) - if z3.is_fprm_value(rm) and z3._dflt_rm(a.ctx).eq(rm): + if z3.is_fprm_value(rm) and z3.get_default_rounding_mode(a.ctx).eq(rm): arg1 = to_format(self.pp_expr(a.arg(1), d+1, xs)) arg2 = to_format(self.pp_expr(a.arg(2), d+1, xs)) r = []
%s