From 0e066fef1faa82a372e63b61cf794729c7a76af3 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 15 Jul 2021 13:43:13 +0200 Subject: [PATCH 001/125] fix boundary cases reported by Clemens --- src/ast/rewriter/seq_axioms.cpp | 38 ++++++++++++++++++++------------- 1 file changed, 23 insertions(+), 15 deletions(-) diff --git a/src/ast/rewriter/seq_axioms.cpp b/src/ast/rewriter/seq_axioms.cpp index cffef51a0..4c8cd932d 100644 --- a/src/ast/rewriter/seq_axioms.cpp +++ b/src/ast/rewriter/seq_axioms.cpp @@ -776,26 +776,27 @@ namespace seq { rational pow(1); for (unsigned i = 0; i < k; ++i) pow *= 10; - if (k == 0) { - ge10k = m.mk_true(); - } - else { - ge10k = bv.mk_ule(bv.mk_numeral(pow, bv_sort), b); - } + ge10k = bv.mk_ule(bv.mk_numeral(pow, bv_sort), b); ge10k1 = bv.mk_ule(bv.mk_numeral(pow * 10, bv_sort), b); unsigned sz = bv.get_bv_size(b); expr_ref_vector es(m); expr_ref bb(b, m), ten(bv.mk_numeral(10, sz), m); - pow = 1; + rational p(1); for (unsigned i = 0; i <= k; ++i) { - if (pow > 1) - bb = bv.mk_bv_udiv(b, bv.mk_numeral(pow, bv_sort)); + if (p > 1) + bb = bv.mk_bv_udiv(b, bv.mk_numeral(p, bv_sort)); es.push_back(seq.str.mk_unit(m_sk.mk_ubv2ch(bv.mk_bv_urem(bb, ten)))); - pow *= 10; + p *= 10; } es.reverse(); eq = m.mk_eq(seq.str.mk_ubv2s(b), seq.str.mk_concat(es, seq.str.mk_string_sort())); - add_clause(~ge10k, ge10k1, eq); + SASSERT(pow < rational::power_of_two(sz)); + if (k == 0) + add_clause(ge10k1, eq); + else if (pow * 10 >= rational::power_of_two(sz)) + add_clause(~ge10k, eq); + else + add_clause(~ge10k, ge10k1, eq); } /* @@ -810,12 +811,19 @@ namespace seq { rational pow(1); for (unsigned i = 1; i < k; ++i) pow *= 10; - if (pow * 10 >= rational::power_of_two(sz)) - return; // TODO: add conflict when k is too large or avoid overflow bounds and limits + expr_ref len(seq.str.mk_length(seq.str.mk_ubv2s(b)), m); + if (pow >= rational::power_of_two(sz)) { + expr_ref ge(a.mk_ge(len, a.mk_int(k)), m); + add_clause(~ge); + return; + } + ge10k = bv.mk_ule(bv.mk_numeral(pow, bv_sort), b); ge10k1 = bv.mk_ule(bv.mk_numeral(pow * 10, bv_sort), b); - eq = m.mk_eq(seq.str.mk_length(seq.str.mk_ubv2s(b)), a.mk_int(k)); - add_clause(~eq, ~ge10k1); + eq = m.mk_eq(len, a.mk_int(k)); + + if (pow * 10 < rational::power_of_two(sz)) + add_clause(~eq, ~ge10k1); if (k > 1) add_clause(~eq, ge10k); } From c7a7d40a8f69d3bc8ac54886a9a5f1d04d3562bc Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 15 Jul 2021 18:47:25 +0200 Subject: [PATCH 002/125] remove incorrect and inefficient default model conversion --- src/solver/solver.cpp | 15 ----- src/solver/solver.h | 3 +- src/solver/solver_params.pyg | 3 +- src/tactic/generic_model_converter.cpp | 62 --------------------- src/tactic/generic_model_converter.h | 4 +- src/tactic/horn_subsume_model_converter.cpp | 4 -- src/tactic/horn_subsume_model_converter.h | 2 - src/tactic/model_converter.h | 3 +- 8 files changed, 6 insertions(+), 90 deletions(-) diff --git a/src/solver/solver.cpp b/src/solver/solver.cpp index 32cb0b940..b53e3daed 100644 --- a/src/solver/solver.cpp +++ b/src/solver/solver.cpp @@ -202,12 +202,6 @@ bool solver::is_literal(ast_manager& m, expr* e) { void solver::assert_expr(expr* f) { expr_ref fml(f, get_manager()); - if (m_enforce_model_conversion) { - model_converter_ref mc = get_model_converter(); - if (mc) { - (*mc)(fml); - } - } assert_expr_core(fml); } @@ -215,13 +209,6 @@ void solver::assert_expr(expr* f, expr* t) { ast_manager& m = get_manager(); expr_ref fml(f, m); expr_ref a(t, m); - if (m_enforce_model_conversion) { - model_converter_ref mc = get_model_converter(); - if (mc) { - (*mc)(fml); - // (*mc)(a); - } - } assert_expr_core2(fml, a); } @@ -241,14 +228,12 @@ void solver::collect_param_descrs(param_descrs & r) { void solver::reset_params(params_ref const & p) { m_params = p; solver_params sp(m_params); - m_enforce_model_conversion = sp.enforce_model_conversion(); m_cancel_backup_file = sp.cancel_backup_file(); } void solver::updt_params(params_ref const & p) { m_params.copy(p); solver_params sp(m_params); - m_enforce_model_conversion = sp.enforce_model_conversion(); m_cancel_backup_file = sp.cancel_backup_file(); } diff --git a/src/solver/solver.h b/src/solver/solver.h index b65dc2fe8..14fd49bce 100644 --- a/src/solver/solver.h +++ b/src/solver/solver.h @@ -49,10 +49,9 @@ solver* mk_smt2_solver(ast_manager& m, params_ref const& p); */ class solver : public check_sat_result { params_ref m_params; - bool m_enforce_model_conversion; symbol m_cancel_backup_file; public: - solver(): m_enforce_model_conversion(false) {} + solver() {} ~solver() override {} /** diff --git a/src/solver/solver_params.pyg b/src/solver/solver_params.pyg index b852afbaa..21d0ab530 100644 --- a/src/solver/solver_params.pyg +++ b/src/solver/solver_params.pyg @@ -2,8 +2,7 @@ def_module_params('solver', description='solver parameters', export=True, - params=(('enforce_model_conversion', BOOL, False, "apply model transformation on new assertions"), - ('smtlib2_log', SYMBOL, '', "file to save solver interaction"), + params=(('smtlib2_log', SYMBOL, '', "file to save solver interaction"), ('cancel_backup_file', SYMBOL, '', "file to save partial search state if search is canceled"), ('timeout', UINT, UINT_MAX, "timeout on the solver object; overwrites a global timeout"), )) diff --git a/src/tactic/generic_model_converter.cpp b/src/tactic/generic_model_converter.cpp index 8ef21d9c9..2886eb6ab 100644 --- a/src/tactic/generic_model_converter.cpp +++ b/src/tactic/generic_model_converter.cpp @@ -139,68 +139,6 @@ void generic_model_converter::set_env(ast_pp_util* visitor) { } } -struct min_app_idx_proc { - unsigned m_min; - obj_map& m_idxs; - min_app_idx_proc(obj_map& idxs) : m_min(UINT_MAX), m_idxs(idxs) {} - void operator()(app * n) { - unsigned idx; - if (m_idxs.find(n->get_decl(), idx)) { - m_min = std::min(m_min, idx); - } - } - void operator()(var * n) {} - void operator()(quantifier * n) {} -}; - -void generic_model_converter::operator()(expr_ref& fml) { - min_app_idx_proc min_proc(m_first_idx); - for_each_expr(min_proc, fml); - unsigned min_idx = min_proc.m_min; - if (min_idx == UINT_MAX) return; - expr_ref_vector fmls(m); - fmls.push_back(fml); - for (unsigned i = m_entries.size(); i-- > min_idx;) { - entry const& e = m_entries[i]; - if (e.m_instruction != instruction::ADD) { - continue; - } - unsigned arity = e.m_f->get_arity(); - if (arity == 0) { - fmls.push_back(simplify_def(e)); - } - else { - expr_ref_vector args(m); - sort_ref_vector sorts(m); - svector names; - for (unsigned i = 0; i < arity; ++i) { - sorts.push_back(e.m_f->get_domain(i)); - names.push_back(symbol(i)); - args.push_back(m.mk_var(i, sorts.back())); - } - // TBD: check if order is correct with respect to quantifier binding ordering - expr_ref lhs(m.mk_app(e.m_f, arity, args.data()), m); - expr_ref body(m.mk_eq(lhs, e.m_def), m); - fmls.push_back(m.mk_forall(arity, sorts.data(), names.data(), body)); - } - if (m_first_idx[e.m_f] == i) { - m_first_idx.remove(e.m_f); - } - } - unsigned j = min_idx; - for (unsigned i = min_idx; i < m_entries.size(); ++i) { - entry& e = m_entries[i]; - if (e.m_instruction == instruction::HIDE) { - if (i != j) { - m_entries[j] = e; - } - ++j; - } - } - m_entries.shrink(j); - fml = mk_and(fmls); -} - void generic_model_converter::get_units(obj_map& units) { th_rewriter rw(m); expr_safe_replace rep(m); diff --git a/src/tactic/generic_model_converter.h b/src/tactic/generic_model_converter.h index 54268ac1b..e809fe734 100644 --- a/src/tactic/generic_model_converter.h +++ b/src/tactic/generic_model_converter.h @@ -54,6 +54,8 @@ public: void operator()(model_ref & md) override; + void operator()(expr_ref& fml) override { UNREACHABLE(); } + void cancel() override {} void display(std::ostream & out) override; @@ -64,8 +66,6 @@ public: void set_env(ast_pp_util* visitor) override; - void operator()(expr_ref& fml) override; - void get_units(obj_map& units) override; }; diff --git a/src/tactic/horn_subsume_model_converter.cpp b/src/tactic/horn_subsume_model_converter.cpp index 38e6a42c5..79b9a038f 100644 --- a/src/tactic/horn_subsume_model_converter.cpp +++ b/src/tactic/horn_subsume_model_converter.cpp @@ -169,10 +169,6 @@ void horn_subsume_model_converter::add_default_false_interpretation(expr* e, mod } -void horn_subsume_model_converter::operator()(expr_ref& fml) { - NOT_IMPLEMENTED_YET(); -} - void horn_subsume_model_converter::operator()(model_ref& mr) { func_decl_ref pred(m); diff --git a/src/tactic/horn_subsume_model_converter.h b/src/tactic/horn_subsume_model_converter.h index f007a63f3..41e59070e 100644 --- a/src/tactic/horn_subsume_model_converter.h +++ b/src/tactic/horn_subsume_model_converter.h @@ -72,8 +72,6 @@ public: void operator()(model_ref& _m) override; - void operator()(expr_ref& fml) override; - model_converter * translate(ast_translation & translator) override; ast_manager& get_manager() { return m; } diff --git a/src/tactic/model_converter.h b/src/tactic/model_converter.h index 2b3a1b510..3ed9f298b 100644 --- a/src/tactic/model_converter.h +++ b/src/tactic/model_converter.h @@ -76,6 +76,8 @@ public: virtual void operator()(model_ref & m) = 0; virtual void operator()(labels_vec & r) {} + + virtual void operator()(expr_ref& fml) { UNREACHABLE(); } virtual model_converter * translate(ast_translation & translator) = 0; @@ -86,7 +88,6 @@ public: The operator has as side effect of adding definitions as assertions to the formula and removing these definitions from the model converter. */ - virtual void operator()(expr_ref& formula) { UNREACHABLE(); } virtual void get_units(obj_map& fmls) { UNREACHABLE(); } }; From 8e9bc86c232fd4567c1e00ebd9b492239f386939 Mon Sep 17 00:00:00 2001 From: Margus Veanes Date: Thu, 15 Jul 2021 13:28:59 -0700 Subject: [PATCH 003/125] fixed bug #5343 and did some related optimizations (#5411) --- src/ast/rewriter/seq_rewriter.cpp | 41 +++++++++++++++++++++++-------- src/smt/seq_regex.cpp | 6 +++-- 2 files changed, 35 insertions(+), 12 deletions(-) diff --git a/src/ast/rewriter/seq_rewriter.cpp b/src/ast/rewriter/seq_rewriter.cpp index 0bd653232..5555f8439 100644 --- a/src/ast/rewriter/seq_rewriter.cpp +++ b/src/ast/rewriter/seq_rewriter.cpp @@ -3158,7 +3158,7 @@ expr_ref seq_rewriter::mk_der_cond(expr* cond, expr* ele, sort* seq_sort) { expr *c1 = nullptr, *c2 = nullptr, *ch1 = nullptr, *ch2 = nullptr; unsigned ch = 0; expr_ref result(m()), r1(m()), r2(m()); - if (m().is_eq(cond, ch1, ch2)) { + if (m().is_eq(cond, ch1, ch2) && u().is_char(ch1)) { r1 = u().mk_le(ch1, ch2); r1 = mk_der_cond(r1, ele, seq_sort); r2 = u().mk_le(ch2, ch1); @@ -3219,11 +3219,17 @@ expr_ref seq_rewriter::mk_derivative_rec(expr* ele, expr* r) { } expr_ref dr2 = mk_derivative(ele, r2); is_n = re_predicate(is_n, seq_sort); - // Instead of mk_der_union here, we use mk_der_antimorov_union to - // force the two cases to be considered separately and lifted to - // the top level. This avoids blowup in cases where determinization - // is expensive. - return mk_der_antimorov_union(result, mk_der_concat(is_n, dr2)); + if (re().is_empty(dr2)) { + //do not concatenate [], it is a deade-end + return result; + } + else { + // Instead of mk_der_union here, we use mk_der_antimorov_union to + // force the two cases to be considered separately and lifted to + // the top level. This avoids blowup in cases where determinization + // is expensive. + return mk_der_antimorov_union(result, mk_der_concat(is_n, dr2)); + } } else if (re().is_star(r, r1)) { return mk_der_concat(mk_derivative(ele, r1), r); @@ -3256,8 +3262,15 @@ expr_ref seq_rewriter::mk_derivative_rec(expr* ele, expr* r) { if (lo > 0) { lo--; } - result = re().mk_loop(r1, lo); - return mk_der_concat(mk_derivative(ele, r1), result); + result = mk_derivative(ele, r1); + //do not concatenate with [] (emptyset) + if (re().is_empty(result)) { + return result; + } + else { + //do not create loop r1{0,}, instead create r1* + return mk_der_concat(result, (lo == 0 ? re().mk_star(r1) : re().mk_loop(r1, lo))); + } } else if (re().is_loop(r, r1, lo, hi)) { if (hi == 0) { @@ -3267,8 +3280,14 @@ expr_ref seq_rewriter::mk_derivative_rec(expr* ele, expr* r) { if (lo > 0) { lo--; } - result = re().mk_loop(r1, lo, hi); - return mk_der_concat(mk_derivative(ele, r1), result); + result = mk_derivative(ele, r1); + //do not concatenate with [] (emptyset) or handle the rest of the loop if no more iterations remain + if (re().is_empty(result) || hi == 0) { + return result; + } + else { + return mk_der_concat(result, re().mk_loop(r1, lo, hi)); + } } else if (re().is_full_seq(r) || re().is_empty(r)) { @@ -3288,6 +3307,8 @@ expr_ref seq_rewriter::mk_derivative_rec(expr* ele, expr* r) { return result; } else if (str().is_empty(r1)) { + //observe: str().is_empty(r1) checks that r = () = epsilon + //while mk_empty() = [], because deriv(epsilon) = [] = nothing return mk_empty(); } #if 0 diff --git a/src/smt/seq_regex.cpp b/src/smt/seq_regex.cpp index c35e413ba..80282c3f8 100644 --- a/src/smt/seq_regex.cpp +++ b/src/smt/seq_regex.cpp @@ -272,13 +272,15 @@ namespace smt { << "PA(" << mk_pp(s, m) << "@" << idx << "," << state_str(r) << ") ";); - if (re().is_empty(r)) { + auto info = re().get_info(r); + + //if the minlength of the regex is UINT_MAX then the regex is a deadend + if (re().is_empty(r) || info.min_length == UINT_MAX) { STRACE("seq_regex_brief", tout << "(empty) ";); th.add_axiom(~lit); return; } - auto info = re().get_info(r); if (info.interpreted) { update_state_graph(r); From 9e5dcf3ecb348460bda8b5ff7da89c37fa364919 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 16 Jul 2021 16:17:59 +0200 Subject: [PATCH 004/125] bound length of ubv2s Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/seq_axioms.cpp | 18 ++++++++++++++++++ src/ast/rewriter/seq_axioms.h | 1 + src/ast/rewriter/seq_rewriter.cpp | 1 + src/smt/seq_axioms.h | 1 + src/smt/theory_seq.cpp | 1 + 5 files changed, 22 insertions(+) diff --git a/src/ast/rewriter/seq_axioms.cpp b/src/ast/rewriter/seq_axioms.cpp index 4c8cd932d..d3bc217a3 100644 --- a/src/ast/rewriter/seq_axioms.cpp +++ b/src/ast/rewriter/seq_axioms.cpp @@ -799,6 +799,24 @@ namespace seq { add_clause(~ge10k, ge10k1, eq); } + /* + * 1 <= len(ubv2s(b)) <= k, where k is min such that 10^k > 2^sz + */ + void axioms::ubv2s_len_axiom(expr* b) { + bv_util bv(m); + sort* bv_sort = b->get_sort(); + unsigned sz = bv.get_bv_size(bv_sort); + unsigned k = 1; + rational pow(10); + while (pow <= rational::power_of_two(sz)) + ++k, pow *= 10; + expr_ref len(seq.str.mk_length(seq.str.mk_ubv2s(b)), m); + expr_ref ge(a.mk_ge(len, a.mk_int(1)), m); + expr_ref le(a.mk_le(len, a.mk_int(k)), m); + add_clause(le); + add_clause(ge); + } + /* * len(ubv2s(b)) = k => 10^k-1 <= b < 10^{k} k > 1 * len(ubv2s(b)) = 1 => b < 10^{1} k = 1 diff --git a/src/ast/rewriter/seq_axioms.h b/src/ast/rewriter/seq_axioms.h index c9cdbfc9a..6cd83b00f 100644 --- a/src/ast/rewriter/seq_axioms.h +++ b/src/ast/rewriter/seq_axioms.h @@ -96,6 +96,7 @@ namespace seq { void itos_axiom(expr* s, unsigned k); void ubv2s_axiom(expr* b, unsigned k); void ubv2s_len_axiom(expr* b, unsigned k); + void ubv2s_len_axiom(expr* b); void ubv2ch_axiom(sort* bv_sort); void lt_axiom(expr* n); void le_axiom(expr* n); diff --git a/src/ast/rewriter/seq_rewriter.cpp b/src/ast/rewriter/seq_rewriter.cpp index 5555f8439..dcea166cd 100644 --- a/src/ast/rewriter/seq_rewriter.cpp +++ b/src/ast/rewriter/seq_rewriter.cpp @@ -3363,6 +3363,7 @@ expr_ref seq_rewriter::mk_derivative_rec(expr* ele, expr* r) { } expr* e1 = nullptr, *e2 = nullptr; if (str().is_unit(r1, e1) && str().is_unit(r2, e2)) { + SASSERT(u().is_char(e1)); // Use mk_der_cond to normalize STRACE("seq_verbose", tout << "deriv range str" << std::endl;); expr_ref p1(u().mk_le(e1, ele), m()); diff --git a/src/smt/seq_axioms.h b/src/smt/seq_axioms.h index c5aa68e0a..e9fc3cb53 100644 --- a/src/smt/seq_axioms.h +++ b/src/smt/seq_axioms.h @@ -81,6 +81,7 @@ namespace smt { void add_itos_axiom(expr* s, unsigned k) { m_ax.itos_axiom(s, k); } void add_ubv2s_axiom(expr* b, unsigned k) { m_ax.ubv2s_axiom(b, k); } void add_ubv2s_len_axiom(expr* b, unsigned k) { m_ax.ubv2s_len_axiom(b, k); } + void add_ubv2s_len_axiom(expr* b) { m_ax.ubv2s_len_axiom(b); } void add_ubv2ch_axioms(sort* s) { m_ax.ubv2ch_axiom(s); } void add_lt_axiom(expr* n) { m_ax.lt_axiom(n); } void add_le_axiom(expr* n) { m_ax.le_axiom(n); } diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index 436752aa7..ba9f7c8fd 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -1542,6 +1542,7 @@ void theory_seq::add_ubv_string(expr* e) { } if (!has_sort) m_ax.add_ubv2ch_axioms(b->get_sort()); + m_ax.add_ubv2s_len_axiom(b); m_ubv_string.push_back(e); m_trail_stack.push(push_back_vector(m_ubv_string)); add_length_to_eqc(e); From 0fa4b63d2699c791e2882c9586186dd53266d871 Mon Sep 17 00:00:00 2001 From: CEisenhofer <56730610+CEisenhofer@users.noreply.github.com> Date: Fri, 16 Jul 2021 17:58:28 +0200 Subject: [PATCH 005/125] Added sbv2s (#5413) * Added sbv2s * Fixed indention Co-authored-by: Clemens Eisenhofer --- src/api/api_ast.cpp | 3 ++- src/api/api_seq.cpp | 1 + src/api/c++/z3++.h | 5 ++++ src/api/dotnet/Context.cs | 41 +++++++++++++++++++------------ src/api/java/Context.java | 10 +++++++- src/api/z3_api.h | 7 ++++++ src/ast/bv_decl_plugin.h | 1 + src/ast/rewriter/seq_rewriter.cpp | 28 +++++++++++++++++++++ src/ast/rewriter/seq_rewriter.h | 1 + src/ast/seq_decl_plugin.cpp | 22 ++++++++++++++--- src/ast/seq_decl_plugin.h | 7 +++++- 11 files changed, 104 insertions(+), 22 deletions(-) diff --git a/src/api/api_ast.cpp b/src/api/api_ast.cpp index 648e3cd97..50a02d262 100644 --- a/src/api/api_ast.cpp +++ b/src/api/api_ast.cpp @@ -1202,7 +1202,8 @@ extern "C" { case OP_STRING_STOI: return Z3_OP_STR_TO_INT; case OP_STRING_ITOS: return Z3_OP_INT_TO_STR; - case OP_STRING_UBVTOS: return Z3_OP_UBV_TO_STR; + case OP_STRING_UBVTOS: return Z3_OP_UBV_TO_STR; + case OP_STRING_SBVTOS: return Z3_OP_SBV_TO_STR; case OP_STRING_LT: return Z3_OP_STRING_LT; case OP_STRING_LE: return Z3_OP_STRING_LE; diff --git a/src/api/api_seq.cpp b/src/api/api_seq.cpp index fc336da74..9ce3ded09 100644 --- a/src/api/api_seq.cpp +++ b/src/api/api_seq.cpp @@ -245,6 +245,7 @@ extern "C" { 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); MK_UNARY(Z3_mk_ubv_to_str, mk_c(c)->get_seq_fid(), OP_STRING_UBVTOS, SKIP); + MK_UNARY(Z3_mk_sbv_to_str, mk_c(c)->get_seq_fid(), OP_STRING_SBVTOS, SKIP); Z3_ast Z3_API Z3_mk_re_loop(Z3_context c, Z3_ast r, unsigned lo, unsigned hi) { diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index 792b038e9..28e8aa052 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -1447,6 +1447,11 @@ namespace z3 { check_error(); return expr(ctx(), r); } + expr sbvtos() const { + Z3_ast r = Z3_mk_sbv_to_str(ctx(), *this); + check_error(); + return expr(ctx(), r); + } friend expr range(expr const& lo, expr const& hi); /** diff --git a/src/api/dotnet/Context.cs b/src/api/dotnet/Context.cs index d40281a81..7279fe847 100644 --- a/src/api/dotnet/Context.cs +++ b/src/api/dotnet/Context.cs @@ -556,18 +556,18 @@ namespace Microsoft.Z3 /// /// Bind a definition to a recursive function declaration. - /// The function must have previously been created using - /// MkRecFuncDecl. The body may contain recursive uses of the function or - /// other mutually recursive functions. + /// The function must have previously been created using + /// MkRecFuncDecl. The body may contain recursive uses of the function or + /// other mutually recursive functions. /// - public void AddRecDef(FuncDecl f, Expr[] args, Expr body) - { - CheckContextMatch(f); - CheckContextMatch(args); - CheckContextMatch(body); + public void AddRecDef(FuncDecl f, Expr[] args, Expr body) + { + CheckContextMatch(f); + CheckContextMatch(args); + CheckContextMatch(body); IntPtr[] argsNative = AST.ArrayToNative(args); - Native.Z3_add_rec_def(nCtx, f.NativeObject, (uint)args.Length, argsNative, body.NativeObject); - } + Native.Z3_add_rec_def(nCtx, f.NativeObject, (uint)args.Length, argsNative, body.NativeObject); + } /// /// Creates a new function declaration. @@ -2405,6 +2405,15 @@ namespace Microsoft.Z3 return new SeqExpr(this, Native.Z3_mk_ubv_to_str(nCtx, e.NativeObject)); } + /// + /// Convert a bit-vector expression, represented as an signed number, to a string. + /// + public SeqExpr SbvToString(Expr e) { + Debug.Assert(e != null); + Debug.Assert(e is ArithExpr); + return new SeqExpr(this, Native.Z3_mk_sbv_to_str(nCtx, e.NativeObject)); + } + /// /// Convert an integer expression to a string. /// @@ -2474,7 +2483,7 @@ namespace Microsoft.Z3 /// /// Check if the string s1 is lexicographically strictly less than s2. /// - public BoolExpr MkStringLt(SeqExpr s1, SeqExpr s2) + public BoolExpr MkStringLt(SeqExpr s1, SeqExpr s2) { Debug.Assert(s1 != null); Debug.Assert(s2 != null); @@ -2485,7 +2494,7 @@ namespace Microsoft.Z3 /// /// Check if the string s1 is lexicographically strictly less than s2. /// - public BoolExpr MkStringLe(SeqExpr s1, SeqExpr s2) + public BoolExpr MkStringLe(SeqExpr s1, SeqExpr s2) { Debug.Assert(s1 != null); Debug.Assert(s2 != null); @@ -2655,7 +2664,7 @@ namespace Microsoft.Z3 /// /// Create the empty regular expression. - /// The sort s should be a regular expression. + /// The sort s should be a regular expression. /// public ReExpr MkEmptyRe(Sort s) { @@ -2665,7 +2674,7 @@ namespace Microsoft.Z3 /// /// Create the full regular expression. - /// The sort s should be a regular expression. + /// The sort s should be a regular expression. /// public ReExpr MkFullRe(Sort s) { @@ -3399,7 +3408,7 @@ namespace Microsoft.Z3 { Debug.Assert(t1 != null); Debug.Assert(t2 != null); - // Debug.Assert(ts == null || Contract.ForAll(0, ts.Length, j => ts[j] != null)); + // Debug.Assert(ts == null || Contract.ForAll(0, ts.Length, j => ts[j] != null)); return AndThen(t1, t2, ts); } @@ -4696,7 +4705,7 @@ namespace Microsoft.Z3 { foreach (Z3Object a in arr) { - Debug.Assert(a != null); // It was an assume, now we added the precondition, and we made it into an assert + Debug.Assert(a != null); // It was an assume, now we added the precondition, and we made it into an assert CheckContextMatch(a); } } diff --git a/src/api/java/Context.java b/src/api/java/Context.java index a6b867eb8..1e581c482 100644 --- a/src/api/java/Context.java +++ b/src/api/java/Context.java @@ -2035,7 +2035,15 @@ public class Context implements AutoCloseable { { return (SeqExpr) Expr.create(this, Native.mkUbvToStr(nCtx(), e.getNativeObject())); } - + + /** + * Convert an signed bitvector expression to a string. + */ + public SeqExpr sbvToString(Expr e) + { + return (SeqExpr) Expr.create(this, Native.mkSbvToStr(nCtx(), e.getNativeObject())); + } + /** * Convert an integer expression to a string. */ diff --git a/src/api/z3_api.h b/src/api/z3_api.h index f636e7caa..79f7ca25d 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -1203,6 +1203,7 @@ typedef enum { Z3_OP_STR_TO_INT, Z3_OP_INT_TO_STR, Z3_OP_UBV_TO_STR, + Z3_OP_SBV_TO_STR, Z3_OP_STRING_LT, Z3_OP_STRING_LE, @@ -3655,6 +3656,12 @@ extern "C" { */ Z3_ast Z3_API Z3_mk_ubv_to_str(Z3_context c, Z3_ast s); + /** + \brief Signed bit-vector to string conversion. + + def_API('Z3_mk_sbv_to_str' ,AST ,(_in(CONTEXT), _in(AST))) + */ + Z3_ast Z3_API Z3_mk_sbv_to_str(Z3_context c, Z3_ast s); /** \brief Create a regular expression that accepts the sequence \c seq. diff --git a/src/ast/bv_decl_plugin.h b/src/ast/bv_decl_plugin.h index e780ad7a7..25c68819a 100644 --- a/src/ast/bv_decl_plugin.h +++ b/src/ast/bv_decl_plugin.h @@ -406,6 +406,7 @@ public: app * mk_ule(expr * arg1, expr * arg2) { return m_manager.mk_app(get_fid(), OP_ULEQ, arg1, arg2); } app * mk_sle(expr * arg1, expr * arg2) { return m_manager.mk_app(get_fid(), OP_SLEQ, arg1, arg2); } + app * mk_slt(expr * arg1, expr * arg2) { return m_manager.mk_app(get_fid(), OP_SLT, arg1, arg2); } app * mk_extract(unsigned high, unsigned low, expr * n) { parameter params[2] = { parameter(high), parameter(low) }; return m_manager.mk_app(get_fid(), OP_EXTRACT, 2, params, 1, &n); diff --git a/src/ast/rewriter/seq_rewriter.cpp b/src/ast/rewriter/seq_rewriter.cpp index dcea166cd..312bab3bb 100644 --- a/src/ast/rewriter/seq_rewriter.cpp +++ b/src/ast/rewriter/seq_rewriter.cpp @@ -718,6 +718,10 @@ br_status seq_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * con SASSERT(num_args == 1); st = mk_str_ubv2s(args[0], result); break; + case OP_STRING_SBVTOS: + SASSERT(num_args == 1); + st = mk_str_sbv2s(args[0], result); + break; case _OP_STRING_CONCAT: case _OP_STRING_PREFIX: case _OP_STRING_SUFFIX: @@ -2218,6 +2222,30 @@ br_status seq_rewriter::mk_str_ubv2s(expr* a, expr_ref& result) { return BR_FAILED; } +br_status seq_rewriter::mk_str_sbv2s(expr *a, expr_ref &result) { + bv_util bv(m()); + rational val; + unsigned bv_size = 0; + if (bv.is_numeral(a, val, bv_size)) { + rational r = mod(val, rational::power_of_two(bv_size)); + SASSERT(!r.is_neg()); + if (r >= rational::power_of_two(bv_size - 1)) { + r -= rational::power_of_two(bv_size); + } + result = str().mk_string(zstring(r)); + return BR_DONE; + } + + bv_size = bv.get_bv_size(a); + result = m().mk_ite( + bv.mk_slt(a,bv.mk_numeral(0, bv_size)), + str().mk_concat( + str().mk_string(zstring("-")), + str().mk_ubv2s(bv.mk_bv_neg(a)) + ), + str().mk_ubv2s(a)); + return BR_REWRITE_FULL; +} br_status seq_rewriter::mk_str_itos(expr* a, expr_ref& result) { rational r; diff --git a/src/ast/rewriter/seq_rewriter.h b/src/ast/rewriter/seq_rewriter.h index 7d102a5fb..c779a5f73 100644 --- a/src/ast/rewriter/seq_rewriter.h +++ b/src/ast/rewriter/seq_rewriter.h @@ -229,6 +229,7 @@ class seq_rewriter { br_status mk_str_itos(expr* a, expr_ref& result); br_status mk_str_stoi(expr* a, expr_ref& result); br_status mk_str_ubv2s(expr* a, expr_ref& result); + br_status mk_str_sbv2s(expr* a, expr_ref& result); br_status mk_str_in_regexp(expr* a, expr* b, expr_ref& result); br_status mk_str_to_regexp(expr* a, expr_ref& result); br_status mk_str_le(expr* a, expr* b, expr_ref& result); diff --git a/src/ast/seq_decl_plugin.cpp b/src/ast/seq_decl_plugin.cpp index ea073f23f..6695d9497 100644 --- a/src/ast/seq_decl_plugin.cpp +++ b/src/ast/seq_decl_plugin.cpp @@ -350,7 +350,7 @@ func_decl* seq_decl_plugin::mk_left_assoc_fun(decl_kind k, unsigned arity, sort* return mk_assoc_fun(k, arity, domain, range, k_seq, k_string, false); } -func_decl* seq_decl_plugin::mk_ubv2s(unsigned arity, sort* const* domain) { +func_decl* seq_decl_plugin::mk_ubv2s(unsigned arity, sort* const* domain) const { ast_manager& m = *m_manager; if (arity != 1) m.raise_exception("Invalid str.from_ubv expects one bit-vector argument"); @@ -361,6 +361,17 @@ func_decl* seq_decl_plugin::mk_ubv2s(unsigned arity, sort* const* domain) { return m.mk_func_decl(symbol("str.from_ubv"), arity, domain, rng, func_decl_info(m_family_id, OP_STRING_UBVTOS)); } +func_decl* seq_decl_plugin::mk_sbv2s(unsigned arity, sort* const* domain) const { + ast_manager &m = *m_manager; + if (arity != 1) + m.raise_exception("Invalid str.from_sbv expects one bit-vector argument"); + bv_util bv(m); + if (!bv.is_bv_sort(domain[0])) + m.raise_exception("Invalid str.from_sbv expects one bit-vector argument"); + sort *rng = m_string; + return m.mk_func_decl(symbol("str.from_sbv"), arity, domain, rng, func_decl_info(m_family_id, OP_STRING_SBVTOS)); +} + func_decl* seq_decl_plugin::mk_assoc_fun(decl_kind k, unsigned arity, sort* const* domain, sort* range, decl_kind k_seq, decl_kind k_string, bool is_right) { ast_manager& m = *m_manager; sort_ref rng(m); @@ -376,7 +387,7 @@ func_decl* seq_decl_plugin::mk_assoc_fun(decl_kind k, unsigned arity, sort* cons } -func_decl * seq_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters, +func_decl* seq_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters, unsigned arity, sort * const * domain, sort * range) { init(); m_has_seq = true; @@ -416,8 +427,12 @@ func_decl * seq_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, case OP_STRING_FROM_CODE: match(*m_sigs[k], arity, domain, range, rng); return m.mk_func_decl(m_sigs[k]->m_name, arity, domain, rng, func_decl_info(m_family_id, k)); + case OP_STRING_UBVTOS: - return mk_ubv2s(arity, domain); + return mk_ubv2s(arity, domain); + + case OP_STRING_SBVTOS: + return mk_sbv2s(arity, domain); case _OP_REGEXP_FULL_CHAR: m_has_re = true; @@ -627,6 +642,7 @@ void seq_decl_plugin::get_op_names(svector & op_names, symbol cons op_names.push_back(builtin_name("re.nostr", _OP_REGEXP_EMPTY)); op_names.push_back(builtin_name("re.complement", OP_RE_COMPLEMENT)); op_names.push_back(builtin_name("str.from_ubv", OP_STRING_UBVTOS)); + op_names.push_back(builtin_name("str.from_sbv", OP_STRING_SBVTOS)); } void seq_decl_plugin::get_sort_names(svector & sort_names, symbol const & logic) { diff --git a/src/ast/seq_decl_plugin.h b/src/ast/seq_decl_plugin.h index 61bbf7ba1..3c0f28ca6 100644 --- a/src/ast/seq_decl_plugin.h +++ b/src/ast/seq_decl_plugin.h @@ -80,6 +80,7 @@ enum seq_op_kind { OP_STRING_ITOS, OP_STRING_STOI, OP_STRING_UBVTOS, + OP_STRING_SBVTOS, OP_STRING_LT, OP_STRING_LE, OP_STRING_IS_DIGIT, @@ -150,7 +151,8 @@ class seq_decl_plugin : public decl_plugin { func_decl* mk_assoc_fun(decl_kind k, unsigned arity, sort* const* domain, sort* range, decl_kind k_string, decl_kind k_seq); func_decl* mk_left_assoc_fun(decl_kind k, unsigned arity, sort* const* domain, sort* range, decl_kind k_string, decl_kind k_seq); func_decl* mk_assoc_fun(decl_kind k, unsigned arity, sort* const* domain, sort* range, decl_kind k_string, decl_kind k_seq, bool is_right); - func_decl* mk_ubv2s(unsigned arity, sort* const* domain); + func_decl* mk_ubv2s(unsigned arity, sort* const* domain) const; + func_decl* mk_sbv2s(unsigned arity, sort* const* domain) const; void init(); @@ -297,6 +299,7 @@ public: app* mk_itos(expr* i) const { return m.mk_app(m_fid, OP_STRING_ITOS, 1, &i); } app* mk_stoi(expr* s) const { return m.mk_app(m_fid, OP_STRING_STOI, 1, &s); } app* mk_ubv2s(expr* b) const { return m.mk_app(m_fid, OP_STRING_UBVTOS, 1, &b); } + app* mk_sbv2s(expr* b) const { return m.mk_app(m_fid, OP_STRING_SBVTOS, 1, &b); } app* mk_is_empty(expr* s) const; app* mk_lex_lt(expr* a, expr* b) const { expr* es[2] = { a, b }; return m.mk_app(m_fid, OP_STRING_LT, 2, es); } app* mk_lex_le(expr* a, expr* b) const { expr* es[2] = { a, b }; return m.mk_app(m_fid, OP_STRING_LE, 2, es); } @@ -336,6 +339,7 @@ public: bool is_itos(expr const* n) const { return is_app_of(n, m_fid, OP_STRING_ITOS); } bool is_stoi(expr const* n) const { return is_app_of(n, m_fid, OP_STRING_STOI); } bool is_ubv2s(expr const* n) const { return is_app_of(n, m_fid, OP_STRING_UBVTOS); } + bool is_sbv2s(expr const* n) const { return is_app_of(n, m_fid, OP_STRING_SBVTOS); } bool is_in_re(expr const* n) const { return is_app_of(n, m_fid, OP_SEQ_IN_RE); } bool is_unit(expr const* n) const { return is_app_of(n, m_fid, OP_SEQ_UNIT); } bool is_lt(expr const* n) const { return is_app_of(n, m_fid, OP_STRING_LT); } @@ -374,6 +378,7 @@ public: MATCH_UNARY(is_itos); MATCH_UNARY(is_stoi); MATCH_UNARY(is_ubv2s); + MATCH_UNARY(is_sbv2s); MATCH_UNARY(is_is_digit); MATCH_UNARY(is_from_code); MATCH_UNARY(is_to_code); From b031fefbb987b364745672fdbffeaac45b951ebd Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 17 Jul 2021 20:30:52 +0200 Subject: [PATCH 006/125] #5336 - assertion violation in q_solver --- src/sat/smt/fpa_solver.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sat/smt/fpa_solver.cpp b/src/sat/smt/fpa_solver.cpp index ef2fd731c..f0deb7020 100644 --- a/src/sat/smt/fpa_solver.cpp +++ b/src/sat/smt/fpa_solver.cpp @@ -121,7 +121,7 @@ namespace fpa { if (!n) n = mk_enode(e, false); SASSERT(!n->is_attached_to(get_id())); - mk_var(n); + attach_new_th_var(n); TRACE("fp", tout << "post: " << mk_bounded_pp(e, m) << "\n";); m_nodes.push_back(std::tuple(n, sign, root)); ctx.push(push_back_trail(m_nodes)); From 6f2bf372680241eb4d5d4ff80c4f5bf3e1bdfaec Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 17 Jul 2021 20:31:11 +0200 Subject: [PATCH 007/125] #5336 missing theory variable creation in fpa_solver --- src/sat/smt/q_mbi.cpp | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/sat/smt/q_mbi.cpp b/src/sat/smt/q_mbi.cpp index 30c6c7e23..c48daef97 100644 --- a/src/sat/smt/q_mbi.cpp +++ b/src/sat/smt/q_mbi.cpp @@ -168,6 +168,9 @@ namespace q { return l_false; if (check_forall_default(q, *qb, *mdl)) return l_false; + else { + return l_undef; + } } if (m_generation_bound >= m_generation_max) return l_true; @@ -279,8 +282,9 @@ namespace q { bool fmls_extracted = false; TRACE("q", tout << "Project\n"; + tout << fmls << "\n"; + tout << "model\n"; tout << *m_model << "\n"; - tout << fmls << "\n"; tout << "model of projection\n" << mdl << "\n"; tout << "var args: " << qb.var_args.size() << "\n"; tout << "domain eqs: " << qb.domain_eqs << "\n"; @@ -294,6 +298,12 @@ namespace q { app* v = vars.get(i); auto* p = get_plugin(v); if (p && !fmls_extracted) { + TRACE("q", tout << "domain eqs\n" << qb.domain_eqs << "\n";); + + for (expr* e : qb.domain_eqs) + if (!m_model->is_true(e)) + return expr_ref(nullptr, m); + fmls.append(qb.domain_eqs); eliminate_nested_vars(fmls, qb); mbp::project_plugin proj(m); @@ -312,6 +322,7 @@ namespace q { eqs.push_back(m.mk_eq(v, val)); } rep(fmls); + TRACE("q", tout << "generated formulas\n" << fmls << "\ngenerated eqs:\n" << eqs;); return mk_and(fmls); } From 439e499dd3be8dde5816e25bca567b77e91f91c2 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 17 Jul 2021 21:29:48 +0200 Subject: [PATCH 008/125] note --- src/sat/smt/fpa_solver.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/sat/smt/fpa_solver.cpp b/src/sat/smt/fpa_solver.cpp index f0deb7020..3589c37c8 100644 --- a/src/sat/smt/fpa_solver.cpp +++ b/src/sat/smt/fpa_solver.cpp @@ -15,6 +15,8 @@ Author: Revision History: + Ported from theory_fpa by nbjorner in 2020. + --*/ #include "sat/smt/fpa_solver.h" From 0bfd24aae90d48ca0c9cce66038be19598b09f15 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 18 Jul 2021 12:05:52 +0200 Subject: [PATCH 009/125] add comments --- src/sat/smt/q_model_fixer.cpp | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/sat/smt/q_model_fixer.cpp b/src/sat/smt/q_model_fixer.cpp index 86c502932..c2defc71a 100644 --- a/src/sat/smt/q_model_fixer.cpp +++ b/src/sat/smt/q_model_fixer.cpp @@ -141,6 +141,19 @@ namespace q { mdl.register_decl(f_new, fi); } + /* + * For function f(...,t_idx, ..) collect the values of terms at position idx of f + * as "values". + * Map t_idx |-> mdl(t_idx) + * and mdl(t_idx) |-> t_idx + * Sort the values as [v_1, v_2, ..., v_n] with corresponding terms + * [t_1, t_2, ..., t_n] + * + * Create the term if p(x) = if x <= v_1 then t_1 else if x <= v_2 then t_2 else ... t_n + * where p is a fresh function + * and return p(x) + */ + expr_ref model_fixer::add_projection_function(model& mdl, func_decl* f, unsigned idx) { sort* srt = f->get_domain(idx); projection_function* proj = get_projection(srt); @@ -230,6 +243,15 @@ namespace q { return value; } + /** + * We are given a term f(...,arg_i,..) and value = mdl(arg_i) + * Create + * 1 the bounds t_j <= arg_i < t_{j+1} where + * v_j <= value < v_{j+1} for the corresponding values of t_j, t_{j+1} + * 2 or the bound arg_i < t_0 if value < v_0 + * 3 or the bound arg_i >= t_last if value > v_last + */ + void model_fixer::invert_arg(app* t, unsigned i, expr* value, expr_ref_vector& lits) { TRACE("q", tout << "invert-arg " << mk_pp(t, m) << " " << i << " " << mk_pp(value, m) << "\n";); auto const* md = get_projection_data(t->get_decl(), i); From 36d265a32cb2734156b3412da2e329737163d1f8 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 18 Jul 2021 12:06:45 +0200 Subject: [PATCH 010/125] na Signed-off-by: Nikolaj Bjorner --- src/sat/smt/q_mbi.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sat/smt/q_mbi.cpp b/src/sat/smt/q_mbi.cpp index c48daef97..802e3d393 100644 --- a/src/sat/smt/q_mbi.cpp +++ b/src/sat/smt/q_mbi.cpp @@ -282,7 +282,7 @@ namespace q { bool fmls_extracted = false; TRACE("q", tout << "Project\n"; - tout << fmls << "\n"; + tout << fmls << "\n"; tout << "model\n"; tout << *m_model << "\n"; tout << "model of projection\n" << mdl << "\n"; From a19910c13d34331d2eeb3ec73be7c0af3f52807c Mon Sep 17 00:00:00 2001 From: Margus Veanes Date: Sun, 18 Jul 2021 03:09:19 -0700 Subject: [PATCH 011/125] added regex simplification rules ~() = .+ and .+* = .* (#5416) --- src/ast/rewriter/seq_rewriter.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/ast/rewriter/seq_rewriter.cpp b/src/ast/rewriter/seq_rewriter.cpp index 312bab3bb..513180bac 100644 --- a/src/ast/rewriter/seq_rewriter.cpp +++ b/src/ast/rewriter/seq_rewriter.cpp @@ -3950,6 +3950,7 @@ br_status seq_rewriter::mk_re_union(expr* a, expr* b, expr_ref& result) { comp(none) -> all comp(all) -> none comp(comp(e1)) -> e1 + comp(epsilon) -> .+ */ br_status seq_rewriter::mk_re_complement(expr* a, expr_ref& result) { expr *e1 = nullptr, *e2 = nullptr; @@ -3973,6 +3974,10 @@ br_status seq_rewriter::mk_re_complement(expr* a, expr_ref& result) { result = e1; return BR_DONE; } + if (re().is_to_re(a, e1) && str().is_empty(e1)) { + result = re().mk_plus(re().mk_full_char(a->get_sort())); + return BR_DONE; + } return BR_FAILED; } @@ -4160,6 +4165,7 @@ br_status seq_rewriter::mk_re_power(func_decl* f, expr* a, expr_ref& result) { a+* = a* emp* = "" all* = all + .+* = all */ br_status seq_rewriter::mk_re_star(expr* a, expr_ref& result) { expr* b, *c, *b1, *c1; @@ -4182,7 +4188,10 @@ br_status seq_rewriter::mk_re_star(expr* a, expr_ref& result) { return BR_DONE; } if (re().is_plus(a, b)) { - result = re().mk_star(b); + if (re().is_full_char(b)) + result = re().mk_full_seq(a->get_sort()); + else + result = re().mk_star(b); return BR_DONE; } if (re().is_union(a, b, c)) { From f239aeb4d4ee99e9e19792d937e76d40174d0aab Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 18 Jul 2021 12:30:56 +0200 Subject: [PATCH 012/125] add consequences forcing character values to be digits --- src/ast/rewriter/seq_axioms.cpp | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/ast/rewriter/seq_axioms.cpp b/src/ast/rewriter/seq_axioms.cpp index d3bc217a3..ba2e3a117 100644 --- a/src/ast/rewriter/seq_axioms.cpp +++ b/src/ast/rewriter/seq_axioms.cpp @@ -820,16 +820,20 @@ namespace seq { /* * len(ubv2s(b)) = k => 10^k-1 <= b < 10^{k} k > 1 * len(ubv2s(b)) = 1 => b < 10^{1} k = 1 + * len(ubv2s(b)) >= k => is_digit(nth(ubv2s(b),0) & ... & is_digit(nth(ubv2s(b),k-1) */ void axioms::ubv2s_len_axiom(expr* b, unsigned k) { - expr_ref ge10k(m), ge10k1(m), eq(m); + expr_ref ge10k(m), ge10k1(m), eq(m), is_digit(m); + expr_ref ubvs(seq.str.mk_ubv2s(b), m); + expr_ref len(seq.str.mk_length(ubvs), m); + expr_ref ge_len(a.mk_ge(len, a.mk_int(k)), m); bv_util bv(m); sort* bv_sort = b->get_sort(); unsigned sz = bv.get_bv_size(bv_sort); rational pow(1); for (unsigned i = 1; i < k; ++i) pow *= 10; - expr_ref len(seq.str.mk_length(seq.str.mk_ubv2s(b)), m); + if (pow >= rational::power_of_two(sz)) { expr_ref ge(a.mk_ge(len, a.mk_int(k)), m); add_clause(~ge); @@ -844,6 +848,12 @@ namespace seq { add_clause(~eq, ~ge10k1); if (k > 1) add_clause(~eq, ge10k); + + for (unsigned i = 0; i < k; ++i) { + expr* ch = seq.str.mk_nth_i(ubvs, i); + is_digit = seq.mk_char_is_digit(ch); + add_clause(~ge_len, is_digit); + } } void axioms::ubv2ch_axiom(sort* bv_sort) { From ce1c8ee9e34278893b57105be1167175c23f1ac9 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 18 Jul 2021 12:32:27 +0200 Subject: [PATCH 013/125] na Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/seq_axioms.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ast/rewriter/seq_axioms.cpp b/src/ast/rewriter/seq_axioms.cpp index ba2e3a117..edc91e21f 100644 --- a/src/ast/rewriter/seq_axioms.cpp +++ b/src/ast/rewriter/seq_axioms.cpp @@ -820,7 +820,7 @@ namespace seq { /* * len(ubv2s(b)) = k => 10^k-1 <= b < 10^{k} k > 1 * len(ubv2s(b)) = 1 => b < 10^{1} k = 1 - * len(ubv2s(b)) >= k => is_digit(nth(ubv2s(b),0) & ... & is_digit(nth(ubv2s(b),k-1) + * len(ubv2s(b)) >= k => is_digit(nth(ubv2s(b), 0)) & ... & is_digit(nth(ubv2s(b), k-1)) */ void axioms::ubv2s_len_axiom(expr* b, unsigned k) { expr_ref ge10k(m), ge10k1(m), eq(m), is_digit(m); From cde3eac7be31c160bb03d37357dceefcfdce6964 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 18 Jul 2021 13:45:21 +0200 Subject: [PATCH 014/125] #5323 --- src/ast/macros/macro_util.cpp | 2 +- src/ast/macros/quasi_macros.cpp | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/ast/macros/macro_util.cpp b/src/ast/macros/macro_util.cpp index e439ae3e0..c024d870e 100644 --- a/src/ast/macros/macro_util.cpp +++ b/src/ast/macros/macro_util.cpp @@ -467,7 +467,7 @@ void macro_util::quasi_macro_head_to_macro_head(app * qhead, unsigned & num_decl See normalize_expr */ void macro_util::mk_macro_interpretation(app * head, unsigned num_decls, expr * def, expr_ref & interp) const { - TRACE("macro_util", tout << mk_pp(head, m_manager) << "\n";); + TRACE("macro_util", tout << mk_pp(head, m_manager) << "\n" << mk_pp(def, m_manager) << "\n";); SASSERT(is_macro_head(head, head->get_num_args()) || is_quasi_macro_ok(head, head->get_num_args(), def)); SASSERT(!occurs(head->get_decl(), def)); diff --git a/src/ast/macros/quasi_macros.cpp b/src/ast/macros/quasi_macros.cpp index f34336d84..2faf736b8 100644 --- a/src/ast/macros/quasi_macros.cpp +++ b/src/ast/macros/quasi_macros.cpp @@ -198,6 +198,7 @@ bool quasi_macros::quasi_macro_to_macro(quantifier * q, app * a, expr * t, quant bit_vector v_seen; v_seen.resize(q->get_num_decls(), false); + unsigned num_seen = 0; for (unsigned i = 0; i < a->get_num_args(); ++i) { expr* arg = a->get_arg(i); if (!is_var(arg) && !is_ground(arg)) @@ -215,8 +216,11 @@ bool quasi_macros::quasi_macro_to_macro(quantifier * q, app * a, expr * t, quant var * v = to_var(arg); m_new_vars.push_back(v); v_seen.set(v->get_idx(), true); + ++num_seen; } } + if (num_seen < q->get_num_decls()) + return false; // Reverse the new variable names and sorts. [CMW: There is a smarter way to do this.] vector new_var_names_rev; From 284d59978839205663687fe3b013295c1971e3bf Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 18 Jul 2021 05:14:14 -0700 Subject: [PATCH 015/125] #5323 https://github.com/Z3Prover/z3/issues/5323#issuecomment-866503616 --- src/smt/proto_model/proto_model.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/smt/proto_model/proto_model.cpp b/src/smt/proto_model/proto_model.cpp index c3e34f0de..d1614f521 100644 --- a/src/smt/proto_model/proto_model.cpp +++ b/src/smt/proto_model/proto_model.cpp @@ -213,11 +213,12 @@ void proto_model::cleanup() { TRACE("model_bug", model_v2_pp(tout, *this);); func_decl_set found_aux_fs; expr_ref_vector trail(m); - for (auto const& kv : m_finterp) { - TRACE("model_bug", tout << kv.m_key->get_name() << "\n";); - func_interp * fi = kv.m_value; + ptr_buffer finterps; + for (auto const& kv : m_finterp) + finterps.push_back(kv.m_value); + for (auto* fi : finterps) cleanup_func_interp(trail, fi, found_aux_fs); - } + for (unsigned i = 0; i < m_const_decls.size(); ++i) { func_decl* d = m_const_decls[i]; expr* e = m_interp[d].second; From 750c06e258bb3a2345dade2b00e863b4935d260c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 18 Jul 2021 10:21:42 -0700 Subject: [PATCH 016/125] #5417 --- src/sat/smt/euf_internalize.cpp | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/src/sat/smt/euf_internalize.cpp b/src/sat/smt/euf_internalize.cpp index a7476bc5d..5576cb8d2 100644 --- a/src/sat/smt/euf_internalize.cpp +++ b/src/sat/smt/euf_internalize.cpp @@ -281,17 +281,11 @@ namespace euf { s().add_clause(1, &lit_th, st); } else { - sat::bool_var v = si.to_bool_var(c); - s().set_external(v); - VERIFY(v != sat::null_bool_var); - VERIFY(s().is_external(v)); - SASSERT(v != sat::null_bool_var); - VERIFY(!s().was_eliminated(v)); + sat::literal lit_c = mk_literal(c); expr_ref eq_el = mk_eq(e, el); - sat::literal lit_el = mk_literal(eq_el); - literal lits1[2] = { literal(v, true), lit_th }; - literal lits2[2] = { literal(v, false), lit_el }; + literal lits1[2] = { ~lit_c, lit_th }; + literal lits2[2] = { lit_c, lit_el }; s().add_clause(2, lits1, st); s().add_clause(2, lits2, st); } From e8bc9f3469e6992d788d0e86bd80f0fcdcb3acac Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 18 Jul 2021 10:44:30 -0700 Subject: [PATCH 017/125] #5417 https://github.com/Z3Prover/z3/issues/5417#issuecomment-882050602 --- src/ast/euf/euf_egraph.h | 1 + src/sat/smt/array_axioms.cpp | 2 ++ src/sat/smt/dt_solver.cpp | 1 + src/sat/smt/euf_solver.cpp | 8 ++++++-- 4 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/ast/euf/euf_egraph.h b/src/ast/euf/euf_egraph.h index 1e0252922..100d00460 100644 --- a/src/ast/euf/euf_egraph.h +++ b/src/ast/euf/euf_egraph.h @@ -326,6 +326,7 @@ namespace euf { void collect_statistics(statistics& st) const; unsigned num_scopes() const { return m_scopes.size() + m_num_scopes; } + unsigned num_nodes() const { return m_nodes.size(); } }; inline std::ostream& operator<<(std::ostream& out, egraph const& g) { return g.display(out); } diff --git a/src/sat/smt/array_axioms.cpp b/src/sat/smt/array_axioms.cpp index 129026b34..89e079df4 100644 --- a/src/sat/smt/array_axioms.cpp +++ b/src/sat/smt/array_axioms.cpp @@ -427,9 +427,11 @@ namespace array { app_ref sel1(m), sel2(m); sel1 = a.mk_select(args1); sel2 = a.mk_select(args2); + prop |= !ctx.get_enode(sel1) || !ctx.get_enode(sel2); if (ctx.propagate(e_internalize(sel1), e_internalize(sel2), array_axiom())) prop = true; } + prop |= !ctx.get_enode(def1) || !ctx.get_enode(def2); if (ctx.propagate(e_internalize(def1), e_internalize(def2), array_axiom())) prop = true; return prop; diff --git a/src/sat/smt/dt_solver.cpp b/src/sat/smt/dt_solver.cpp index 07c269d48..76c154a4a 100644 --- a/src/sat/smt/dt_solver.cpp +++ b/src/sat/smt/dt_solver.cpp @@ -714,6 +714,7 @@ namespace dt { if (v == euf::null_theory_var) return false; euf::enode* con = m_var_data[m_find.find(v)]->m_constructor; + CTRACE("dt", !con, display(tout) << ctx.bpp(n) << "\n";); if (con->num_args() == 0) dep.insert(n, nullptr); for (enode* arg : euf::enode_args(con)) diff --git a/src/sat/smt/euf_solver.cpp b/src/sat/smt/euf_solver.cpp index f66c4a331..8efd3c9e4 100644 --- a/src/sat/smt/euf_solver.cpp +++ b/src/sat/smt/euf_solver.cpp @@ -449,8 +449,8 @@ namespace euf { if (!init_relevancy()) give_up = true; - - + + unsigned num_nodes = m_egraph.num_nodes(); for (auto* e : m_solvers) { if (!m.inc()) return sat::check_result::CR_GIVEUP; @@ -468,6 +468,10 @@ namespace euf { return sat::check_result::CR_CONTINUE; if (give_up) return sat::check_result::CR_GIVEUP; + if (num_nodes < m_egraph.num_nodes()) { + IF_VERBOSE(1, verbose_stream() << "new nodes created, but not detected\n"); + return sat::check_result::CR_CONTINUE; + } if (m_qsolver) return m_qsolver->check(); TRACE("after_search", s().display(tout);); From 7d915eb295318eb24aa7f221c8abb437a03a2ac0 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 19 Jul 2021 07:40:46 -0700 Subject: [PATCH 018/125] #5417 - revise q_eval based on bug based on non-chronological dependencies with post-hoc explain function --- src/ast/euf/euf_egraph.h | 20 ++--- src/ast/euf/euf_etable.h | 2 +- src/sat/smt/q_clause.h | 8 +- src/sat/smt/q_ematch.cpp | 18 +++-- src/sat/smt/q_ematch.h | 13 +-- src/sat/smt/q_eval.cpp | 168 ++++++++++++++------------------------- src/sat/smt/q_eval.h | 15 ++-- 7 files changed, 99 insertions(+), 145 deletions(-) diff --git a/src/ast/euf/euf_egraph.h b/src/ast/euf/euf_egraph.h index 100d00460..9533a83e6 100644 --- a/src/ast/euf/euf_egraph.h +++ b/src/ast/euf/euf_egraph.h @@ -156,26 +156,26 @@ namespace euf { svector m_updates; unsigned_vector m_scopes; enode_vector m_expr2enode; - enode* m_tmp_eq { nullptr }; - enode* m_tmp_node { nullptr }; - unsigned m_tmp_node_capacity { 0 }; + enode* m_tmp_eq = nullptr; + enode* m_tmp_node = nullptr; + unsigned m_tmp_node_capacity = 0; enode_vector m_nodes; expr_ref_vector m_exprs; vector m_decl2enodes; enode_vector m_empty_enodes; - unsigned m_num_scopes { 0 }; - bool m_inconsistent { false }; - enode *m_n1 { nullptr }; - enode *m_n2 { nullptr }; + unsigned m_num_scopes = 0; + bool m_inconsistent = false; + enode *m_n1 = nullptr; + enode *m_n2 = nullptr; justification m_justification; - unsigned m_new_lits_qhead { 0 }; - unsigned m_new_th_eqs_qhead { 0 }; + unsigned m_new_lits_qhead = 0; + unsigned m_new_th_eqs_qhead = 0; svector m_new_lits; svector m_new_th_eqs; bool_vector m_th_propagates_diseqs; enode_vector m_todo; stats m_stats; - bool m_uses_congruence { false }; + bool m_uses_congruence = false; std::function m_on_merge; std::function m_on_make; std::function m_used_eq; diff --git a/src/ast/euf/euf_etable.h b/src/ast/euf/euf_etable.h index 68ae95cd2..d6b64e756 100644 --- a/src/ast/euf/euf_etable.h +++ b/src/ast/euf/euf_etable.h @@ -125,7 +125,7 @@ namespace euf { ast_manager & m_manager; - bool m_commutativity{ false }; //!< true if the last found congruence used commutativity + bool m_commutativity = false; //!< true if the last found congruence used commutativity ptr_vector m_tables; map m_func_decl2id; diff --git a/src/sat/smt/q_clause.h b/src/sat/smt/q_clause.h index 7278d1db1..8eca0df76 100644 --- a/src/sat/smt/q_clause.h +++ b/src/sat/smt/q_clause.h @@ -57,7 +57,7 @@ namespace q { unsigned m_index; vector m_lits; quantifier_ref m_q; - sat::literal m_literal; + sat::literal m_literal = sat::null_literal; q::quantifier_stat* m_stat = nullptr; binding* m_bindings = nullptr; @@ -75,10 +75,12 @@ namespace q { struct justification { expr* m_lhs, *m_rhs; bool m_sign; + unsigned m_num_ev; + euf::enode_pair* m_evidence; clause& m_clause; euf::enode* const* m_binding; - justification(lit const& l, clause& c, euf::enode* const* b): - m_lhs(l.lhs), m_rhs(l.rhs), m_sign(l.sign), m_clause(c), m_binding(b) {} + justification(lit const& l, clause& c, euf::enode* const* b, unsigned n, euf::enode_pair* ev): + m_lhs(l.lhs), m_rhs(l.rhs), m_sign(l.sign), m_clause(c), m_binding(b), m_num_ev(n), m_evidence(ev) {} sat::ext_constraint_idx to_index() const { return sat::constraint_base::mem2base(this); } diff --git a/src/sat/smt/q_ematch.cpp b/src/sat/smt/q_ematch.cpp index e997476ed..7de922f40 100644 --- a/src/sat/smt/q_ematch.cpp +++ b/src/sat/smt/q_ematch.cpp @@ -94,7 +94,10 @@ namespace q { lit lit(expr_ref(l, m), expr_ref(r, m), sign); if (idx != UINT_MAX) lit = c[idx]; - auto* constraint = new (sat::constraint_base::ptr2mem(mem)) justification(lit, c, b); + auto* ev = static_cast(ctx.get_region().allocate(sizeof(euf::enode_pair) * m_evidence.size())); + for (unsigned i = m_evidence.size(); i-- > 0; ) + ev[i] = m_evidence[i]; + auto* constraint = new (sat::constraint_base::ptr2mem(mem)) justification(lit, c, b, m_evidence.size(), ev); return constraint->to_index(); } @@ -251,7 +254,8 @@ namespace q { bool ematch::propagate(bool is_owned, euf::enode* const* binding, unsigned max_generation, clause& c, bool& propagated) { TRACE("q", c.display(ctx, tout) << "\n";); unsigned idx = UINT_MAX; - lbool ev = m_eval(binding, c, idx); + m_evidence.reset(); + lbool ev = m_eval(binding, c, idx, m_evidence); if (ev == l_true) { ++m_stats.m_num_redundant; return true; @@ -267,15 +271,18 @@ namespace q { if (ev == l_undef && max_generation > m_generation_propagation_threshold) return false; if (!is_owned) - binding = alloc_binding(c, binding); - auto j_idx = mk_justification(idx, c, binding); + binding = alloc_binding(c, binding); + + auto j_idx = mk_justification(idx, c, binding); + if (ev == l_false) { ++m_stats.m_num_conflicts; ctx.set_conflict(j_idx); } else { ++m_stats.m_num_propagations; - ctx.propagate(instantiate(c, binding, c[idx]), j_idx); + auto lit = instantiate(c, binding, c[idx]); + ctx.propagate(lit, j_idx); } propagated = true; return true; @@ -295,6 +302,7 @@ namespace q { } void ematch::add_instantiation(clause& c, binding& b, sat::literal lit) { + m_evidence.reset(); ctx.propagate(lit, mk_justification(UINT_MAX, c, b.nodes())); } diff --git a/src/sat/smt/q_ematch.h b/src/sat/smt/q_ematch.h index 443b9d947..0f8add4c1 100644 --- a/src/sat/smt/q_ematch.h +++ b/src/sat/smt/q_ematch.h @@ -63,7 +63,7 @@ namespace q { quantifier_stat_gen m_qstat_gen; fingerprints m_fingerprints; scoped_ptr m_tmp_binding; - unsigned m_tmp_binding_capacity { 0 }; + unsigned m_tmp_binding_capacity = 0; queue m_inst_queue; pattern_inference_rw m_infer_patterns; scoped_ptr m_mam, m_lazy_mam; @@ -72,13 +72,14 @@ namespace q { vector m_watch; // expr_id -> clause-index* stats m_stats; expr_fast_mark1 m_mark; - unsigned m_generation_propagation_threshold{ 3 }; + unsigned m_generation_propagation_threshold = 3; ptr_vector m_ground; - bool m_in_queue_set{ false }; + bool m_in_queue_set = false; nat_set m_node_in_queue; nat_set m_clause_in_queue; - unsigned m_qhead { 0 }; + unsigned m_qhead = 0; unsigned_vector m_clause_queue; + euf::enode_pair_vector m_evidence; binding* alloc_binding(unsigned n, app* pat, unsigned max_generation, unsigned min_top, unsigned max_top); euf::enode* const* alloc_binding(clause& c, euf::enode* const* _binding); @@ -115,7 +116,7 @@ namespace q { bool propagate(bool flush); - void init_search(); + // void init_search(); void add(quantifier* q); @@ -127,7 +128,7 @@ namespace q { void on_binding(quantifier* q, app* pat, euf::enode* const* binding, unsigned max_generation, unsigned min_gen, unsigned max_gen); // callbacks from queue - lbool evaluate(euf::enode* const* binding, clause& c) { return m_eval(binding, c); } + lbool evaluate(euf::enode* const* binding, clause& c) { m_evidence.reset(); return m_eval(binding, c, m_evidence); } void add_instantiation(clause& c, binding& b, sat::literal lit); diff --git a/src/sat/smt/q_eval.cpp b/src/sat/smt/q_eval.cpp index 5e5cc83b8..9dcf5755f 100644 --- a/src/sat/smt/q_eval.cpp +++ b/src/sat/smt/q_eval.cpp @@ -32,7 +32,7 @@ namespace q { m(ctx.get_manager()) {} - lbool eval::operator()(euf::enode* const* binding, clause& c, unsigned& idx) { + lbool eval::operator()(euf::enode* const* binding, clause& c, unsigned& idx, euf::enode_pair_vector& evidence) { scoped_mark_reset _sr(*this); idx = UINT_MAX; unsigned sz = c.m_lits.size(); @@ -41,7 +41,7 @@ namespace q { for (unsigned i = 0; i < sz; ++i) { unsigned lim = m_indirect_nodes.size(); lit l = c[i]; - lbool cmp = compare(n, binding, l.lhs, l.rhs); + lbool cmp = compare(n, binding, l.lhs, l.rhs, evidence); switch (cmp) { case l_false: m_indirect_nodes.shrink(lim); @@ -75,46 +75,55 @@ namespace q { return l_undef; } - lbool eval::operator()(euf::enode* const* binding, clause& c) { + lbool eval::operator()(euf::enode* const* binding, clause& c, euf::enode_pair_vector& evidence) { unsigned idx = 0; - return (*this)(binding, c, idx); + return (*this)(binding, c, idx, evidence); } - lbool eval::compare(unsigned n, euf::enode* const* binding, expr* s, expr* t) { + lbool eval::compare(unsigned n, euf::enode* const* binding, expr* s, expr* t, euf::enode_pair_vector& evidence) { if (s == t) return l_true; if (m.are_distinct(s, t)) return l_false; - euf::enode* sn = (*this)(n, binding, s); - euf::enode* tn = (*this)(n, binding, t); - if (sn) sn = sn->get_root(); - if (tn) tn = tn->get_root(); + euf::enode* sn = (*this)(n, binding, s, evidence); + euf::enode* tn = (*this)(n, binding, t, evidence); + euf::enode* sr = sn ? sn->get_root() : sn; + euf::enode* tr = tn ? tn->get_root() : tn; + if (sn != sr) evidence.push_back(euf::enode_pair(sn, sr)), sn = sr; + if (tn != tr) evidence.push_back(euf::enode_pair(tn, tr)), tn = tr; TRACE("q", tout << mk_pp(s, m) << " ~~ " << mk_pp(t, m) << "\n"; tout << ctx.bpp(sn) << " " << ctx.bpp(tn) << "\n";); lbool c; if (sn && sn == tn) return l_true; - if (sn && tn && ctx.get_egraph().are_diseq(sn, tn)) + if (sn && tn && ctx.get_egraph().are_diseq(sn, tn)) { + evidence.push_back(euf::enode_pair(sn, tn)); return l_false; + } if (sn && tn) return l_undef; if (!sn && !tn) - return compare_rec(n, binding, s, t); + return compare_rec(n, binding, s, t, evidence); if (!tn && sn) { std::swap(tn, sn); std::swap(t, s); } - for (euf::enode* t1 : euf::enode_class(tn)) - if (c = compare_rec(n, binding, s, t1->get_expr()), c != l_undef) + unsigned sz = evidence.size(); + for (euf::enode* t1 : euf::enode_class(tn)) { + if (c = compare_rec(n, binding, s, t1->get_expr(), evidence), c != l_undef) { + evidence.push_back(euf::enode_pair(t1, tn)); return c; + } + evidence.shrink(sz); + } return l_undef; } // f(p1) = f(p2) if p1 = p2 // f(p1) != f(p2) if p1 != p2 and f is injective - lbool eval::compare_rec(unsigned n, euf::enode* const* binding, expr* s, expr* t) { + lbool eval::compare_rec(unsigned n, euf::enode* const* binding, expr* s, expr* t, euf::enode_pair_vector& evidence) { if (m.are_equal(s, t)) return l_true; if (m.are_distinct(s, t)) @@ -127,14 +136,20 @@ namespace q { return l_undef; bool is_injective = to_app(s)->get_decl()->is_injective(); bool has_undef = false; + unsigned sz = evidence.size(); for (unsigned i = to_app(s)->get_num_args(); i-- > 0; ) { - switch (compare(n, binding, to_app(s)->get_arg(i), to_app(t)->get_arg(i))) { + unsigned sz1 = evidence.size(), sz2; + switch (compare(n, binding, to_app(s)->get_arg(i), to_app(t)->get_arg(i), evidence)) { case l_true: break; - case l_false: - if (is_injective) - return l_false; - return l_undef; + case l_false: + if (!is_injective) + return l_undef; + sz2 = evidence.size(); + for (unsigned i = 0; i < sz2 - sz1; ++i) + evidence[sz + i] = evidence[sz1 + i]; + evidence.shrink(sz + sz2 - sz1); + return l_false; case l_undef: if (!is_injective) return l_undef; @@ -142,10 +157,15 @@ namespace q { break; } } - return has_undef ? l_undef : l_true; + + if (!has_undef) + return l_true; + + evidence.shrink(sz); + return l_undef; } - euf::enode* eval::operator()(unsigned n, euf::enode* const* binding, expr* e) { + euf::enode* eval::operator()(unsigned n, euf::enode* const* binding, expr* e, euf::enode_pair_vector& evidence) { if (is_ground(e)) return ctx.get_egraph().find(e); if (m_mark.is_marked(e)) @@ -186,6 +206,15 @@ namespace q { euf::enode* n = ctx.get_egraph().find(t, args.size(), args.data()); if (!n) return nullptr; + for (unsigned i = args.size(); i-- > 0; ) { + if (args[i] != n->get_arg(i)) { + // roots could be different when using commutativity + // instead of compensating for this, we just bail out + if (args[i]->get_root() != n->get_arg(i)->get_root()) + return nullptr; + evidence.push_back(euf::enode_pair(args[i], n->get_arg(i))); + } + } m_indirect_nodes.push_back(n); m_eval.setx(t->get_id(), n, nullptr); m_mark.mark(t); @@ -195,99 +224,18 @@ namespace q { return m_eval[e->get_id()]; } - void eval::explain(clause& c, unsigned literal_idx, euf::enode* const* b) { - unsigned n = c.num_decls(); - for (unsigned i = c.size(); i-- > 0; ) { - if (i == literal_idx) - continue; - auto const& lit = c[i]; - if (lit.sign) - explain_eq(n, b, lit.lhs, lit.rhs); - else - explain_diseq(n, b, lit.lhs, lit.rhs); - } - } - - void eval::explain_eq(unsigned n, euf::enode* const* binding, expr* s, expr* t) { - SASSERT(l_true == compare(n, binding, s, t)); - if (s == t) - return; - euf::enode* sn = (*this)(n, binding, s); - euf::enode* tn = (*this)(n, binding, t); - if (sn && tn) { - SASSERT(sn->get_root() == tn->get_root()); - ctx.add_antecedent(sn, tn); - return; - } - if (!sn && tn) { - std::swap(sn, tn); - std::swap(s, t); - } - if (sn && !tn) { - for (euf::enode* s1 : euf::enode_class(sn)) { - if (l_true == compare_rec(n, binding, t, s1->get_expr())) { - ctx.add_antecedent(sn, s1); - explain_eq(n, binding, t, s1->get_expr()); - return; - } - } - UNREACHABLE(); - } - SASSERT(is_app(s) && is_app(t)); - SASSERT(to_app(s)->get_decl() == to_app(t)->get_decl()); - for (unsigned i = to_app(s)->get_num_args(); i-- > 0; ) - explain_eq(n, binding, to_app(s)->get_arg(i), to_app(t)->get_arg(i)); - } - - void eval::explain_diseq(unsigned n, euf::enode* const* binding, expr* s, expr* t) { - SASSERT(l_false == compare(n, binding, s, t)); - if (m.are_distinct(s, t)) - return; - euf::enode* sn = (*this)(n, binding, s); - euf::enode* tn = (*this)(n, binding, t); - if (sn && tn && ctx.get_egraph().are_diseq(sn, tn)) { - ctx.add_diseq_antecedent(sn, tn); - return; - } - if (!sn && tn) { - std::swap(sn, tn); - std::swap(s, t); - } - if (sn && !tn) { - for (euf::enode* s1 : euf::enode_class(sn)) { - if (l_false == compare_rec(n, binding, t, s1->get_expr())) { - ctx.add_antecedent(sn, s1); - explain_diseq(n, binding, t, s1->get_expr()); - return; - } - } - UNREACHABLE(); - } - SASSERT(is_app(s) && is_app(t)); - app* at = to_app(t); - app* as = to_app(s); - SASSERT(as->get_decl() == at->get_decl()); - for (unsigned i = as->get_num_args(); i-- > 0; ) { - if (l_false == compare_rec(n, binding, as->get_arg(i), at->get_arg(i))) { - explain_eq(n, binding, as->get_arg(i), at->get_arg(i)); - return; - } - } - UNREACHABLE(); - } - - void eval::explain(sat::literal l, justification& j, sat::literal_vector& r, bool probing) { - scoped_mark_reset _sr(*this); - unsigned l_idx = 0; clause& c = j.m_clause; - for (; l_idx < c.size(); ++l_idx) { - if (c[l_idx].lhs == j.m_lhs && c[l_idx].rhs == j.m_rhs && c[l_idx].sign == j.m_sign) - break; + for (unsigned i = 0; i < j.m_num_ev; ++i) { + auto [a, b] = j.m_evidence[i]; + SASSERT(a->get_root() == b->get_root() || ctx.get_egraph().are_diseq(a, b)); + if (a->get_root() == b->get_root()) + ctx.add_antecedent(a, b); + else + ctx.add_diseq_antecedent(a, b); } - explain(c, l_idx, j.m_binding); r.push_back(c.m_literal); - (void)probing; // ignored + (void)probing; // ignored } diff --git a/src/sat/smt/q_eval.h b/src/sat/smt/q_eval.h index 6219c473a..5e520dc17 100644 --- a/src/sat/smt/q_eval.h +++ b/src/sat/smt/q_eval.h @@ -30,25 +30,20 @@ namespace q { expr_fast_mark1 m_mark; euf::enode_vector m_eval; euf::enode_vector m_indirect_nodes; - ptr_vector m_explain; struct scoped_mark_reset; - void explain(clause& c, unsigned literal_idx, euf::enode* const* binding); - void explain_eq(unsigned n, euf::enode* const* binding, expr* s, expr* t); - void explain_diseq(unsigned n, euf::enode* const* binding, expr* s, expr* t); - // compare s, t modulo binding - lbool compare(unsigned n, euf::enode* const* binding, expr* s, expr* t); - lbool compare_rec(unsigned n, euf::enode* const* binding, expr* s, expr* t); + lbool compare(unsigned n, euf::enode* const* binding, expr* s, expr* t, euf::enode_pair_vector& evidence); + lbool compare_rec(unsigned n, euf::enode* const* binding, expr* s, expr* t, euf::enode_pair_vector& evidence); public: eval(euf::solver& ctx); void explain(sat::literal l, justification& j, sat::literal_vector& r, bool probing); - lbool operator()(euf::enode* const* binding, clause& c); - lbool operator()(euf::enode* const* binding, clause& c, unsigned& idx); - euf::enode* operator()(unsigned n, euf::enode* const* binding, expr* e); + lbool operator()(euf::enode* const* binding, clause& c, euf::enode_pair_vector& evidence); + lbool operator()(euf::enode* const* binding, clause& c, unsigned& idx, euf::enode_pair_vector& evidence); + euf::enode* operator()(unsigned n, euf::enode* const* binding, expr* e, euf::enode_pair_vector& evidence); euf::enode_vector const& get_watch() { return m_indirect_nodes; } }; From 776f270b64a52fd85fe6c3f9c0c733d34722f27c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 19 Jul 2021 09:08:51 -0700 Subject: [PATCH 019/125] #5417 normalize clause --- src/sat/smt/q_clause.h | 4 +++- src/sat/smt/q_ematch.cpp | 10 ++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/sat/smt/q_clause.h b/src/sat/smt/q_clause.h index 8eca0df76..2107b2172 100644 --- a/src/sat/smt/q_clause.h +++ b/src/sat/smt/q_clause.h @@ -29,7 +29,9 @@ namespace q { expr_ref rhs; bool sign; lit(expr_ref const& lhs, expr_ref const& rhs, bool sign): - lhs(lhs), rhs(rhs), sign(sign) {} + lhs(lhs), rhs(rhs), sign(sign) { + SASSERT(!rhs.m().is_false(rhs) || !sign); + } std::ostream& display(std::ostream& out) const; }; diff --git a/src/sat/smt/q_ematch.cpp b/src/sat/smt/q_ematch.cpp index 7de922f40..6040c4b4b 100644 --- a/src/sat/smt/q_ematch.cpp +++ b/src/sat/smt/q_ematch.cpp @@ -419,6 +419,16 @@ namespace q { r = sign ? m.mk_false() : m.mk_true(); sign = false; } + if (m.is_true(l) || m.is_false(l)) + std::swap(l, r); + if (sign && m.is_false(r)) { + r = m.mk_true(); + sign = false; + } + else if (sign && m.is_true(r)) { + r = m.mk_false(); + sign = false; + } cl->m_lits.push_back(lit(expr_ref(l, m), expr_ref(r, m), sign)); } if (q->get_num_patterns() == 0) { From 3156ca5e77998f4e8ec16bf9440ce7ab49d339f3 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 19 Jul 2021 11:10:48 -0700 Subject: [PATCH 020/125] #5417 - delay propagation from callbacks from mam mam assumes the egraph isn't updated during callbacks. --- src/sat/smt/q_ematch.cpp | 28 +++++++++++++++++++++++----- src/sat/smt/q_ematch.h | 11 +++++++++++ 2 files changed, 34 insertions(+), 5 deletions(-) diff --git a/src/sat/smt/q_ematch.cpp b/src/sat/smt/q_ematch.cpp index 6040c4b4b..99282bf30 100644 --- a/src/sat/smt/q_ematch.cpp +++ b/src/sat/smt/q_ematch.cpp @@ -275,16 +275,34 @@ namespace q { auto j_idx = mk_justification(idx, c, binding); - if (ev == l_false) { + if (is_owned) + propagate(ev == l_false, idx, j_idx); + else + m_prop_queue.push_back(prop(ev == l_false, idx, j_idx)); + propagated = true; + return true; + } + + void ematch::propagate(bool is_conflict, unsigned idx, sat::ext_justification_idx j_idx) { + if (is_conflict) { ++m_stats.m_num_conflicts; ctx.set_conflict(j_idx); } else { ++m_stats.m_num_propagations; - auto lit = instantiate(c, binding, c[idx]); - ctx.propagate(lit, j_idx); + auto& j = justification::from_index(j_idx); + auto lit = instantiate(j.m_clause, j.m_binding, j.m_clause[idx]); + ctx.propagate(lit, j_idx); + } + } + + bool ematch::flush_prop_queue() { + if (m_prop_queue.empty()) + return false; + for (unsigned i = 0; i < m_prop_queue.size(); ++i) { + auto [is_conflict, idx, j_idx] = m_prop_queue[i]; + propagate(is_conflict, idx, j_idx); } - propagated = true; return true; } @@ -508,7 +526,7 @@ namespace q { bool ematch::propagate(bool flush) { m_mam->propagate(); - bool propagated = false; + bool propagated = flush_prop_queue(); if (m_qhead >= m_clause_queue.size()) return m_inst_queue.propagate(); ctx.push(value_trail(m_qhead)); diff --git a/src/sat/smt/q_ematch.h b/src/sat/smt/q_ematch.h index 0f8add4c1..9c4cf9d98 100644 --- a/src/sat/smt/q_ematch.h +++ b/src/sat/smt/q_ematch.h @@ -49,6 +49,13 @@ namespace q { } }; + struct prop { + bool is_conflict; + unsigned idx; + sat::ext_justification_idx j; + prop(bool is_conflict, unsigned idx, sat::ext_justification_idx j) : is_conflict(is_conflict), idx(idx), j(j) {} + }; + struct remove_binding; struct insert_binding; struct pop_clause; @@ -65,6 +72,7 @@ namespace q { scoped_ptr m_tmp_binding; unsigned m_tmp_binding_capacity = 0; queue m_inst_queue; + svector m_prop_queue; pattern_inference_rw m_infer_patterns; scoped_ptr m_mam, m_lazy_mam; ptr_vector m_clauses; @@ -108,6 +116,9 @@ namespace q { fingerprint* add_fingerprint(clause& c, binding& b, unsigned max_generation); void set_tmp_binding(fingerprint& fp); + bool flush_prop_queue(); + void propagate(bool is_conflict, unsigned idx, sat::ext_justification_idx j_idx); + public: ematch(euf::solver& ctx, solver& s); From 49b94a00902a8a591be1c62a70aa8e2fe34c44b8 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 19 Jul 2021 11:38:04 -0700 Subject: [PATCH 021/125] #5417 extend definition of ground to be variable free --- src/sat/smt/q_eval.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sat/smt/q_eval.cpp b/src/sat/smt/q_eval.cpp index 9dcf5755f..accc4f526 100644 --- a/src/sat/smt/q_eval.cpp +++ b/src/sat/smt/q_eval.cpp @@ -15,6 +15,7 @@ Author: --*/ +#include "ast/has_free_vars.h" #include "sat/smt/q_eval.h" #include "sat/smt/euf_solver.h" #include "sat/smt/q_solver.h" @@ -176,7 +177,7 @@ namespace q { while (!todo.empty()) { expr* t = todo.back(); SASSERT(!is_ground(t) || ctx.get_egraph().find(t)); - if (is_ground(t)) { + if (is_ground(t) || (has_quantifiers(t) && !has_free_vars(t))) { m_mark.mark(t); m_eval.setx(t->get_id(), ctx.get_egraph().find(t), nullptr); SASSERT(m_eval[t->get_id()]); From 188a47821416273ee269d0ce16b1c1471d8569a8 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 19 Jul 2021 13:19:03 -0700 Subject: [PATCH 022/125] #5417 strict inequality (over reals) require solving for least-upper/greatest-lower bounds that may coincide with non-strict inequalities (be epsilon stronger). Instead of using the coefficient 'a' to turn the inequality into an equality, add the slack value as a constant. --- src/math/simplex/model_based_opt.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/math/simplex/model_based_opt.cpp b/src/math/simplex/model_based_opt.cpp index 6a05de93f..1701fd00f 100644 --- a/src/math/simplex/model_based_opt.cpp +++ b/src/math/simplex/model_based_opt.cpp @@ -528,6 +528,13 @@ namespace opt { } } + /** + * a1 > 0 + * a1*x + r1 = value + * a2*x + r2 <= 0 + * ------------------ + * a1*r2 - a2*r1 <= value + */ void model_based_opt::solve(unsigned row_src, rational const& a1, unsigned row_dst, unsigned x) { SASSERT(a1 == get_coefficient(row_src, x)); SASSERT(a1.is_pos()); @@ -1205,10 +1212,9 @@ namespace opt { SASSERT(a.is_pos()); if (ty == t_lt) { SASSERT(compute_def); - m_rows[row_id1].m_coeff += a; + m_rows[row_id1].m_coeff -= m_rows[row_id1].m_value; m_rows[row_id1].m_type = t_le; - m_rows[row_id1].m_value += a; - } + m_rows[row_id1].m_value = 0; if (m_var2is_int[x] && !a.is_one()) { row& r1 = m_rows[row_id1]; vector coeffs; From b0a22105d6dbb199fd76578e8c51388f520519dd Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 19 Jul 2021 13:28:20 -0700 Subject: [PATCH 023/125] na --- src/math/simplex/model_based_opt.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/math/simplex/model_based_opt.cpp b/src/math/simplex/model_based_opt.cpp index 1701fd00f..429a97ae2 100644 --- a/src/math/simplex/model_based_opt.cpp +++ b/src/math/simplex/model_based_opt.cpp @@ -1215,6 +1215,8 @@ namespace opt { m_rows[row_id1].m_coeff -= m_rows[row_id1].m_value; m_rows[row_id1].m_type = t_le; m_rows[row_id1].m_value = 0; + } + if (m_var2is_int[x] && !a.is_one()) { row& r1 = m_rows[row_id1]; vector coeffs; From 0a34eef470af62a2e61fbdcf50b34a12e7641cc0 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 19 Jul 2021 13:41:02 -0700 Subject: [PATCH 024/125] #5417 --- src/sat/smt/euf_solver.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/sat/smt/euf_solver.cpp b/src/sat/smt/euf_solver.cpp index 8efd3c9e4..65c383977 100644 --- a/src/sat/smt/euf_solver.cpp +++ b/src/sat/smt/euf_solver.cpp @@ -348,9 +348,7 @@ namespace euf { void solver::propagate_literals() { for (; m_egraph.has_literal() && !s().inconsistent() && !m_egraph.inconsistent(); m_egraph.next_literal()) { - euf::enode_bool_pair p = m_egraph.get_literal(); - euf::enode* n = p.first; - bool is_eq = p.second; + auto [n, is_eq] = m_egraph.get_literal(); expr* e = n->get_expr(); expr* a = nullptr, *b = nullptr; bool_var v = n->bool_var(); @@ -364,6 +362,10 @@ namespace euf { } else { lbool val = n->get_root()->value(); + if (val == l_undef && m.is_false(n->get_root()->get_expr())) + val = l_false; + if (val == l_undef && m.is_true(n->get_root()->get_expr())) + val = l_true; a = e; b = (val == l_true) ? m.mk_true() : m.mk_false(); SASSERT(val != l_undef); From 4388ab2e3e266e89639ee555d92667719905b456 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 19 Jul 2021 13:50:20 -0700 Subject: [PATCH 025/125] #5417 more gracefully handle non-implemented theories --- src/sat/smt/euf_model.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/sat/smt/euf_model.cpp b/src/sat/smt/euf_model.cpp index 5ac8e7caa..be4c824b3 100644 --- a/src/sat/smt/euf_model.cpp +++ b/src/sat/smt/euf_model.cpp @@ -178,6 +178,10 @@ namespace euf { mbS->add_value(n, *mdl, m_values); else if (auto* mbE = expr2solver(e)) mbE->add_value(n, *mdl, m_values); + else if (is_app(e) && to_app(e)->get_family_id() != m.get_basic_family_id()) { + m_values.set(id, e); + IF_VERBOSE(1, verbose_stream() << "creating self-value for " << mk_pp(e, m) << "\n"); + } else { IF_VERBOSE(1, verbose_stream() << "no model values created for " << mk_pp(e, m) << "\n"); } @@ -212,9 +216,10 @@ namespace euf { args.reset(); for (expr* arg : *a) { enode* earg = get_enode(arg); - args.push_back(m_values.get(earg->get_root_id())); - CTRACE("euf", !args.back(), tout << "no value for " << bpp(earg) << "\n";); - SASSERT(args.back()); + expr* val = m_values.get(earg->get_root_id()); + args.push_back(val); + CTRACE("euf", !val, tout << "no value for " << bpp(earg) << "\n";); + SASSERT(val); } SASSERT(args.size() == arity); if (!fi->get_entry(args.data())) From a64867942d912f06b778bd17722c64e236f1688e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 19 Jul 2021 15:35:18 -0700 Subject: [PATCH 026/125] #5417 designate quantifier axioms as auxiliary Signed-off-by: Nikolaj Bjorner --- src/sat/smt/euf_relevancy.cpp | 4 ++++ src/sat/smt/euf_solver.h | 1 + src/sat/smt/q_solver.cpp | 7 +++---- src/sat/smt/sat_dual_solver.cpp | 5 +++-- 4 files changed, 11 insertions(+), 6 deletions(-) diff --git a/src/sat/smt/euf_relevancy.cpp b/src/sat/smt/euf_relevancy.cpp index f5c05cea9..03f9f8ed1 100644 --- a/src/sat/smt/euf_relevancy.cpp +++ b/src/sat/smt/euf_relevancy.cpp @@ -39,11 +39,15 @@ namespace euf { } void solver::add_root(unsigned n, sat::literal const* lits) { + if (!relevancy_enabled()) + return; ensure_dual_solver(); m_dual_solver->add_root(n, lits); } void solver::add_aux(unsigned n, sat::literal const* lits) { + if (!relevancy_enabled()) + return; ensure_dual_solver(); m_dual_solver->add_aux(n, lits); } diff --git a/src/sat/smt/euf_solver.h b/src/sat/smt/euf_solver.h index 73c44649c..cf8b9766e 100644 --- a/src/sat/smt/euf_solver.h +++ b/src/sat/smt/euf_solver.h @@ -361,6 +361,7 @@ namespace euf { void add_root(sat::literal_vector const& lits) { add_root(lits.size(), lits.data()); } void add_root(sat::literal lit) { add_root(1, &lit); } void add_root(sat::literal a, sat::literal b) { sat::literal lits[2] = {a, b}; add_root(2, lits); } + void add_aux(sat::literal_vector const& lits) { add_aux(lits.size(), lits.data()); } void add_aux(unsigned n, sat::literal const* lits); void add_aux(sat::literal a, sat::literal b) { sat::literal lits[2] = {a, b}; add_aux(2, lits); } void track_relevancy(sat::bool_var v); diff --git a/src/sat/smt/q_solver.cpp b/src/sat/smt/q_solver.cpp index af670297c..f74ce4778 100644 --- a/src/sat/smt/q_solver.cpp +++ b/src/sat/smt/q_solver.cpp @@ -45,8 +45,7 @@ namespace q { for (expr* e : exp) { sat::literal lit = ctx.internalize(e, l.sign(), false, false); add_clause(~l, lit); - if (ctx.relevancy_enabled()) - ctx.add_root(~l, lit); + ctx.add_aux(~l, lit); } return; } @@ -56,14 +55,14 @@ namespace q { for (expr* e : exp) lits.push_back(ctx.internalize(e, l.sign(), false, false)); add_clause(lits); - ctx.add_root(lits); + ctx.add_aux(lits); return; } if (l.sign() == is_forall(e)) { sat::literal lit = skolemize(q); add_clause(~l, lit); - ctx.add_root(~l, lit); + ctx.add_aux(~l, lit); } else { ctx.push_vec(m_universal, l); diff --git a/src/sat/smt/sat_dual_solver.cpp b/src/sat/smt/sat_dual_solver.cpp index b392254a1..6676603bc 100644 --- a/src/sat/smt/sat_dual_solver.cpp +++ b/src/sat/smt/sat_dual_solver.cpp @@ -81,9 +81,9 @@ namespace sat { return literal(m_var2ext[lit.var()], lit.sign()); } - void dual_solver::add_root(unsigned sz, literal const* clause) { - TRACE("dual", tout << "root: " << literal_vector(sz, clause) << "\n";); + void dual_solver::add_root(unsigned sz, literal const* clause) { if (sz == 1) { + TRACE("dual", tout << "unit: " << clause[0] << "\n";); m_units.push_back(clause[0]); return; } @@ -91,6 +91,7 @@ namespace sat { for (unsigned i = 0; i < sz; ++i) m_solver.mk_clause(root, ~ext2lit(clause[i]), status::input()); m_roots.push_back(~root); + TRACE("dual", tout << "root: " << ~root << " => " << literal_vector(sz, clause) << "\n";); } void dual_solver::add_aux(unsigned sz, literal const* clause) { From a8b433e6ac860486871c3e394b06022618bcb682 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 19 Jul 2021 15:58:10 -0700 Subject: [PATCH 027/125] #5331 Signed-off-by: Nikolaj Bjorner --- src/solver/assertions/asserted_formulas.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/solver/assertions/asserted_formulas.cpp b/src/solver/assertions/asserted_formulas.cpp index 816ccb4e1..be931ccd6 100644 --- a/src/solver/assertions/asserted_formulas.cpp +++ b/src/solver/assertions/asserted_formulas.cpp @@ -424,7 +424,8 @@ void asserted_formulas::apply_quasi_macros() { TRACE("before_quasi_macros", display(tout);); vector new_fmls; quasi_macros proc(m, m_macro_manager); - while (proc(m_formulas.size() - m_qhead, + while (m_qhead == 0 && + proc(m_formulas.size() - m_qhead, m_formulas.data() + m_qhead, new_fmls)) { swap_asserted_formulas(new_fmls); From 7af2309faeba4c12c85abddeeed4ccc03f004e1e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 19 Jul 2021 16:09:13 -0700 Subject: [PATCH 028/125] #5331 --- src/tactic/arith/recover_01_tactic.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/tactic/arith/recover_01_tactic.cpp b/src/tactic/arith/recover_01_tactic.cpp index dc193f9a8..7e1fe17ca 100644 --- a/src/tactic/arith/recover_01_tactic.cpp +++ b/src/tactic/arith/recover_01_tactic.cpp @@ -321,8 +321,6 @@ class recover_01_tactic : public tactic { SASSERT(new_goal->depth() == g->depth()); SASSERT(new_goal->prec() == g->prec()); new_goal->inc_depth(); - new_goal->add(g->mc()); - new_goal->add(g->pc()); for (unsigned i = 0; i < g->size(); i++) { expr * f = g->form(i); @@ -375,7 +373,7 @@ class recover_01_tactic : public tactic { new_goal->update(idx, new_curr); } result.push_back(new_goal.get()); - TRACE("recover_01", new_goal->display(tout);); + TRACE("recover_01", new_goal->display(tout); if (new_goal->mc()) new_goal->mc()->display(tout);); SASSERT(new_goal->is_well_formed()); } From 49bd3ad159240ce4176756e8585302f54900e0ef Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 19 Jul 2021 16:56:10 -0700 Subject: [PATCH 029/125] #5417 again, refining root clauses above search level Signed-off-by: Nikolaj Bjorner --- src/sat/smt/euf_relevancy.cpp | 9 ++++++++- src/sat/smt/q_solver.cpp | 2 +- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/sat/smt/euf_relevancy.cpp b/src/sat/smt/euf_relevancy.cpp index 03f9f8ed1..7e9b20af7 100644 --- a/src/sat/smt/euf_relevancy.cpp +++ b/src/sat/smt/euf_relevancy.cpp @@ -38,11 +38,18 @@ namespace euf { } } + /** + * Add a root clause. Root clauses must all be satisfied by the + * final assignment. If a clause is added above search level it + * is subject to removal on backtracking. These clauses are therefore + * not tracked. + */ void solver::add_root(unsigned n, sat::literal const* lits) { if (!relevancy_enabled()) return; ensure_dual_solver(); - m_dual_solver->add_root(n, lits); + if (s().at_search_lvl()) + m_dual_solver->add_root(n, lits); } void solver::add_aux(unsigned n, sat::literal const* lits) { diff --git a/src/sat/smt/q_solver.cpp b/src/sat/smt/q_solver.cpp index f74ce4778..524c3f1c6 100644 --- a/src/sat/smt/q_solver.cpp +++ b/src/sat/smt/q_solver.cpp @@ -62,7 +62,7 @@ namespace q { if (l.sign() == is_forall(e)) { sat::literal lit = skolemize(q); add_clause(~l, lit); - ctx.add_aux(~l, lit); + ctx.add_root(~l, lit); } else { ctx.push_vec(m_universal, l); From f90795c42fc15e812edf61bdab6df1798c5203ef Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 20 Jul 2021 07:58:21 -0700 Subject: [PATCH 030/125] #5420 --- src/sat/smt/q_eval.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/sat/smt/q_eval.cpp b/src/sat/smt/q_eval.cpp index accc4f526..4d5a37821 100644 --- a/src/sat/smt/q_eval.cpp +++ b/src/sat/smt/q_eval.cpp @@ -179,8 +179,9 @@ namespace q { SASSERT(!is_ground(t) || ctx.get_egraph().find(t)); if (is_ground(t) || (has_quantifiers(t) && !has_free_vars(t))) { m_mark.mark(t); - m_eval.setx(t->get_id(), ctx.get_egraph().find(t), nullptr); - SASSERT(m_eval[t->get_id()]); + m_eval.setx(t->get_id(), ctx.get_egraph().find(t), nullptr); + if (!m_eval[t->get_id()]) + return nullptr; todo.pop_back(); continue; } From b84b5d091e77724a3c842f7e5d7009be6552f041 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 20 Jul 2021 08:02:21 -0700 Subject: [PATCH 031/125] #5420 --- src/sat/smt/q_ematch.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/sat/smt/q_ematch.cpp b/src/sat/smt/q_ematch.cpp index 99282bf30..c83680f72 100644 --- a/src/sat/smt/q_ematch.cpp +++ b/src/sat/smt/q_ematch.cpp @@ -303,6 +303,7 @@ namespace q { auto [is_conflict, idx, j_idx] = m_prop_queue[i]; propagate(is_conflict, idx, j_idx); } + m_prop_queue.reset(); return true; } From 89ed19a7196f9201d61d9995b1ba503003cdc3b9 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 20 Jul 2021 11:20:16 -0700 Subject: [PATCH 032/125] #5420 --- src/sat/smt/fpa_solver.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/sat/smt/fpa_solver.cpp b/src/sat/smt/fpa_solver.cpp index 3589c37c8..42e3f8726 100644 --- a/src/sat/smt/fpa_solver.cpp +++ b/src/sat/smt/fpa_solver.cpp @@ -312,7 +312,9 @@ namespace fpa { if (!wrapped) wrapped = m_converter.wrap(e); return expr2enode(wrapped) != nullptr; }; - if (m_fpa_util.is_fp(e)) { + if (m_fpa_util.is_rm_numeral(e) || m_fpa_util.is_numeral(e)) + value = e; + else if (m_fpa_util.is_fp(e)) { SASSERT(n->num_args() == 3); expr* a = values.get(n->get_arg(0)->get_root_id()); expr* b = values.get(n->get_arg(1)->get_root_id()); From 614cb264897de551d29dccbcdad721455eb0cc27 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 20 Jul 2021 11:44:57 -0700 Subject: [PATCH 033/125] #5420 --- src/sat/smt/euf_solver.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sat/smt/euf_solver.cpp b/src/sat/smt/euf_solver.cpp index 65c383977..8e959e964 100644 --- a/src/sat/smt/euf_solver.cpp +++ b/src/sat/smt/euf_solver.cpp @@ -342,7 +342,7 @@ namespace euf { break; propagated = true; } - DEBUG_CODE(if (!s().inconsistent()) check_missing_eq_propagation();); + DEBUG_CODE(if (!propagated && !s().inconsistent()) check_missing_eq_propagation();); return propagated; } @@ -354,7 +354,7 @@ namespace euf { bool_var v = n->bool_var(); SASSERT(m.is_bool(e)); size_t cnstr; - literal lit; + literal lit; if (is_eq) { VERIFY(m.is_eq(e, a, b)); cnstr = eq_constraint().to_index(); From 134562162a03f57eddd9433e765c6ba86f99480e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 20 Jul 2021 13:50:21 -0700 Subject: [PATCH 034/125] #5420 --- src/sat/smt/q_solver.cpp | 82 ++++++++++------------------------------ 1 file changed, 19 insertions(+), 63 deletions(-) diff --git a/src/sat/smt/q_solver.cpp b/src/sat/smt/q_solver.cpp index 524c3f1c6..23276a3f1 100644 --- a/src/sat/smt/q_solver.cpp +++ b/src/sat/smt/q_solver.cpp @@ -40,34 +40,25 @@ namespace q { return; quantifier* q = to_quantifier(e); - auto const& exp = expand(q); - if (exp.size() > 1 && is_forall(q) && !l.sign()) { - for (expr* e : exp) { - sat::literal lit = ctx.internalize(e, l.sign(), false, false); - add_clause(~l, lit); - ctx.add_aux(~l, lit); - } - return; - } - if (exp.size() > 1 && is_exists(q) && l.sign()) { - sat::literal_vector lits; - lits.push_back(~l); - for (expr* e : exp) - lits.push_back(ctx.internalize(e, l.sign(), false, false)); - add_clause(lits); - ctx.add_aux(lits); - return; - } - if (l.sign() == is_forall(e)) { sat::literal lit = skolemize(q); add_clause(~l, lit); ctx.add_root(~l, lit); } else { - ctx.push_vec(m_universal, l); - if (ctx.get_config().m_ematching) - m_ematch.add(q); + auto const& exp = expand(q); + if (exp.size() > 1) { + for (expr* e : exp) { + sat::literal lit = ctx.internalize(e, l.sign(), false, false); + add_clause(~l, lit); + ctx.add_aux(~l, lit); + } + } + else { + ctx.push_vec(m_universal, l); + if (ctx.get_config().m_ematching) + m_ematch.add(q); + } } m_stats.m_num_quantifier_asserts++; } @@ -146,9 +137,9 @@ namespace q { } /* - * Find initial values to instantiate quantifier with so to make it as hard as possible for solver - * to find values to free variables. - */ + * Find initial values to instantiate quantifier with so to make it as hard as possible for solver + * to find values to free variables. + */ sat::literal solver::specialize(quantifier* q) { std::function mk_var = [&](quantifier* q, unsigned i) { return get_unit(q->get_decl_sort(i)); @@ -243,46 +234,11 @@ namespace q { ctx.get_rewriter()(tmp); m_expanded[i] = tmp; } - return m_expanded; } - -#if 0 - m_expanded.reset(); - m_expanded2.reset(); - if (is_forall(q)) - flatten_or(q->get_expr(), m_expanded2); - else if (is_exists(q)) - flatten_and(q->get_expr(), m_expanded2); - else - UNREACHABLE(); - for (unsigned i = m_expanded2.size(); i-- > 0; ) { - expr* lit = m_expanded2.get(i); - if (!is_ground(lit) && is_and(lit) && is_forall(q)) { - - // get free vars of lit - // create fresh predicate over free vars - // replace in expanded, pack and push on m_expanded - - expr_ref p(m); - // TODO introduce fresh p. - flatten_and(lit, m_expanded); - for (unsigned i = m_expanded.size(); i-- > 0; ) { - tmp = m.mk_or(m.mk_not(p), m_expanded.get(i)); - expr_ref tmp(m.update_quantifier(q, tmp), m); - ctx.get_rewriter()(tmp); - m_expanded[i] = tmp; - } - m_expanded2[i] = p; - tmp = m.mk_or(m_expanded2); - expr_ref tmp(m.update_quantifier(q, tmp), m); - ctx.get_rewriter()(tmp); - m_expanded.push_back(tmp); - return m_expanded; - } + else { + m_expanded.reset(); + m_expanded.push_back(q); } -#endif - m_expanded.reset(); - m_expanded.push_back(q); return m_expanded; } From 574246ff7aced4e98aea66b8bd9c53cf24c17454 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 20 Jul 2021 15:29:24 -0700 Subject: [PATCH 035/125] #5420 --- src/model/model_evaluator.cpp | 6 +++--- src/sat/smt/q_mbi.cpp | 9 ++++----- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/src/model/model_evaluator.cpp b/src/model/model_evaluator.cpp index 23bab1761..fc620d757 100644 --- a/src/model/model_evaluator.cpp +++ b/src/model/model_evaluator.cpp @@ -150,9 +150,9 @@ struct evaluator_cfg : public default_rewriter_cfg { br_status reduce_app(func_decl * f, unsigned num, expr * const * args, expr_ref & result, proof_ref & result_pr) { auto st = reduce_app_core(f, num, args, result, result_pr); CTRACE("model_evaluator", st != BR_FAILED, - tout << f->get_name() << "\n"; - for (unsigned i = 0; i < num; ++i) tout << mk_pp(args[i], m) << "\n"; - tout << result << "\n";); + tout << f->get_name() << " "; + for (unsigned i = 0; i < num; ++i) tout << mk_pp(args[i], m) << " "; + tout << "\n--> " << result << "\n";); return st; } diff --git a/src/sat/smt/q_mbi.cpp b/src/sat/smt/q_mbi.cpp index 802e3d393..5c30bedd4 100644 --- a/src/sat/smt/q_mbi.cpp +++ b/src/sat/smt/q_mbi.cpp @@ -299,13 +299,12 @@ namespace q { auto* p = get_plugin(v); if (p && !fmls_extracted) { TRACE("q", tout << "domain eqs\n" << qb.domain_eqs << "\n";); - - for (expr* e : qb.domain_eqs) - if (!m_model->is_true(e)) - return expr_ref(nullptr, m); - + fmls.append(qb.domain_eqs); eliminate_nested_vars(fmls, qb); + for (expr* e : fmls) + if (!m_model->is_true(e)) + return expr_ref(nullptr, m); mbp::project_plugin proj(m); proj.extract_literals(*m_model, vars, fmls); fmls_extracted = true; From 0ba518b0c0337c0a33c1f9de596be7df8f7e5f63 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 20 Jul 2021 20:07:06 -0700 Subject: [PATCH 036/125] avoid perf abyss for macros Signed-off-by: Nikolaj Bjorner --- src/api/api_ast.cpp | 2 +- src/ast/recfun_decl_plugin.cpp | 21 +++++++++++---------- src/ast/recfun_decl_plugin.h | 10 +++++----- src/cmd_context/cmd_context.cpp | 4 ++-- src/smt/theory_special_relations.cpp | 6 +++--- 5 files changed, 22 insertions(+), 21 deletions(-) diff --git a/src/api/api_ast.cpp b/src/api/api_ast.cpp index 50a02d262..0d9b00351 100644 --- a/src/api/api_ast.cpp +++ b/src/api/api_ast.cpp @@ -159,7 +159,7 @@ extern "C" { return; } recfun_replace replace(m); - p.set_definition(replace, pd, n, _vars.data(), abs_body); + p.set_definition(replace, pd, true, n, _vars.data(), abs_body); Z3_CATCH; } diff --git a/src/ast/recfun_decl_plugin.cpp b/src/ast/recfun_decl_plugin.cpp index 3411f8cec..bd23e1838 100644 --- a/src/ast/recfun_decl_plugin.cpp +++ b/src/ast/recfun_decl_plugin.cpp @@ -209,6 +209,7 @@ namespace recfun { void def::compute_cases(util& u, replace& subst, is_immediate_pred & is_i, + bool is_macro, unsigned n_vars, var *const * vars, expr* rhs) { VERIFY(m_cases.empty() && "cases cannot already be computed"); @@ -227,7 +228,7 @@ namespace recfun { expr_ref_vector conditions(m); // is the function a macro (unconditional body)? - if (n_vars == 0 || !contains_ite(u, rhs)) { + if (is_macro || n_vars == 0 || !contains_ite(u, rhs)) { // constant function or trivial control flow, only one (dummy) case add_case(name, 0, conditions, rhs); return; @@ -336,9 +337,9 @@ namespace recfun { } - void util::set_definition(replace& subst, promise_def & d, unsigned n_vars, var * const * vars, expr * rhs) { + void util::set_definition(replace& subst, promise_def & d, bool is_macro, unsigned n_vars, var * const * vars, expr * rhs) { expr_ref rhs1 = get_plugin().redirect_ite(subst, n_vars, vars, rhs); - d.set_definition(subst, n_vars, vars, rhs1); + d.set_definition(subst, is_macro, n_vars, vars, rhs1); } app_ref util::mk_num_rounds_pred(unsigned d) { @@ -369,11 +370,11 @@ namespace recfun { }; // set definition - void promise_def::set_definition(replace& r, unsigned n_vars, var * const * vars, expr * rhs) { + void promise_def::set_definition(replace& r, bool is_macro, unsigned n_vars, var * const * vars, expr * rhs) { SASSERT(n_vars == d->get_arity()); is_imm_pred is_i(*u); - d->compute_cases(*u, r, is_i, n_vars, vars, rhs); + d->compute_cases(*u, r, is_i, is_macro, n_vars, vars, rhs); } namespace decl { @@ -426,8 +427,8 @@ namespace recfun { } } - void plugin::set_definition(replace& r, promise_def & d, unsigned n_vars, var * const * vars, expr * rhs) { - u().set_definition(r, d, n_vars, vars, rhs); + void plugin::set_definition(replace& r, promise_def & d, bool is_macro, unsigned n_vars, var * const * vars, expr * rhs) { + u().set_definition(r, d, is_macro, n_vars, vars, rhs); for (case_def & c : d.get_def()->get_cases()) { m_case_defs.insert(c.get_decl(), &c); } @@ -437,12 +438,12 @@ namespace recfun { return !m_case_defs.empty(); } - def* plugin::mk_def(replace& subst, + def* plugin::mk_def(replace& subst, bool is_macro, symbol const& name, unsigned n, sort ** params, sort * range, unsigned n_vars, var ** vars, expr * rhs) { promise_def d = mk_def(name, n, params, range); SASSERT(! m_defs.contains(d.get_def()->get_decl())); - set_definition(subst, d, n_vars, vars, rhs); + set_definition(subst, d, is_macro, n_vars, vars, rhs); return d.get_def(); } @@ -520,7 +521,7 @@ namespace recfun { auto pd = mk_def(fresh_name, n, domain.data(), max_expr->get_sort()); func_decl* f = pd.get_def()->get_decl(); expr_ref new_body(m().mk_app(f, n, args.data()), m()); - set_definition(subst, pd, n, vars, max_expr); + set_definition(subst, pd, false, n, vars, max_expr); subst.reset(); subst.insert(max_expr, new_body); result = subst(result); diff --git a/src/ast/recfun_decl_plugin.h b/src/ast/recfun_decl_plugin.h index 22f2e76fe..dd6f5181a 100644 --- a/src/ast/recfun_decl_plugin.h +++ b/src/ast/recfun_decl_plugin.h @@ -114,7 +114,7 @@ namespace recfun { // compute cases for a function, given its RHS (possibly containing `ite`). void compute_cases(util& u, replace& subst, is_immediate_pred &, - unsigned n_vars, var *const * vars, expr* rhs); + bool is_macro, unsigned n_vars, var *const * vars, expr* rhs); void add_case(std::string & name, unsigned case_index, expr_ref_vector const& conditions, expr* rhs, bool is_imm = false); bool contains_ite(util& u, expr* e); // expression contains a test over a def? bool contains_def(util& u, expr* e); // expression contains a def @@ -138,7 +138,7 @@ namespace recfun { friend class util; util * u; def * d; - void set_definition(replace& r, unsigned n_vars, var * const * vars, expr * rhs); // call only once + void set_definition(replace& r, bool is_macro, unsigned n_vars, var * const * vars, expr * rhs); // call only once public: promise_def(util * u, def * d) : u(u), d(d) {} promise_def(promise_def const & from) : u(from.u), d(from.d) {} @@ -182,9 +182,9 @@ namespace recfun { promise_def ensure_def(symbol const& name, unsigned n, sort *const * params, sort * range, bool is_generated = false); - void set_definition(replace& r, promise_def & d, unsigned n_vars, var * const * vars, expr * rhs); + void set_definition(replace& r, promise_def & d, bool is_macro, unsigned n_vars, var * const * vars, expr * rhs); - def* mk_def(replace& subst, symbol const& name, unsigned n, sort ** params, sort * range, unsigned n_vars, var ** vars, expr * rhs); + def* mk_def(replace& subst, bool is_macro, symbol const& name, unsigned n, sort ** params, sort * range, unsigned n_vars, var ** vars, expr * rhs); void erase_def(func_decl* f); @@ -216,7 +216,7 @@ namespace recfun { decl::plugin * m_plugin; bool compute_is_immediate(expr * rhs); - void set_definition(replace& r, promise_def & d, unsigned n_vars, var * const * vars, expr * rhs); + void set_definition(replace& r, promise_def & d, bool is_macro, unsigned n_vars, var * const * vars, expr * rhs); public: util(ast_manager &m); diff --git a/src/cmd_context/cmd_context.cpp b/src/cmd_context/cmd_context.cpp index 2ec910595..2133a1c00 100644 --- a/src/cmd_context/cmd_context.cpp +++ b/src/cmd_context/cmd_context.cpp @@ -365,7 +365,7 @@ void cmd_context::insert_macro(symbol const& s, unsigned arity, sort*const* doma // recursive functions have opposite calling convention from macros! var_subst sub(m(), true); expr_ref tt = sub(t, rvars); - p.set_definition(replace, d, vars.size(), vars.data(), tt); + p.set_definition(replace, d, true, vars.size(), vars.data(), tt); register_fun(s, d.get_def()->get_decl()); } @@ -1004,7 +1004,7 @@ void cmd_context::insert_rec_fun(func_decl* f, expr_ref_vector const& binding, s recfun::promise_def d = p.get_promise_def(f); recfun_replace replace(m()); - p.set_definition(replace, d, vars.size(), vars.data(), rhs); + p.set_definition(replace, d, false, vars.size(), vars.data(), rhs); } func_decl * cmd_context::find_func_decl(symbol const & s) const { diff --git a/src/smt/theory_special_relations.cpp b/src/smt/theory_special_relations.cpp index c612d4938..4a8070927 100644 --- a/src/smt/theory_special_relations.cpp +++ b/src/smt/theory_special_relations.cpp @@ -903,7 +903,7 @@ namespace smt { m.mk_app(memf, x, m.mk_app(tl, S)))); recfun_replace rep(m); var* vars[2] = { xV, SV }; - p.set_definition(rep, mem, 2, vars, mem_body); + p.set_definition(rep, mem, false, 2, vars, mem_body); } sort_ref tup(dt.mk_pair_datatype(listS, listS, fst, snd, pair), m); @@ -926,7 +926,7 @@ namespace smt { recfun_replace rep(m); var* vars[5] = { aV, bV, AV, SV, tupV }; - p.set_definition(rep, nxt, 5, vars, next_body); + p.set_definition(rep, nxt, false, 5, vars, next_body); } { @@ -961,7 +961,7 @@ namespace smt { TRACE("special_relations", tout << connected_body << "\n";); recfun_replace rep(m); var* vars[3] = { AV, dstV, SV }; - p.set_definition(rep, connected, 3, vars, connected_body); + p.set_definition(rep, connected, false, 3, vars, connected_body); } { From 8a4b292f3e3c656a205d42424ebe48658c68979a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 21 Jul 2021 06:25:11 -0700 Subject: [PATCH 037/125] #5422 --- src/sat/tactic/goal2sat.cpp | 23 ++++++++--------------- 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/src/sat/tactic/goal2sat.cpp b/src/sat/tactic/goal2sat.cpp index 925dac7f8..b1332cdb2 100644 --- a/src/sat/tactic/goal2sat.cpp +++ b/src/sat/tactic/goal2sat.cpp @@ -69,7 +69,6 @@ struct goal2sat::imp : public sat::sat_internalizer { atom2bool_var & m_map; dep2asm_map & m_dep2asm; obj_map* m_expr2var_replay { nullptr }; - sat::literal m_true; bool m_ite_extra; unsigned long long m_max_memory; expr_ref_vector m_trail; @@ -92,7 +91,6 @@ struct goal2sat::imp : public sat::sat_internalizer { m_unhandled_funs(m), m_default_external(default_external) { updt_params(p); - m_true = sat::null_literal; } ~imp() override { @@ -198,16 +196,6 @@ struct goal2sat::imp : public sat::sat_internalizer { ensure_euf()->drat_bool_def(v, n); } - sat::literal mk_true() { - if (m_true == sat::null_literal) { - // create fake variable to represent true; - m_true = sat::literal(add_var(false, m.mk_true()), false); - mk_clause(m_true); // v is true - add_dual_root(1, &m_true); - } - return m_true; - } - sat::bool_var to_bool_var(expr* e) override { sat::literal l; sat::bool_var v = m_map.to_bool_var(e); @@ -301,10 +289,16 @@ struct goal2sat::imp : public sat::sat_internalizer { sat::bool_var v = m_map.to_bool_var(t); if (v == sat::null_bool_var) { if (m.is_true(t)) { - l = sign ? ~mk_true() : mk_true(); + sat::literal tt = sat::literal(add_var(false, m.mk_true()), false); + mk_clause(tt); + add_dual_root(1, &tt); + l = sign ? ~tt : tt; } else if (m.is_false(t)) { - l = sign ? mk_true() : ~mk_true(); + sat::literal tt = sat::literal(add_var(false, m.mk_false()), true); + mk_clause(tt); + add_dual_root(1, &tt); + l = sign ? tt : ~tt; } else { if (m_euf) { @@ -932,7 +926,6 @@ struct goal2sat::imp : public sat::sat_internalizer { } void user_pop(unsigned n) { - m_true = sat::null_literal; } }; From e5e7c510d52a3ccebe5d450a349576820b093387 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 21 Jul 2021 07:14:54 -0700 Subject: [PATCH 038/125] #5422 --- src/qe/mbp/mbp_plugin.cpp | 188 +++++++++++++++++++------------------- src/qe/mbp/mbp_plugin.h | 1 + 2 files changed, 95 insertions(+), 94 deletions(-) diff --git a/src/qe/mbp/mbp_plugin.cpp b/src/qe/mbp/mbp_plugin.cpp index 723ef26fa..7731f803c 100644 --- a/src/qe/mbp/mbp_plugin.cpp +++ b/src/qe/mbp/mbp_plugin.cpp @@ -95,6 +95,97 @@ namespace mbp { lits.push_back(e); } + bool project_plugin::reduce(model_evaluator& eval, model& model, expr* fml, expr_ref_vector& fmls) { + expr* nfml, * f1, * f2, * f3; + expr_ref val(m); + if (m.is_not(fml, nfml) && m.is_distinct(nfml)) + push_back(fmls, pick_equality(m, model, nfml)); + else if (m.is_or(fml)) { + for (expr* arg : *to_app(fml)) { + val = eval(arg); + if (m.is_true(val)) { + fmls.push_back(arg); + break; + } + } + } + else if (m.is_and(fml)) { + fmls.append(to_app(fml)->get_num_args(), to_app(fml)->get_args()); + } + else if (m.is_iff(fml, f1, f2) || (m.is_not(fml, nfml) && m.is_xor(nfml, f1, f2))) { + val = eval(f1); + if (m.is_false(val)) { + push_back(fmls, mk_not(m, f1)); + push_back(fmls, mk_not(m, f2)); + } + else { + push_back(fmls, f1); + push_back(fmls, f2); + } + } + else if (m.is_implies(fml, f1, f2)) { + val = eval(f2); + if (m.is_true(val)) + push_back(fmls, f2); + else + push_back(fmls, mk_not(m, f1)); + } + else if (m.is_ite(fml, f1, f2, f3)) { + val = eval(f1); + if (m.is_true(val)) { + push_back(fmls, f1); + push_back(fmls, f2); + } + else { + push_back(fmls, mk_not(m, f1)); + push_back(fmls, f3); + } + } + else if (m.is_not(fml, nfml) && m.is_not(nfml, nfml)) { + push_back(fmls, nfml); + } + else if (m.is_not(fml, nfml) && m.is_and(nfml)) { + for (expr* arg : *to_app(nfml)) { + val = eval(arg); + if (m.is_false(val)) { + push_back(fmls, mk_not(m, arg)); + break; + } + } + } + else if (m.is_not(fml, nfml) && m.is_or(nfml)) { + for (expr* arg : *to_app(nfml)) + push_back(fmls, mk_not(m, arg)); + } + else if ((m.is_not(fml, nfml) && m.is_iff(nfml, f1, f2)) || m.is_xor(fml, f1, f2)) { + val = eval(f1); + if (m.is_true(val)) + f2 = mk_not(m, f2); + else + f1 = mk_not(m, f1); + push_back(fmls, f1); + push_back(fmls, f2); + } + else if (m.is_not(fml, nfml) && m.is_implies(nfml, f1, f2)) { + push_back(fmls, f1); + push_back(fmls, mk_not(m, f2)); + } + else if (m.is_not(fml, nfml) && m.is_ite(nfml, f1, f2, f3)) { + val = eval(f1); + if (m.is_true(val)) { + push_back(fmls, f1); + push_back(fmls, mk_not(m, f2)); + } + else { + push_back(fmls, mk_not(m, f1)); + push_back(fmls, mk_not(m, f3)); + } + } + else + return false; + return true; + } + void project_plugin::extract_literals(model& model, app_ref_vector const& vars, expr_ref_vector& fmls) { m_cache.reset(); m_bool_visited.reset(); @@ -105,100 +196,9 @@ namespace mbp { DEBUG_CODE(for (expr* fml : fmls) { CTRACE("qe", m.is_false(eval(fml)), tout << mk_pp(fml, m) << " is false\n" << model;); SASSERT(!m.is_false(eval(fml))); }); for (unsigned i = 0; i < fmls.size(); ++i) { - expr* fml = fmls.get(i), * nfml, * f1, * f2, * f3; - SASSERT(m.is_bool(fml)); - if (m.is_not(fml, nfml) && m.is_distinct(nfml)) - fmls[i--] = pick_equality(m, model, nfml); - else if (m.is_or(fml)) { - for (expr* arg : *to_app(fml)) { - val = eval(arg); - if (m.is_true(val)) { - fmls[i] = arg; - --i; - break; - } - } - } - else if (m.is_and(fml)) { - fmls.append(to_app(fml)->get_num_args(), to_app(fml)->get_args()); - erase(fmls, i); - } - else if (m.is_iff(fml, f1, f2) || (m.is_not(fml, nfml) && m.is_xor(nfml, f1, f2))) { - val = eval(f1); - if (m.is_false(val)) { - f1 = mk_not(m, f1); - f2 = mk_not(m, f2); - } - fmls[i--] = f1; - push_back(fmls, f2); - } - else if (m.is_implies(fml, f1, f2)) { - val = eval(f2); - if (m.is_true(val)) { - fmls[i] = f2; - } - else { - fmls[i] = mk_not(m, f1); - } - --i; - } - else if (m.is_ite(fml, f1, f2, f3)) { - val = eval(f1); - if (m.is_true(val)) { - push_back(fmls, f1); - push_back(fmls, f2); - } - else { - push_back(fmls, mk_not(m, f1)); - push_back(fmls, f3); - } - erase(fmls, i); - } - else if (m.is_not(fml, nfml) && m.is_not(nfml, nfml)) { - push_back(fmls, nfml); - erase(fmls, i); - } - else if (m.is_not(fml, nfml) && m.is_and(nfml)) { - for (expr* arg : *to_app(nfml)) { - val = eval(arg); - if (m.is_false(val)) { - fmls[i--] = mk_not(m, arg); - break; - } - } - } - else if (m.is_not(fml, nfml) && m.is_or(nfml)) { - for (expr* arg : *to_app(nfml)) - push_back(fmls, mk_not(m, arg)); - erase(fmls, i); - } - else if ((m.is_not(fml, nfml) && m.is_iff(nfml, f1, f2)) || m.is_xor(fml, f1, f2)) { - val = eval(f1); - if (m.is_true(val)) - f2 = mk_not(m, f2); - else - f1 = mk_not(m, f1); - push_back(fmls, f1); - push_back(fmls, f2); - erase(fmls, i); - } - else if (m.is_not(fml, nfml) && m.is_implies(nfml, f1, f2)) { - push_back(fmls, f1); - push_back(fmls, mk_not(m, f2)); - erase(fmls, i); - } - else if (m.is_not(fml, nfml) && m.is_ite(nfml, f1, f2, f3)) { - val = eval(f1); - if (m.is_true(val)) { - push_back(fmls, f1); - push_back(fmls, mk_not(m, f2)); - } - else { - push_back(fmls, mk_not(m, f1)); - push_back(fmls, mk_not(m, f3)); - } - erase(fmls, i); - } + expr* nfml, * fml = fmls.get(i); + if (reduce(eval, model, fml, fmls)) + erase(fmls, i); else if (m.is_not(fml, nfml)) extract_bools(eval, fmls, i, nfml, false); else diff --git a/src/qe/mbp/mbp_plugin.h b/src/qe/mbp/mbp_plugin.h index 121c7672e..741639aaa 100644 --- a/src/qe/mbp/mbp_plugin.h +++ b/src/qe/mbp/mbp_plugin.h @@ -43,6 +43,7 @@ namespace mbp { expr_mark m_non_ground; expr_ref_vector m_cache, m_args, m_pure_eqs; + bool reduce(model_evaluator& eval, model& model, expr* fml, expr_ref_vector& fmls); void extract_bools(model_evaluator& eval, expr_ref_vector& fmls, unsigned i, expr* fml, bool is_true); void visit_app(expr* e); bool visit_ite(model_evaluator& eval, expr* e, expr_ref_vector& fmls); From ca8f914dd886ada1def33b7e8a5772e33d8fd5cc Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 21 Jul 2021 07:22:05 -0700 Subject: [PATCH 039/125] #5422 --- src/math/simplex/model_based_opt.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/math/simplex/model_based_opt.cpp b/src/math/simplex/model_based_opt.cpp index 429a97ae2..5bc0b1836 100644 --- a/src/math/simplex/model_based_opt.cpp +++ b/src/math/simplex/model_based_opt.cpp @@ -134,7 +134,15 @@ namespace opt { } void model_based_opt::def::normalize() { - SASSERT(m_div.is_int()); + if (!m_div.is_int()) { + rational den = denominator(m_div); + SASSERT(den > 1); + for (var& v : m_vars) + v.m_coeff *= den; + m_coeff *= den; + m_div *= den; + + } if (m_div.is_neg()) { for (var& v : m_vars) v.m_coeff.neg(); @@ -1249,6 +1257,7 @@ namespace opt { } def result; if (compute_def) { + TRACE("opt1", tout << m_rows[row_id1] << "\n";); result = def(m_rows[row_id1], x); m_var2value[x] = eval(result); TRACE("opt1", tout << "updated eval " << x << " := " << eval(x) << "\n";); From 005d35f9c931bf0c0bd6087285b2cb0af9d18944 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 21 Jul 2021 07:39:39 -0700 Subject: [PATCH 040/125] #5422 --- src/math/simplex/model_based_opt.cpp | 1 - src/sat/smt/q_solver.cpp | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/math/simplex/model_based_opt.cpp b/src/math/simplex/model_based_opt.cpp index 5bc0b1836..1acbb592b 100644 --- a/src/math/simplex/model_based_opt.cpp +++ b/src/math/simplex/model_based_opt.cpp @@ -1257,7 +1257,6 @@ namespace opt { } def result; if (compute_def) { - TRACE("opt1", tout << m_rows[row_id1] << "\n";); result = def(m_rows[row_id1], x); m_var2value[x] = eval(result); TRACE("opt1", tout << "updated eval " << x << " := " << eval(x) << "\n";); diff --git a/src/sat/smt/q_solver.cpp b/src/sat/smt/q_solver.cpp index 23276a3f1..5769340ee 100644 --- a/src/sat/smt/q_solver.cpp +++ b/src/sat/smt/q_solver.cpp @@ -51,7 +51,7 @@ namespace q { for (expr* e : exp) { sat::literal lit = ctx.internalize(e, l.sign(), false, false); add_clause(~l, lit); - ctx.add_aux(~l, lit); + ctx.add_root(~l, lit); } } else { From 644bd82ac73121f37bbac7ca72466527006232e3 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 21 Jul 2021 09:08:55 -0700 Subject: [PATCH 041/125] #5422 --- src/ast/euf/euf_egraph.cpp | 10 ++++++++++ src/sat/smt/array_axioms.cpp | 2 +- src/sat/smt/array_model.cpp | 11 ++++++----- 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/src/ast/euf/euf_egraph.cpp b/src/ast/euf/euf_egraph.cpp index 2bc9b1cde..0f82c2e6c 100644 --- a/src/ast/euf/euf_egraph.cpp +++ b/src/ast/euf/euf_egraph.cpp @@ -417,6 +417,16 @@ namespace euf { std::swap(r1, r2); std::swap(n1, n2); } + if (m.is_false(r2->get_expr()) && r1->value() == l_true) { + std::cout << "value assign conflict\n"; + set_conflict(n1, n2, j); + return; + } + if (m.is_true(r2->get_expr()) && r1->value() == l_false) { + std::cout << "value assign conflict\n"; + set_conflict(n1, n2, j); + return; + } if (j.is_congruence() && (m.is_false(r2->get_expr()) || m.is_true(r2->get_expr()))) add_literal(n1, false); if (n1->is_equality() && n1->value() == l_false) diff --git a/src/sat/smt/array_axioms.cpp b/src/sat/smt/array_axioms.cpp index 89e079df4..2e8a0603d 100644 --- a/src/sat/smt/array_axioms.cpp +++ b/src/sat/smt/array_axioms.cpp @@ -540,7 +540,7 @@ namespace array { for (euf::enode* p : euf::enode_parents(n)) has_default |= a.is_default(p->get_expr()); if (has_default) - propagate_parent_default(v); + propagate_parent_default(v); } bool change = false; unsigned sz = m_axiom_trail.size(); diff --git a/src/sat/smt/array_model.cpp b/src/sat/smt/array_model.cpp index 964f6902d..b4e7d3cab 100644 --- a/src/sat/smt/array_model.cpp +++ b/src/sat/smt/array_model.cpp @@ -26,8 +26,8 @@ namespace array { if (!a.is_array(n->get_expr())) { dep.insert(n, nullptr); return true; - } - for (euf::enode* p : euf::enode_parents(n)) { + } + for (euf::enode* p : euf::enode_parents(n->get_root())) { if (a.is_default(p->get_expr())) { dep.add(n, p); continue; @@ -51,6 +51,7 @@ namespace array { SASSERT(a.is_array(n->get_expr())); ptr_vector args; sort* srt = n->get_sort(); + n = n->get_root(); unsigned arity = get_array_arity(srt); func_decl * f = mk_aux_decl_for_array_sort(m, srt); func_interp * fi = alloc(func_interp, m, arity); @@ -70,7 +71,7 @@ namespace array { expr* else_value = nullptr; unsigned max_occ_num = 0; obj_map num_occ; - for (euf::enode* p : euf::enode_parents(n)) { + for (euf::enode* p : euf::enode_parents(n->get_root())) { if (a.is_select(p->get_expr()) && p->get_arg(0)->get_root() == n->get_root()) { expr* v = values.get(p->get_root_id()); if (!v) @@ -90,7 +91,7 @@ namespace array { } for (euf::enode* p : euf::enode_parents(n)) { - if (a.is_select(p->get_expr()) && p->get_arg(0)->get_root() == n->get_root()) { + if (a.is_select(p->get_expr()) && p->get_arg(0)->get_root() == n) { expr* value = values.get(p->get_root_id()); if (!value || value == fi->get_else()) continue; @@ -102,7 +103,7 @@ namespace array { } parameter p(f); - values.set(n->get_root_id(), m.mk_app(get_id(), OP_AS_ARRAY, 1, &p)); + values.set(n->get_expr_id(), m.mk_app(get_id(), OP_AS_ARRAY, 1, &p)); } From 39c3f34a304f6b04af275ac25643fd68a346f5f9 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 21 Jul 2021 09:25:08 -0700 Subject: [PATCH 042/125] remove unused dependency --- src/ast/macros/quasi_macros.cpp | 7 +++---- src/solver/assertions/CMakeLists.txt | 1 - 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/ast/macros/quasi_macros.cpp b/src/ast/macros/quasi_macros.cpp index 2faf736b8..a3e6c61e7 100644 --- a/src/ast/macros/quasi_macros.cpp +++ b/src/ast/macros/quasi_macros.cpp @@ -110,10 +110,9 @@ bool quasi_macros::fully_depends_on(app * a, quantifier * q) const { // direct argument of a, i.e., a->get_arg(i) == v for some i bit_vector bitset; bitset.resize(q->get_num_decls(), false); - for (unsigned i = 0 ; i < a->get_num_args() ; i++) { - if (is_var(a->get_arg(i))) - bitset.set(to_var(a->get_arg(i))->get_idx(), true); - } + for (expr* arg : *a) + if (is_var(arg)) + bitset.set(to_var(arg)->get_idx(), true); for (unsigned i = 0; i < bitset.size() ; i++) { if (!bitset.get(i)) diff --git a/src/solver/assertions/CMakeLists.txt b/src/solver/assertions/CMakeLists.txt index 3e1c1c0e3..7cc320458 100644 --- a/src/solver/assertions/CMakeLists.txt +++ b/src/solver/assertions/CMakeLists.txt @@ -2,7 +2,6 @@ z3_add_component(solver_assertions SOURCES asserted_formulas.cpp COMPONENT_DEPENDENCIES - solver smt2parser smt_params ) From 9a5c0f2312fc5174845d537ca9e09b498ec85948 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 22 Jul 2021 09:38:05 -0700 Subject: [PATCH 043/125] #5427 --- src/sat/smt/euf_model.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/sat/smt/euf_model.cpp b/src/sat/smt/euf_model.cpp index be4c824b3..412aec533 100644 --- a/src/sat/smt/euf_model.cpp +++ b/src/sat/smt/euf_model.cpp @@ -61,6 +61,7 @@ namespace euf { }; void solver::update_model(model_ref& mdl) { + mdl->reset_eval_cache(); for (auto* mb : m_solvers) mb->init_model(); m_values.reset(); From 76427cd2815f4648921209c7708f566ca05ba7ae Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 22 Jul 2021 11:33:47 -0700 Subject: [PATCH 044/125] #5427 --- src/sat/tactic/goal2sat.cpp | 4 ++++ src/sat/tactic/goal2sat.h | 2 ++ src/sat/tactic/sat_tactic.cpp | 5 ++++- 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/sat/tactic/goal2sat.cpp b/src/sat/tactic/goal2sat.cpp index b1332cdb2..72b825a09 100644 --- a/src/sat/tactic/goal2sat.cpp +++ b/src/sat/tactic/goal2sat.cpp @@ -999,6 +999,10 @@ bool goal2sat::has_interpreted_funs() const { return m_imp && !m_imp->interpreted_funs().empty(); } +bool goal2sat::has_euf() const { + return m_imp && m_imp->m_euf; +} + void goal2sat::update_model(model_ref& mdl) { if (m_imp) m_imp->update_model(mdl); diff --git a/src/sat/tactic/goal2sat.h b/src/sat/tactic/goal2sat.h index 940777447..bc6b8dcb1 100644 --- a/src/sat/tactic/goal2sat.h +++ b/src/sat/tactic/goal2sat.h @@ -66,6 +66,8 @@ public: bool has_interpreted_funs() const; + bool has_euf() const; + sat::sat_internalizer& si(ast_manager& m, params_ref const& p, sat::solver_core& t, atom2bool_var& a2b, dep2asm_map& dep2asm, bool default_external = false); void update_model(model_ref& mdl); diff --git a/src/sat/tactic/sat_tactic.cpp b/src/sat/tactic/sat_tactic.cpp index 4d7b23166..c8c009bbf 100644 --- a/src/sat/tactic/sat_tactic.cpp +++ b/src/sat/tactic/sat_tactic.cpp @@ -113,8 +113,11 @@ class sat_tactic : public tactic { break; } } + + bool euf = m_goal2sat.has_euf(); + for (auto* f : fmls_to_validate) - if (md->is_false(f)) + if (!euf && md->is_false(f)) IF_VERBOSE(0, verbose_stream() << "failed to validate: " << mk_pp(f, m) << "\n";); m_goal2sat.update_model(md); From 2589f2bad4b3583147758288713bc54ce61264d9 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 22 Jul 2021 12:07:11 -0700 Subject: [PATCH 045/125] #5427 --- src/sat/smt/euf_solver.cpp | 2 +- src/sat/smt/q_clause.h | 2 ++ src/sat/smt/q_eval.cpp | 20 +++++++++----------- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/sat/smt/euf_solver.cpp b/src/sat/smt/euf_solver.cpp index 8e959e964..295216ef9 100644 --- a/src/sat/smt/euf_solver.cpp +++ b/src/sat/smt/euf_solver.cpp @@ -211,7 +211,7 @@ namespace euf { for (sat::literal lit : r) if (s().lvl(lit) > 0) r[j++] = lit; r.shrink(j); - TRACE("euf", tout << "eplain " << l << " <- " << r << " " << probing << "\n";); + TRACE("euf", tout << "explain " << l << " <- " << r << " " << probing << "\n";); DEBUG_CODE(for (auto lit : r) SASSERT(s().value(lit) == l_true);); if (!probing) diff --git a/src/sat/smt/q_clause.h b/src/sat/smt/q_clause.h index 2107b2172..6cb889ee1 100644 --- a/src/sat/smt/q_clause.h +++ b/src/sat/smt/q_clause.h @@ -59,10 +59,12 @@ namespace q { unsigned m_index; vector m_lits; quantifier_ref m_q; + unsigned m_watch = 0; sat::literal m_literal = sat::null_literal; q::quantifier_stat* m_stat = nullptr; binding* m_bindings = nullptr; + clause(ast_manager& m, unsigned idx): m_index(idx), m_q(m) {} std::ostream& display(euf::solver& ctx, std::ostream& out) const; diff --git a/src/sat/smt/q_eval.cpp b/src/sat/smt/q_eval.cpp index 4d5a37821..1ecc0e4ec 100644 --- a/src/sat/smt/q_eval.cpp +++ b/src/sat/smt/q_eval.cpp @@ -39,40 +39,37 @@ namespace q { unsigned sz = c.m_lits.size(); unsigned n = c.num_decls(); m_indirect_nodes.reset(); - for (unsigned i = 0; i < sz; ++i) { + for (unsigned j = 0; j < sz; ++j) { + unsigned i = (j + c.m_watch) % sz; unsigned lim = m_indirect_nodes.size(); lit l = c[i]; lbool cmp = compare(n, binding, l.lhs, l.rhs, evidence); + std::cout << l.sign << ": " << l.lhs << " ~~ " << l.rhs << " " << cmp << "\n"; switch (cmp) { case l_false: m_indirect_nodes.shrink(lim); if (!l.sign) break; - if (i > 0) - std::swap(c[0], c[i]); + c.m_watch = i; return l_true; case l_true: m_indirect_nodes.shrink(lim); if (l.sign) break; - if (i > 0) - std::swap(c[0], c[i]); + c.m_watch = i; return l_true; case l_undef: TRACE("q", tout << l.lhs << " ~~ " << l.rhs << " is undef\n";); - if (idx == 0) { + if (idx != UINT_MAX) { idx = UINT_MAX; return l_undef; } - if (i > 0) - std::swap(c[0], c[i]); - idx = 0; + idx = i; break; } } if (idx == UINT_MAX) return l_false; - return l_undef; } @@ -97,8 +94,9 @@ namespace q { tout << ctx.bpp(sn) << " " << ctx.bpp(tn) << "\n";); lbool c; - if (sn && sn == tn) + if (sn && sn == tn) return l_true; + if (sn && tn && ctx.get_egraph().are_diseq(sn, tn)) { evidence.push_back(euf::enode_pair(sn, tn)); return l_false; From 848a8ebb98b27015ffb04cb809c68f8db6a64bd9 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 22 Jul 2021 13:35:54 -0700 Subject: [PATCH 046/125] #5427 --- src/sat/smt/array_internalize.cpp | 4 +++- src/sat/smt/q_eval.cpp | 1 - 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/sat/smt/array_internalize.cpp b/src/sat/smt/array_internalize.cpp index 9d5476e31..55496a729 100644 --- a/src/sat/smt/array_internalize.cpp +++ b/src/sat/smt/array_internalize.cpp @@ -177,6 +177,8 @@ namespace array { auto set_index = [&](euf::enode* arg) { if (arg->get_root() == r) is_index = true; }; auto set_value = [&](euf::enode* arg) { if (arg->get_root() == r) is_value = true; }; + if (a.is_ext(n->get_expr())) + return true; for (euf::enode* parent : euf::enode_parents(r)) { app* p = parent->get_app(); unsigned num_args = parent->num_args(); @@ -193,7 +195,7 @@ namespace array { } else if (a.is_const(p)) { set_value(parent->get_arg(0)); - } + } if (is_array + is_index + is_value > 1) return true; } diff --git a/src/sat/smt/q_eval.cpp b/src/sat/smt/q_eval.cpp index 1ecc0e4ec..59d7a5f91 100644 --- a/src/sat/smt/q_eval.cpp +++ b/src/sat/smt/q_eval.cpp @@ -44,7 +44,6 @@ namespace q { unsigned lim = m_indirect_nodes.size(); lit l = c[i]; lbool cmp = compare(n, binding, l.lhs, l.rhs, evidence); - std::cout << l.sign << ": " << l.lhs << " ~~ " << l.rhs << " " << cmp << "\n"; switch (cmp) { case l_false: m_indirect_nodes.shrink(lim); From 800fef665319f6144bd3b9ba4e4312f8447a11ed Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 22 Jul 2021 18:31:37 -0700 Subject: [PATCH 047/125] fix #5424 --- src/model/model.cpp | 12 +++++++----- src/sat/smt/q_eval.cpp | 1 + 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/model/model.cpp b/src/model/model.cpp index f2861292f..e93e80bfe 100644 --- a/src/model/model.cpp +++ b/src/model/model.cpp @@ -22,6 +22,7 @@ Revision History: #include "ast/ast_ll_pp.h" #include "ast/rewriter/var_subst.h" #include "ast/rewriter/th_rewriter.h" +#include "ast/rewriter/expr_safe_replace.h" #include "ast/array_decl_plugin.h" #include "ast/bv_decl_plugin.h" #include "ast/recfun_decl_plugin.h" @@ -605,12 +606,13 @@ void model::add_rec_funs() { func_interp* fi = alloc(func_interp, m, f->get_arity()); // reverse argument order so that variable 0 starts at the beginning. - expr_ref_vector subst(m); - for (unsigned i = 0; i < f->get_arity(); ++i) { - subst.push_back(m.mk_var(i, f->get_domain(i))); + expr_safe_replace subst(m); + unsigned arity = f->get_arity(); + for (unsigned i = 0; i < arity; ++i) { + subst.insert(m.mk_var(arity - i - 1, f->get_domain(i)), m.mk_var(i, f->get_domain(i))); } - var_subst sub(m, true); - expr_ref bodyr = sub(rhs, subst); + expr_ref bodyr(m); + subst(rhs, bodyr); fi->set_else(bodyr); register_decl(f, fi); diff --git a/src/sat/smt/q_eval.cpp b/src/sat/smt/q_eval.cpp index 59d7a5f91..e341979de 100644 --- a/src/sat/smt/q_eval.cpp +++ b/src/sat/smt/q_eval.cpp @@ -69,6 +69,7 @@ namespace q { } if (idx == UINT_MAX) return l_false; + c.m_watch = idx; return l_undef; } From 32beb91efac2648afef01084af65a02c9e1d76ae Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 22 Jul 2021 19:17:17 -0700 Subject: [PATCH 048/125] sat.euf add missing function --- src/ast/euf/euf_egraph.cpp | 10 +++++++--- src/ast/euf/euf_egraph.h | 3 ++- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/ast/euf/euf_egraph.cpp b/src/ast/euf/euf_egraph.cpp index 0f82c2e6c..bbb63540e 100644 --- a/src/ast/euf/euf_egraph.cpp +++ b/src/ast/euf/euf_egraph.cpp @@ -129,7 +129,7 @@ namespace euf { return n; } - egraph::egraph(ast_manager& m) : m(m), m_table(m), m_exprs(m) { + egraph::egraph(ast_manager& m) : m(m), m_table(m), m_tmp_app(2), m_exprs(m) { m_tmp_eq = enode::mk_tmp(m_region, 2); } @@ -418,12 +418,10 @@ namespace euf { std::swap(n1, n2); } if (m.is_false(r2->get_expr()) && r1->value() == l_true) { - std::cout << "value assign conflict\n"; set_conflict(n1, n2, j); return; } if (m.is_true(r2->get_expr()) && r1->value() == l_false) { - std::cout << "value assign conflict\n"; set_conflict(n1, n2, j); return; } @@ -604,6 +602,12 @@ namespace euf { return false; } + enode* egraph::get_enode_eq_to(func_decl* f, unsigned num_args, enode* const* args) { + m_tmp_app.set_decl(f); + m_tmp_app.set_num_args(num_args); + return find(m_tmp_app.get_app(), num_args, args); + } + /** \brief generate an explanation for a congruence. Each pair of children under a congruence have the same roots diff --git a/src/ast/euf/euf_egraph.h b/src/ast/euf/euf_egraph.h index 9533a83e6..1ac54f6f0 100644 --- a/src/ast/euf/euf_egraph.h +++ b/src/ast/euf/euf_egraph.h @@ -159,6 +159,7 @@ namespace euf { enode* m_tmp_eq = nullptr; enode* m_tmp_node = nullptr; unsigned m_tmp_node_capacity = 0; + tmp_app m_tmp_app; enode_vector m_nodes; expr_ref_vector m_exprs; vector m_decl2enodes; @@ -261,7 +262,7 @@ namespace euf { */ bool are_diseq(enode* a, enode* b) const; - enode * get_enode_eq_to(func_decl * f, unsigned num_args, enode * const * args) { UNREACHABLE(); return nullptr; } + enode* get_enode_eq_to(func_decl* f, unsigned num_args, enode* const* args); /** \brief Maintain and update cursor into propagated consequences. From 10145366b2f11c4eb53869df1276a9de9dea4c11 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 23 Jul 2021 21:02:25 -0700 Subject: [PATCH 049/125] #5425 Add an alternative to unit-subsume-simplify It is called solver-subsumption It does a little more than unit-subsume-simplify and also uses a different decomposition algorithm for clauses. It removes redundant constraints and simplifies clauses in a single pass. A possible use of this tactic is in isolation where the maximal number of conflicts (smt.conflicts_max, sat.conflicts_max) are bounded. For simpler formulas full solver calls may be still feasible. --- src/tactic/portfolio/CMakeLists.txt | 3 + .../portfolio/solver_subsumption_tactic.cpp | 167 ++++++++++++++++++ .../portfolio/solver_subsumption_tactic.h | 25 +++ 3 files changed, 195 insertions(+) create mode 100644 src/tactic/portfolio/solver_subsumption_tactic.cpp create mode 100644 src/tactic/portfolio/solver_subsumption_tactic.h diff --git a/src/tactic/portfolio/CMakeLists.txt b/src/tactic/portfolio/CMakeLists.txt index 0913bf7f0..6e954717f 100644 --- a/src/tactic/portfolio/CMakeLists.txt +++ b/src/tactic/portfolio/CMakeLists.txt @@ -3,6 +3,7 @@ z3_add_component(portfolio default_tactic.cpp smt_strategic_solver.cpp solver2lookahead.cpp + solver_subsumption_tactic.cpp COMPONENT_DEPENDENCIES aig_tactic fp @@ -16,4 +17,6 @@ z3_add_component(portfolio fd_solver TACTIC_HEADERS default_tactic.h + solver_subsumption_tactic.h + ) diff --git a/src/tactic/portfolio/solver_subsumption_tactic.cpp b/src/tactic/portfolio/solver_subsumption_tactic.cpp new file mode 100644 index 000000000..57edce73d --- /dev/null +++ b/src/tactic/portfolio/solver_subsumption_tactic.cpp @@ -0,0 +1,167 @@ +/*++ +Copyright (c) 2011 Microsoft Corporation + +Module Name: + + solver_subsumption_tactic.cpp + +Author: + + Nikolaj Bjorner (nbjorner) 2021-7-23 + +--*/ +#include "ast/ast_util.h" +#include "tactic/tactical.h" +#include "tactic/portfolio/solver_subsumption_tactic.h" +#include "solver/solver.h" + +class solver_subsumption_tactic : public tactic { + ast_manager& m; + params_ref m_params; + solver_ref m_solver; + + void push() { + m_solver->push(); + } + + void pop() { + m_solver->pop(1); + } + + void assert_expr(expr* f) { + m_solver->assert_expr(f); + } + + bool subsumed(expr* f) { + expr_ref_vector fmls(m); + fmls.push_back(m.mk_not(f)); + lbool is_sat = m_solver->check_sat(fmls); + return (is_sat == l_false); + } + + /** + * Check subsumption (a \/ b \/ c) + * if (a \/ b) is already implied + * Use a naive algorithm (not binary disection here) + */ + + bool simplify(expr_ref& f) { + if (!m.is_or(f)) + return false; + expr_ref_vector ors(m); + ors.append(to_app(f)->get_num_args(), to_app(f)->get_args()); + unsigned j = 0; + expr_ref_vector prefix(m); + for (unsigned i = 0; i < ors.size(); ++i) { + expr_ref_vector fmls(m); + fmls.append(prefix); + for (unsigned k = i + 1; k < ors.size(); ++k) + fmls.push_back(m.mk_not(ors.get(k))); + lbool is_sat = m_solver->check_sat(fmls); + if (is_sat == l_false) + continue; + fmls.reset(); + fmls.push_back(ors.get(i)); + + is_sat = m_solver->check_sat(fmls); + if (is_sat == l_false) + continue; + prefix.push_back(ors.get(i)); + } + if (ors.size() != prefix.size()) { + ors.reset(); + ors.append(prefix.size(), prefix.data()); + f = mk_or(ors); + return true; + } + return false; + } + + void simplify(vector>& fmls, unsigned_vector& change) { + + if (fmls.size() == 0) + return; + + if (fmls.size() == 1) { + if (subsumed(fmls[0].second)) { + change.push_back(fmls[0].first); + fmls[0].second = m.mk_true(); + } + else if (simplify(fmls[0].second)) + change.push_back(fmls[0].first); + return; + } + unsigned mid = fmls.size() / 2; + + vector> pre(mid, fmls.data()); + vector> post(fmls.size() - mid, fmls.data() + mid); + push(); + for (auto [p, f] : post) + assert_expr(f); + simplify(pre, change); + pop(); + push(); + for (auto [p, f] : pre) + assert_expr(f); + simplify(post, change); + pop(); + if (!change.empty()) { + fmls.reset(); + fmls.append(pre); + fmls.append(post); + } + } + +public: + solver_subsumption_tactic(ast_manager& m, params_ref const& p) : + m(m), + m_params(p) { + } + + tactic* translate(ast_manager& other_m) override { + return alloc(solver_subsumption_tactic, other_m, m_params); + } + + ~solver_subsumption_tactic() override {} + + void updt_params(params_ref const& p) override { m_params = p; } + + void collect_param_descrs(param_descrs& r) override { + } + + void operator()(goal_ref const& g, goal_ref_buffer& result) override { + TRACE("tactic", tout << "params: " << m_params << "\n"; g->display(tout);); + tactic_report report("subsumption", *g); + + vector> fmls; + unsigned_vector change; + unsigned sz = g->size(); + if (sz == 1) { + result.push_back(g.get()); + return; + } + for (unsigned i = 0; i < sz; i++) + fmls.push_back(std::make_pair(i, expr_ref(g->form(i), m))); + if (!m_solver) { + scoped_ptr f = mk_smt_strategic_solver_factory(); + m_solver = (*f)(m, m_params, false, false, true, symbol::null); + } + simplify(fmls, change); + if (change.empty()) { + result.push_back(g.get()); + return; + } + g->inc_depth(); + for (unsigned idx : change) + g->update(idx, fmls[idx].second); + g->elim_true(); + result.push_back(g.get()); + } + + void cleanup() override {} +}; + +tactic* mk_solver_subsumption_tactic(ast_manager& m, params_ref const& p) { + return alloc(solver_subsumption_tactic, m, p); +} + diff --git a/src/tactic/portfolio/solver_subsumption_tactic.h b/src/tactic/portfolio/solver_subsumption_tactic.h new file mode 100644 index 000000000..c088aa0b0 --- /dev/null +++ b/src/tactic/portfolio/solver_subsumption_tactic.h @@ -0,0 +1,25 @@ +/*++ +Copyright (c) 2011 Microsoft Corporation + +Module Name: + + solver_subsumption_tactic.h + +Author: + + Nikolaj Bjorner (nbjorner) 2021-7-23 + +--*/ +#pragma once + +#include "util/params.h" +class ast_manager; +class tactic; + +tactic * mk_solver_subsumption_tactic(ast_manager & m, params_ref const & p = params_ref()); + +/* + ADD_TACTIC("solver_subsumption", "remove assertions that are subsumed.", "mk_solver_subsumption_tactic(m, p)") +*/ + + From 2fa156eaf40f4b61a0632adbed884a90fd215925 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 25 Jul 2021 09:36:45 -0700 Subject: [PATCH 050/125] #5429 --- src/sat/smt/array_solver.cpp | 1 + src/sat/smt/fpa_solver.cpp | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/sat/smt/array_solver.cpp b/src/sat/smt/array_solver.cpp index 4e6f75c4d..bb588948e 100644 --- a/src/sat/smt/array_solver.cpp +++ b/src/sat/smt/array_solver.cpp @@ -176,6 +176,7 @@ namespace array { TRACE("array", tout << "v" << v_child << " - " << ctx.bpp(select) << " " << ctx.bpp(child) << " prop: " << should_prop_upward(get_var_data(v_child)) << "\n";); if (can_beta_reduce(child)) push_axiom(select_axiom(select, child)); + propagate_parent_select_axioms(v_child); } void solver::add_lambda(theory_var v, euf::enode* lambda) { diff --git a/src/sat/smt/fpa_solver.cpp b/src/sat/smt/fpa_solver.cpp index 42e3f8726..13837d0ce 100644 --- a/src/sat/smt/fpa_solver.cpp +++ b/src/sat/smt/fpa_solver.cpp @@ -93,7 +93,10 @@ namespace fpa { SASSERT(m.is_bool(e)); if (!visit_rec(m, e, sign, root, redundant)) return sat::null_literal; - return expr2literal(e); + sat::literal lit = expr2literal(e); + if (sign) + lit.neg(); + return lit; } void solver::internalize(expr* e, bool redundant) { From 4fd1e6d32c31e87a255dd7b651d1ad1fb64d7265 Mon Sep 17 00:00:00 2001 From: Margus Veanes Date: Sun, 25 Jul 2021 09:51:48 -0700 Subject: [PATCH 051/125] added derivative support for (str.to_re (str.from_int ...)) (#5431) --- src/ast/rewriter/seq_rewriter.cpp | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/ast/rewriter/seq_rewriter.cpp b/src/ast/rewriter/seq_rewriter.cpp index 513180bac..99de59aec 100644 --- a/src/ast/rewriter/seq_rewriter.cpp +++ b/src/ast/rewriter/seq_rewriter.cpp @@ -3339,6 +3339,26 @@ expr_ref seq_rewriter::mk_derivative_rec(expr* ele, expr* r) { //while mk_empty() = [], because deriv(epsilon) = [] = nothing return mk_empty(); } + else if (str().is_itos(r1, r2)) + { + //here r1 = (str.from_int r2) and r2 is non-ground + //or else the expression would have been simplified earlier + //so r1 must be nonempty and must consists of decimal digits + //'0' = char(48) <= elem <= char(57) = '9' + m_br.mk_and(u().mk_le(m_util.mk_char(48), ele), u().mk_le(ele, m_util.mk_char(57)), result); + if (m().is_false(result)) + return mk_empty(); + + hd = str().mk_nth_i(r1, m_autil.mk_int(0)); + m_br.mk_and(result, m().mk_eq(hd, ele), result); // result := result & ele = (hd r1) + if (m().is_false(result)) + return mk_empty(); + + tl = str().mk_substr(r1, m_autil.mk_int(1), m_autil.mk_sub(str().mk_length(r1), m_autil.mk_int(1))); + //if ((isdigit ele) and (ele = (hd r1))) then (to_re (tl r1)) else [] + result = re_and(result, re().mk_to_re(tl)); + return result; + } #if 0 else { hd = str().mk_nth_i(r1, m_autil.mk_int(0)); From b638405e4201fcf9b907b34646752eee59ac9a08 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 25 Jul 2021 09:57:38 -0700 Subject: [PATCH 052/125] simplify #5431 Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/seq_rewriter.cpp | 27 ++++++++++----------------- 1 file changed, 10 insertions(+), 17 deletions(-) diff --git a/src/ast/rewriter/seq_rewriter.cpp b/src/ast/rewriter/seq_rewriter.cpp index 99de59aec..f2286503f 100644 --- a/src/ast/rewriter/seq_rewriter.cpp +++ b/src/ast/rewriter/seq_rewriter.cpp @@ -3341,23 +3341,16 @@ expr_ref seq_rewriter::mk_derivative_rec(expr* ele, expr* r) { } else if (str().is_itos(r1, r2)) { - //here r1 = (str.from_int r2) and r2 is non-ground - //or else the expression would have been simplified earlier - //so r1 must be nonempty and must consists of decimal digits - //'0' = char(48) <= elem <= char(57) = '9' - m_br.mk_and(u().mk_le(m_util.mk_char(48), ele), u().mk_le(ele, m_util.mk_char(57)), result); - if (m().is_false(result)) - return mk_empty(); - - hd = str().mk_nth_i(r1, m_autil.mk_int(0)); - m_br.mk_and(result, m().mk_eq(hd, ele), result); // result := result & ele = (hd r1) - if (m().is_false(result)) - return mk_empty(); - - tl = str().mk_substr(r1, m_autil.mk_int(1), m_autil.mk_sub(str().mk_length(r1), m_autil.mk_int(1))); - //if ((isdigit ele) and (ele = (hd r1))) then (to_re (tl r1)) else [] - result = re_and(result, re().mk_to_re(tl)); - return result; + // + // here r1 = (str.from_int r2) and r2 is non-ground + // or else the expression would have been simplified earlier + // so r1 must be nonempty and must consists of decimal digits + // '0' <= elem <= '9' + // if ((isdigit ele) and (ele = (hd r1))) then (to_re (tl r1)) else [] + // + m_br.mk_and(u().mk_le(m_util.mk_char('0'), ele), u().mk_le(ele, m_util.mk_char('9')), m().mk_eq(hd, ele), result); + tl = re().mk_to_re(str().mk_substr(r1, m_autil.mk_int(1), m_autil.mk_sub(str().mk_length(r1), m_autil.mk_int(1)))); + return re_and(result, tl); } #if 0 else { From 5652d2a157b85afb3a96bd0732fe219b379dbf78 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 25 Jul 2021 11:59:42 -0700 Subject: [PATCH 053/125] #5429 #5431 --- src/ast/rewriter/seq_rewriter.cpp | 15 +-------------- src/smt/mam.cpp | 8 ++++++-- 2 files changed, 7 insertions(+), 16 deletions(-) diff --git a/src/ast/rewriter/seq_rewriter.cpp b/src/ast/rewriter/seq_rewriter.cpp index f2286503f..ff4f62533 100644 --- a/src/ast/rewriter/seq_rewriter.cpp +++ b/src/ast/rewriter/seq_rewriter.cpp @@ -3339,8 +3339,7 @@ expr_ref seq_rewriter::mk_derivative_rec(expr* ele, expr* r) { //while mk_empty() = [], because deriv(epsilon) = [] = nothing return mk_empty(); } - else if (str().is_itos(r1, r2)) - { + else if (str().is_itos(r1, r2)) { // // here r1 = (str.from_int r2) and r2 is non-ground // or else the expression would have been simplified earlier @@ -3352,18 +3351,6 @@ expr_ref seq_rewriter::mk_derivative_rec(expr* ele, expr* r) { tl = re().mk_to_re(str().mk_substr(r1, m_autil.mk_int(1), m_autil.mk_sub(str().mk_length(r1), m_autil.mk_int(1)))); return re_and(result, tl); } -#if 0 - else { - hd = str().mk_nth_i(r1, m_autil.mk_int(0)); - tl = str().mk_substr(r1, m_autil.mk_int(1), m_autil.mk_sub(str().mk_length(r1), m_autil.mk_int(1))); - result = re().mk_to_re(tl); - result = - m().mk_ite(m_br.mk_eq_rw(r1, str().mk_empty(m().get_sort(r1))), - mk_empty(), - re_and(m_br.mk_eq_rw(ele, hd), result)); - return result; - } -#endif } else if (re().is_reverse(r, r1) && re().is_to_re(r1, r2)) { // Reverses are rewritten so that the only derivative case is diff --git a/src/smt/mam.cpp b/src/smt/mam.cpp index f8d99f398..0d09f07ea 100644 --- a/src/smt/mam.cpp +++ b/src/smt/mam.cpp @@ -121,7 +121,7 @@ namespace { struct instruction { opcode m_opcode; - instruction * m_next; + instruction* m_next = nullptr; #ifdef _PROFILE_MAM unsigned m_counter; // how often it was executed #endif @@ -1224,9 +1224,10 @@ namespace { return; SASSERT(head->m_next == 0); + m_seq.push_back(m_ct_manager.mk_yield(m_qa, m_mp, m_qa->get_num_decls(), reinterpret_cast(m_vars.begin()))); - for (instruction * curr : m_seq) { + for (instruction* curr : m_seq) { head->m_next = curr; head = curr; } @@ -2309,7 +2310,10 @@ namespace { main_loop: + if (!m_pc) + goto backtrack; TRACE("mam_int", display_pc_info(tout);); + #ifdef _PROFILE_MAM const_cast(m_pc)->m_counter++; #endif From 7e705c485404aaf6c82f0d29b5a444d006b3db8f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 26 Jul 2021 13:47:21 -0700 Subject: [PATCH 054/125] fix #5430 --- src/opt/maxres.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/opt/maxres.cpp b/src/opt/maxres.cpp index e87965133..27b3b7260 100644 --- a/src/opt/maxres.cpp +++ b/src/opt/maxres.cpp @@ -871,6 +871,8 @@ public: m_dump_benchmarks = p.dump_benchmarks(); m_enable_lns = p.enable_lns(); m_lns_conflicts = p.lns_conflicts(); + if (m_c.num_objectives() > 1) + m_add_upper_bound_block = false; } lbool init_local() { From 2f49094d490e3536b1da93b0fb513144a3b327a5 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 26 Jul 2021 19:36:16 -0700 Subject: [PATCH 055/125] change debug output --- src/qe/mbp/mbp_arith.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/qe/mbp/mbp_arith.cpp b/src/qe/mbp/mbp_arith.cpp index 31329b3dd..a2101e2d1 100644 --- a/src/qe/mbp/mbp_arith.cpp +++ b/src/qe/mbp/mbp_arith.cpp @@ -47,7 +47,6 @@ namespace mbp { ~imp() {} 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); @@ -362,6 +361,10 @@ namespace mbp { optdefs2mbpdef(defs, index2expr, real_vars, result); if (m_apply_projection) apply_projection(result, fmls); + TRACE("qe", + for (auto [v, t] : result) + tout << v << " := " << t << "\n"; + tout << "fmls:" << fmls << "\n";); return result; } From 7cb4932ae8a46777e2527db0a88f756eeb806c7a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 27 Jul 2021 09:04:29 -0700 Subject: [PATCH 056/125] fix #5435 --- src/api/c++/z3++.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index 28e8aa052..f63590493 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -1879,11 +1879,13 @@ namespace z3 { Z3_ast r; if (a.is_int()) { expr zero = a.ctx().int_val(0); - r = Z3_mk_ite(a.ctx(), Z3_mk_ge(a.ctx(), a, zero), a, -a); + expr ge = a >= zero; + r = Z3_mk_ite(a.ctx(), ge, a, zero), a, -a); } else if (a.is_real()) { expr zero = a.ctx().real_val(0); - r = Z3_mk_ite(a.ctx(), Z3_mk_ge(a.ctx(), a, zero), a, -a); + expr ge = a >= zero; + r = Z3_mk_ite(a.ctx(), ge, a, -a); } else { r = Z3_mk_fpa_abs(a.ctx(), a); From 5964b26ca2a73c6320e5a498821d10ce660ddda1 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 27 Jul 2021 09:07:34 -0700 Subject: [PATCH 057/125] err --- 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 f63590493..a14f04606 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -1880,7 +1880,7 @@ namespace z3 { if (a.is_int()) { expr zero = a.ctx().int_val(0); expr ge = a >= zero; - r = Z3_mk_ite(a.ctx(), ge, a, zero), a, -a); + r = Z3_mk_ite(a.ctx(), ge, a, -a); } else if (a.is_real()) { expr zero = a.ctx().real_val(0); From 79296d8dfc644fc907700491b9acb1a68778a746 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 27 Jul 2021 09:09:21 -0700 Subject: [PATCH 058/125] proviso for different life-time of objects allocated in arguments. --- src/api/c++/z3++.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index a14f04606..73330da89 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -1880,12 +1880,14 @@ namespace z3 { if (a.is_int()) { expr zero = a.ctx().int_val(0); expr ge = a >= zero; - r = Z3_mk_ite(a.ctx(), ge, a, -a); + expr na = -a; + r = Z3_mk_ite(a.ctx(), ge, a, na); } else if (a.is_real()) { expr zero = a.ctx().real_val(0); expr ge = a >= zero; - r = Z3_mk_ite(a.ctx(), ge, a, -a); + expr na = -a; + r = Z3_mk_ite(a.ctx(), ge, a, na); } else { r = Z3_mk_fpa_abs(a.ctx(), a); From 16413b4f9aec688af52aed6152175f6b76b6e37f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 27 Jul 2021 17:18:22 -0700 Subject: [PATCH 059/125] #5429 --- src/math/simplex/model_based_opt.cpp | 3 ++- src/sat/smt/q_clause.cpp | 18 +++++++++--------- src/sat/smt/q_mbi.cpp | 1 - 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/math/simplex/model_based_opt.cpp b/src/math/simplex/model_based_opt.cpp index 1acbb592b..83e83cfe7 100644 --- a/src/math/simplex/model_based_opt.cpp +++ b/src/math/simplex/model_based_opt.cpp @@ -1261,7 +1261,8 @@ namespace opt { m_var2value[x] = eval(result); TRACE("opt1", tout << "updated eval " << x << " := " << eval(x) << "\n";); } - retire_row(row_id1); + else + retire_row(row_id1); return result; } diff --git a/src/sat/smt/q_clause.cpp b/src/sat/smt/q_clause.cpp index 7c8a260e5..097a61a14 100644 --- a/src/sat/smt/q_clause.cpp +++ b/src/sat/smt/q_clause.cpp @@ -23,9 +23,9 @@ namespace q { std::ostream& lit::display(std::ostream& out) const { ast_manager& m = lhs.m(); if (m.is_true(rhs) && !sign) - return out << mk_bounded_pp(lhs, m, 2); + return out << lhs; if (m.is_false(rhs) && !sign) - return out << "(not " << mk_bounded_pp(lhs, m, 2) << ")"; + return out << "(not " << lhs << ")"; return out << mk_bounded_pp(lhs, m, 2) << (sign ? " != " : " == ") @@ -43,13 +43,13 @@ namespace q { for (auto const& lit : m_lits) lit.display(out) << "\n"; binding* b = m_bindings; - if (b) { - do { - b->display(ctx, num_decls(), out) << "\n"; - b = b->next(); - } - while (b != m_bindings); - } + if (!b) + return out; + do { + b->display(ctx, num_decls(), out) << "\n"; + b = b->next(); + } + while (b != m_bindings); return out; } diff --git a/src/sat/smt/q_mbi.cpp b/src/sat/smt/q_mbi.cpp index 5c30bedd4..03d748236 100644 --- a/src/sat/smt/q_mbi.cpp +++ b/src/sat/smt/q_mbi.cpp @@ -162,7 +162,6 @@ namespace q { return r; if (r == l_true) { model_ref mdl; - expr_ref proj(m); m_solver->get_model(mdl); if (check_forall_subst(q, *qb, *mdl)) return l_false; From 442d1d28ea5f51d208bb0e39b24fe6b0006f28f7 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 27 Jul 2021 19:11:16 -0700 Subject: [PATCH 060/125] #5429 --- src/sat/tactic/goal2sat.cpp | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/src/sat/tactic/goal2sat.cpp b/src/sat/tactic/goal2sat.cpp index 72b825a09..123eacee5 100644 --- a/src/sat/tactic/goal2sat.cpp +++ b/src/sat/tactic/goal2sat.cpp @@ -544,6 +544,29 @@ struct goal2sat::imp : public sat::sat_internalizer { } } + void convert_not(app* t, bool root, bool sign) { + SASSERT(t->get_num_args() == 1); + unsigned sz = m_result_stack.size(); + SASSERT(sz >= 1); + sat::literal lit = m_result_stack[sz - 1]; + m_result_stack.shrink(sz - 1); + if (root) { + SASSERT(sz == 1); + mk_root_clause(sign ? lit : ~lit); + } + else { + sat::bool_var k = add_var(false, t); + sat::literal l(k, false); + cache(t, l); + // l <=> ~lit + mk_clause(lit, l); + mk_clause(~lit, ~l); + if (sign) + l.neg(); + m_result_stack.push_back(l); + } + } + void convert_implies(app* t, bool root, bool sign) { SASSERT(t->get_num_args() == 2); unsigned sz = m_result_stack.size(); @@ -702,6 +725,9 @@ struct goal2sat::imp : public sat::sat_internalizer { case OP_IMPLIES: convert_implies(t, root, sign); break; + case OP_NOT: + convert_not(t, root, sign); + break; default: UNREACHABLE(); } @@ -767,7 +793,7 @@ struct goal2sat::imp : public sat::sat_internalizer { m_frame_stack.pop_back(); continue; } - if (m.is_not(t)) { + if (m.is_not(t) && !m.is_not(t->get_arg(0))) { m_frame_stack.pop_back(); visit(t->get_arg(0), root, !sign); continue; From 81b8f397b3dfd510aed918c775ca35d5a8923f24 Mon Sep 17 00:00:00 2001 From: Kiwamu Okabe Date: Thu, 29 Jul 2021 08:57:26 +0900 Subject: [PATCH 061/125] Need `-thread` option to compile OCaml example (#5440) I can compile the OCaml example with `-thread` option at Linux. ``` $ ocaml --version The OCaml toplevel, version 4.05.0 ``` --- examples/ml/README | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/ml/README b/examples/ml/README index 9797b85e3..a8d03eaea 100644 --- a/examples/ml/README +++ b/examples/ml/README @@ -14,9 +14,9 @@ for the byte-code version. If Z3 was installed into the ocamlfind package repository (see src/api/ml/README), then we can also compile this example as follows: -ocamlfind ocamlc -o ml_example.byte -package Z3 -linkpkg ml_example.ml +ocamlfind ocamlc -o ml_example.byte -thread -package Z3 -linkpkg ml_example.ml or -ocamlfind ocamlopt -o ml_example -package Z3 -linkpkg ml_example.ml +ocamlfind ocamlopt -o ml_example -thread -package Z3 -linkpkg ml_example.ml Note that the resulting binaries depend on the shared z3 library (libz3.dll/.so/.dylb), which needs to be in the PATH (Windows), LD_LIBRARY_PATH From 703659a3a88d2b7e2f03b2905ebacf3fb75330e3 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 28 Jul 2021 17:15:55 -0700 Subject: [PATCH 062/125] fix #5439 --- src/ast/recfun_decl_plugin.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/ast/recfun_decl_plugin.cpp b/src/ast/recfun_decl_plugin.cpp index bd23e1838..04c5d0545 100644 --- a/src/ast/recfun_decl_plugin.cpp +++ b/src/ast/recfun_decl_plugin.cpp @@ -338,7 +338,9 @@ namespace recfun { void util::set_definition(replace& subst, promise_def & d, bool is_macro, unsigned n_vars, var * const * vars, expr * rhs) { - expr_ref rhs1 = get_plugin().redirect_ite(subst, n_vars, vars, rhs); + expr_ref rhs1(rhs, m()); + if (!is_macro) + rhs1 = get_plugin().redirect_ite(subst, n_vars, vars, rhs); d.set_definition(subst, is_macro, n_vars, vars, rhs1); } From 72d3074a440b1eaa9eb24bc663d314ab49df9eb5 Mon Sep 17 00:00:00 2001 From: 0152la Date: Thu, 29 Jul 2021 19:29:49 +0100 Subject: [PATCH 063/125] Add Ubuntu CMake Coverage CI step (#5442) Adds an extra step to CI jobs which executes the Z3 test suite with coverage enabled, and additionally executed coverage-enhancing tests added to z3test. --- azure-pipelines.yml | 25 +++++++++++++++++++++++++ scripts/test-regressions-coverage.yaml | 4 ++++ 2 files changed, 29 insertions(+) create mode 100644 scripts/test-regressions-coverage.yaml diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 1735f2337..3db84ce71 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -5,6 +5,7 @@ variables: cmakeNet: '-DZ3_BUILD_DOTNET_BINDINGS=True' cmakePy: '-DZ3_BUILD_PYTHON_BINDINGS=True' cmakeStdArgs: '-DZ3_BUILD_DOTNET_BINDINGS=True -DZ3_BUILD_JAVA_BINDINGS=True -DZ3_BUILD_PYTHON_BINDINGS=True -G "Ninja" ../' + cmakeCovArgs: '-DCMAKE_INSTALL_PREFIX=./install -G "Ninja" ../' asanEnv: 'CXXFLAGS="${CXXFLAGS} -fsanitize=address -fno-omit-frame-pointer" CFLAGS="${CFLAGS} -fsanitize=address -fno-omit-frame-pointer"' ubsanEnv: 'CXXFLAGS="${CXXFLAGS} -fsanitize=undefined" CFLAGS="${CFLAGS} -fsanitize=undefined"' msanEnv: 'CC=clang LDFLAGS="-L../libcxx/libcxx_msan/lib -lc++abi -Wl,-rpath=../libcxx/libcxx_msan/lib" CXX=clang++ CXXFLAGS="${CXXFLAGS} -stdlib=libc++ -fsanitize-memory-track-origins -fsanitize=memory -fPIE -fno-omit-frame-pointer -g -O2" CFLAGS="${CFLAGS} -stdlib=libc -fsanitize=memory -fsanitize-memory-track-origins -fno-omit-frame-pointer -g -O2"' @@ -150,6 +151,30 @@ jobs: - ${{if eq(variables['runTests'], 'True')}}: - template: scripts/test-regressions.yml + +- job: "Ubuntu16CMakeCoverage" + displayName: "Ubuntu build - cmake w/ coverage" + pool: + vmImage: "ubuntu-latest" + steps: + - script: sudo apt-get install ninja-build + - script: | + set -e + mkdir build + cd build + CXXFLAGS=--coverage LDFLAGS=-lgcov CC=clang CXX=clang++ cmake -DCMAKE_BUILD_TYPE=Debug $(cmakeCovArgs) + ninja + ninja test-z3 + ninja install + cd .. + - script: | + cd build + ./test-z3 -a + cd .. + - template: scripts/test-examples-cmake.yml + - template: scripts/test-regressions-coverage.yml + + - job: "WindowsLatest" displayName: "Windows" pool: diff --git a/scripts/test-regressions-coverage.yaml b/scripts/test-regressions-coverage.yaml new file mode 100644 index 000000000..363ea2c19 --- /dev/null +++ b/scripts/test-regressions-coverage.yaml @@ -0,0 +1,4 @@ +steps: +- script: git clone https://github.com/z3prover/z3test z3test +- script: python z3test/scripts/test_benchmarks.py build/z3 z3test/regressions/smt2 +- script: python z3test/scripts/test_coverage_tests.py build/install z3test/coverage/cpp From db5252a81b1b6950443996b0ed7359d79fd68c70 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 29 Jul 2021 11:31:39 -0700 Subject: [PATCH 064/125] add dummy Signed-off-by: Nikolaj Bjorner --- scripts/test-regressions-coverage.yml | 1 + 1 file changed, 1 insertion(+) create mode 100644 scripts/test-regressions-coverage.yml diff --git a/scripts/test-regressions-coverage.yml b/scripts/test-regressions-coverage.yml new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/scripts/test-regressions-coverage.yml @@ -0,0 +1 @@ + From 211a6c87520aad8ea9a9b6423ec00969b45f73cc Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 29 Jul 2021 11:32:20 -0700 Subject: [PATCH 065/125] rename Signed-off-by: Nikolaj Bjorner --- scripts/test-regressions-coverage.yaml | 4 ---- scripts/test-regressions-coverage.yml | 5 ++++- 2 files changed, 4 insertions(+), 5 deletions(-) delete mode 100644 scripts/test-regressions-coverage.yaml diff --git a/scripts/test-regressions-coverage.yaml b/scripts/test-regressions-coverage.yaml deleted file mode 100644 index 363ea2c19..000000000 --- a/scripts/test-regressions-coverage.yaml +++ /dev/null @@ -1,4 +0,0 @@ -steps: -- script: git clone https://github.com/z3prover/z3test z3test -- script: python z3test/scripts/test_benchmarks.py build/z3 z3test/regressions/smt2 -- script: python z3test/scripts/test_coverage_tests.py build/install z3test/coverage/cpp diff --git a/scripts/test-regressions-coverage.yml b/scripts/test-regressions-coverage.yml index 8b1378917..363ea2c19 100644 --- a/scripts/test-regressions-coverage.yml +++ b/scripts/test-regressions-coverage.yml @@ -1 +1,4 @@ - +steps: +- script: git clone https://github.com/z3prover/z3test z3test +- script: python z3test/scripts/test_benchmarks.py build/z3 z3test/regressions/smt2 +- script: python z3test/scripts/test_coverage_tests.py build/install z3test/coverage/cpp From b8a437bd8a69de54d1d0ad013bfae50ca069d337 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 29 Jul 2021 15:04:49 -0700 Subject: [PATCH 066/125] #5429 relevancy propagation applies to quantifier unfolding. --- src/ast/ast_ll_pp.cpp | 30 +++++++++++++++---------- src/ast/normal_forms/pull_quant.cpp | 6 ++--- src/ast/recfun_decl_plugin.cpp | 2 -- src/sat/smt/euf_relevancy.cpp | 3 +-- src/sat/smt/euf_solver.cpp | 10 ++++----- src/sat/smt/q_mbi.cpp | 7 +++--- src/sat/smt/sat_dual_solver.cpp | 35 +++++++++++++++++++++-------- src/sat/smt/sat_dual_solver.h | 3 +++ 8 files changed, 60 insertions(+), 36 deletions(-) diff --git a/src/ast/ast_ll_pp.cpp b/src/ast/ast_ll_pp.cpp index f7ba8132f..de6efe020 100644 --- a/src/ast/ast_ll_pp.cpp +++ b/src/ast/ast_ll_pp.cpp @@ -248,8 +248,7 @@ public: } } - void operator()(quantifier * n) { - display_def_header(n); + void display_quantifier_header(quantifier* n) { m_out << "(" << (n->get_kind() == forall_k ? "forall" : (n->get_kind() == exists_k ? "exists" : "lambda")) << " "; unsigned num_decls = n->get_num_decls(); m_out << "(vars "; @@ -272,6 +271,12 @@ public: display_children(n->get_num_no_patterns(), n->get_no_patterns()); m_out << ") "; } + + } + + void operator()(quantifier * n) { + display_def_header(n); + display_quantifier_header(n); display_child(n->get_expr()); m_out << ")\n"; } @@ -281,6 +286,12 @@ public: m_out << "(:var " << to_var(n)->get_idx() << ")"; return; } + if (is_quantifier(n)) { + display_quantifier_header(to_quantifier(n)); + display(to_quantifier(n)->get_expr(), depth - 1); + m_out << ")"; + return; + } if (!is_app(n) || depth == 0 || to_app(n)->get_num_args() == 0) { display_child(n); @@ -304,16 +315,11 @@ public: void display_bounded(ast * n, unsigned depth) { if (!n) - m_out << "null"; - else if (is_app(n)) { - display(to_expr(n), depth); - } - else if (is_var(n)) { - m_out << "(:var " << to_var(n)->get_idx() << ")"; - } - else { - m_out << "#" << n->get_id(); - } + m_out << "null"; + else if (is_expr(n)) + display(to_expr(n), depth); + else + m_out << "#" << n->get_id(); } }; diff --git a/src/ast/normal_forms/pull_quant.cpp b/src/ast/normal_forms/pull_quant.cpp index 209772f3b..8a94a3482 100644 --- a/src/ast/normal_forms/pull_quant.cpp +++ b/src/ast/normal_forms/pull_quant.cpp @@ -281,9 +281,9 @@ struct pull_quant::imp { m.mk_rewrite(old_q, result); return true; } - if (is_lambda(old_q)) { - return false; - } + + if (is_lambda(old_q)) + return false; if (!is_forall(new_body)) return false; diff --git a/src/ast/recfun_decl_plugin.cpp b/src/ast/recfun_decl_plugin.cpp index 04c5d0545..a702b4bfd 100644 --- a/src/ast/recfun_decl_plugin.cpp +++ b/src/ast/recfun_decl_plugin.cpp @@ -336,7 +336,6 @@ namespace recfun { return alloc(def, m(), m_fid, name, n, domain, range, is_generated); } - void util::set_definition(replace& subst, promise_def & d, bool is_macro, unsigned n_vars, var * const * vars, expr * rhs) { expr_ref rhs1(rhs, m()); if (!is_macro) @@ -531,7 +530,6 @@ namespace recfun { } return result; } - } case_expansion::case_expansion(recfun::util& u, app * n) : diff --git a/src/sat/smt/euf_relevancy.cpp b/src/sat/smt/euf_relevancy.cpp index 7e9b20af7..28ac99d9a 100644 --- a/src/sat/smt/euf_relevancy.cpp +++ b/src/sat/smt/euf_relevancy.cpp @@ -48,8 +48,7 @@ namespace euf { if (!relevancy_enabled()) return; ensure_dual_solver(); - if (s().at_search_lvl()) - m_dual_solver->add_root(n, lits); + m_dual_solver->add_root(n, lits); } void solver::add_aux(unsigned n, sat::literal const* lits) { diff --git a/src/sat/smt/euf_solver.cpp b/src/sat/smt/euf_solver.cpp index 295216ef9..781a94c85 100644 --- a/src/sat/smt/euf_solver.cpp +++ b/src/sat/smt/euf_solver.cpp @@ -489,6 +489,8 @@ namespace euf { for (auto* e : m_solvers) e->push(); m_egraph.push(); + if (m_dual_solver) + m_dual_solver->push(); } void solver::pop(unsigned n) { @@ -506,20 +508,18 @@ namespace euf { } m_var_trail.shrink(sc.m_var_lim); m_scopes.shrink(m_scopes.size() - n); + if (m_dual_solver) + m_dual_solver->pop(n); SASSERT(m_egraph.num_scopes() == m_scopes.size()); TRACE("euf_verbose", display(tout << "pop to: " << m_scopes.size() << "\n");); } void solver::user_push() { - push(); - if (m_dual_solver) - m_dual_solver->push(); + push(); } void solver::user_pop(unsigned n) { pop(n); - if (m_dual_solver) - m_dual_solver->pop(n); } void solver::start_reinit(unsigned n) { diff --git a/src/sat/smt/q_mbi.cpp b/src/sat/smt/q_mbi.cpp index 03d748236..c7ed4913a 100644 --- a/src/sat/smt/q_mbi.cpp +++ b/src/sat/smt/q_mbi.cpp @@ -66,10 +66,11 @@ namespace q { } } m_max_cex += ctx.get_config().m_mbqi_max_cexs; - for (auto p : m_instantiations) { - unsigned generation = std::get<2>(p); + for (auto [qlit, fml, generation] : m_instantiations) { euf::solver::scoped_generation sg(ctx, generation + 1); - m_qs.add_clause(~std::get<0>(p), ~ctx.mk_literal(std::get<1>(p))); + sat::literal lit = ctx.mk_literal(fml); + m_qs.add_clause(~qlit, ~lit); + ctx.add_root(~qlit, ~lit); } m_instantiations.reset(); return result; diff --git a/src/sat/smt/sat_dual_solver.cpp b/src/sat/smt/sat_dual_solver.cpp index 6676603bc..1e2068707 100644 --- a/src/sat/smt/sat_dual_solver.cpp +++ b/src/sat/smt/sat_dual_solver.cpp @@ -28,15 +28,28 @@ namespace sat { SASSERT(!m_solver.get_config().m_drat); } - void dual_solver::push() { - m_solver.user_push(); - m_roots.push_scope(); - m_tracked_vars.push_scope(); - m_units.push_scope(); - m_vars.push_scope(); + void dual_solver::flush() { + while (m_num_scopes > 0) { + m_solver.user_push(); + m_roots.push_scope(); + m_tracked_vars.push_scope(); + m_units.push_scope(); + m_vars.push_scope(); + --m_num_scopes; + } } - void dual_solver::pop(unsigned num_scopes) { + void dual_solver::push() { + ++m_num_scopes; + } + + void dual_solver::pop(unsigned num_scopes) { + if (m_num_scopes >= num_scopes) { + m_num_scopes -= num_scopes; + return; + } + num_scopes -= m_num_scopes; + m_num_scopes = 0; m_solver.user_pop(num_scopes); unsigned old_sz = m_tracked_vars.old_size(num_scopes); for (unsigned i = m_tracked_vars.size(); i-- > old_sz; ) @@ -66,6 +79,7 @@ namespace sat { } void dual_solver::track_relevancy(bool_var w) { + flush(); bool_var v = ext2var(w); if (!m_is_tracked.get(v, false)) { m_is_tracked.setx(v, true, false); @@ -81,7 +95,8 @@ namespace sat { return literal(m_var2ext[lit.var()], lit.sign()); } - void dual_solver::add_root(unsigned sz, literal const* clause) { + void dual_solver::add_root(unsigned sz, literal const* clause) { + flush(); if (sz == 1) { TRACE("dual", tout << "unit: " << clause[0] << "\n";); m_units.push_back(clause[0]); @@ -95,6 +110,7 @@ namespace sat { } void dual_solver::add_aux(unsigned sz, literal const* clause) { + flush(); TRACE("dual", tout << "aux: " << literal_vector(sz, clause) << "\n";); m_lits.reset(); for (unsigned i = 0; i < sz; ++i) @@ -103,6 +119,7 @@ namespace sat { } void dual_solver::add_assumptions(solver const& s) { + flush(); m_lits.reset(); for (bool_var v : m_tracked_vars) m_lits.push_back(literal(v, l_false == s.value(m_var2ext[v]))); @@ -113,7 +130,7 @@ namespace sat { } } - bool dual_solver::operator()(solver const& s) { + bool dual_solver::operator()(solver const& s) { m_core.reset(); m_core.append(m_units); if (m_roots.empty()) diff --git a/src/sat/smt/sat_dual_solver.h b/src/sat/smt/sat_dual_solver.h index 2b040128c..9c9b2568e 100644 --- a/src/sat/smt/sat_dual_solver.h +++ b/src/sat/smt/sat_dual_solver.h @@ -35,6 +35,7 @@ namespace sat { unsigned_vector m_ext2var; unsigned_vector m_var2ext; lim_svector m_vars; + unsigned m_num_scopes = 0; void add_literal(literal lit); bool_var ext2var(bool_var v); @@ -46,6 +47,8 @@ namespace sat { std::ostream& display(solver const& s, std::ostream& out) const; + void flush(); + public: dual_solver(reslimit& l); void push(); From 38250fc304ab66bf39613e6694bade2dbb4530b3 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 29 Jul 2021 15:33:19 -0700 Subject: [PATCH 067/125] re-move #5442 --- src/api/c++/z3++.h | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index 73330da89..72cd364c6 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -506,7 +506,7 @@ namespace z3 { public: ast(context & c):object(c), m_ast(0) {} ast(context & c, Z3_ast n):object(c), m_ast(n) { Z3_inc_ref(ctx(), m_ast); } - ast(ast const & s):object(s), m_ast(s.m_ast) { Z3_inc_ref(ctx(), m_ast); } + ast(ast const & s) :object(s), m_ast(s.m_ast) { Z3_inc_ref(ctx(), m_ast); } ast(ast && s) noexcept : object(std::forward(s)), m_ast(s.m_ast) { s.m_ast = nullptr; } ~ast() { if (m_ast) Z3_dec_ref(*m_ctx, m_ast); } operator Z3_ast() const { return m_ast; } @@ -519,14 +519,6 @@ namespace z3 { m_ast = s.m_ast; return *this; } - ast & operator=(ast && s) noexcept { - if (this != &s) { - object::operator=(std::forward(s)); - m_ast = s.m_ast; - s.m_ast = nullptr; - } - return *this; - } 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); From 5ca8628e0d58bda1a61f8a6a4d607169f32a603a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 30 Jul 2021 13:42:54 -0700 Subject: [PATCH 068/125] na Signed-off-by: Nikolaj Bjorner --- src/sat/smt/euf_solver.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/sat/smt/euf_solver.cpp b/src/sat/smt/euf_solver.cpp index 781a94c85..a6e58c6d1 100644 --- a/src/sat/smt/euf_solver.cpp +++ b/src/sat/smt/euf_solver.cpp @@ -214,6 +214,14 @@ namespace euf { TRACE("euf", tout << "explain " << l << " <- " << r << " " << probing << "\n";); DEBUG_CODE(for (auto lit : r) SASSERT(s().value(lit) == l_true);); +#if 0 + if (r.size() == 5 && r[0] == literal(401, true) && r[1] == literal(259, false) && r[2] == literal(250, false) && + r[3] == literal(631, false) && r[4] == literal(639, false)) { + TRACE("euf", s().display(tout);); + exit(0); + } +#endif + if (!probing) log_antecedents(l, r); } From f3f83d04457cdca1c924ba5164c964b3aeb12edb Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 30 Jul 2021 13:42:22 -0700 Subject: [PATCH 069/125] #5429 --- src/sat/sat_drat.cpp | 61 +++++++++++++++------------------ src/sat/sat_solver.cpp | 3 +- src/sat/sat_solver.h | 5 +++ src/sat/smt/sat_dual_solver.cpp | 4 --- src/sat/smt/sat_dual_solver.h | 3 -- 5 files changed, 34 insertions(+), 42 deletions(-) diff --git a/src/sat/sat_drat.cpp b/src/sat/sat_drat.cpp index 982b6bb9b..f0ca7132f 100644 --- a/src/sat/sat_drat.cpp +++ b/src/sat/sat_drat.cpp @@ -37,9 +37,8 @@ namespace sat { if (s.get_config().m_drat && s.get_config().m_drat_file.is_non_empty_string()) { auto mode = s.get_config().m_drat_binary ? (std::ios_base::binary | std::ios_base::out | std::ios_base::trunc) : std::ios_base::out; m_out = alloc(std::ofstream, s.get_config().m_drat_file.str(), mode); - if (s.get_config().m_drat_binary) { - std::swap(m_out, m_bout); - } + if (s.get_config().m_drat_binary) + std::swap(m_out, m_bout); } } @@ -50,9 +49,8 @@ namespace sat { dealloc(m_bout); for (unsigned i = 0; i < m_proof.size(); ++i) { clause* c = m_proof[i]; - if (c) { - m_alloc.del_clause(c); - } + if (c) + m_alloc.del_clause(c); } m_proof.reset(); m_out = nullptr; @@ -93,6 +91,7 @@ namespace sat { unsigned len = 0; + if (st.is_deleted()) { buffer[len++] = 'd'; buffer[len++] = ' '; @@ -133,7 +132,7 @@ namespace sat { memcpy(buffer + len, d, lastd - d); len += static_cast(lastd - d); buffer[len++] = ' '; - if (len + 50 > sizeof(buffer)) { + if (static_cast(len) + 50 > sizeof(buffer)) { m_out->write(buffer, len); len = 0; } @@ -208,15 +207,14 @@ namespace sat { declare(l); IF_VERBOSE(20, trace(verbose_stream(), 1, &l, st);); - if (st.is_redundant() && st.is_sat()) { + if (st.is_redundant() && st.is_sat()) verify(1, &l); - } - if (st.is_deleted()) { + + if (st.is_deleted()) return; - } - if (m_check_unsat) { - assign_propagate(l); - } + + if (m_check_unsat) + assign_propagate(l); m_units.push_back(l); } @@ -233,9 +231,9 @@ namespace sat { // don't record binary as deleted. } else { - if (st.is_redundant() && st.is_sat()) { + if (st.is_redundant() && st.is_sat()) verify(2, lits); - } + clause* c = m_alloc.mk_clause(2, lits, st.is_redundant()); m_proof.push_back(c); m_status.push_back(st); @@ -245,15 +243,12 @@ namespace sat { m_watches[(~l1).index()].push_back(idx); m_watches[(~l2).index()].push_back(idx); - if (value(l1) == l_false && value(l2) == l_false) { - m_inconsistent = true; - } - else if (value(l1) == l_false) { - assign_propagate(l2); - } - else if (value(l2) == l_false) { - assign_propagate(l1); - } + if (value(l1) == l_false && value(l2) == l_false) + m_inconsistent = true; + else if (value(l1) == l_false) + assign_propagate(l2); + else if (value(l2) == l_false) + assign_propagate(l1); } } @@ -403,16 +398,14 @@ namespace sat { if (n == 0) return false; unsigned num_units = m_units.size(); - for (unsigned i = 0; !m_inconsistent && i < n; ++i) { + for (unsigned i = 0; !m_inconsistent && i < n; ++i) assign_propagate(~c[i]); - } - if (!m_inconsistent) { - DEBUG_CODE(validate_propagation();); - } + + DEBUG_CODE(if (!m_inconsistent) validate_propagation();); DEBUG_CODE( - for (literal u : m_units) { + for (literal u : m_units) SASSERT(m_assignment[u.var()] != l_undef); - }); + ); #if 0 if (!m_inconsistent) { @@ -465,9 +458,9 @@ namespace sat { } #endif - for (unsigned i = num_units; i < m_units.size(); ++i) { + for (unsigned i = num_units; i < m_units.size(); ++i) m_assignment[m_units[i].var()] = l_undef; - } + m_units.shrink(num_units); bool ok = m_inconsistent; m_inconsistent = false; diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index d923014c1..3c4569907 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -1304,7 +1304,8 @@ namespace sat { flet _searching(m_searching, true); m_clone = nullptr; if (m_mc.empty() && gparams::get_ref().get_bool("model_validate", false)) { - m_clone = alloc(solver, m_params, m_rlimit); + + m_clone = alloc(solver, m_no_drat_params, m_rlimit); m_clone->copy(*this); m_clone->set_extension(nullptr); } diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index 10e5bd06d..a5d83f273 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -82,6 +82,10 @@ namespace sat { void reset(); void collect_statistics(statistics & st) const; }; + + struct no_drat_params : public params_ref { + no_drat_params() { set_sym("drat.file", symbol()); } + }; class solver : public solver_core { public: @@ -183,6 +187,7 @@ namespace sat { scoped_limit_trail m_vars_lim; stopwatch m_stopwatch; params_ref m_params; + no_drat_params m_no_drat_params; scoped_ptr m_clone; // for debugging purposes literal_vector m_assumptions; // additional assumptions during check literal_set m_assumption_set; // set of enabled assumptions diff --git a/src/sat/smt/sat_dual_solver.cpp b/src/sat/smt/sat_dual_solver.cpp index 1e2068707..e16b09ed1 100644 --- a/src/sat/smt/sat_dual_solver.cpp +++ b/src/sat/smt/sat_dual_solver.cpp @@ -18,10 +18,6 @@ Author: namespace sat { - dual_solver::no_drat_params::no_drat_params() { - set_sym("drat.file", symbol()); - } - dual_solver::dual_solver(reslimit& l): m_solver(m_params, l) { diff --git a/src/sat/smt/sat_dual_solver.h b/src/sat/smt/sat_dual_solver.h index 9c9b2568e..d0465ac32 100644 --- a/src/sat/smt/sat_dual_solver.h +++ b/src/sat/smt/sat_dual_solver.h @@ -23,9 +23,6 @@ Author: namespace sat { class dual_solver { - struct no_drat_params : public params_ref { - no_drat_params(); - }; no_drat_params m_params; solver m_solver; lim_svector m_units, m_roots; From 31267e6ab8dda19f0df344d077dacd516f225d0f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 30 Jul 2021 14:55:59 -0700 Subject: [PATCH 070/125] #5429 --- src/ast/euf/euf_egraph.cpp | 9 +-------- src/sat/smt/euf_solver.cpp | 23 ++++++++--------------- 2 files changed, 9 insertions(+), 23 deletions(-) diff --git a/src/ast/euf/euf_egraph.cpp b/src/ast/euf/euf_egraph.cpp index bbb63540e..2a0159265 100644 --- a/src/ast/euf/euf_egraph.cpp +++ b/src/ast/euf/euf_egraph.cpp @@ -417,14 +417,7 @@ namespace euf { std::swap(r1, r2); std::swap(n1, n2); } - if (m.is_false(r2->get_expr()) && r1->value() == l_true) { - set_conflict(n1, n2, j); - return; - } - if (m.is_true(r2->get_expr()) && r1->value() == l_false) { - set_conflict(n1, n2, j); - return; - } + if (j.is_congruence() && (m.is_false(r2->get_expr()) || m.is_true(r2->get_expr()))) add_literal(n1, false); if (n1->is_equality() && n1->value() == l_false) diff --git a/src/sat/smt/euf_solver.cpp b/src/sat/smt/euf_solver.cpp index a6e58c6d1..cbdc44743 100644 --- a/src/sat/smt/euf_solver.cpp +++ b/src/sat/smt/euf_solver.cpp @@ -214,14 +214,6 @@ namespace euf { TRACE("euf", tout << "explain " << l << " <- " << r << " " << probing << "\n";); DEBUG_CODE(for (auto lit : r) SASSERT(s().value(lit) == l_true);); -#if 0 - if (r.size() == 5 && r[0] == literal(401, true) && r[1] == literal(259, false) && r[2] == literal(250, false) && - r[3] == literal(631, false) && r[4] == literal(639, false)) { - TRACE("euf", s().display(tout);); - exit(0); - } -#endif - if (!probing) log_antecedents(l, r); } @@ -311,19 +303,20 @@ namespace euf { if (n->value_conflict()) { euf::enode* nb = sign ? mk_false() : mk_true(); m_egraph.merge(n, nb, c); + return; } - else if (!sign && n->is_equality()) { + if (n->merge_tf()) { + euf::enode* nb = sign ? mk_false() : mk_true(); + m_egraph.merge(n, nb, c); + } + if (!sign && n->is_equality()) { SASSERT(!m.is_iff(e)); euf::enode* na = n->get_arg(0); euf::enode* nb = n->get_arg(1); m_egraph.merge(na, nb, c); } - else if (n->merge_tf()) { - euf::enode* nb = sign ? mk_false() : mk_true(); - m_egraph.merge(n, nb, c); - } - else if (sign && n->is_equality()) - m_egraph.new_diseq(n); + else if (sign && n->is_equality()) + m_egraph.new_diseq(n); } From 1488bf81ae345f96426573517ba6966d872a5c4d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 30 Jul 2021 15:34:12 -0700 Subject: [PATCH 071/125] #5429 Signed-off-by: Nikolaj Bjorner --- src/sat/smt/array_solver.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/sat/smt/array_solver.cpp b/src/sat/smt/array_solver.cpp index bb588948e..eab37066e 100644 --- a/src/sat/smt/array_solver.cpp +++ b/src/sat/smt/array_solver.cpp @@ -174,6 +174,7 @@ namespace array { ctx.push_vec(get_var_data(v_child).m_parent_selects, select); euf::enode* child = var2enode(v_child); TRACE("array", tout << "v" << v_child << " - " << ctx.bpp(select) << " " << ctx.bpp(child) << " prop: " << should_prop_upward(get_var_data(v_child)) << "\n";); + TRACE("array", tout << "can beta reduce " << can_beta_reduce(child) << "\n";); if (can_beta_reduce(child)) push_axiom(select_axiom(select, child)); propagate_parent_select_axioms(v_child); @@ -227,6 +228,12 @@ namespace array { auto& d = get_var_data(v); + for (euf::enode* lambda : d.m_lambdas) { + expr* e = lambda->get_expr(); + if (a.is_const(e) || a.is_map(e)) + propagate_select_axioms(d, lambda); + } + for (euf::enode* lambda : d.m_parent_lambdas) propagate_select_axioms(d, lambda); } From 53ab93162654778e7daf5450ead078bfa70544ed Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 30 Jul 2021 21:35:09 -0700 Subject: [PATCH 072/125] #5429 Signed-off-by: Nikolaj Bjorner --- src/parsers/smt2/smt2parser.cpp | 24 ++++++++++++++ src/parsers/smt2/smt2parser.h | 1 + src/sat/dimacs.cpp | 27 +++++++++++++++ src/sat/dimacs.h | 2 +- src/sat/smt/euf_proof.cpp | 33 ++++++++++++++++--- src/shell/drat_frontend.cpp | 58 +++++++++++++++++++++++++++++++-- 6 files changed, 137 insertions(+), 8 deletions(-) diff --git a/src/parsers/smt2/smt2parser.cpp b/src/parsers/smt2/smt2parser.cpp index 344c61283..248e783e5 100644 --- a/src/parsers/smt2/smt2parser.cpp +++ b/src/parsers/smt2/smt2parser.cpp @@ -3118,6 +3118,25 @@ namespace smt2 { return sexpr_ref(nullptr, sm()); } + sort_ref parse_sort_ref(char const* context) { + m_num_bindings = 0; + m_num_open_paren = 0; + + unsigned found_errors = 0; + try { + scan_core(); + parse_sort(context); + if (!sort_stack().empty()) { + return sort_ref(sort_stack().back(), m()); + } + } + catch (z3_exception & ex) { + error(ex.msg()); + } + return sort_ref(nullptr, m()); + } + + bool operator()() { m_num_bindings = 0; unsigned found_errors = 0; @@ -3190,6 +3209,11 @@ bool parse_smt2_commands(cmd_context & ctx, std::istream & is, bool interactive, return p(); } +sort_ref parse_smt2_sort(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.parse_sort_ref(filename); +} + sexpr_ref parse_sexpr(cmd_context& ctx, std::istream& is, params_ref const& ps, char const* filename) { smt2::parser p(ctx, is, false, ps, filename); return p.parse_sexpr_ref(); diff --git a/src/parsers/smt2/smt2parser.h b/src/parsers/smt2/smt2parser.h index 1b7834c9e..ad8f040b4 100644 --- a/src/parsers/smt2/smt2parser.h +++ b/src/parsers/smt2/smt2parser.h @@ -24,3 +24,4 @@ bool parse_smt2_commands(cmd_context & ctx, std::istream & is, bool interactive sexpr_ref parse_sexpr(cmd_context& ctx, std::istream& is, params_ref const& ps, char const* filename); +sort_ref parse_smt2_sort(cmd_context & ctx, std::istream & is, bool interactive, params_ref const & ps, char const * filename); diff --git a/src/sat/dimacs.cpp b/src/sat/dimacs.cpp index 6800b5c8d..9c9a40a24 100644 --- a/src/sat/dimacs.cpp +++ b/src/sat/dimacs.cpp @@ -165,6 +165,10 @@ namespace dimacs { return out << "f " << r.m_node_id << " " << r.m_name << " " << r.m_args << "0\n"; case drat_record::tag_t::is_bool_def: return out << "b " << r.m_node_id << " " << r.m_args << "0\n"; + case drat_record::tag_t::is_var: + return out << "v " << r.m_node_id << " " << r.m_name << " " << r.m_args << "0\n"; + case drat_record::tag_t::is_quantifier: + return out << "q " << r.m_node_id << " " << r.m_name << " " << r.m_args << "0\n"; } return out; } @@ -256,6 +260,23 @@ namespace dimacs { m_record.m_args.push_back(n); } }; + auto parse_var = [&]() { + ++in; + skip_whitespace(in); + n = parse_int(in, err); + skip_whitespace(in); + m_record.m_name = parse_sexpr(); + m_record.m_tag = drat_record::tag_t::is_var; + m_record.m_node_id = n; + m_record.m_args.reset(); + n = parse_int(in, err); + if (n < 0) + throw lex_error(); + m_record.m_args.push_back(n); + n = parse_int(in, err); + if (n != 0) + throw lex_error(); + }; try { loop: skip_whitespace(in); @@ -290,6 +311,12 @@ namespace dimacs { // parse expression definition parse_ast(drat_record::tag_t::is_node); break; + case 'v': + parse_var(); + break; + case 'q': + parse_ast(drat_record::tag_t::is_quantifier); + break; case 'f': // parse function declaration parse_ast(drat_record::tag_t::is_decl); diff --git a/src/sat/dimacs.h b/src/sat/dimacs.h index eb5fea442..cc4b27182 100644 --- a/src/sat/dimacs.h +++ b/src/sat/dimacs.h @@ -53,7 +53,7 @@ namespace dimacs { }; struct drat_record { - enum class tag_t { is_clause, is_node, is_decl, is_sort, is_bool_def }; + enum class tag_t { is_clause, is_node, is_decl, is_sort, is_bool_def, is_var, is_quantifier }; tag_t m_tag{ tag_t::is_clause }; // a clause populates m_lits and m_status // a node populates m_node_id, m_name, m_args diff --git a/src/sat/smt/euf_proof.cpp b/src/sat/smt/euf_proof.cpp index 42fc8ccde..638a64193 100644 --- a/src/sat/smt/euf_proof.cpp +++ b/src/sat/smt/euf_proof.cpp @@ -41,12 +41,32 @@ namespace euf { for (expr* arg : *a) get_drat().def_add_arg(arg->get_id()); get_drat().def_end(); - m_drat_asts.insert(e); - push(insert_obj_trail(m_drat_asts, e)); } - else { - IF_VERBOSE(0, verbose_stream() << "logging binders is TBD\n"); + else if (is_var(e)) { + var* v = to_var(e); + std::stringstream strm; + strm << mk_pp(e->get_sort(), m); + get_drat().def_begin('v', v->get_id(), strm.str()); + get_drat().def_add_arg(v->get_idx()); + get_drat().def_end(); } + else if (is_quantifier(e)) { + quantifier* q = to_quantifier(e); + std::stringstream strm; + strm << "("; + strm << (is_forall(q) ? "forall" : (is_exists(q) ? "exists" : "lambda")); + for (unsigned i = 0; i < q->get_num_decls(); ++i) { + strm << " (" << q->get_decl_name(i) << " " << mk_pp(q->get_decl_sort(i), m) << ")"; + } + strm << ")"; + get_drat().def_begin('q', q->get_id(), strm.str()); + get_drat().def_add_arg(q->get_expr()->get_id()); + get_drat().def_end(); + } + else + UNREACHABLE(); + m_drat_asts.insert(e); + push(insert_obj_trail(m_drat_asts, e)); } void solver::drat_log_expr(expr* e) { @@ -61,6 +81,11 @@ namespace euf { for (expr* arg : *to_app(e)) if (!m_drat_asts.contains(arg)) m_drat_todo.push_back(arg); + if (is_quantifier(e)) { + expr* arg = to_quantifier(e)->get_expr(); + if (!m_drat_asts.contains(arg)) + m_drat_todo.push_back(arg); + } if (m_drat_todo.size() != sz) continue; drat_log_expr1(e); diff --git a/src/shell/drat_frontend.cpp b/src/shell/drat_frontend.cpp index 6972571e0..b3e9876d0 100644 --- a/src/shell/drat_frontend.cpp +++ b/src/shell/drat_frontend.cpp @@ -171,6 +171,34 @@ public: unsigned_vector params; ptr_vector sorts; + void parse_quantifier(sexpr_ref const& sexpr, cmd_context& ctx, quantifier_kind& k, sort_ref_vector& domain, svector& names) { + k = quantifier_kind::forall_k; + if (sexpr->get_kind() != sexpr::kind_t::COMPOSITE) + goto bail; + unsigned sz = sexpr->get_num_children(); + if (sz == 0) + goto bail; + symbol q = sexpr->get_child(0)->get_symbol(); + if (q == "forall") + k = quantifier_kind::forall_k; + else if (q == "exists") + k = quantifier_kind::exists_k; + else if (q == "lambda") + k = quantifier_kind::lambda_k; + else + goto bail; + for (unsigned i = 1; i < sz; ++i) { + std::cout << "parse bound\n"; + } + return; + bail: + std::cout << "Could not parse expression\n"; + sexpr->display(std::cout); + std::cout << "\n"; + exit(0); + + } + void parse_sexpr(sexpr_ref const& sexpr, cmd_context& ctx, expr_ref_vector const& args, expr_ref& result) { params.reset(); sorts.reset(); @@ -310,7 +338,17 @@ static void verify_smt(char const* drat_file, char const* smt_file) { std::istringstream strm(r.m_name); auto sexpr = parse_sexpr(ctx, strm, p, drat_file); checker.parse_sexpr(sexpr, ctx, args, e); - exprs.reserve(r.m_node_id+1); + exprs.reserve(r.m_node_id + 1); + exprs.set(r.m_node_id, e); + break; + } + case dimacs::drat_record::tag_t::is_var: { + var_ref e(m); + SASSERT(r.m_args.size() == 1); + std::istringstream strm(r.m_name); + auto srt = parse_smt2_sort(ctx, strm, false, p, drat_file); + e = m.mk_var(r.m_args[0], srt); + exprs.reserve(r.m_node_id + 1); exprs.set(r.m_node_id, e); break; } @@ -331,12 +369,26 @@ static void verify_smt(char const* drat_file, char const* smt_file) { srt = pd->instantiate(ctx.pm(), sargs.size(), sargs.data()); else srt = m.mk_uninterpreted_sort(name); - sorts.reserve(r.m_node_id+1); + sorts.reserve(r.m_node_id + 1); sorts.set(r.m_node_id, srt); break; } + case dimacs::drat_record::tag_t::is_quantifier: { + quantifier_ref q(m); + std::istringstream strm(r.m_name); + auto sexpr = parse_sexpr(ctx, strm, p, drat_file); + sort_ref_vector domain(m); + svector names; + quantifier_kind k; + checker.parse_quantifier(sexpr, ctx, k, domain, names); + sexpr->display(std::cout << "QQ "); + std::cout << "\n"; + exprs.reserve(r.m_node_id + 1); + exprs.set(r.m_node_id, m.mk_true()); + break; + } case dimacs::drat_record::tag_t::is_bool_def: - bool_var2expr.reserve(r.m_node_id+1); + bool_var2expr.reserve(r.m_node_id + 1); bool_var2expr.set(r.m_node_id, exprs.get(r.m_args[0])); break; default: From 1e8009bbfc0b3dae587af4de999f26a0b5206bc9 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 30 Jul 2021 22:29:00 -0700 Subject: [PATCH 073/125] build/labels --- src/sat/smt/euf_proof.cpp | 2 ++ src/shell/drat_frontend.cpp | 29 ++++++++++++++++++++--------- 2 files changed, 22 insertions(+), 9 deletions(-) diff --git a/src/sat/smt/euf_proof.cpp b/src/sat/smt/euf_proof.cpp index 638a64193..610027c53 100644 --- a/src/sat/smt/euf_proof.cpp +++ b/src/sat/smt/euf_proof.cpp @@ -179,6 +179,8 @@ namespace euf { void solver::drat_eq_def(literal lit, expr* eq) { expr *a = nullptr, *b = nullptr; VERIFY(m.is_eq(eq, a, b)); + drat_log_expr(a); + drat_log_expr(b); get_drat().def_begin('e', eq->get_id(), std::string("=")); get_drat().def_add_arg(a->get_id()); get_drat().def_add_arg(b->get_id()); diff --git a/src/shell/drat_frontend.cpp b/src/shell/drat_frontend.cpp index b3e9876d0..bd07edc0a 100644 --- a/src/shell/drat_frontend.cpp +++ b/src/shell/drat_frontend.cpp @@ -173,12 +173,14 @@ public: void parse_quantifier(sexpr_ref const& sexpr, cmd_context& ctx, quantifier_kind& k, sort_ref_vector& domain, svector& names) { k = quantifier_kind::forall_k; + symbol q; + unsigned sz; if (sexpr->get_kind() != sexpr::kind_t::COMPOSITE) goto bail; - unsigned sz = sexpr->get_num_children(); + sz = sexpr->get_num_children(); if (sz == 0) goto bail; - symbol q = sexpr->get_child(0)->get_symbol(); + q = sexpr->get_child(0)->get_symbol(); if (q == "forall") k = quantifier_kind::forall_k; else if (q == "exists") @@ -188,7 +190,19 @@ public: else goto bail; for (unsigned i = 1; i < sz; ++i) { - std::cout << "parse bound\n"; + auto* e = sexpr->get_child(i); + if (e->get_kind() != sexpr::kind_t::COMPOSITE) + goto bail; + if (2 != e->get_num_children()) + goto bail; + symbol name = e->get_child(0)->get_symbol(); + std::ostringstream ostrm; + e->get_child(1)->display(ostrm); + std::istringstream istrm(ostrm.str()); + params_ref p; + auto srt = parse_smt2_sort(ctx, istrm, false, p, "quantifier"); + names.push_back(name); + domain.push_back(srt); } return; bail: @@ -374,6 +388,7 @@ static void verify_smt(char const* drat_file, char const* smt_file) { break; } case dimacs::drat_record::tag_t::is_quantifier: { + VERIFY(r.m_args.size() == 1); quantifier_ref q(m); std::istringstream strm(r.m_name); auto sexpr = parse_sexpr(ctx, strm, p, drat_file); @@ -381,8 +396,7 @@ static void verify_smt(char const* drat_file, char const* smt_file) { svector names; quantifier_kind k; checker.parse_quantifier(sexpr, ctx, k, domain, names); - sexpr->display(std::cout << "QQ "); - std::cout << "\n"; + q = m.mk_quantifier(k, domain.size(), domain.data(), names.data(), exprs.get(r.m_args[0])); exprs.reserve(r.m_node_id + 1); exprs.set(r.m_node_id, m.mk_true()); break; @@ -399,7 +413,6 @@ static void verify_smt(char const* drat_file, char const* smt_file) { statistics st; drat_checker.collect_statistics(st); std::cout << st << "\n"; - } @@ -410,6 +423,4 @@ unsigned read_drat(char const* drat_file, char const* problem_file) { } verify_smt(drat_file, problem_file); return 0; -} - - +} \ No newline at end of file From ce23798cd0f2b79ba9f1fb9552cb6d0cfd9ce9a6 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 30 Jul 2021 22:36:14 -0700 Subject: [PATCH 074/125] coverage.yml Signed-off-by: Nikolaj Bjorner --- scripts/coverage.yml | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 scripts/coverage.yml diff --git a/scripts/coverage.yml b/scripts/coverage.yml new file mode 100644 index 000000000..bfc8c6447 --- /dev/null +++ b/scripts/coverage.yml @@ -0,0 +1,37 @@ + +variables: + cmakeJulia: '-DZ3_BUILD_JULIA_BINDINGS=True' + cmakeJava: '-DZ3_BUILD_JAVA_BINDINGS=True' + cmakeNet: '-DZ3_BUILD_DOTNET_BINDINGS=True' + cmakePy: '-DZ3_BUILD_PYTHON_BINDINGS=True' + cmakeStdArgs: '-DZ3_BUILD_DOTNET_BINDINGS=True -DZ3_BUILD_JAVA_BINDINGS=True -DZ3_BUILD_PYTHON_BINDINGS=True -G "Ninja" ../' + cmakeCovArgs: '-DCMAKE_INSTALL_PREFIX=./install -G "Ninja" ../' + asanEnv: 'CXXFLAGS="${CXXFLAGS} -fsanitize=address -fno-omit-frame-pointer" CFLAGS="${CFLAGS} -fsanitize=address -fno-omit-frame-pointer"' + ubsanEnv: 'CXXFLAGS="${CXXFLAGS} -fsanitize=undefined" CFLAGS="${CFLAGS} -fsanitize=undefined"' + msanEnv: 'CC=clang LDFLAGS="-L../libcxx/libcxx_msan/lib -lc++abi -Wl,-rpath=../libcxx/libcxx_msan/lib" CXX=clang++ CXXFLAGS="${CXXFLAGS} -stdlib=libc++ -fsanitize-memory-track-origins -fsanitize=memory -fPIE -fno-omit-frame-pointer -g -O2" CFLAGS="${CFLAGS} -stdlib=libc -fsanitize=memory -fsanitize-memory-track-origins -fno-omit-frame-pointer -g -O2"' + + + +- job: "UbuntuCMakeCoverage" + displayName: "Ubuntu build - cmake w/ coverage" + pool: + vmImage: "ubuntu-latest" + steps: + - script: sudo apt-get install ninja-build + - script: | + set -e + mkdir build + cd build + CXXFLAGS=--coverage LDFLAGS=-lgcov CC=clang CXX=clang++ cmake -DCMAKE_BUILD_TYPE=Debug $(cmakeCovArgs) + ninja + ninja test-z3 + ninja install + cd .. + - script: | + cd build + ./test-z3 -a + cd .. + - template: scripts/test-examples-cmake.yml + - template: scripts/test-regressions-coverage.yml + + From 3f6a7748fac0756f2d29e784df5226bcd57546ed Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 30 Jul 2021 22:38:16 -0700 Subject: [PATCH 075/125] jobs Signed-off-by: Nikolaj Bjorner --- scripts/coverage.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/coverage.yml b/scripts/coverage.yml index bfc8c6447..023870234 100644 --- a/scripts/coverage.yml +++ b/scripts/coverage.yml @@ -10,7 +10,7 @@ variables: ubsanEnv: 'CXXFLAGS="${CXXFLAGS} -fsanitize=undefined" CFLAGS="${CFLAGS} -fsanitize=undefined"' msanEnv: 'CC=clang LDFLAGS="-L../libcxx/libcxx_msan/lib -lc++abi -Wl,-rpath=../libcxx/libcxx_msan/lib" CXX=clang++ CXXFLAGS="${CXXFLAGS} -stdlib=libc++ -fsanitize-memory-track-origins -fsanitize=memory -fPIE -fno-omit-frame-pointer -g -O2" CFLAGS="${CFLAGS} -stdlib=libc -fsanitize=memory -fsanitize-memory-track-origins -fno-omit-frame-pointer -g -O2"' - +jobs: - job: "UbuntuCMakeCoverage" displayName: "Ubuntu build - cmake w/ coverage" From 6dfaaa43cd329ba982a833ce9e1d8257cdcc31fc Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 30 Jul 2021 22:38:56 -0700 Subject: [PATCH 076/125] jobs Signed-off-by: Nikolaj Bjorner --- scripts/coverage.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/coverage.yml b/scripts/coverage.yml index 023870234..c091039b0 100644 --- a/scripts/coverage.yml +++ b/scripts/coverage.yml @@ -31,7 +31,7 @@ jobs: cd build ./test-z3 -a cd .. - - template: scripts/test-examples-cmake.yml - - template: scripts/test-regressions-coverage.yml + - template: test-examples-cmake.yml + - template: test-regressions-coverage.yml From bcf0f671b8d893b5937ce7f4d073b1f10b969524 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 30 Jul 2021 23:27:37 -0700 Subject: [PATCH 077/125] disable drat inside of quantifier elaboration --- src/sat/smt/q_mbi.cpp | 3 ++- src/sat/smt/q_mbi.h | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/sat/smt/q_mbi.cpp b/src/sat/smt/q_mbi.cpp index c7ed4913a..ba6bc77b3 100644 --- a/src/sat/smt/q_mbi.cpp +++ b/src/sat/smt/q_mbi.cpp @@ -42,6 +42,7 @@ namespace q { add_plugin(ap); add_plugin(alloc(mbp::datatype_project_plugin, m)); add_plugin(alloc(mbp::array_project_plugin, m)); + } lbool mbqi::operator()() { @@ -565,7 +566,7 @@ namespace q { void mbqi::init_solver() { if (!m_solver) - m_solver = mk_smt2_solver(m, ctx.s().params()); + m_solver = mk_smt2_solver(m, m_no_drat_params); } void mbqi::init_search() { diff --git a/src/sat/smt/q_mbi.h b/src/sat/smt/q_mbi.h index 174462ca4..1920baa52 100644 --- a/src/sat/smt/q_mbi.h +++ b/src/sat/smt/q_mbi.h @@ -20,6 +20,7 @@ Author: #include "qe/mbp/mbp_plugin.h" #include "sat/smt/sat_th.h" #include "sat/smt/q_model_fixer.h" +#include "sat/sat_solver.h" namespace euf { class solver; @@ -60,6 +61,7 @@ namespace q { stats m_stats; model_fixer m_model_fixer; model_ref m_model; + sat::no_drat_params m_no_drat_params; ref<::solver> m_solver; scoped_ptr_vector> m_values; scoped_ptr_vector m_plugins; From 77cd82a5ca28b49e9fdad444f25762bcfbb629cf Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 30 Jul 2021 23:28:30 -0700 Subject: [PATCH 078/125] flatten if-then-else --- src/sat/tactic/goal2sat.cpp | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/sat/tactic/goal2sat.cpp b/src/sat/tactic/goal2sat.cpp index 123eacee5..b45438675 100644 --- a/src/sat/tactic/goal2sat.cpp +++ b/src/sat/tactic/goal2sat.cpp @@ -300,24 +300,24 @@ struct goal2sat::imp : public sat::sat_internalizer { add_dual_root(1, &tt); l = sign ? tt : ~tt; } - else { - if (m_euf) { - convert_euf(t, root, sign); - return; - } - if (!is_uninterp_const(t)) { - if (!is_app(t)) { - std::ostringstream strm; - strm << mk_ismt2_pp(t, m); - throw_op_not_handled(strm.str()); - } - else - m_unhandled_funs.push_back(to_app(t)->get_decl()); + else if (m_euf) { + convert_euf(t, root, sign); + return; + } + else if (!is_uninterp_const(t)) { + if (!is_app(t)) { + std::ostringstream strm; + strm << mk_ismt2_pp(t, m); + throw_op_not_handled(strm.str()); } + else + m_unhandled_funs.push_back(to_app(t)->get_decl()); + } + else { v = mk_bool_var(t); l = sat::literal(v, sign); bool ext = m_default_external || !is_uninterp_const(t) || m_interface_vars.contains(t); - if (ext) + if (ext) m_solver.set_external(v); TRACE("sat", tout << "new_var: " << v << ": " << mk_bounded_pp(t, m, 2) << " " << is_uninterp_const(t) << "\n";); } From e5401a4303dad8aa67edb40088e93159092dcbf5 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 31 Jul 2021 00:32:43 -0700 Subject: [PATCH 079/125] use quantifier --- src/shell/drat_frontend.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shell/drat_frontend.cpp b/src/shell/drat_frontend.cpp index bd07edc0a..647b28445 100644 --- a/src/shell/drat_frontend.cpp +++ b/src/shell/drat_frontend.cpp @@ -398,7 +398,7 @@ static void verify_smt(char const* drat_file, char const* smt_file) { checker.parse_quantifier(sexpr, ctx, k, domain, names); q = m.mk_quantifier(k, domain.size(), domain.data(), names.data(), exprs.get(r.m_args[0])); exprs.reserve(r.m_node_id + 1); - exprs.set(r.m_node_id, m.mk_true()); + exprs.set(r.m_node_id, q); break; } case dimacs::drat_record::tag_t::is_bool_def: From 6a9241ff0f3b7b190b00eb7b25880ad747dd9b68 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 31 Jul 2021 11:00:12 -0700 Subject: [PATCH 080/125] #5429 --- src/ast/ast_pp.h | 14 ++++++++++++++ src/sat/sat_drat.cpp | 1 - src/sat/smt/euf_proof.cpp | 23 ++++++++--------------- src/sat/tactic/goal2sat.cpp | 20 +++++++++++++------- src/shell/drat_frontend.cpp | 13 +++++++++---- 5 files changed, 44 insertions(+), 27 deletions(-) diff --git a/src/ast/ast_pp.h b/src/ast/ast_pp.h index 58ee3145c..1b3ca4a81 100644 --- a/src/ast/ast_pp.h +++ b/src/ast/ast_pp.h @@ -31,6 +31,7 @@ struct mk_pp : public mk_ismt2_pp { } }; + //get_decl()); std::stringstream strm; strm << mk_ismt2_func(a->get_decl(), m); - if (a->get_num_parameters() == 0) - get_drat().def_begin('e', e->get_id(), strm.str()); - else { - get_drat().def_begin('e', e->get_id(), strm.str()); - } + get_drat().def_begin('e', e->get_id(), strm.str()); for (expr* arg : *a) get_drat().def_add_arg(arg->get_id()); get_drat().def_end(); } else if (is_var(e)) { var* v = to_var(e); - std::stringstream strm; - strm << mk_pp(e->get_sort(), m); - get_drat().def_begin('v', v->get_id(), strm.str()); + get_drat().def_begin('v', v->get_id(), "" + mk_pp(e->get_sort(), m)); get_drat().def_add_arg(v->get_idx()); get_drat().def_end(); } else if (is_quantifier(e)) { quantifier* q = to_quantifier(e); - std::stringstream strm; - strm << "("; - strm << (is_forall(q) ? "forall" : (is_exists(q) ? "exists" : "lambda")); - for (unsigned i = 0; i < q->get_num_decls(); ++i) { - strm << " (" << q->get_decl_name(i) << " " << mk_pp(q->get_decl_sort(i), m) << ")"; - } + std::stringstream strm; + strm << "(" << (is_forall(q) ? "forall" : (is_exists(q) ? "exists" : "lambda")); + for (unsigned i = 0; i < q->get_num_decls(); ++i) + strm << " (" << q->get_decl_name(i) << " " << mk_pp(q->get_decl_sort(i), m) << ")"; strm << ")"; get_drat().def_begin('q', q->get_id(), strm.str()); get_drat().def_add_arg(q->get_expr()->get_id()); @@ -88,7 +80,8 @@ namespace euf { } if (m_drat_todo.size() != sz) continue; - drat_log_expr1(e); + if (!m_drat_asts.contains(e)) + drat_log_expr1(e); m_drat_todo.pop_back(); } } diff --git a/src/sat/tactic/goal2sat.cpp b/src/sat/tactic/goal2sat.cpp index b45438675..bdc1b8b9e 100644 --- a/src/sat/tactic/goal2sat.cpp +++ b/src/sat/tactic/goal2sat.cpp @@ -599,8 +599,8 @@ struct goal2sat::imp : public sat::sat_internalizer { } void convert_iff(app * t, bool root, bool sign) { - if (t->get_num_args() != 2) - throw default_exception("unexpected number of arguments to xor"); + if (t->get_num_args() != 2) + throw default_exception("unexpected number of arguments to " + mk_pp(t, m)); SASSERT(t->get_num_args() == 2); unsigned sz = m_result_stack.size(); SASSERT(sz >= 2); @@ -608,6 +608,8 @@ struct goal2sat::imp : public sat::sat_internalizer { sat::literal l2 = m_result_stack[sz-2]; m_result_stack.shrink(sz - 2); if (root) { + if (m.is_xor(t)) + sign = !sign; SASSERT(sz == 2); if (sign) { mk_root_clause(l1, l2); @@ -616,17 +618,20 @@ struct goal2sat::imp : public sat::sat_internalizer { else { mk_root_clause(l1, ~l2); mk_root_clause(~l1, l2); - } + } } else { sat::bool_var k = add_var(false, t); sat::literal l(k, false); + if (m.is_xor(t)) + l1.neg(); mk_clause(~l, l1, ~l2); mk_clause(~l, ~l1, l2); - mk_clause(l, l1, l2); + mk_clause(l, l1, l2); mk_clause(l, ~l1, ~l2); - if (aig()) aig()->add_iff(l, l1, l2); - cache(t, m.is_xor(t) ? ~l : l); + if (aig()) aig()->add_iff(l, l1, l2); + + cache(t, l); if (sign) l.neg(); m_result_stack.push_back(l); @@ -720,7 +725,7 @@ struct goal2sat::imp : public sat::sat_internalizer { convert_iff(t, root, sign); break; case OP_XOR: - convert_iff(t, root, !sign); + convert_iff(t, root, sign); break; case OP_IMPLIES: convert_implies(t, root, sign); @@ -828,6 +833,7 @@ struct goal2sat::imp : public sat::sat_internalizer { process(n, false, redundant); SASSERT(m_result_stack.size() == sz + 1); sat::literal result = m_result_stack.back(); + TRACE("goal2sat", tout << "done internalize " << result << " " << mk_bounded_pp(n, m, 2) << "\n";); m_result_stack.pop_back(); if (!result.sign() && m_map.to_bool_var(n) == sat::null_bool_var) { force_push(); diff --git a/src/shell/drat_frontend.cpp b/src/shell/drat_frontend.cpp index 647b28445..f1ae29586 100644 --- a/src/shell/drat_frontend.cpp +++ b/src/shell/drat_frontend.cpp @@ -122,12 +122,17 @@ class smt_checker { m_input_solver->assert_expr(lit2expr(~lit)); lbool is_sat = m_input_solver->check_sat(); if (is_sat != l_false) { - std::cout << "did not verify: " << lits << "\n"; - for (sat::literal lit : lits) { - std::cout << lit2expr(lit) << "\n"; - } + std::cout << "did not verify: " << is_sat << " " << lits << "\n"; + for (sat::literal lit : lits) + std::cout << lit2expr(lit) << "\n"; std::cout << "\n"; m_input_solver->display(std::cout); + if (is_sat == l_true) { + model_ref mdl; + m_input_solver->get_model(mdl); + std::cout << *mdl << "\n"; + } + exit(0); } m_input_solver->pop(1); From f6d6d2cc2d2045427dc26c0da538aafecc522627 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 31 Jul 2021 11:03:14 -0700 Subject: [PATCH 081/125] Create coverage.yml Move coverage to self-contained github action --- .github/workflows/coverage.yml | 38 ++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 .github/workflows/coverage.yml diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml new file mode 100644 index 000000000..5600a57e2 --- /dev/null +++ b/.github/workflows/coverage.yml @@ -0,0 +1,38 @@ +name: CodeCoverage + +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + +env: + # Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.) + BUILD_TYPE: Debug + +jobs: + build: + # The CMake configure and build commands are platform agnostic and should work equally + # well on Windows or Mac. You can convert this to a matrix build if you need + # cross-platform coverage. + # See: https://docs.github.com/en/free-pro-team@latest/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + + - name: Configure CMake + # Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make. + # See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type + run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} + + - name: Build + # Build your program with the given configuration + run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} + + - name: Test + working-directory: ${{github.workspace}}/build + # Execute tests defined by the CMake configuration. + # See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail + run: ctest -C ${{env.BUILD_TYPE}} + From 5533fc9dbc6639895398c1080e1b6172ddd2d645 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 31 Jul 2021 11:11:21 -0700 Subject: [PATCH 082/125] Update README.md --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index f9fad4f46..681ef24d5 100644 --- a/README.md +++ b/README.md @@ -14,9 +14,9 @@ See the [release notes](RELEASE_NOTES) for notes on various stable releases of Z ## Build status -| Azure Pipelines | -| --------------- | -[![Build Status](https://dev.azure.com/Z3Public/Z3/_apis/build/status/Z3Prover.z3?branchName=master)](https://dev.azure.com/Z3Public/Z3/_build/latest?definitionId=1&branchName=master) +| Azure Pipelines | Code Coverage | +| --------------- | --------------| +| [![Build Status](https://dev.azure.com/Z3Public/Z3/_apis/build/status/Z3Prover.z3?branchName=master)](https://dev.azure.com/Z3Public/Z3/_build/latest?definitionId=1&branchName=master) | [![CodeCoverage](https://github.com/Z3Prover/z3/actions/workflows/coverage.yml/badge.svg)](https://github.com/Z3Prover/z3/actions/workflows/coverage.yml) | [1]: #building-z3-on-windows-using-visual-studio-command-prompt [2]: #building-z3-using-make-and-gccclang From 7de8c722468d9cd369cc659f3954c4b33c6ce82c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 31 Jul 2021 11:32:47 -0700 Subject: [PATCH 083/125] cleanups Signed-off-by: Nikolaj Bjorner --- src/parsers/smt2/smt2parser.cpp | 4 +--- src/sat/smt/array_solver.cpp | 2 +- src/sat/smt/bv_internalize.cpp | 5 ++--- src/sat/smt/q_clause.h | 2 +- src/shell/drat_frontend.cpp | 5 +++-- src/smt/smt_conflict_resolution.cpp | 2 +- src/smt/theory_seq.cpp | 1 - src/smt/theory_str.cpp | 1 + src/tactic/portfolio/solver_subsumption_tactic.cpp | 9 +++++++-- 9 files changed, 17 insertions(+), 14 deletions(-) diff --git a/src/parsers/smt2/smt2parser.cpp b/src/parsers/smt2/smt2parser.cpp index 248e783e5..953b1979f 100644 --- a/src/parsers/smt2/smt2parser.cpp +++ b/src/parsers/smt2/smt2parser.cpp @@ -3122,13 +3122,11 @@ namespace smt2 { m_num_bindings = 0; m_num_open_paren = 0; - unsigned found_errors = 0; try { scan_core(); parse_sort(context); - if (!sort_stack().empty()) { + if (!sort_stack().empty()) return sort_ref(sort_stack().back(), m()); - } } catch (z3_exception & ex) { error(ex.msg()); diff --git a/src/sat/smt/array_solver.cpp b/src/sat/smt/array_solver.cpp index eab37066e..b56f4efb1 100644 --- a/src/sat/smt/array_solver.cpp +++ b/src/sat/smt/array_solver.cpp @@ -177,7 +177,7 @@ namespace array { TRACE("array", tout << "can beta reduce " << can_beta_reduce(child) << "\n";); if (can_beta_reduce(child)) push_axiom(select_axiom(select, child)); - propagate_parent_select_axioms(v_child); + propagate_parent_select_axioms(v_child); } void solver::add_lambda(theory_var v, euf::enode* lambda) { diff --git a/src/sat/smt/bv_internalize.cpp b/src/sat/smt/bv_internalize.cpp index e3c193f5a..e8e4305d0 100644 --- a/src/sat/smt/bv_internalize.cpp +++ b/src/sat/smt/bv_internalize.cpp @@ -653,9 +653,8 @@ namespace bv { if (!argn->is_attached_to(get_id())) { mk_var(argn); } - theory_var v_arg = argn->get_th_var(get_id()); - unsigned arg_sz = get_bv_size(v_arg); - SASSERT(idx < arg_sz); + theory_var v_arg = argn->get_th_var(get_id()); + SASSERT(idx < get_bv_size(v_arg)); sat::literal lit = expr2literal(n); sat::literal lit0 = m_bits[v_arg][idx]; if (lit0 == sat::null_literal) { diff --git a/src/sat/smt/q_clause.h b/src/sat/smt/q_clause.h index 6cb889ee1..66daf07ea 100644 --- a/src/sat/smt/q_clause.h +++ b/src/sat/smt/q_clause.h @@ -84,7 +84,7 @@ namespace q { clause& m_clause; euf::enode* const* m_binding; justification(lit const& l, clause& c, euf::enode* const* b, unsigned n, euf::enode_pair* ev): - m_lhs(l.lhs), m_rhs(l.rhs), m_sign(l.sign), m_clause(c), m_binding(b), m_num_ev(n), m_evidence(ev) {} + m_lhs(l.lhs), m_rhs(l.rhs), m_sign(l.sign), m_num_ev(n), m_evidence(ev), m_clause(c), m_binding(b) {} sat::ext_constraint_idx to_index() const { return sat::constraint_base::mem2base(this); } diff --git a/src/shell/drat_frontend.cpp b/src/shell/drat_frontend.cpp index f1ae29586..1dba2e768 100644 --- a/src/shell/drat_frontend.cpp +++ b/src/shell/drat_frontend.cpp @@ -206,6 +206,8 @@ public: std::istringstream istrm(ostrm.str()); params_ref p; auto srt = parse_smt2_sort(ctx, istrm, false, p, "quantifier"); + if (!srt) + goto bail; names.push_back(name); domain.push_back(srt); } @@ -215,7 +217,6 @@ public: sexpr->display(std::cout); std::cout << "\n"; exit(0); - } void parse_sexpr(sexpr_ref const& sexpr, cmd_context& ctx, expr_ref_vector const& args, expr_ref& result) { @@ -428,4 +429,4 @@ unsigned read_drat(char const* drat_file, char const* problem_file) { } verify_smt(drat_file, problem_file); return 0; -} \ No newline at end of file +} diff --git a/src/smt/smt_conflict_resolution.cpp b/src/smt/smt_conflict_resolution.cpp index 47bc13242..14a71ae28 100644 --- a/src/smt/smt_conflict_resolution.cpp +++ b/src/smt/smt_conflict_resolution.cpp @@ -315,7 +315,7 @@ namespace smt { void conflict_resolution::process_antecedent(literal antecedent, unsigned & num_marks) { bool_var var = antecedent.var(); unsigned lvl = m_ctx.get_assign_level(var); - SASSERT(var < static_cast(m_ctx.get_num_bool_vars())); + SASSERT(var < m_ctx.get_num_bool_vars()); TRACE("conflict_", tout << "processing antecedent (level " << lvl << "):"; m_ctx.display_literal(tout, antecedent); m_ctx.display_detailed_literal(tout << " ", antecedent) << "\n";); diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index ba9f7c8fd..e9e80efcb 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -1558,7 +1558,6 @@ bool theory_seq::check_ubv_string() { } bool theory_seq::check_ubv_string(expr* e) { - expr* n = nullptr; if (ctx.inconsistent()) return true; if (m_has_ubv_axiom.contains(e)) diff --git a/src/smt/theory_str.cpp b/src/smt/theory_str.cpp index e5c1469a6..6705d40e4 100644 --- a/src/smt/theory_str.cpp +++ b/src/smt/theory_str.cpp @@ -5523,6 +5523,7 @@ namespace smt { TRACE("str", tout << mk_pp(node, get_manager()) << std::endl;); if (groundedMap.find(node) != groundedMap.end()) { for (auto const &itor : groundedMap[node]) { + (void) itor; TRACE("str", tout << "\t[grounded] "; for (auto const &vIt : itor.first) { diff --git a/src/tactic/portfolio/solver_subsumption_tactic.cpp b/src/tactic/portfolio/solver_subsumption_tactic.cpp index 57edce73d..ac6cdede2 100644 --- a/src/tactic/portfolio/solver_subsumption_tactic.cpp +++ b/src/tactic/portfolio/solver_subsumption_tactic.cpp @@ -50,7 +50,6 @@ class solver_subsumption_tactic : public tactic { return false; expr_ref_vector ors(m); ors.append(to_app(f)->get_num_args(), to_app(f)->get_args()); - unsigned j = 0; expr_ref_vector prefix(m); for (unsigned i = 0; i < ors.size(); ++i) { expr_ref_vector fmls(m); @@ -124,9 +123,15 @@ public: ~solver_subsumption_tactic() override {} - void updt_params(params_ref const& p) override { m_params = p; } + void updt_params(params_ref const& p) override { + m_params = p; + unsigned max_conflicts = p.get_uint("max_conflicts", 2); + m_params.set_uint("sat.max_conflicts", max_conflicts); + m_params.set_uint("smt.max_conflicts", max_conflicts); + } void collect_param_descrs(param_descrs& r) override { + r.insert("max_conflicts", CPK_UINT, "(default: 10) maximal number of conflicts allowed per solver call."); } void operator()(goal_ref const& g, goal_ref_buffer& result) override { From ed27ce5526bb4b42407579eb9622b9dd6251e9e7 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 31 Jul 2021 11:41:55 -0700 Subject: [PATCH 084/125] fix regression in goal2sat Signed-off-by: Nikolaj Bjorner --- src/sat/tactic/goal2sat.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/sat/tactic/goal2sat.cpp b/src/sat/tactic/goal2sat.cpp index bdc1b8b9e..c809ba0f8 100644 --- a/src/sat/tactic/goal2sat.cpp +++ b/src/sat/tactic/goal2sat.cpp @@ -304,16 +304,16 @@ struct goal2sat::imp : public sat::sat_internalizer { convert_euf(t, root, sign); return; } - else if (!is_uninterp_const(t)) { - if (!is_app(t)) { - std::ostringstream strm; - strm << mk_ismt2_pp(t, m); - throw_op_not_handled(strm.str()); - } - else - m_unhandled_funs.push_back(to_app(t)->get_decl()); - } else { + if (!is_uninterp_const(t)) { + if (!is_app(t)) { + std::ostringstream strm; + strm << mk_ismt2_pp(t, m); + throw_op_not_handled(strm.str()); + } + m_unhandled_funs.push_back(to_app(t)->get_decl()); + } + v = mk_bool_var(t); l = sat::literal(v, sign); bool ext = m_default_external || !is_uninterp_const(t) || m_interface_vars.contains(t); From 8b887cb0b8477d2d14d8272d7a391e2b4d60efd0 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 31 Jul 2021 11:46:26 -0700 Subject: [PATCH 085/125] Update coverage.yml --- .github/workflows/coverage.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index 5600a57e2..5ad96d596 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -24,7 +24,7 @@ jobs: - name: Configure CMake # Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make. # See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type - run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} + run: CXXFLAGS=--coverage LDFLAGS=-lgcov CC=clang CXX=clang++ cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DCMAKE_INSTALL_PREFIX=./install -G "Ninja" ../ - name: Build # Build your program with the given configuration From a2bd1d8fa288d3dee6dab9d438b81862057928ee Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 31 Jul 2021 11:51:00 -0700 Subject: [PATCH 086/125] Update coverage.yml --- .github/workflows/coverage.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index 5ad96d596..09a2f6f1d 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -24,7 +24,8 @@ jobs: - name: Configure CMake # Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make. # See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type - run: CXXFLAGS=--coverage LDFLAGS=-lgcov CC=clang CXX=clang++ cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DCMAKE_INSTALL_PREFIX=./install -G "Ninja" ../ + # run: CXXFLAGS=--coverage LDFLAGS=-lgcov CC=clang CXX=clang++ cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DCMAKE_INSTALL_PREFIX=./install -G "Ninja" ../ + run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} - name: Build # Build your program with the given configuration From 07283ddea9aedbe4fda7154f308d28509161630f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 31 Jul 2021 11:53:30 -0700 Subject: [PATCH 087/125] Update coverage.yml --- .github/workflows/coverage.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index 09a2f6f1d..356e170b0 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -25,7 +25,7 @@ jobs: # Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make. # See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type # run: CXXFLAGS=--coverage LDFLAGS=-lgcov CC=clang CXX=clang++ cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DCMAKE_INSTALL_PREFIX=./install -G "Ninja" ../ - run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} + run: CC=clang CXX=clang++ cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} - name: Build # Build your program with the given configuration From 2046907aaa23dac12aa93d7ce3136745eb10e721 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 31 Jul 2021 11:57:03 -0700 Subject: [PATCH 088/125] Update coverage.yml --- .github/workflows/coverage.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index 356e170b0..54e0c6f10 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -25,7 +25,7 @@ jobs: # Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make. # See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type # run: CXXFLAGS=--coverage LDFLAGS=-lgcov CC=clang CXX=clang++ cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DCMAKE_INSTALL_PREFIX=./install -G "Ninja" ../ - run: CC=clang CXX=clang++ cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} + run: CXXFLAGS=--coverage LDFLAGS=-lgcov CC=clang CXX=clang++ cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} - name: Build # Build your program with the given configuration From 8f362872294dba1064cb095ef0a109f82c6a6a02 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 31 Jul 2021 12:00:15 -0700 Subject: [PATCH 089/125] Update coverage.yml --- .github/workflows/coverage.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index 54e0c6f10..f8fe1083d 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -25,7 +25,7 @@ jobs: # Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make. # See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type # run: CXXFLAGS=--coverage LDFLAGS=-lgcov CC=clang CXX=clang++ cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DCMAKE_INSTALL_PREFIX=./install -G "Ninja" ../ - run: CXXFLAGS=--coverage LDFLAGS=-lgcov CC=clang CXX=clang++ cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} + run: CXXFLAGS=--coverage LDFLAGS=-lgcov CC=clang CXX=clang++ cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DCMAKE_INSTALL_PREFIX=./install -G "Ninja" ${{github.workspace}} - name: Build # Build your program with the given configuration From f17131fd065112016b69a1800bce03d1b3b48ac1 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 31 Jul 2021 12:01:39 -0700 Subject: [PATCH 090/125] Update coverage.yml --- .github/workflows/coverage.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index f8fe1083d..2ee5f6df3 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -24,8 +24,8 @@ jobs: - name: Configure CMake # Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make. # See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type - # run: CXXFLAGS=--coverage LDFLAGS=-lgcov CC=clang CXX=clang++ cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DCMAKE_INSTALL_PREFIX=./install -G "Ninja" ../ - run: CXXFLAGS=--coverage LDFLAGS=-lgcov CC=clang CXX=clang++ cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DCMAKE_INSTALL_PREFIX=./install -G "Ninja" ${{github.workspace}} + # run: CXXFLAGS=--coverage LDFLAGS=-lgcov CC=clang CXX=clang++ cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DCMAKE_INSTALL_PREFIX=./install -G "Ninja" ${{github.workspace}} + run: CXXFLAGS=--coverage LDFLAGS=-lgcov CC=clang CXX=clang++ cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DCMAKE_INSTALL_PREFIX=./install - name: Build # Build your program with the given configuration From 42b3254c46424d26c092ab98551f0cea1ee5a19f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 31 Jul 2021 12:36:32 -0700 Subject: [PATCH 091/125] Update coverage.yml --- .github/workflows/coverage.yml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index 2ee5f6df3..7efc4d0d2 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -31,6 +31,15 @@ jobs: # Build your program with the given configuration run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} + - name: Clone z3test + run: git clone https://github.com/z3prover/z3test z3test + + - name: Run regressions + run: python z3test/scripts/test_benchmarks.py build/z3 z3test/regressions/smt2 + + - name: Run coverage + run: python z3test/scripts/test_coverage_tests.py build/install z3test/coverage/cpp + - name: Test working-directory: ${{github.workspace}}/build # Execute tests defined by the CMake configuration. From efa82fa4f053b6cb3f3cabdf264d0b291b107582 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 31 Jul 2021 13:13:22 -0700 Subject: [PATCH 092/125] Update coverage.yml --- .github/workflows/coverage.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index 7efc4d0d2..3d5e0fb78 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -29,13 +29,13 @@ jobs: - name: Build # Build your program with the given configuration - run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} + run: cmake --build ${{github.workspace}}/build --install --config ${{env.BUILD_TYPE}} - name: Clone z3test run: git clone https://github.com/z3prover/z3test z3test - - name: Run regressions - run: python z3test/scripts/test_benchmarks.py build/z3 z3test/regressions/smt2 + # - name: Run regressions + # run: python z3test/scripts/test_benchmarks.py build/z3 z3test/regressions/smt2 - name: Run coverage run: python z3test/scripts/test_coverage_tests.py build/install z3test/coverage/cpp From 173257b4a0511da4e4a9ba0c2f0edf3d72071628 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 31 Jul 2021 13:15:11 -0700 Subject: [PATCH 093/125] Update coverage.yml --- .github/workflows/coverage.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index 3d5e0fb78..b68bf1068 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -29,7 +29,7 @@ jobs: - name: Build # Build your program with the given configuration - run: cmake --build ${{github.workspace}}/build --install --config ${{env.BUILD_TYPE}} + run: cmake --build ${{github.workspace}}/build --target install --config ${{env.BUILD_TYPE}} - name: Clone z3test run: git clone https://github.com/z3prover/z3test z3test From 84e628cf7444e5723797e25223372a8369431063 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 31 Jul 2021 13:49:37 -0700 Subject: [PATCH 094/125] Update coverage.yml --- .github/workflows/coverage.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index b68bf1068..63307d98e 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -38,7 +38,7 @@ jobs: # run: python z3test/scripts/test_benchmarks.py build/z3 z3test/regressions/smt2 - name: Run coverage - run: python z3test/scripts/test_coverage_tests.py build/install z3test/coverage/cpp + run: python z3test/scripts/test_coverage_tests.py ./install z3test/coverage/cpp - name: Test working-directory: ${{github.workspace}}/build From ada873631e8ee7b65cc07ee12c5d45ad481f2f94 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 31 Jul 2021 14:56:20 -0700 Subject: [PATCH 095/125] Update coverage.yml --- .github/workflows/coverage.yml | 20 +++----------------- 1 file changed, 3 insertions(+), 17 deletions(-) diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index 63307d98e..85639bd95 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -1,4 +1,4 @@ -name: CodeCoverage +name: Code Coverage on: push: @@ -7,24 +7,16 @@ on: branches: [ master ] env: - # Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.) BUILD_TYPE: Debug jobs: build: - # The CMake configure and build commands are platform agnostic and should work equally - # well on Windows or Mac. You can convert this to a matrix build if you need - # cross-platform coverage. - # See: https://docs.github.com/en/free-pro-team@latest/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: Configure CMake - # Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make. - # See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type - # run: CXXFLAGS=--coverage LDFLAGS=-lgcov CC=clang CXX=clang++ cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DCMAKE_INSTALL_PREFIX=./install -G "Ninja" ${{github.workspace}} run: CXXFLAGS=--coverage LDFLAGS=-lgcov CC=clang CXX=clang++ cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DCMAKE_INSTALL_PREFIX=./install - name: Build @@ -34,15 +26,9 @@ jobs: - name: Clone z3test run: git clone https://github.com/z3prover/z3test z3test - # - name: Run regressions - # run: python z3test/scripts/test_benchmarks.py build/z3 z3test/regressions/smt2 + - name: Run regressions + run: python z3test/scripts/test_benchmarks.py build/z3 z3test/regressions/smt2 - name: Run coverage run: python z3test/scripts/test_coverage_tests.py ./install z3test/coverage/cpp - - - name: Test - working-directory: ${{github.workspace}}/build - # Execute tests defined by the CMake configuration. - # See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail - run: ctest -C ${{env.BUILD_TYPE}} From b723e1093b81391deb66ff7a2cff7ec0e267e635 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 31 Jul 2021 13:01:02 -0700 Subject: [PATCH 096/125] misc warnings Signed-off-by: Nikolaj Bjorner --- src/muz/spacer/spacer_manager.cpp | 2 +- src/sat/smt/euf_model.cpp | 1 + src/sat/smt/fpa_solver.cpp | 1 - src/smt/theory_str.cpp | 12 ++++++------ 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/muz/spacer/spacer_manager.cpp b/src/muz/spacer/spacer_manager.cpp index ba20e5f24..e8d769621 100644 --- a/src/muz/spacer/spacer_manager.cpp +++ b/src/muz/spacer/spacer_manager.cpp @@ -247,7 +247,7 @@ bool is_zk_const (const app *a, int &n) { } bool sk_lt_proc::operator()(const app *a1, const app *a2) { if (a1 == a2) return false; - int n1, n2; + int n1 = 0, n2 = 0; bool z1, z2; z1 = is_zk_const(a1, n1); z2 = is_zk_const(a2, n2); diff --git a/src/sat/smt/euf_model.cpp b/src/sat/smt/euf_model.cpp index 412aec533..d2fa19eee 100644 --- a/src/sat/smt/euf_model.cpp +++ b/src/sat/smt/euf_model.cpp @@ -284,6 +284,7 @@ namespace euf { tout << "Failed to validate " << n->bool_var() << " " << bpp(n) << " " << mdl(e) << "\n"; s().display(tout); tout << mdl << "\n";); + (void)first; first = false; } diff --git a/src/sat/smt/fpa_solver.cpp b/src/sat/smt/fpa_solver.cpp index 13837d0ce..590929a91 100644 --- a/src/sat/smt/fpa_solver.cpp +++ b/src/sat/smt/fpa_solver.cpp @@ -121,7 +121,6 @@ namespace fpa { bool solver::post_visit(expr* e, bool sign, bool root) { euf::enode* n = expr2enode(e); - app* a = to_app(e); SASSERT(!n || !n->is_attached_to(get_id())); if (!n) n = mk_enode(e, false); diff --git a/src/smt/theory_str.cpp b/src/smt/theory_str.cpp index 6705d40e4..0b772f17d 100644 --- a/src/smt/theory_str.cpp +++ b/src/smt/theory_str.cpp @@ -1859,18 +1859,18 @@ namespace smt { axiomatized_terms.insert(ex); TRACE("str", tout << "instantiate str.from_code axiom for " << mk_pp(ex, m) << std::endl;); - expr * arg; - u.str.is_from_code(ex, arg); + expr * arg = nullptr; + VERIFY(u.str.is_from_code(ex, arg)); // (str.from_code N) == "" if N is not in the range [0, max_char]. { - expr_ref premise(m.mk_or(m_autil.mk_le(arg, mk_int(-1)), m_autil.mk_ge(arg, mk_int(u.max_char() + 1))), m); + expr_ref premise(m.mk_or(m_autil.mk_le(arg, mk_int(-1)), m_autil.mk_ge(arg, mk_int(u.max_char() + 1))), m); expr_ref conclusion(ctx.mk_eq_atom(ex, mk_string("")), m); expr_ref axiom(rewrite_implication(premise, conclusion), m); assert_axiom_rw(axiom); } // len (str.from_code N) == 1 if N is in the range [0, max_char]. { - expr_ref premise(m.mk_and(m_autil.mk_ge(arg, mk_int(0)), m_autil.mk_le(arg, mk_int(u.max_char() + 1))), m); + expr_ref premise(m.mk_and(m_autil.mk_ge(arg, mk_int(0)), m_autil.mk_le(arg, mk_int(u.max_char() + 1))), m); expr_ref conclusion(ctx.mk_eq_atom(mk_strlen(ex), mk_int(1)), m); expr_ref axiom(rewrite_implication(premise, conclusion), m); assert_axiom_rw(axiom); @@ -1895,8 +1895,8 @@ namespace smt { axiomatized_terms.insert(ex); TRACE("str", tout << "instantiate str.to_code axiom for " << mk_pp(ex, m) << std::endl;); - expr * arg; - u.str.is_to_code(ex, arg); + expr * arg = nullptr; + VERIFY(u.str.is_to_code(ex, arg)); // (str.to_code S) == -1 if len(S) != 1. { expr_ref premise(m.mk_not(ctx.mk_eq_atom(mk_strlen(arg), mk_int(1))), m); From eefde76bd4a1b71d0316f4f644ad8d0f24df170a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 31 Jul 2021 13:54:00 -0700 Subject: [PATCH 097/125] na --- src/smt/smt_model_generator.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/smt/smt_model_generator.cpp b/src/smt/smt_model_generator.cpp index 9422c2963..dcdb9a198 100644 --- a/src/smt/smt_model_generator.cpp +++ b/src/smt/smt_model_generator.cpp @@ -389,8 +389,7 @@ namespace smt { if (fid == null_family_id) return !m_hidden_ufs.contains(f); if (fid == m.get_basic_family_id()) return false; theory * th = m_context->get_theory(fid); - if (!th) return true; - return th->include_func_interp(f); + return !th || th->include_func_interp(f); } /** From 55f56037144528ec239704d5741fa74824288024 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 31 Jul 2021 17:16:52 -0700 Subject: [PATCH 098/125] remove coverage job from azure-pipeline as it is now in a self-contained action Signed-off-by: Nikolaj Bjorner --- azure-pipelines.yml | 24 ------------------------ 1 file changed, 24 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 3db84ce71..6c1cac8d5 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -5,7 +5,6 @@ variables: cmakeNet: '-DZ3_BUILD_DOTNET_BINDINGS=True' cmakePy: '-DZ3_BUILD_PYTHON_BINDINGS=True' cmakeStdArgs: '-DZ3_BUILD_DOTNET_BINDINGS=True -DZ3_BUILD_JAVA_BINDINGS=True -DZ3_BUILD_PYTHON_BINDINGS=True -G "Ninja" ../' - cmakeCovArgs: '-DCMAKE_INSTALL_PREFIX=./install -G "Ninja" ../' asanEnv: 'CXXFLAGS="${CXXFLAGS} -fsanitize=address -fno-omit-frame-pointer" CFLAGS="${CFLAGS} -fsanitize=address -fno-omit-frame-pointer"' ubsanEnv: 'CXXFLAGS="${CXXFLAGS} -fsanitize=undefined" CFLAGS="${CFLAGS} -fsanitize=undefined"' msanEnv: 'CC=clang LDFLAGS="-L../libcxx/libcxx_msan/lib -lc++abi -Wl,-rpath=../libcxx/libcxx_msan/lib" CXX=clang++ CXXFLAGS="${CXXFLAGS} -stdlib=libc++ -fsanitize-memory-track-origins -fsanitize=memory -fPIE -fno-omit-frame-pointer -g -O2" CFLAGS="${CFLAGS} -stdlib=libc -fsanitize=memory -fsanitize-memory-track-origins -fno-omit-frame-pointer -g -O2"' @@ -150,29 +149,6 @@ jobs: # - template: scripts/test-java-cmake.yml - ${{if eq(variables['runTests'], 'True')}}: - template: scripts/test-regressions.yml - - -- job: "Ubuntu16CMakeCoverage" - displayName: "Ubuntu build - cmake w/ coverage" - pool: - vmImage: "ubuntu-latest" - steps: - - script: sudo apt-get install ninja-build - - script: | - set -e - mkdir build - cd build - CXXFLAGS=--coverage LDFLAGS=-lgcov CC=clang CXX=clang++ cmake -DCMAKE_BUILD_TYPE=Debug $(cmakeCovArgs) - ninja - ninja test-z3 - ninja install - cd .. - - script: | - cd build - ./test-z3 -a - cd .. - - template: scripts/test-examples-cmake.yml - - template: scripts/test-regressions-coverage.yml - job: "WindowsLatest" From f5a08cc54e41de2b624a318096dfeedfe82aef31 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 31 Jul 2021 17:57:36 -0700 Subject: [PATCH 099/125] add wip Signed-off-by: Nikolaj Bjorner --- .github/workflows/wip.yml | 30 ++++++++++++++++++++++++++++++ src/ast/fpa/fpa2bv_converter.cpp | 1 + 2 files changed, 31 insertions(+) create mode 100644 .github/workflows/wip.yml diff --git a/.github/workflows/wip.yml b/.github/workflows/wip.yml new file mode 100644 index 000000000..4173d7985 --- /dev/null +++ b/.github/workflows/wip.yml @@ -0,0 +1,30 @@ +name: Open Issues + +on: + push: + branches: [ master ] + +env: + BUILD_TYPE: Debug + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + + - name: Configure CMake + run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} + + - name: Build + # Build your program with the given configuration + run: cmake --build ${{github.workspace}}/build --target install --config ${{env.BUILD_TYPE}} + + - name: Clone z3test + run: git clone https://github.com/z3prover/z3test z3test + + - name: Run regressions + run: python z3test/scripts/test_benchmarks.py build/z3 z3test/regressions/issues + + diff --git a/src/ast/fpa/fpa2bv_converter.cpp b/src/ast/fpa/fpa2bv_converter.cpp index a654e6070..243e3b378 100644 --- a/src/ast/fpa/fpa2bv_converter.cpp +++ b/src/ast/fpa/fpa2bv_converter.cpp @@ -3815,6 +3815,7 @@ void fpa2bv_converter::mk_rounding_mode(decl_kind k, expr_ref & result) } result = m_util.mk_bv2rm(result); + std::cout << "Rounding: " << result << "\n"; } void fpa2bv_converter::dbg_decouple(const char * prefix, expr_ref & e) { From 5b32c3778f4e5c84f1e282712a76ca0b6f2e2f12 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 31 Jul 2021 18:00:37 -0700 Subject: [PATCH 100/125] remove out Signed-off-by: Nikolaj Bjorner --- src/ast/fpa/fpa2bv_converter.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/ast/fpa/fpa2bv_converter.cpp b/src/ast/fpa/fpa2bv_converter.cpp index 243e3b378..a654e6070 100644 --- a/src/ast/fpa/fpa2bv_converter.cpp +++ b/src/ast/fpa/fpa2bv_converter.cpp @@ -3815,7 +3815,6 @@ void fpa2bv_converter::mk_rounding_mode(decl_kind k, expr_ref & result) } result = m_util.mk_bv2rm(result); - std::cout << "Rounding: " << result << "\n"; } void fpa2bv_converter::dbg_decouple(const char * prefix, expr_ref & e) { From b3e63638f2a991aba2be1bf020c2135ca49a7c44 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 31 Jul 2021 18:02:13 -0700 Subject: [PATCH 101/125] Update README.md --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 681ef24d5..1eda3db92 100644 --- a/README.md +++ b/README.md @@ -14,9 +14,9 @@ See the [release notes](RELEASE_NOTES) for notes on various stable releases of Z ## Build status -| Azure Pipelines | Code Coverage | -| --------------- | --------------| -| [![Build Status](https://dev.azure.com/Z3Public/Z3/_apis/build/status/Z3Prover.z3?branchName=master)](https://dev.azure.com/Z3Public/Z3/_build/latest?definitionId=1&branchName=master) | [![CodeCoverage](https://github.com/Z3Prover/z3/actions/workflows/coverage.yml/badge.svg)](https://github.com/Z3Prover/z3/actions/workflows/coverage.yml) | +| Azure Pipelines | Code Coverage | Open Bugs | +| --------------- | --------------|-----------| +| [![Build Status](https://dev.azure.com/Z3Public/Z3/_apis/build/status/Z3Prover.z3?branchName=master)](https://dev.azure.com/Z3Public/Z3/_build/latest?definitionId=1&branchName=master) | [![CodeCoverage](https://github.com/Z3Prover/z3/actions/workflows/coverage.yml/badge.svg)](https://github.com/Z3Prover/z3/actions/workflows/coverage.yml) | [![Open Issues](https://github.com/Z3Prover/z3/actions/workflows/wip.yml/badge.svg)](https://github.com/Z3Prover/z3/actions/workflows/wip.yml) | [1]: #building-z3-on-windows-using-visual-studio-command-prompt [2]: #building-z3-using-make-and-gccclang From e148eea35d392c7ca9a5193894f7edd335006757 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 31 Jul 2021 18:54:37 -0700 Subject: [PATCH 102/125] Update wip.yml --- .github/workflows/wip.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/wip.yml b/.github/workflows/wip.yml index 4173d7985..e0129757b 100644 --- a/.github/workflows/wip.yml +++ b/.github/workflows/wip.yml @@ -19,7 +19,7 @@ jobs: - name: Build # Build your program with the given configuration - run: cmake --build ${{github.workspace}}/build --target install --config ${{env.BUILD_TYPE}} + run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} - name: Clone z3test run: git clone https://github.com/z3prover/z3test z3test From 490dc66ec2fa6780f5e117bb3224e202b53fd921 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 1 Aug 2021 05:05:45 -0700 Subject: [PATCH 103/125] remove sine filter #5446 Signed-off-by: Nikolaj Bjorner --- src/tactic/CMakeLists.txt | 2 - src/tactic/sine_filter.cpp | 236 ------------------------------------- src/tactic/sine_filter.h | 30 ----- 3 files changed, 268 deletions(-) delete mode 100644 src/tactic/sine_filter.cpp delete mode 100644 src/tactic/sine_filter.h diff --git a/src/tactic/CMakeLists.txt b/src/tactic/CMakeLists.txt index 495078afc..114e4f849 100644 --- a/src/tactic/CMakeLists.txt +++ b/src/tactic/CMakeLists.txt @@ -12,7 +12,6 @@ z3_add_component(tactic probe.cpp proof_converter.cpp replace_proof_converter.cpp - sine_filter.cpp tactical.cpp tactic.cpp COMPONENT_DEPENDENCIES @@ -20,7 +19,6 @@ z3_add_component(tactic model TACTIC_HEADERS probe.h - sine_filter.h tactic.h PYG_FILES tactic_params.pyg diff --git a/src/tactic/sine_filter.cpp b/src/tactic/sine_filter.cpp deleted file mode 100644 index 781150a6a..000000000 --- a/src/tactic/sine_filter.cpp +++ /dev/null @@ -1,236 +0,0 @@ -/*++ -Copyright (c) 2016 Microsoft Corporation - -Module Name: - - sine_filter.cpp - -Abstract: - - Tactic that performs Sine Qua Non premise selection - -Author: - - Doug Woos - -Revision History: ---*/ - -#include "tactic/sine_filter.h" -#include "tactic/tactical.h" -#include "tactic/generic_model_converter.h" -#include "ast/datatype_decl_plugin.h" -#include "ast/rewriter/rewriter_def.h" -#include "ast/rewriter/var_subst.h" -#include "ast/ast_util.h" -#include "util/obj_pair_hashtable.h" -#include "ast/ast_pp.h" - -class sine_tactic : public tactic { - - ast_manager& m; - params_ref m_params; - -public: - - sine_tactic(ast_manager& m, params_ref const& p): - m(m), m_params(p) {} - - tactic * translate(ast_manager & m) override { - return alloc(sine_tactic, m, m_params); - } - - void updt_params(params_ref const & p) override { - } - - void collect_param_descrs(param_descrs & r) override { - } - - void operator()(goal_ref const & g, goal_ref_buffer& result) override { - 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), nullptr, nullptr); - } - g->inc_depth(); - g->updt_prec(goal::OVER); - result.push_back(g.get()); - TRACE("sine", result[0]->display(tout);); - SASSERT(g->is_well_formed()); - } - - void cleanup() override { - } - -private: - - 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) && is_uninterp(curr)) { - app *a = to_app(curr); - func_decl *f = a->get_decl(); - consts.insert_if_not_there(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 (func_decl* f : consts) tout << f->get_name() << "\n";); - - bool matched = false; - for (unsigned i = 0; i < q->get_num_patterns(); i++) { - bool p_matched = true; - ptr_vector stack; - expr * curr; - - // patterns are wrapped with "pattern" - if (!m.is_pattern(q->get_pattern(i), stack)) - continue; - - 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 << mk_pp(f, m) << "\n";); - p_matched = false; - next_consts.push_back(f); - break; - } - for (unsigned 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; - t_work_item curr; - - for (unsigned i = 0; i < g->size(); i++) - stack.push_back(work_item(g->form(i), g->form(i))); - - while (!stack.empty()) { - curr = stack.back(); - stack.pop_back(); - if (is_app(curr.first) && is_uninterp(curr.first)) { - app * a = to_app(curr.first); - func_decl * f = a->get_decl(); - if (!consts.contains(f)) { - consts.insert(f); - if (const2quantifier.contains(f)) { - for (auto const& p : const2quantifier[f]) - stack.push_back(p); - 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 (unsigned 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 (is_forall(q)) { - 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 (is_exists(q)) { - 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); - if (!exp2const.contains(visiting)) - continue; - for (func_decl* f : exp2const[visiting]) - for (expr* e : const2exp[f]) { - if (!visited.contains(e)) - to_visit.push_back(e); - } - } - - for (unsigned 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 deleted file mode 100644 index d7e5ed59a..000000000 --- a/src/tactic/sine_filter.h +++ /dev/null @@ -1,30 +0,0 @@ -/*++ -Copyright (c) 2016 Microsoft Corporation - -Module Name: - - sine_filter.h - -Abstract: - - Tactic that performs Sine Qua Non premise selection - -Author: - - Doug Woos - -Revision History: - ---*/ -#pragma once - -#include "util/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)") -*/ - From 50f5cafb5048e788ce6b314db68ed2bd838b6972 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 1 Aug 2021 05:09:58 -0700 Subject: [PATCH 104/125] fix #5446 Signed-off-by: Nikolaj Bjorner --- src/tactic/arith/fm_tactic.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tactic/arith/fm_tactic.cpp b/src/tactic/arith/fm_tactic.cpp index 44b771d53..f87261dcf 100644 --- a/src/tactic/arith/fm_tactic.cpp +++ b/src/tactic/arith/fm_tactic.cpp @@ -162,7 +162,7 @@ class fm_tactic : public tactic { fm_model_converter(ast_manager & _m):m(_m) {} ~fm_model_converter() override { - m.dec_array_ref(m_xs.size(), m_xs.data()); + m.dec_array_ref(m_xs.size(), m_xs.data()); vector::iterator it = m_clauses.begin(); vector::iterator end = m_clauses.end(); for (; it != end; ++it) @@ -1598,7 +1598,7 @@ class fm_tactic : public tactic { report_tactic_progress(":fm-cost", m_counter); if (!m_inconsistent) { copy_remaining(); - m_new_goal->add(concat(g->mc(), m_mc.get())); + m_new_goal->add(m_mc.get()); } } reset_constraints(); From 924ea6ab3102e078e868d54998cc7b10530ed6d6 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 1 Aug 2021 12:00:22 -0700 Subject: [PATCH 105/125] #5429 again --- src/sat/smt/euf_internalize.cpp | 6 +++--- src/sat/smt/euf_solver.cpp | 7 ++++--- src/sat/tactic/goal2sat.cpp | 6 ++---- 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/src/sat/smt/euf_internalize.cpp b/src/sat/smt/euf_internalize.cpp index 5576cb8d2..f44967885 100644 --- a/src/sat/smt/euf_internalize.cpp +++ b/src/sat/smt/euf_internalize.cpp @@ -34,7 +34,8 @@ namespace euf { sat::literal solver::mk_literal(expr* e) { expr_ref _e(e, m); - return internalize(e, false, false, m_is_redundant); + bool is_not = m.is_not(e, e); + return internalize(e, is_not, false, m_is_redundant); } sat::literal solver::internalize(expr* e, bool sign, bool root, bool redundant) { @@ -129,8 +130,7 @@ namespace euf { sat::literal solver::attach_lit(literal lit, expr* e) { sat::bool_var v = lit.var(); s().set_external(v); - s().set_eliminated(v, false); - + s().set_eliminated(v, false); if (lit.sign()) { v = si.add_bool_var(e); diff --git a/src/sat/smt/euf_solver.cpp b/src/sat/smt/euf_solver.cpp index cbdc44743..9c652ac10 100644 --- a/src/sat/smt/euf_solver.cpp +++ b/src/sat/smt/euf_solver.cpp @@ -236,7 +236,7 @@ namespace euf { sat::bool_var v = get_egraph().explain_diseq(m_explain, a, b); SASSERT(v == sat::null_bool_var || s().value(v) == l_false); if (v != sat::null_bool_var) - m_explain.push_back(to_ptr(sat::literal(v, false))); + m_explain.push_back(to_ptr(sat::literal(v, true))); } bool solver::propagate(enode* a, enode* b, ext_justification_idx idx) { @@ -286,13 +286,14 @@ namespace euf { void solver::asserted(literal l) { expr* e = m_bool_var2expr.get(l.var(), nullptr); - TRACE("euf", tout << "asserted: " << l << "@" << s().scope_lvl() << " := " << mk_bounded_pp(e, m) << "\n";); + TRACE("euf", tout << "asserted: " << l << "@" << s().scope_lvl() << " := " << mk_bounded_pp(e, m) << "\n";); if (!e) return; + euf::enode* n = m_egraph.find(e); if (!n) return; - bool sign = l.sign(); + bool sign = l.sign(); m_egraph.set_value(n, sign ? l_false : l_true); for (auto th : enode_th_vars(n)) m_id2solver[th.get_id()]->asserted(l); diff --git a/src/sat/tactic/goal2sat.cpp b/src/sat/tactic/goal2sat.cpp index c809ba0f8..a5c60d3db 100644 --- a/src/sat/tactic/goal2sat.cpp +++ b/src/sat/tactic/goal2sat.cpp @@ -290,14 +290,12 @@ struct goal2sat::imp : public sat::sat_internalizer { if (v == sat::null_bool_var) { if (m.is_true(t)) { sat::literal tt = sat::literal(add_var(false, m.mk_true()), false); - mk_clause(tt); - add_dual_root(1, &tt); + mk_root_clause(tt); l = sign ? ~tt : tt; } else if (m.is_false(t)) { sat::literal tt = sat::literal(add_var(false, m.mk_false()), true); - mk_clause(tt); - add_dual_root(1, &tt); + mk_root_clause(tt); l = sign ? tt : ~tt; } else if (m_euf) { From a4cc9e789540ffbf46af41e5c25bc2ff1993ec57 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 1 Aug 2021 12:49:36 -0700 Subject: [PATCH 106/125] #5429 #5445 --- src/math/simplex/model_based_opt.cpp | 3 +-- src/qe/mbp/mbp_arith.cpp | 8 ++++++++ src/sat/smt/euf_solver.cpp | 26 ++++++++++++++++---------- 3 files changed, 25 insertions(+), 12 deletions(-) diff --git a/src/math/simplex/model_based_opt.cpp b/src/math/simplex/model_based_opt.cpp index 83e83cfe7..1acbb592b 100644 --- a/src/math/simplex/model_based_opt.cpp +++ b/src/math/simplex/model_based_opt.cpp @@ -1261,8 +1261,7 @@ namespace opt { m_var2value[x] = eval(result); TRACE("opt1", tout << "updated eval " << x << " := " << eval(x) << "\n";); } - else - retire_row(row_id1); + retire_row(row_id1); return result; } diff --git a/src/qe/mbp/mbp_arith.cpp b/src/qe/mbp/mbp_arith.cpp index a2101e2d1..8b855a758 100644 --- a/src/qe/mbp/mbp_arith.cpp +++ b/src/qe/mbp/mbp_arith.cpp @@ -319,6 +319,14 @@ namespace mbp { tids.insert(v, mbo.add_var(r, a.is_int(v))); } } + + // bail on variables in non-linear sub-terms + for (auto& kv : tids) { + expr* e = kv.m_key; + if (is_arith(e) && !var_mark.is_marked(e)) + mark_rec(fmls_mark, e); + } + if (m_check_purified) { for (expr* fml : fmls) mark_rec(fmls_mark, fml); diff --git a/src/sat/smt/euf_solver.cpp b/src/sat/smt/euf_solver.cpp index 9c652ac10..739cbf9b7 100644 --- a/src/sat/smt/euf_solver.cpp +++ b/src/sat/smt/euf_solver.cpp @@ -288,8 +288,7 @@ namespace euf { expr* e = m_bool_var2expr.get(l.var(), nullptr); TRACE("euf", tout << "asserted: " << l << "@" << s().scope_lvl() << " := " << mk_bounded_pp(e, m) << "\n";); if (!e) - return; - + return; euf::enode* n = m_egraph.find(e); if (!n) return; @@ -303,21 +302,28 @@ namespace euf { SASSERT(l == get_literal(c)); if (n->value_conflict()) { euf::enode* nb = sign ? mk_false() : mk_true(); + euf::enode* r = n->get_root(); + euf::enode* rb = sign ? mk_true() : mk_false(); + sat::literal rl(r->bool_var(), r->value() == l_false); m_egraph.merge(n, nb, c); + m_egraph.merge(r, rb, to_ptr(rl)); + SASSERT(m_egraph.inconsistent()); return; } if (n->merge_tf()) { euf::enode* nb = sign ? mk_false() : mk_true(); m_egraph.merge(n, nb, c); } - if (!sign && n->is_equality()) { - SASSERT(!m.is_iff(e)); - euf::enode* na = n->get_arg(0); - euf::enode* nb = n->get_arg(1); - m_egraph.merge(na, nb, c); - } - else if (sign && n->is_equality()) - m_egraph.new_diseq(n); + if (n->is_equality()) { + if (sign) + m_egraph.new_diseq(n); + else { + SASSERT(!m.is_iff(e)); + euf::enode* na = n->get_arg(0); + euf::enode* nb = n->get_arg(1); + m_egraph.merge(na, nb, c); + } + } } From 123c44639564455ff09490446b8c0abbca807533 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 1 Aug 2021 13:03:40 -0700 Subject: [PATCH 107/125] fix #5449 --- src/util/mpq.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/util/mpq.cpp b/src/util/mpq.cpp index 296fd6886..ed73e21f0 100644 --- a/src/util/mpq.cpp +++ b/src/util/mpq.cpp @@ -260,6 +260,7 @@ void mpq_manager::set(mpq & a, char const * val) { if (exp > 0) { _scoped_numeral> _exp(*this); _scoped_numeral> _qten(*this); + _qten = 10; power(_qten, static_cast(exp), _exp); TRACE("mpq_set", tout << "a: " << to_string(a) << ", exp_sign:" << exp_sign << ", exp: " << exp << " " << to_string(_exp) << std::endl;); if (exp_sign) From e3be25dad611df6772b15bcb91039f9b2908f741 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 1 Aug 2021 16:48:25 -0700 Subject: [PATCH 108/125] #5445 --- src/sat/smt/euf_internalize.cpp | 5 +- src/sat/smt/euf_solver.cpp | 114 ++++++++++++++++++++++++++++++-- src/sat/smt/euf_solver.h | 8 ++- src/sat/smt/sat_dual_solver.cpp | 4 +- src/sat/tactic/goal2sat.cpp | 2 +- 5 files changed, 120 insertions(+), 13 deletions(-) diff --git a/src/sat/smt/euf_internalize.cpp b/src/sat/smt/euf_internalize.cpp index f44967885..020d29baa 100644 --- a/src/sat/smt/euf_internalize.cpp +++ b/src/sat/smt/euf_internalize.cpp @@ -35,7 +35,10 @@ namespace euf { sat::literal solver::mk_literal(expr* e) { expr_ref _e(e, m); bool is_not = m.is_not(e, e); - return internalize(e, is_not, false, m_is_redundant); + sat::literal lit = internalize(e, false, false, m_is_redundant); + if (is_not) + lit.neg(); + return lit; } sat::literal solver::internalize(expr* e, bool sign, bool root, bool redundant) { diff --git a/src/sat/smt/euf_solver.cpp b/src/sat/smt/euf_solver.cpp index 739cbf9b7..d2ae0a0dd 100644 --- a/src/sat/smt/euf_solver.cpp +++ b/src/sat/smt/euf_solver.cpp @@ -561,14 +561,11 @@ namespace euf { scoped_set_replay replay(*this); scoped_suspend_rlimit suspend_rlimit(m.limit()); - for (auto const& t : m_reinit) - replay.m.insert(std::get<0>(t), std::get<2>(t)); - + for (auto const& [e, generation, v] : m_reinit) + replay.m.insert(e, v); + TRACE("euf", for (auto const& kv : replay.m) tout << kv.m_value << "\n";); - for (auto const& t : m_reinit) { - expr_ref e = std::get<0>(t); - unsigned generation = std::get<1>(t); - sat::bool_var v = std::get<2>(t); + for (auto const& [e, generation, v] : m_reinit) { scoped_generation _sg(*this, generation); TRACE("euf", tout << "replay: " << v << " " << mk_bounded_pp(e, m) << "\n";); sat::literal lit; @@ -579,9 +576,112 @@ namespace euf { VERIFY(lit.var() == v); attach_lit(lit, e); } + + if (relevancy_enabled()) + for (auto const& [e, generation, v] : m_reinit) + if (si.is_bool_op(e)) + relevancy_reinit(e); TRACE("euf", display(tout << "replay done\n");); } + /** + * Boolean structure needs to be replayed for relevancy tracking. + * Main cases for replaying Boolean functions are included. When a replay + * is not supported, we just disable relevancy. + */ + void solver::relevancy_reinit(expr* e) { + TRACE("euf", tout << "internalize again " << mk_pp(e, m) << "\n";); + if (to_app(e)->get_family_id() != m.get_basic_family_id()) { + disable_relevancy(e); + return; + } + auto lit = si.internalize(e, true); + switch (to_app(e)->get_decl_kind()) { + case OP_NOT: { + auto lit2 = si.internalize(to_app(e)->get_arg(0), true); + add_aux(lit, lit2); + add_aux(~lit, ~lit2); + break; + } + case OP_EQ: { + if (to_app(e)->get_num_args() != 2) { + disable_relevancy(e); + return; + } + auto lit1 = si.internalize(to_app(e)->get_arg(0), true); + auto lit2 = si.internalize(to_app(e)->get_arg(1), true); + add_aux(~lit, ~lit1, lit2); + add_aux(~lit, lit1, ~lit2); + add_aux(lit, lit1, lit2); + add_aux(lit, ~lit1, ~lit2); + break; + } + case OP_OR: { + sat::literal_vector lits; + for (expr* arg : *to_app(e)) + lits.push_back(si.internalize(arg, true)); + for (auto lit2 : lits) + add_aux(~lit2, lit); + lits.push_back(~lit); + add_aux(lits); + break; + } + case OP_AND: { + sat::literal_vector lits; + for (expr* arg : *to_app(e)) + lits.push_back(~si.internalize(arg, true)); + for (auto nlit2 : lits) + add_aux(~lit, ~nlit2); + lits.push_back(lit); + add_aux(lits); + break; + } + case OP_TRUE: + add_root(lit); + break; + case OP_FALSE: + add_root(~lit); + break; + case OP_ITE: { + auto lit1 = si.internalize(to_app(e)->get_arg(0), true); + auto lit2 = si.internalize(to_app(e)->get_arg(1), true); + auto lit3 = si.internalize(to_app(e)->get_arg(2), true); + add_aux(~lit, ~lit1, lit2); + add_aux(~lit, lit1, lit3); + add_aux(lit, ~lit1, ~lit2); + add_aux(lit, lit1, ~lit3); + break; + } + case OP_XOR: { + if (to_app(e)->get_num_args() != 2) { + disable_relevancy(e); + break; + } + auto lit1 = si.internalize(to_app(e)->get_arg(0), true); + auto lit2 = si.internalize(to_app(e)->get_arg(1), true); + add_aux(lit, ~lit1, lit2); + add_aux(lit, lit1, ~lit2); + add_aux(~lit, lit1, lit2); + add_aux(~lit, ~lit1, ~lit2); + break; + } + case OP_IMPLIES: { + if (to_app(e)->get_num_args() != 2) { + disable_relevancy(e); + break; + } + auto lit1 = si.internalize(to_app(e)->get_arg(0), true); + auto lit2 = si.internalize(to_app(e)->get_arg(1), true); + add_aux(~lit, ~lit1, lit2); + add_aux(lit, lit1); + add_aux(lit, ~lit2); + break; + } + default: + UNREACHABLE(); + } + } + void solver::pre_simplify() { for (auto* e : m_solvers) e->pre_simplify(); diff --git a/src/sat/smt/euf_solver.h b/src/sat/smt/euf_solver.h index cf8b9766e..5f3b62781 100644 --- a/src/sat/smt/euf_solver.h +++ b/src/sat/smt/euf_solver.h @@ -134,8 +134,9 @@ namespace euf { typedef std::tuple reinit_t; vector m_reinit; - void start_reinit(unsigned num_scopes); + void start_reinit(unsigned num_scopes); void finish_reinit(); + void relevancy_reinit(expr* e); // extensions th_solver* get_solver(family_id fid, func_decl* f); @@ -356,7 +357,9 @@ namespace euf { bool is_shared(euf::enode* n) const; // relevancy - bool relevancy_enabled() const { return get_config().m_relevancy_lvl > 0; } + bool m_relevancy = true; + bool relevancy_enabled() const { return m_relevancy && get_config().m_relevancy_lvl > 0; } + void disable_relevancy(expr* e) { IF_VERBOSE(0, verbose_stream() << "disabling relevancy " << mk_pp(e, m) << "\n"); m_relevancy = false; } void add_root(unsigned n, sat::literal const* lits); void add_root(sat::literal_vector const& lits) { add_root(lits.size(), lits.data()); } void add_root(sat::literal lit) { add_root(1, &lit); } @@ -364,6 +367,7 @@ namespace euf { void add_aux(sat::literal_vector const& lits) { add_aux(lits.size(), lits.data()); } void add_aux(unsigned n, sat::literal const* lits); void add_aux(sat::literal a, sat::literal b) { sat::literal lits[2] = {a, b}; add_aux(2, lits); } + void add_aux(sat::literal a, sat::literal b, sat::literal c) { sat::literal lits[3] = { a, b, c }; add_aux(3, lits); } void track_relevancy(sat::bool_var v); bool is_relevant(expr* e) const; bool is_relevant(enode* n) const; diff --git a/src/sat/smt/sat_dual_solver.cpp b/src/sat/smt/sat_dual_solver.cpp index e16b09ed1..00d01b1b7 100644 --- a/src/sat/smt/sat_dual_solver.cpp +++ b/src/sat/smt/sat_dual_solver.cpp @@ -106,11 +106,11 @@ namespace sat { } void dual_solver::add_aux(unsigned sz, literal const* clause) { - flush(); - TRACE("dual", tout << "aux: " << literal_vector(sz, clause) << "\n";); + flush(); m_lits.reset(); for (unsigned i = 0; i < sz; ++i) m_lits.push_back(ext2lit(clause[i])); + TRACE("dual", tout << "aux: " << literal_vector(sz, clause) << " -> " << m_lits << "\n";); m_solver.mk_clause(sz, m_lits.data(), status::input()); } diff --git a/src/sat/tactic/goal2sat.cpp b/src/sat/tactic/goal2sat.cpp index a5c60d3db..4d0cc7880 100644 --- a/src/sat/tactic/goal2sat.cpp +++ b/src/sat/tactic/goal2sat.cpp @@ -796,7 +796,7 @@ struct goal2sat::imp : public sat::sat_internalizer { m_frame_stack.pop_back(); continue; } - if (m.is_not(t) && !m.is_not(t->get_arg(0))) { + if (m.is_not(t) && !m.is_not(t->get_arg(0)) && fsz != sz + 1) { m_frame_stack.pop_back(); visit(t->get_arg(0), root, !sign); continue; From da8530e2dbc601b87c64548565ecde95e0f96ea1 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 2 Aug 2021 09:03:15 -0700 Subject: [PATCH 109/125] #5447 That the bug went away is a fluke. It wasnt fixed. It is in pb-preprocess, an essentially unused tactic. The special subsumption resolution rule wasn't accounting for membership of all variables. --- src/tactic/core/pb_preprocess_tactic.cpp | 33 ++++++++++++++---------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/src/tactic/core/pb_preprocess_tactic.cpp b/src/tactic/core/pb_preprocess_tactic.cpp index 87f10dfc2..5b889efe6 100644 --- a/src/tactic/core/pb_preprocess_tactic.cpp +++ b/src/tactic/core/pb_preprocess_tactic.cpp @@ -199,7 +199,7 @@ public: expr* fml = g->form(m_ge[i]); if (!to_ge(fml, args1, coeffs1, k1)) continue; if (args1.empty()) continue; - expr* arg = args1[0].get(); + expr* arg = args1.get(0); bool neg = m.is_not(arg, arg); if (!is_uninterp_const(arg)) continue; if (!m_vars.contains(to_app(arg))) continue; @@ -478,24 +478,28 @@ private: expr_ref_vector args1(m), args2(m); vector coeffs1, coeffs2; rational k1, k2; - if (!to_ge(fml1, args1, coeffs1, k1)) return; - if (!k1.is_one()) return; - if (!to_ge(g->form(idx2), args2, coeffs2, k2)) return; + if (!to_ge(fml1, args1, coeffs1, k1) || !k1.is_one()) + return; + if (!to_ge(fml2, args2, coeffs2, k2)) + return; // check that each variable in idx1 occurs only in idx2 unsigned min_index = 0; rational min_coeff(0); unsigned_vector indices; for (unsigned i = 0; i < args1.size(); ++i) { - expr* x = args1[i].get(); + expr* x = args1.get(i); m.is_not(x, x); - if (!is_app(x)) return; - if (!m_vars.contains(to_app(x))) return; + if (!is_app(x) || !m_vars.contains(to_app(x))) + return; TRACE("pb", tout << mk_pp(x, m) << "\n";); rec const& r = m_vars.find(to_app(x)); - if (r.pos.size() != 1 || r.neg.size() != 1) return; - if (r.pos[0] != idx2 && r.neg[0] != idx2) return; + if (r.pos.size() != 1 || r.neg.size() != 1) + return; + if (r.pos[0] != idx2 && r.neg[0] != idx2) + return; + bool found = false; for (unsigned j = 0; j < args2.size(); ++j) { - if (is_complement(args1[i].get(), args2[j].get())) { + if (is_complement(args1.get(i), args2.get(j))) { if (i == 0) { min_coeff = coeffs2[j]; } @@ -504,12 +508,15 @@ private: min_index = j; } indices.push_back(j); + found = true; } } + if (!found) + return; } for (unsigned i = 0; i < indices.size(); ++i) { unsigned j = indices[i]; - expr* arg = args2[j].get(); + expr* arg = args2.get(j); if (j == min_index) { args2[j] = m.mk_false(); } @@ -521,9 +528,7 @@ private: tmp1 = pb.mk_ge(args2.size(), coeffs2.data(), args2.data(), k2); IF_VERBOSE(3, verbose_stream() << " " << tmp1 << "\n"; - for (unsigned i = 0; i < args2.size(); ++i) { - verbose_stream() << mk_pp(args2[i].get(), m) << " "; - } + verbose_stream() << args2 << "\n"; verbose_stream() << "\n"; ); m_r(tmp1, tmp2); From 6c0a79057664cc4099c75eb8a135a8289a31390b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 2 Aug 2021 09:22:54 -0700 Subject: [PATCH 110/125] #5445 --- src/sat/smt/bv_solver.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/sat/smt/bv_solver.cpp b/src/sat/smt/bv_solver.cpp index 4df92596e..d030394a8 100644 --- a/src/sat/smt/bv_solver.cpp +++ b/src/sat/smt/bv_solver.cpp @@ -478,6 +478,9 @@ namespace bv { if (!assign_bit(bit2, v1, v2, idx, bit1, false)) break; } + if (s().value(m_bits[v1][m_wpos[v1]]) != l_undef) + find_wpos(v1); + return num_assigned > 0; } From d3194bb8a8263e7a69459838b2100924fb441f9a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 2 Aug 2021 11:07:28 -0700 Subject: [PATCH 111/125] #5445 --- src/sat/smt/q_solver.cpp | 8 ++++++-- src/sat/smt/sat_dual_solver.cpp | 13 +++++++++---- src/sat/tactic/goal2sat.cpp | 14 ++++++++------ 3 files changed, 23 insertions(+), 12 deletions(-) diff --git a/src/sat/smt/q_solver.cpp b/src/sat/smt/q_solver.cpp index 5769340ee..0f3eaf3d3 100644 --- a/src/sat/smt/q_solver.cpp +++ b/src/sat/smt/q_solver.cpp @@ -54,6 +54,11 @@ namespace q { ctx.add_root(~l, lit); } } + else if (is_ground(q->get_expr())) { + auto lit = ctx.internalize(q->get_expr(), l.sign(), false, false); + add_clause(~l, lit); + ctx.add_root(~l, lit); + } else { ctx.push_vec(m_universal, l); if (ctx.get_config().m_ematching) @@ -78,8 +83,7 @@ namespace q { } std::ostream& solver::display(std::ostream& out) const { - m_ematch.display(out); - return out; + return m_ematch.display(out); } std::ostream& solver::display_constraint(std::ostream& out, sat::ext_constraint_idx idx) const { diff --git a/src/sat/smt/sat_dual_solver.cpp b/src/sat/smt/sat_dual_solver.cpp index 00d01b1b7..dcc90ddb0 100644 --- a/src/sat/smt/sat_dual_solver.cpp +++ b/src/sat/smt/sat_dual_solver.cpp @@ -93,14 +93,19 @@ namespace sat { void dual_solver::add_root(unsigned sz, literal const* clause) { flush(); - if (sz == 1) { + if (false && sz == 1) { TRACE("dual", tout << "unit: " << clause[0] << "\n";); m_units.push_back(clause[0]); return; } - literal root(m_solver.mk_var(), false); - for (unsigned i = 0; i < sz; ++i) - m_solver.mk_clause(root, ~ext2lit(clause[i]), status::input()); + literal root; + if (sz == 1) + root = ext2lit(clause[0]); + else { + root = literal(m_solver.mk_var(), false); + for (unsigned i = 0; i < sz; ++i) + m_solver.mk_clause(root, ~ext2lit(clause[i]), status::input()); + } m_roots.push_back(~root); TRACE("dual", tout << "root: " << ~root << " => " << literal_vector(sz, clause) << "\n";); } diff --git a/src/sat/tactic/goal2sat.cpp b/src/sat/tactic/goal2sat.cpp index 4d0cc7880..ddc13f06a 100644 --- a/src/sat/tactic/goal2sat.cpp +++ b/src/sat/tactic/goal2sat.cpp @@ -216,8 +216,10 @@ struct goal2sat::imp : public sat::sat_internalizer { if (!m_expr2var_replay || !m_expr2var_replay->find(t, v)) v = add_var(true, t); m_map.insert(t, v); - if (relevancy_enabled() && (m.is_true(t) || m.is_false(t))) + if (relevancy_enabled() && (m.is_true(t) || m.is_false(t))) { add_dual_root(sat::literal(v, m.is_false(t))); + ensure_euf()->track_relevancy(v); + } return v; } @@ -289,14 +291,14 @@ struct goal2sat::imp : public sat::sat_internalizer { sat::bool_var v = m_map.to_bool_var(t); if (v == sat::null_bool_var) { if (m.is_true(t)) { - sat::literal tt = sat::literal(add_var(false, m.mk_true()), false); + sat::literal tt = sat::literal(mk_bool_var(t), false); mk_root_clause(tt); l = sign ? ~tt : tt; } else if (m.is_false(t)) { - sat::literal tt = sat::literal(add_var(false, m.mk_false()), true); - mk_root_clause(tt); - l = sign ? tt : ~tt; + sat::literal ff = sat::literal(mk_bool_var(t), false); + mk_root_clause(~ff); + l = sign ? ~ff : ff; } else if (m_euf) { convert_euf(t, root, sign); @@ -796,7 +798,7 @@ struct goal2sat::imp : public sat::sat_internalizer { m_frame_stack.pop_back(); continue; } - if (m.is_not(t) && !m.is_not(t->get_arg(0)) && fsz != sz + 1) { + if (m.is_not(t) && (root || (!m.is_not(t->get_arg(0)) && fsz != sz + 1))) { m_frame_stack.pop_back(); visit(t->get_arg(0), root, !sign); continue; From fcb55257beede8e5882f20e04de5537341b90acb Mon Sep 17 00:00:00 2001 From: 0152la Date: Mon, 2 Aug 2021 20:01:41 +0100 Subject: [PATCH 112/125] Improve coverage CI script (#5451) * Due to the long duration of the CI execution, execute it at a set time daily (currently 11 UTC / 4 PDT) * Use `Ninja` to build instead of Makefile, due to better compilation time * Execute all the available Z3 tests and examples: `test-z3 -a`, `z3test` regression suites (`smt2`, `smt2-debug`, and `smt2-extra`), `z3test` coverage tests, and the 4 provided examples * Upload `gcovr` report as an artifact associated with the CI run TODOs: * Fix `gcovr` emitting an empty report * Potentially take the artifact and upload it somewhere accessible Co-authored-by: Andrei Lascu --- .github/workflows/coverage.yml | 82 ++++++++++++++++++++++++++++------ 1 file changed, 69 insertions(+), 13 deletions(-) diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index 85639bd95..e5b19bebd 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -1,34 +1,90 @@ name: Code Coverage on: - push: - branches: [ master ] - pull_request: - branches: [ master ] + #push: + #branches: [ master ] + schedule: + - cron: "0 11 * * *" env: BUILD_TYPE: Debug + CMAKE_GENERATOR: Ninja jobs: build: runs-on: ubuntu-latest + env: + CC: clang + CXX: clang++ + steps: - uses: actions/checkout@v2 - - name: Configure CMake - run: CXXFLAGS=--coverage LDFLAGS=-lgcov CC=clang CXX=clang++ cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DCMAKE_INSTALL_PREFIX=./install + - name: Setup + run: | + sudo apt-get remove -y --purge man-db + sudo apt-get update -y + sudo apt-get install -y gcovr ninja-build - - name: Build + ## Building + - name: Configure CMake Z3 + run: CFLAGS=="--coverage" CXXFLAGS="--coverage" LDFLAGS="-lgcov" cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DCMAKE_INSTALL_PREFIX=./install + + - name: Build Z3 # Build your program with the given configuration run: cmake --build ${{github.workspace}}/build --target install --config ${{env.BUILD_TYPE}} + - name: Build test-z3 + run: cmake --build ${{github.workspace}}/build --target test-z3 --config ${{env.BUILD_TYPE}} + + - name: Build examples + run: | + cmake --build ${{github.workspace}}/build --target c_example + cmake --build ${{github.workspace}}/build --target cpp_example + cmake --build ${{github.workspace}}/build --target z3_tptp5 + cmake --build ${{github.workspace}}/build --target c_maxsat_example + - name: Clone z3test run: git clone https://github.com/z3prover/z3test z3test - + + ## Testing + - name: Run test-z3 + run: | + cd ${{github.workspace}}/build + ./test-z3 -a + cd - + + - name: Run examples + run: | + ${{github.workspace}}/build/examples/c_example_build_dir/c_example + ${{github.workspace}}/build/examples/cpp_example_build_dir/cpp_example + ${{github.workspace}}/build/examples/tptp_build_dir/z3_tptp5 --help + ${{github.workspace}}/build/examples/c_maxsat_example_build_dir/c_maxsat_example ${{github.workspace}}/examples/maxsat/ex.smt + - name: Run regressions - run: python z3test/scripts/test_benchmarks.py build/z3 z3test/regressions/smt2 - - - name: Run coverage - run: python z3test/scripts/test_coverage_tests.py ./install z3test/coverage/cpp - + run: | + python z3test/scripts/test_benchmarks.py build/z3 z3test/regressions/smt2 + python z3test/scripts/test_benchmarks.py build/z3 z3test/regressions/smt2-debug + python z3test/scripts/test_benchmarks.py build/z3 z3test/regressions/smt2-extra + + - name: Run coverage tests + run: python z3test/scripts/test_coverage_tests.py ./install z3test/coverage/cpp + + ## Artifact + - name: Gather coverage + run: | + cd ${{github.workspace}} + gcovr + #gcovr --html -o coverage.html . + cd - + + - name: Get date + id: date + run: echo "::set-output name=date::$(date +'%Y-%m-%d')" + + - uses: actions/upload-artifact@v2 + with: + name: coverage-${{steps.date.outputs.date}} + path: coverage.html + retention-days: 10 From 7f6f7eff1ee1294b9d8c8dd10434129b44356b70 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 2 Aug 2021 13:45:17 -0700 Subject: [PATCH 113/125] Update coverage.yml --- .github/workflows/coverage.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index e5b19bebd..0833a0837 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -1,8 +1,8 @@ name: Code Coverage on: - #push: - #branches: [ master ] + push: + branches: [ master ] schedule: - cron: "0 11 * * *" From fc36fb115ffa782d7e55091231ce7018008ca0b7 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 2 Aug 2021 12:05:54 -0700 Subject: [PATCH 114/125] format Signed-off-by: Nikolaj Bjorner --- src/sat/tactic/goal2sat.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/sat/tactic/goal2sat.cpp b/src/sat/tactic/goal2sat.cpp index ddc13f06a..9be810e9d 100644 --- a/src/sat/tactic/goal2sat.cpp +++ b/src/sat/tactic/goal2sat.cpp @@ -275,7 +275,6 @@ struct goal2sat::imp : public sat::sat_internalizer { } } - void cache(app* t, sat::literal l) override { force_push(); SASSERT(!m_app2lit.contains(t)); @@ -284,8 +283,8 @@ struct goal2sat::imp : public sat::sat_internalizer { m_lit2app.insert(l.index(), t); m_cache_trail.push_back(t); } - - void convert_atom(expr * t, bool root, bool sign) { + + void convert_atom(expr * t, bool root, bool sign) { SASSERT(m.is_bool(t)); sat::literal l; sat::bool_var v = m_map.to_bool_var(t); From 4aaf026b49803d5859bad2fe709434e7bba57f8c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 2 Aug 2021 12:30:26 -0700 Subject: [PATCH 115/125] format --- src/sat/smt/euf_solver.h | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/sat/smt/euf_solver.h b/src/sat/smt/euf_solver.h index 5f3b62781..e8e707897 100644 --- a/src/sat/smt/euf_solver.h +++ b/src/sat/smt/euf_solver.h @@ -96,27 +96,27 @@ namespace euf { stats m_stats; th_rewriter m_rewriter; func_decl_ref_vector m_unhandled_functions; - sat::lookahead* m_lookahead{ nullptr }; + sat::lookahead* m_lookahead = nullptr; ast_manager* m_to_m; sat::sat_internalizer* m_to_si; scoped_ptr m_ackerman; scoped_ptr m_dual_solver; - user::solver* m_user_propagator{ nullptr }; - th_solver* m_qsolver { nullptr }; - unsigned m_generation { 0 }; + user::solver* m_user_propagator = nullptr; + th_solver* m_qsolver = nullptr; + unsigned m_generation = 0; mutable ptr_vector m_todo; ptr_vector m_bool_var2expr; ptr_vector m_explain; - unsigned m_num_scopes{ 0 }; + unsigned m_num_scopes = 0; unsigned_vector m_var_trail; svector m_scopes; scoped_ptr_vector m_solvers; ptr_vector m_id2solver; - constraint* m_conflict{ nullptr }; - constraint* m_eq{ nullptr }; - constraint* m_lit{ nullptr }; + constraint* m_conflict = nullptr; + constraint* m_eq = nullptr; + constraint* m_lit = nullptr; // internalization bool visit(expr* e) override; From 1173c93150b06000e1b51ee1ffe9cc73f370400c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 2 Aug 2021 17:13:47 -0700 Subject: [PATCH 116/125] #5140 --- src/ast/rewriter/seq_rewriter.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/ast/rewriter/seq_rewriter.cpp b/src/ast/rewriter/seq_rewriter.cpp index ff4f62533..6bf44f4ba 100644 --- a/src/ast/rewriter/seq_rewriter.cpp +++ b/src/ast/rewriter/seq_rewriter.cpp @@ -672,6 +672,14 @@ br_status seq_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * con SASSERT(num_args == 3); st = mk_seq_replace_all(args[0], args[1], args[2], result); break; + case OP_SEQ_REPLACE_RE: + SASSERT(num_args == 3); + st = mk_seq_replace_re(args[0], args[1], args[2], result); + break; + case OP_SEQ_REPLACE_RE_ALL: + SASSERT(num_args == 3); + st = mk_seq_replace_re_all(args[0], args[1], args[2], result); + break; case OP_SEQ_TO_RE: SASSERT(num_args == 1); st = mk_str_to_regexp(args[0], result); @@ -1904,6 +1912,8 @@ br_status seq_rewriter::mk_seq_replace_all(expr* a, expr* b, expr* c, expr_ref& result = str().mk_concat(strs, a->get_sort()); return BR_REWRITE_FULL; } + // TBD: add case when a, b are concatenation of units that are values. + // in this case we can use a similar loop as for strings. return BR_FAILED; } @@ -1915,7 +1925,6 @@ br_status seq_rewriter::mk_seq_replace_re(expr* a, expr* b, expr* c, expr_ref& r return BR_FAILED; } - br_status seq_rewriter::mk_seq_prefix(expr* a, expr* b, expr_ref& result) { TRACE("seq", tout << mk_pp(a, m()) << " " << mk_pp(b, m()) << "\n";); zstring s1, s2; @@ -3347,6 +3356,7 @@ expr_ref seq_rewriter::mk_derivative_rec(expr* ele, expr* r) { // '0' <= elem <= '9' // if ((isdigit ele) and (ele = (hd r1))) then (to_re (tl r1)) else [] // + hd = str().mk_nth_i(r1, m_autil.mk_int(0)); m_br.mk_and(u().mk_le(m_util.mk_char('0'), ele), u().mk_le(ele, m_util.mk_char('9')), m().mk_eq(hd, ele), result); tl = re().mk_to_re(str().mk_substr(r1, m_autil.mk_int(1), m_autil.mk_sub(str().mk_length(r1), m_autil.mk_int(1)))); return re_and(result, tl); From f333d78f0198e21bb91ba5a4ee9012e60332f2eb Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 2 Aug 2021 20:41:34 -0700 Subject: [PATCH 117/125] #5445 --- src/sat/sat_simplifier.cpp | 1 + src/sat/sat_simplifier.h | 6 ++++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/sat/sat_simplifier.cpp b/src/sat/sat_simplifier.cpp index faa940869..7a6957467 100644 --- a/src/sat/sat_simplifier.cpp +++ b/src/sat/sat_simplifier.cpp @@ -656,6 +656,7 @@ namespace sat { s.propagate_core(false); // must not use propagate(), since s.m_clauses is not in a consistent state. if (s.inconsistent()) return; + m_use_list.reserve(s.num_vars()); unsigned new_trail_sz = s.m_trail.size(); for (unsigned i = old_trail_sz; i < new_trail_sz; i++) { literal l = s.m_trail[i]; diff --git a/src/sat/sat_simplifier.h b/src/sat/sat_simplifier.h index 0b512275e..a1bd18901 100644 --- a/src/sat/sat_simplifier.h +++ b/src/sat/sat_simplifier.h @@ -40,15 +40,17 @@ namespace sat { class use_list { vector m_use_list; + public: void init(unsigned num_vars); + void reserve(unsigned num_vars) { while (m_use_list.size() <= 2*num_vars) m_use_list.push_back(clause_use_list()); } void insert(clause & c); void block(clause & c); void unblock(clause & c); void erase(clause & c); void erase(clause & c, literal l); - clause_use_list & get(literal l) { return m_use_list[l.index()]; } - clause_use_list const & get(literal l) const { return m_use_list[l.index()]; } + clause_use_list& get(literal l) { return m_use_list[l.index()]; } + clause_use_list const& get(literal l) const { return m_use_list[l.index()]; } void finalize() { m_use_list.finalize(); } std::ostream& display(std::ostream& out, literal l) const { return m_use_list[l.index()].display(out); } }; From 60a25053c6e64f186e987bb1b9736f42a30daa31 Mon Sep 17 00:00:00 2001 From: Felix Yan Date: Tue, 3 Aug 2021 23:29:15 +0800 Subject: [PATCH 118/125] Correct a typo in contrib/ci/README.md (#5453) --- contrib/ci/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/ci/README.md b/contrib/ci/README.md index 8b48ac32e..9a8262e37 100644 --- a/contrib/ci/README.md +++ b/contrib/ci/README.md @@ -43,7 +43,7 @@ the future. * `Z3_CMAKE_GENERATOR` - CMake generator (`Ninja` or `Unix Makefiles`) * `Z3_VERBOSE_BUILD_OUTPUT` - Show compile commands in CMake builds (`0` or `1`) * `Z3_BUILD_LIBZ3_SHARED` - Build Z3 binaries and libraries dynamically/statically (`0` or `1`) -* `Z3_SYSTEM_TEST_GIT_REVISION` - Git revision of [z3test](https://github.com/Z3Prover/z3test). If empty lastest revision will be used. +* `Z3_SYSTEM_TEST_GIT_REVISION` - Git revision of [z3test](https://github.com/Z3Prover/z3test). If empty latest revision will be used. * `Z3_WARNINGS_AS_ERRORS` - Set the `WARNINGS_AS_ERRORS` CMake option passed to Z3 (`OFF`, `ON`, or `SERIOUS_ONLY`) ### Linux From 202ed79a24479a4cc63596c145e87030e12c481f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 3 Aug 2021 11:17:23 -0700 Subject: [PATCH 119/125] #5445 --- src/math/simplex/model_based_opt.cpp | 2 ++ src/sat/smt/euf_solver.cpp | 9 +++------ src/util/sexpr.cpp | 4 +++- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/math/simplex/model_based_opt.cpp b/src/math/simplex/model_based_opt.cpp index 1acbb592b..6c0d48f96 100644 --- a/src/math/simplex/model_based_opt.cpp +++ b/src/math/simplex/model_based_opt.cpp @@ -1227,6 +1227,8 @@ namespace opt { if (m_var2is_int[x] && !a.is_one()) { row& r1 = m_rows[row_id1]; + r1.m_coeff -= r1.m_value; + r1.m_value = 0; vector coeffs; mk_coeffs_without(coeffs, r1.m_vars, x); rational c = mod(-eval(coeffs), a); diff --git a/src/sat/smt/euf_solver.cpp b/src/sat/smt/euf_solver.cpp index d2ae0a0dd..3e1620090 100644 --- a/src/sat/smt/euf_solver.cpp +++ b/src/sat/smt/euf_solver.cpp @@ -315,14 +315,11 @@ namespace euf { m_egraph.merge(n, nb, c); } if (n->is_equality()) { + SASSERT(!m.is_iff(e)); if (sign) m_egraph.new_diseq(n); - else { - SASSERT(!m.is_iff(e)); - euf::enode* na = n->get_arg(0); - euf::enode* nb = n->get_arg(1); - m_egraph.merge(na, nb, c); - } + else + m_egraph.merge(n->get_arg(0), n->get_arg(1), c); } } diff --git a/src/util/sexpr.cpp b/src/util/sexpr.cpp index bebce4273..e20c56234 100644 --- a/src/util/sexpr.cpp +++ b/src/util/sexpr.cpp @@ -185,8 +185,10 @@ void sexpr::display_atom(std::ostream & out) const { } void sexpr::display(std::ostream & out) const { - if (!is_composite()) + if (!is_composite()) { display_atom(out); + return; + } vector > todo; todo.push_back(std::make_pair(static_cast(this), 0)); while (!todo.empty()) { From da60abd84be49bcd3e15b2f9652cb396c9e7f617 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 3 Aug 2021 11:19:42 -0700 Subject: [PATCH 120/125] #5445 --- src/math/simplex/model_based_opt.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/math/simplex/model_based_opt.cpp b/src/math/simplex/model_based_opt.cpp index 6c0d48f96..e63e71be6 100644 --- a/src/math/simplex/model_based_opt.cpp +++ b/src/math/simplex/model_based_opt.cpp @@ -1210,23 +1210,23 @@ namespace opt { model_based_opt::def model_based_opt::solve_for(unsigned row_id1, unsigned x, bool compute_def) { TRACE("opt", tout << "v" << x << " := " << eval(x) << "\n" << m_rows[row_id1] << "\n";); rational a = get_coefficient(row_id1, x), b; - ineq_type ty = m_rows[row_id1].m_type; + row& r1 = m_rows[row_id1]; + ineq_type ty = r1.m_type; SASSERT(!a.is_zero()); - SASSERT(m_rows[row_id1].m_alive); + SASSERT(r1.m_alive); if (a.is_neg()) { a.neg(); - m_rows[row_id1].neg(); + r1.neg(); } SASSERT(a.is_pos()); if (ty == t_lt) { SASSERT(compute_def); - m_rows[row_id1].m_coeff -= m_rows[row_id1].m_value; - m_rows[row_id1].m_type = t_le; - m_rows[row_id1].m_value = 0; + r1.m_coeff -= r1.m_value; + r1.m_type = t_le; + r1.m_value = 0; } - if (m_var2is_int[x] && !a.is_one()) { - row& r1 = m_rows[row_id1]; + if (m_var2is_int[x] && !a.is_one()) { r1.m_coeff -= r1.m_value; r1.m_value = 0; vector coeffs; From 7ae4e93e86b8939680246ff959513dc2178395f5 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 3 Aug 2021 16:45:25 -0700 Subject: [PATCH 121/125] Sharon & Neta notes Signed-off-by: Nikolaj Bjorner --- src/sat/smt/q_mbi.cpp | 17 ++++++++--------- src/sat/smt/q_model_fixer.cpp | 12 ++++++++++++ 2 files changed, 20 insertions(+), 9 deletions(-) diff --git a/src/sat/smt/q_mbi.cpp b/src/sat/smt/q_mbi.cpp index ba6bc77b3..da6fe4191 100644 --- a/src/sat/smt/q_mbi.cpp +++ b/src/sat/smt/q_mbi.cpp @@ -169,9 +169,8 @@ namespace q { return l_false; if (check_forall_default(q, *qb, *mdl)) return l_false; - else { - return l_undef; - } + else + return l_undef; } if (m_generation_bound >= m_generation_max) return l_true; @@ -337,8 +336,8 @@ namespace q { qb.domain_eqs.reset(); var_subst subst(m); - for (auto p : qb.var_args) { - expr_ref bounds = m_model_fixer.restrict_arg(p.first, p.second); + for (auto [t, idx] : qb.var_args) { + expr_ref bounds = m_model_fixer.restrict_arg(t, idx); if (m.is_true(bounds)) continue; expr_ref vbounds = subst(bounds, qb.vars); @@ -393,11 +392,11 @@ namespace q { if (qb.var_args.empty()) return; var_subst subst(m); - for (auto p : qb.var_args) { - expr_ref _term = subst(p.first, qb.vars); + for (auto [t, idx] : qb.var_args) { + expr_ref _term = subst(t, qb.vars); app_ref term(to_app(_term), m); - expr_ref value = (*m_model)(term->get_arg(p.second)); - m_model_fixer.invert_arg(term, p.second, value, qb.domain_eqs); + expr_ref value = (*m_model)(term->get_arg(idx)); + m_model_fixer.invert_arg(term, idx, value, qb.domain_eqs); } } diff --git a/src/sat/smt/q_model_fixer.cpp b/src/sat/smt/q_model_fixer.cpp index c2defc71a..41b6f31fb 100644 --- a/src/sat/smt/q_model_fixer.cpp +++ b/src/sat/smt/q_model_fixer.cpp @@ -111,6 +111,18 @@ namespace q { add_projection_functions(mdl, f); } + /** + * we are given f with interpretation: + * if x = v0 and y = w0 then f0 + * else if x = v1 and y = w1 then f1 + * ... + * Create a new interpretation for f as follows: + * f := f_aux(project1(x), project2(y)) + * f_aux uses the original interpretation of f + * project1 sorts the values of v0, v1, ..., and maps arguments below v0 to v0, between v0, v1 to v1 etc. + * project2 sorts values of w0, w1, ... and maps argument y to values w0, w1, .. + * + */ void model_fixer::add_projection_functions(model& mdl, func_decl* f) { // update interpretation of f so that the graph of f is fully determined by the // ground values of its arguments. From 40f5270ae299043177f91d1988535b783536ab9f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 3 Aug 2021 17:23:41 -0700 Subject: [PATCH 122/125] fix #5452 Signed-off-by: Nikolaj Bjorner --- src/tactic/arith/fm_tactic.cpp | 12 ++++++++---- src/tactic/core/pb_preprocess_tactic.cpp | 5 ++++- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/tactic/arith/fm_tactic.cpp b/src/tactic/arith/fm_tactic.cpp index f87261dcf..9c77dec17 100644 --- a/src/tactic/arith/fm_tactic.cpp +++ b/src/tactic/arith/fm_tactic.cpp @@ -93,7 +93,8 @@ class fm_tactic : public tactic { expr * lhs = to_app(l)->get_arg(0); expr * rhs = to_app(l)->get_arg(1); rational c; - u.is_numeral(rhs, c); + if (!u.is_numeral(rhs, c)) + return NONE; if (neg) c.neg(); unsigned num_mons; @@ -112,7 +113,8 @@ class fm_tactic : public tactic { expr * xi; rational ai_val; if (u.is_mul(monomial, ai, xi)) { - u.is_numeral(ai, ai_val); + if (!u.is_numeral(ai, ai_val)) + return NONE; } else { xi = monomial; @@ -120,7 +122,8 @@ class fm_tactic : public tactic { } if (u.is_to_real(xi)) xi = to_app(xi)->get_arg(0); - SASSERT(is_uninterp_const(xi)); + if (!is_uninterp_const(xi)) + return NONE; if (x == to_app(xi)->get_decl()) { a_val = ai_val; if (neg) @@ -129,7 +132,8 @@ class fm_tactic : public tactic { else { expr_ref val(m); val = ev(monomial); - SASSERT(u.is_numeral(val)); + if (!u.is_numeral(val)) + return NONE; rational tmp; u.is_numeral(val, tmp); if (neg) diff --git a/src/tactic/core/pb_preprocess_tactic.cpp b/src/tactic/core/pb_preprocess_tactic.cpp index 5b889efe6..95638cef7 100644 --- a/src/tactic/core/pb_preprocess_tactic.cpp +++ b/src/tactic/core/pb_preprocess_tactic.cpp @@ -44,6 +44,7 @@ class pb_preprocess_tactic : public tactic { struct rec { unsigned_vector pos, neg; rec() { } }; typedef obj_map var_map; ast_manager& m; + expr_ref_vector m_trail; pb_util pb; var_map m_vars; unsigned_vector m_ge; @@ -99,7 +100,7 @@ class pb_preprocess_tactic : public tactic { public: pb_preprocess_tactic(ast_manager& m, params_ref const& p = params_ref()): - m(m), pb(m), m_r(m) {} + m(m), m_trail(m), pb(m), m_r(m) {} ~pb_preprocess_tactic() override {} @@ -121,6 +122,7 @@ public: g->inc_depth(); result.push_back(g.get()); while (simplify(g, *pp)); + m_trail.reset(); // decompose(g); } @@ -406,6 +408,7 @@ private: void insert(unsigned i, app* e, bool pos) { SASSERT(is_uninterp_const(e)); if (!m_vars.contains(e)) { + m_trail.push_back(e); m_vars.insert(e, rec()); } if (pos) { From 2891ac7dec52f1532768a2ea10fdd3212b02e7bd Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 3 Aug 2021 19:47:38 -0700 Subject: [PATCH 123/125] merge Signed-off-by: Nikolaj Bjorner --- src/tactic/arith/fm_tactic.cpp | 27 ++++++++++----------------- 1 file changed, 10 insertions(+), 17 deletions(-) diff --git a/src/tactic/arith/fm_tactic.cpp b/src/tactic/arith/fm_tactic.cpp index 9c77dec17..4f10b0b3f 100644 --- a/src/tactic/arith/fm_tactic.cpp +++ b/src/tactic/arith/fm_tactic.cpp @@ -132,10 +132,9 @@ class fm_tactic : public tactic { else { expr_ref val(m); val = ev(monomial); - if (!u.is_numeral(val)) - return NONE; rational tmp; - u.is_numeral(val, tmp); + if (!u.is_numeral(val, tmp)) + return NONE; if (neg) tmp.neg(); c -= tmp; @@ -166,11 +165,9 @@ class fm_tactic : public tactic { fm_model_converter(ast_manager & _m):m(_m) {} ~fm_model_converter() override { - m.dec_array_ref(m_xs.size(), m_xs.data()); - vector::iterator it = m_clauses.begin(); - vector::iterator end = m_clauses.end(); - for (; it != end; ++it) - m.dec_array_ref(it->size(), it->data()); + m.dec_array_ref(m_xs.size(), m_xs.data()); + for (auto& c : m_clauses) + m.dec_array_ref(c.size(), c.data()); } void insert(func_decl * x, clauses & c) { @@ -181,6 +178,7 @@ class fm_tactic : public tactic { m_clauses.back().swap(c); } + void get_units(obj_map& units) override { units.reset(); } void operator()(model_ref & md) override { @@ -256,11 +254,8 @@ class fm_tactic : public tactic { for (unsigned i = 0; i < sz; i++) { out << "\n(" << m_xs[i]->get_name(); clauses const & cs = m_clauses[i]; - clauses::const_iterator it = cs.begin(); - clauses::const_iterator end = cs.end(); - for (; it != end; ++it) { - out << "\n " << mk_ismt2_pp(*it, m, 2); - } + for (auto& c : cs) + out << "\n " << mk_ismt2_pp(c, m, 2); out << ")"; } out << ")\n"; @@ -278,10 +273,8 @@ class fm_tactic : public tactic { clauses const & cs = m_clauses[i]; res->m_clauses.push_back(clauses()); clauses & new_cs = res->m_clauses.back(); - clauses::const_iterator it = cs.begin(); - clauses::const_iterator end = cs.end(); - for (; it != end; ++it) { - app * new_c = translator(*it); + for (auto& c : cs) { + app * new_c = translator(c); to_m.inc_ref(new_c); new_cs.push_back(new_c); } From 939860148fdfe914b3832127fc190bc2a008e69f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 3 Aug 2021 20:03:34 -0700 Subject: [PATCH 124/125] #5452 Signed-off-by: Nikolaj Bjorner --- src/tactic/core/pb_preprocess_tactic.cpp | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/tactic/core/pb_preprocess_tactic.cpp b/src/tactic/core/pb_preprocess_tactic.cpp index 95638cef7..720f90543 100644 --- a/src/tactic/core/pb_preprocess_tactic.cpp +++ b/src/tactic/core/pb_preprocess_tactic.cpp @@ -503,10 +503,7 @@ private: bool found = false; for (unsigned j = 0; j < args2.size(); ++j) { if (is_complement(args1.get(i), args2.get(j))) { - if (i == 0) { - min_coeff = coeffs2[j]; - } - else if (min_coeff > coeffs2[j]) { + if (i == 0 || min_coeff > coeffs2[j]) { min_coeff = coeffs2[j]; min_index = j; } @@ -517,9 +514,9 @@ private: if (!found) return; } - for (unsigned i = 0; i < indices.size(); ++i) { - unsigned j = indices[i]; + for (unsigned j : indices) { expr* arg = args2.get(j); + TRACE("pb", tout << "j " << j << " " << min_index << "\n";); if (j == min_index) { args2[j] = m.mk_false(); } From a39d1c61885698042a02efedf4de134e35828a6d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 4 Aug 2021 10:07:29 -0700 Subject: [PATCH 125/125] fix #5456 --- src/tactic/core/pb_preprocess_tactic.cpp | 30 ++++++++++++++---------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/src/tactic/core/pb_preprocess_tactic.cpp b/src/tactic/core/pb_preprocess_tactic.cpp index 720f90543..c9ee5d532 100644 --- a/src/tactic/core/pb_preprocess_tactic.cpp +++ b/src/tactic/core/pb_preprocess_tactic.cpp @@ -44,7 +44,6 @@ class pb_preprocess_tactic : public tactic { struct rec { unsigned_vector pos, neg; rec() { } }; typedef obj_map var_map; ast_manager& m; - expr_ref_vector m_trail; pb_util pb; var_map m_vars; unsigned_vector m_ge; @@ -100,7 +99,7 @@ class pb_preprocess_tactic : public tactic { public: pb_preprocess_tactic(ast_manager& m, params_ref const& p = params_ref()): - m(m), m_trail(m), pb(m), m_r(m) {} + m(m), pb(m), m_r(m) {} ~pb_preprocess_tactic() override {} @@ -122,7 +121,6 @@ public: g->inc_depth(); result.push_back(g.get()); while (simplify(g, *pp)); - m_trail.reset(); // decompose(g); } @@ -141,7 +139,8 @@ public: } for (unsigned i = 0; i < m_ge.size(); ++i) { - classify_vars(i, to_app(g->form(m_ge[i]))); + if (!classify_vars(i, to_app(g->form(m_ge[i])))) + return false; } declassifier dcl(m_vars); @@ -379,15 +378,15 @@ private: } } - void classify_vars(unsigned idx, app* e) { + bool classify_vars(unsigned idx, app* e) { expr* r; if (m.is_not(e, r) && is_uninterp_const(r)) { insert(idx, to_app(r), false); - return; + return true; } if (is_uninterp_const(e)) { insert(idx, e, true); - return; + return true; } for (unsigned i = 0; i < e->get_num_args(); ++i) { expr* arg = e->get_arg(i); @@ -395,20 +394,22 @@ private: // no-op } else if (m.is_not(arg, r)) { - SASSERT(is_uninterp_const(r)); + if (!is_uninterp_const(r)) + return false; insert(idx, to_app(r), false); } else { - SASSERT(is_uninterp_const(arg)); + if (!is_uninterp_const(arg)) + return false; insert(idx, to_app(arg), true); } } + return true; } void insert(unsigned i, app* e, bool pos) { SASSERT(is_uninterp_const(e)); if (!m_vars.contains(e)) { - m_trail.push_back(e); m_vars.insert(e, rec()); } if (pos) { @@ -503,7 +504,10 @@ private: bool found = false; for (unsigned j = 0; j < args2.size(); ++j) { if (is_complement(args1.get(i), args2.get(j))) { - if (i == 0 || min_coeff > coeffs2[j]) { + if (i == 0) { + min_coeff = coeffs2[j]; + } + else if (min_coeff > coeffs2[j]) { min_coeff = coeffs2[j]; min_index = j; } @@ -514,9 +518,9 @@ private: if (!found) return; } - for (unsigned j : indices) { + for (unsigned i = 0; i < indices.size(); ++i) { + unsigned j = indices[i]; expr* arg = args2.get(j); - TRACE("pb", tout << "j " << j << " " << min_index << "\n";); if (j == min_index) { args2[j] = m.mk_false(); }